CampaignRepo is a Git-backed campaign platform for tabletop RPG game masters. Every campaign lives in a normal repository - GitHub or a local folder - and a purpose-built web app turns that repository into a wiki, map viewer, session workspace, relationship graph, calendar, and more. The Markdown files stay portable; nothing requires CampaignRepo to read them.
GMs get version history, private notes, a review queue, and full control over what players see. Players get a clean portal that only exposes approved, player-safe lore - no GitHub account needed.
CampaignRepo is now a usable campaign management app, not just a wiki prototype. It supports local-folder and GitHub-backed campaigns; private GM workspaces; player-safe portals; public published worlds; public campaign discovery and cloning; session planning; quest tracking; fantasy calendars; maps; relationship graphs; manuscripts; boards; lexicons; AI tools; MCP access; full ZIP/JSON campaign backups; and Docker/GHCR deployment.
The next priority is reliability. CampaignRepo's long-term shape is app-first, Git-backed:
- CampaignRepo should feel fast even when GitHub is slow.
- Markdown and repo files remain portable and durable.
- The app should keep a local working copy for live editing.
- Git commits should be batched sync operations, not the hot path for every sidebar move, approval, or page edit.
- Generated files such as
.campaignrepo/index.jsonandwiki/search/index.jsonshould be rebuildable snapshots, not irreplaceable sources of truth.
See ROADMAP.md for the reliability and sync roadmap, including testing, fallbacks, and the biggest hidden risks.
Search across every connected campaign, open a repo, or expand setup tools only when you need them. Once GitHub is connected, setup panels stay collapsed by default.
Each campaign has a workspace with a wiki, maps, relationship graph, timeline, calendar, session board, quest tracker, media manager, settings, and health center. Campaign themes reskin the workspace for any RPG system.
Pages are Markdown with YAML frontmatter. The editor shows source and preview side by side, with a slash-command menu, format toolbar, paste-to-upload images, wiki-link insert, gallery blocks, transclusion, and GM-only blocks.
AI-created, imported, or otherwise unapproved content waits for GM review before it becomes player-visible.
Players see only pages that are both approved and marked player-visible. GM-only blocks, import metadata, and draft content are stripped.
- Stores everything in Git: pages, media, maps, sessions, quests, templates, calendar config, and campaign settings as Markdown and YAML.
- Loads campaign navigation from a generated
.campaignrepo/index.jsonmanifest, so large repos do not need to enumerate every folder or download every Markdown file on startup. - Renders wiki pages with
[[links]], aliases, backlinks, covers, galleries, transclusion, and:::gmsecret blocks. - Provides an interactive map viewer with pins, player/GM layers, nested map links, and article panels.
- Shows a force-directed relationship graph with typed edges, category filters, and a detail panel.
- Tracks quests with objectives, faction clocks, participant links, and arc grouping.
- Runs a session workspace with agenda checklists, pinned pages, GM notes, handout queues, and session-to-event report generation.
- Manages a custom fantasy calendar with configurable months, weekdays, and eras - and a world timeline across sessions and events.
- Keeps a version history for every page with diff and restore-to-editor workflows.
- Publishes a no-login public site for approved, player-visible lore and quests - shareable and cloneable.
- Sends in-app notifications for review requests, assignments, mentions, and watched page changes.
- Imports from Foundry actors and journals, character JSON, Obsidian, Notion, Google Docs, CSV, Roll20, LegendKeeper, World Anvil, and other world/journal exports.
- Exports a full CampaignRepo backup as ZIP or JSON, including pages, media, maps, sessions, quests, search data, templates, and settings.
- Offers AI page generation and full-campaign Q&A over Markdown with citations.
- Exposes an MCP JSON-RPC API for AI tools and external clients.
- Local accounts with username/password login.
- Seeded admin account with forced first-login password change.
- Global admin dashboard for users, campaign memberships, roles, password resets, and disabled accounts.
- Per-campaign GM tools for members, invite links, and player access.
- Owner, GM, and player campaign roles.
- Local folder - no GitHub account required; works offline; compatible with Dropbox, Syncthing, Nextcloud, or OneDrive for optional sync.
- GitHub - version history, offsite backup, collaboration, multi-machine access via GitHub App or personal token.
GitHub-backed campaigns are powerful, but GitHub is not a low-latency database. The roadmap moves routine editing toward a local DB working copy with queued Git sync, so page organization and approvals stay fast while repositories remain the durable archive.
- Markdown pages with YAML frontmatter and structured fields per article type.
- Categories: characters, NPCs, organizations, species, locations, items, events, lore, game notes, and more.
[[Page]]and[[Page|Label]]wiki links, aliases, key links, and backlinks.- Slash-command menu (
/) for headings, tables, code blocks, dividers, GM blocks, transclusion, and task lists. - Paste an image into the editor to upload and insert it in one step.
:::gmGM-only blocks,:::galleryimage grids with lightbox, and:::includetransclusion.- Cover images rendered as article banners.
- Save conflict detection when a file changes after it was opened.
- GM preview, player preview, and handout views.
- In-editor slash commands, format toolbar, and diff-based history restore.
- Upload a map image and place pins that link to wiki pages.
- Organize pins into player-visible or GM-only layers.
- Mark locations discovered/undiscovered and preview the player-safe map view.
- Link pins to nested maps as well as wiki pages.
- Click a pin to open an article panel without leaving the map.
- Pins stored as portable JSON alongside the map image.
- Early UI exists for routes, regions, measuring, and journeys; the full 2.0 map model still needs complete persistence.
- Force-directed SVG graph of all pages as nodes colored by category.
- 20 built-in typed relationships (member-of, located-in, allied-with, parent-of, appears-in-session, and more) with defined inverses.
- Typed edges dashed and labeled on hover; category filter checkboxes and typed-only toggle.
- Click a node to focus: dims unconnected nodes, shows detail panel with outgoing and incoming links.
- Dedicated family-tree route separate from the general relationship graph.
- Shows only family relationships: parent, child, spouse, sibling, guardian, and ward.
- Defaults to hierarchy layout, places spouses beside each other, and uses existing page portraits/images when available.
- Edits write normal relationship frontmatter, so genealogy stays portable in the campaign repo.
- Sessions stored as
wiki/sessions/<slug>.mdwith YAML frontmatter and Markdown notes. - Agenda checklist, pinned pages, status, date, private GM notes, and handout queue with copy-link.
- "Make report page" converts checked agenda items and notes into a wiki event page.
- Next-session widget on the campaign overview dashboard.
- Quests stored as
wiki/quests/<slug>.mdwith status, arc, reward, visibility, objectives, and participant/location links. - Faction clocks: SVG ring segments with click-to-fill and configurable segment count.
- Active quests widget on the campaign overview dashboard.
- Player-visible quests appear in the player portal and public
/site/<slug>view.
- Custom calendar per campaign: configurable months (name + length), weekdays, and era name.
- Tracks the current in-world date with weekday-correct formatting.
- Advance the date by day, week, or month from the calendar view.
- World timeline on the calendar page shows past and future sessions and events sorted by in-world date with a "Now" divider.
- Current date widget on the campaign overview dashboard.
- History tab in the page reader: last 20 commits with date, author, message, SHA, and GitHub diff link.
- Diff viewer: click-to-compare any historical version against the current text, with colored add/remove/unchanged lines.
- Restore: load any historical version into the editor for review before saving.
- Campaign activity feed on the overview dashboard: last 30 repo commits with author, date, and message.
- Configurable widget layout stored in
campaign.yaml. - Widgets: page counts, active quests, next session, current calendar date, recent activity, review queue, and campaign health.
- GMs enable/disable and drag-to-reorder widgets; players get a spoiler-safe view (GM-only widgets are never rendered).
- Scans every page for broken wiki links, invalid parents, parent category mismatches, missing media, duplicate aliases, empty names, unapproved pages, orphaned pages (no incoming links and no parent), and oversized media files.
- Findings grouped by type with severity badges and links to affected pages.
- Inline bulk repair: approve all unapproved, clear invalid parents, and more.
- Table view for pages with filters, sorting, multi-select, and bulk changes for category, visibility, approval, parent, and tags in one commit.
- Media table with name/type/tag/unused filters, sorting, bulk tag add/remove, and bulk delete.
- Single-character JSON imports preserve the original source under
wiki/imports/characters. - Imported pages store the source path, source ID, and stable source hash in frontmatter so later imports can be recognized as new, unchanged, or changed.
- Traveller (Mongoose 2e): characteristics (STR/DEX/END/INT/EDU/SOC) with computed DMs, skills, weapons, armour, equipment, contacts, and credits. Click any characteristic or skill to roll 2D6 + that modifier with an animated result toast.
- D&D 5e: fenced
dnd-sheetYAML blocks render as designed character sheets, and Foundry D&D actor import can create those blocks. - Pathfinder 2e: fenced
dnd-sheetYAML blocks withsystem: pathfinder2render rank-aware skills, saves, actions, feats, equipment, and spell/focus sections. - World of Darkness: fenced
wod-sheetYAML blocks render World of Darkness style sheets. - Traveller has the most complete editor/roller experience today; D&D, Pathfinder, and World of Darkness still need deeper field editors and more print polish.
- GMs publish a no-login public site for any campaign at a stable
/site/<slug>URL. - Public link names can be customized from campaign settings.
- Public sites include approved player-visible pages, media, covers, galleries, wiki links, and player-visible quests.
- Individual pages and quests can also get token-based public share links at
/share/<token>. - Public gallery at
/sitelists all published worlds, sorted by most-cloned, with name and system search. - "Clone this world" copies a published campaign into the viewer's own GitHub repo as a new campaign.
- Fork proposals are available for public-world collaboration; true cross-repo GitHub pull requests are still roadmap work.
Cmd/Ctrl+Kfrom any authenticated screen: search pages, navigate to workspace sections, and find media.
- Foundry Actor JSON and generic character JSON import with optional field mapping and source diffing for re-import.
- Foundry journal, Obsidian, Notion, Google Docs, CSV, Roll20, LegendKeeper, World Anvil, and world export import routes.
- Basic export downloads as ZIP or JSON from the import/export hub.
- Media upload, rename, delete, captions, alt text, tags, and repo-persisted metadata.
- SQLite full-text search, portable
/wiki/search/index.jsonsnapshots, and the repository navigation manifest at/.campaignrepo/index.json. - MCP JSON-RPC endpoint at
/api/mcpwith tools for search, page reads/creates/updates, templates, media, graph data, review queues, and setup instructions.
- Random-table generators for NPCs, settlements, factions, rumors, quests, and encounters.
- Optional OpenAI-compatible endpoint expansion with generated drafts kept unapproved until reviewed.
- Full-campaign Q&A chat over the search index with page citations.
- Review queue for player-visible drafts.
- In-app notifications for review requests, assignments, mentions, and watched page changes.
- Page watches and assignee frontmatter.
- Presence endpoint foundation for future soft locks and live collaboration.
- Per-campaign accent colors, display font, and banner image stored in
campaign.yaml. - Flagship themes for specific RPG systems (Traveller, Dark Ages: Vampire, and others) with curated palettes and campaign title logos.
- Applied to the workspace, player portal, and public site.
Install dependencies and run the development server:
npm install
npm run devOpen:
http://127.0.0.1:3000
The local database seeds this first admin account:
Email: admin@example.local
Password: admin
CampaignRepo forces the seeded admin password to be changed before the dashboard or APIs can be used.
npm run dev # Start local development server
npm run typecheck # TypeScript check
npm test # Run Vitest tests
npm run build # Production build
npm start # Start built Next.js appThe easiest setup path is from the CampaignRepo dashboard:
- Sign in as a global admin.
- Click Connect GitHub.
- Let GitHub create the CampaignRepo GitHub App from the manifest.
- Choose the campaign repositories the app can access.
- Return to CampaignRepo and connect or repair a campaign repo.
CampaignRepo stores the GitHub App configuration in SQLite and uses short-lived installation tokens for repo access.
To create the GitHub App manually, create a new app at:
https://github.com/settings/apps/new
Use these values:
- Homepage URL: your CampaignRepo URL.
- Callback URL:
https://YOUR-CAMPAIGNREPO-HOST/api/github/app/callback. - Setup URL:
https://YOUR-CAMPAIGNREPO-HOST/api/github/app/callback. - Repository permissions:
- Contents: read/write.
- Metadata: read-only.
- Installation access: only the repositories CampaignRepo should manage.
After adding the GITHUB_APP_* environment variables and restarting the app, use Install or update GitHub App access from the dashboard.
CampaignRepo creates and expects this structure inside each campaign repo:
/.campaignrepo
index.json
/wiki
/pages
/media
media.json
/templates/<game-type>
/imports/characters
/sessions
/quests
/maps
/search
index.json
campaign.yaml
README.md
Manual edits are welcome. Preserve YAML frontmatter and CampaignRepo conventions for wiki links, visibility, approvals, and GM-only blocks.
CampaignRepo repositories include a generated manifest at:
.campaignrepo/index.json
The manifest is the fast navigation/index layer for CampaignRepo. It stores page IDs, titles, paths, types, tags, aliases, summaries, visibility, approval status, parent metadata, and link metadata. Markdown files remain the canonical source for page content and frontmatter; the manifest does not duplicate full Markdown bodies.
Normal repository loading uses this pattern:
Open campaign:
1. Fetch .campaignrepo/index.json
2. Build sidebar, tags, links, backlinks, and public navigation from the manifest
Open page:
1. Fetch that one Markdown file
2. Render the page body
If .campaignrepo/index.json is missing, CampaignRepo falls back to wiki/search/index.json and older cache/rebuild paths. Rebuilding the search index also writes the repository manifest. Creating a page through CampaignRepo commits the Markdown file and manifest update together, keeping the repository index consistent.
Generated indexes are disposable. If a manifest, search snapshot, or DB cache disagrees with real page content, the repair path should rebuild generated state from the canonical page source rather than treating the generated file as truth.
The Git Trees API is used for recovery and rebuild paths, not as the normal navigation source. The GitHub Contents API remains suitable for reading or writing a single known file.
Player safety is based on page metadata and GM-only blocks:
visibility: playersmakes a page eligible for player view.approvalStatus: approvedis required before players can see it.:::gmblocks are removed from player reads.- Source import metadata is hidden from player reads.
- Players can read campaign content without GitHub credentials.
Run the prebuilt image from GitHub Container Registry:
docker compose -f docker-compose.image.yml up -dThe published image is:
ghcr.io/avorial/campaignrepo:latest
For Portainer, create a stack from docker-compose.image.yml or use this image in your own compose file. The SQLite database is stored in the campaignrepo-data volume at /app/data.
After the first publish, make the GHCR package public in GitHub Packages if you want unauthenticated pulls.
To build locally instead:
docker compose up -d --buildOpen:
http://127.0.0.1:3000
Useful environment variables:
APP_URL=https://campaignrepo.example.com
SECURE_COOKIES=true
GITHUB_APP_ID=123456
GITHUB_APP_SLUG=your-github-app-slug
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
GOOGLE_CLIENT_ID=your-google-oauth-client-id
GOOGLE_CLIENT_SECRET=your-google-oauth-client-secret
GITHUB_OAUTH_CLIENT_ID=your-github-oauth-client-id
GITHUB_OAUTH_CLIENT_SECRET=your-github-oauth-client-secretSet SECURE_COOKIES=true when serving behind HTTPS so session cookies use the Secure flag.
Google and GitHub login are optional. The Docker image only contains the OAuth code; each server supplies its own credentials at runtime. Use these redirect URLs when creating OAuth clients:
- Google:
https://your-domain.example/api/auth/oauth/google/callback - GitHub OAuth App:
https://your-domain.example/api/auth/oauth/github/callback
GitHub OAuth login requests repo access so it can also act as the user's
GitHub connection inside CampaignRepo. Use the separate GitHub App settings
above if you want repository connection through the install-per-repo flow
instead.
Without Compose:
docker build -t campaignrepo .
docker run -p 3000:3000 -v campaignrepo-data:/app/data campaignrepoFor a local Portainer install, GitOps polling is simpler than a webhook while testing.
Recommended stack settings:
- Repository:
https://github.com/avorial/CampaignRepo.git - Reference:
refs/heads/main - Compose path:
docker-compose.yml - Update method: polling
- Polling interval: 5 minutes
See ROADMAP.md for the current shipped/partial/open feature status, the reliability/sync architecture plan, and the recommended next release sequence.
See LICENSE.




