Roadmap
What's coming, what's being weighed up, and what's already landed. The Tavern's work stays out where you can see it.
Parking lot for disconnected graph nodes
detect nodes with no explicit edges (in or out) and no parent relationship at layout time. Render them in a collapsible right-side tray within the graph wrapper rather than letting dagre float them in leftover space. From the tray, drag...
Stage asset composer: wall/door/lighting geometry + VTT export
Current stage asset composer (BL-079/ADR-0068) handles decorative environmental assets (free placement, scaling, rotation, z-ordering) but treats them all as flat decoration. A richer version would treat walls/doors/windows as...
Richer roadmap description formatting
The roadmap detail field is a plain text column rendered through Kramdown (markdown-to-HTML) on the detail page. It works but is basic -- no persisted structure, no editor affordances, and card/list truncation on plain markdown text can...
AI-generated adventure cover art
in-app "Generate" button on the adventure edit page that calls an image generation API with a DM-written prompt. Needs ADR covering: which API (PixelLab for pixel art vs Replicate/DALL-E/etc. for painterly/illustrative), token storage,...
Activate social OAuth in production
register OAuth apps with Google (console.cloud.google.com), Facebook (developers.facebook.com), and GitHub (github.com/settings/developers). Populate `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `FACEBOOK_APP_ID`, `FACEBOOK_APP_SECRET`,...
User levelling system
XP earned for activity in the Tavern: running sessions, voting on schedules, submitting feature votes, creating articles, adding characters, completing campaigns, etc. Levels unlock cosmetic rewards (profile flair, badge titles, avatar...
Feature voting
users can submit and upvote feature requests. Vote weight is global: DMs (anyone who owns at least one campaign) carry more weight than players. Future extension: bonus votes per session run, rewarding active use. Public roadmap page...
Automated time-advance triggers
tie time advancement to game mechanics: long rest (+8 hours), short rest (+1 hour), travel (distance-based), session start/end. DM configures which actions auto-advance time. Builds on ADR-0031 time-of-day and play surface time controls.
Push character template changes down to existing characters
when a world's character sheet template changes (new attributes added, mechanics tweaked), existing characters don't retroactively pick up the diff. They were seeded at creation, then frozen. For mature systems this is correct...
Global characters
currently Character belongs to a single Campaign. A DM might want a character that exists at the user level and can be played across multiple campaigns/worlds with campaign-specific state per appearance (level, inventory, memories)....
Pantheon system
world-level Pantheon model containing Gods/Deities. Each deity has a name, domains (War, Knowledge, Trickery, etc.), description, alignment, symbol, and associated articles. Domains could be a structured list or link to GameElements....
Rich text editor upgrade (Trix -> Lexical)
Trix doesn't support tables, which means pasted/synced content with markdown tables renders as raw pipe text. Lexical (or similar) would add table support, better block handling, and a more modern editing experience. Key constraint:...
[Honeybadger 131428679] `NoMethodError: undefined method 'attachable' for an instance of Image` on game_sessions#show
the play-surface **lore tab** (`app/views/game_sessions/show.html.erb:195`) called `image.attachable` (an ActionText method) on an `Image` model, whose ActiveStorage attachment is `image.file`....
Article forking
a subject can mean different things per campaign (the Grip of Resolve is one Sevenforged relic, but "Guts bears it + this boon" is campaign-specific canon). Chose **fork over the layer model**...
[Sentinel:v0.10.22] `destroy_article` threw "You cannot call create unless the parent is saved"
root cause was `after_commit :set_references` (Article model) firing on the **destroy** commit: `set_references` calls `reference` → `from_references.create`, and `CollectionAssociation#create`...
Moments rendered raw HTML
`app/views/moments/_moment.html.erb` output `moment.content` with escaping `<%= %>` inside a single `<p>`, so `<strong>`/`<br>`/`<em>` showed as literal text and newlines collapsed (ugly all...
Push-loop out of the DM conversation
`bin/push-loop` now runs `bin/sync-session NNN --push-only` as a detached OS daemon (started by `/txt-session-open` via `nohup`, stopped with `bin/push-loop --stop NNN`). No `/loop`, no in-thread...
Live-session mode for the Archivist
enforced by a `UserPromptSubmit` hook (`.claude/hooks/live-session-mode.sh`, registered in checked-in `.claude/settings.json`), not memory. While `story/sessions/.live-session` exists (created by...
Canon-verification discipline
CLAUDE.md "Conversation Discipline" now carries a "Verify before asserting canon" rule (read the actual wiki page, never trust `_status.md` for specifics, never guess a lore gap, confirm volatile...
`create_moment` deny-list contradiction
resolved. The `permissions.deny` list in `.claude/settings.local.json` is now empty, and the local-only discipline is preserved structurally: the scribe/narrate skills write the Scroll and never...
MCP article cross-reference linking (`[[wiki-link]]` resolution on create/update)
`WikiLinkResolver` service (`app/services/wiki_link_resolver.rb`) pre-processes `content` and `dm_notes` in `create_article` and `update_article` tools before save. `[[Name]]` resolves by name...
DM Notes as a separate tab on the article show page
`app/views/articles/show.html.erb` now tabs the main content column via the `tabs` Stimulus controller: an "Overview" tab (article content) and an owner-only "DM Notes" tab (with the lock icon),...
Session log only showed the latest 5 moments
`app/views/game_sessions/show.html.erb` had a hardcoded `.limit(5)` on the moment render. Made sense as a glance-preview during live sessions but hid the rest of the story for completed sessions....
Registration "couldn't set passwords"
`config.allow_unconfirmed_access_for` was commented out in `config/initializers/devise.rb`, defaulting to 0 days. New users registered fine (with valid encrypted_password), but Devise blocked...
Fix `PG::UndefinedColumn: column "display_name" does not exist` on characters#show
Fix `PG::UndefinedColumn: column "display_name" does not exist` on characters#show. The character transfer dropdown ordered `@campaign.members` by `:display_name`, but `display_name` is a Ruby...
Fix `NoMethodError: undefined method 'articles'` on game_sessions#show
Fix `NoMethodError: undefined method 'articles' for an instance of Campaign` on game_sessions#show. BL-045's lore tab called `@campaign.articles` but Campaign has no `has_many :articles`...
Email on WIN SendGrid account
swapped `SENDGRID_API_KEY` in `.kamal/secrets` to WIN account, deployed via `kamal deploy`. Registration emails now route through the higher-quota account.
Party tab member-character linking
DM's characters now appear under the DM row in the Party tab; unassigned characters (user_id nil) surface in an "Unassigned" section at the bottom. No model changes.
Play surface lore tab
new "Lore" tab in ps-tabs showing all campaign articles grouped by kind (NPCs, locations, creatures, etc.) with portrait/initial + name. Links open the article in a new tab. `@lore_articles`...
Herald pre-commit hook
`dev/hooks/pre-commit` guards against forbidden system names (D&D, 5e, One D&D) in user-facing copy paths. `bin/setup` installs all hooks from `dev/hooks/` into `.git/hooks/` automatically, so...
Encounter playtest
`GET /stages/:id/playtest` scroll viewer renders the latest JSONL from `story/sessions/playtests/stage-NNN-*.jsonl`. Balance report header (outcome, rounds, stage name), event timeline (round...
Populate the Stage
entity token UI on the Stage show page. Party column (campaign characters → PC tokens, HP auto-seeded from `max_hp` CharacterAttribute via snapshot model); NPC column (campaign articles with kind:...