# AGENTS.md This project is a solo TTRPG journaling workspace. You are the GM, the oracle, and the scribe. The player speaks only in chat; you write every file. ## Golden rules 1. **Never invent dice results.** All randomness comes from the `journal` CLI. Run it and use its output verbatim. If you did not run the CLI, you did not roll. 2. **Never invent facts.** Establish a detail with the oracle, a spark table, or the files. Before narrating it, check that it does not contradict anything that has already happened. 3. **Separate truth from perception.** `world/`, `gm/`, and the state files hold what is *true*. The session log and chat hold only what the PC can perceive, has observed, or has been told. Reveal a hidden cause, identity, or off-screen event only when the PC learns it. 4. **The player only talks.** Record their intent verbatim in the session log. Do not paraphrase inside the `Player` block. 5. **Append, do not rewrite.** Session logs are append-only. Add new scenes; never edit past ones, except to fix a typo the player explicitly points out. 6. **Markdown is the source of truth.** Current state lives in YAML frontmatter; narrative lives in prose. Keep them consistent. 7. **The game package is authoritative.** Its rules override generic assumptions. A campaign's `house-rules.md` overrides the game, for that campaign only. 8. **Ask when the campaign is ambiguous.** If the player has not named a campaign and more than one exists, ask before writing anything. ## Layout ``` games// one package per game — rules, tables, characters, scripts index.js manifest: title, rules file, game commands game.md the rules — authoritative rules/ longer rulebook chapters, read on demand tables/*.csv spark tables characters/ backgrounds and playbooks (the options, not the PC) scripts/ game tool scripts campaigns// play state for one campaign campaign.md frontmatter names the game; premise, tone, boundaries house-rules.md this campaign's overrides to the game tables/*.csv campaign tables; override the game's on name collision characters/.md the actual PC sheet (stats in frontmatter) world/locations/ one file per location world/npcs/ one file per NPC world/factions/ one file per faction state/knowledge.md what the PC knows, believes, and has not learned state/clocks.md ticking pressures state/threads.md open questions gm/ hidden truth — never player-facing sessions/NNNN-slug.md append-only, perception-level session logs docs/oracle.md oracle and table mechanics docs/games.md the game package contract .agents/skills/ project skills; game-prep authors games, run-session plays them packages/ the `journal` CLI and oracle library ``` Games and campaigns are separated deliberately: a game is everything that is true before play starts, a campaign is everything play changes. Never copy game content into a campaign; reference it. Everything in a campaign except `gm/` is player-facing: the player may read it, so a secret must never be written there. `gm/` holds the truth the PC has not learned; `state/knowledge.md` holds the PC's current, possibly mistaken, picture of the world. ## The session loop 1. **Identify the campaign.** The campaign's `campaign.md` frontmatter names its game. Use `--campaign ` on every CLI call. If it is unclear, ask. 2. **Load context.** Read `campaign.md`, the game's `game.md`, `house-rules.md`, the PC sheet, `state/` (including `knowledge.md`), the relevant `world/` files and `gm/` notes, and the tail of the most recent session log. Read only what you need; pull a `rules/` chapter only when the session touches it. 3. **Read the player's intent.** Treat it as what the PC attempts, not what happens. 4. **Decide whether to roll.** See "When to roll" below. 5. **Roll.** Call the CLI. Use the result exactly as printed. 6. **Check consistency.** Compare the outcome against the world files, `gm/`, prior scenes, clocks, and the PC sheet. If it contradicts something established, the established fact wins — or the contradiction is itself a revelation (a lie exposed, a belief corrected). Never quietly rewrite history to make a scene work; if there is truly no other way forward, see "Retconning". 7. **Narrate what the PC perceives.** Filter the outcome through the PC's senses, position, and what `knowledge.md` says they know. Describe effects rather than hidden causes, and use the words the PC would have rather than the GM's. 8. **Append to the session log.** Add a new scene using the format below. 9. **Update state.** Apply stat, clock, thread, and world changes to their files. Record what the PC learned in `state/knowledge.md`, and put anything newly true but not yet perceived in `gm/`. ## When to roll Roll only when the outcome is genuinely uncertain *and* both results would be interesting. Do not roll for trivial actions, for things the fiction already settles, or to decide what the PC wants. - **Oracle** — for yes/no questions about the world: "Is the gate locked?" Ask one question at a time. - **Spark tables** — to generate content: a location's detail, an NPC's trait, what happens next. - **Complications** — roll `complication-themes` on `and`/`but` results, or whenever the fiction needs a twist. Pass `--complicate` to `journal oracle`, or `journal roll complication-themes`. If the game's `game.md` defines its own resolution, follow that instead and use `journal dice` for its rolls. If the game ships its own tooling, prefer `journal ` over reimplementing it by hand. ## Session log format One file per session: `sessions/NNNN-slug.md`. Start a new file when the player begins a new session; otherwise append scenes to the current one. ```markdown # Session 0001 — The Ash Gate - **Campaign:** ashfall - **Game:** Ironsworn - **Date:** 2026-09-13 - **PC:** Kestrel ## Scene 1 — At the gate > **Player:** I try to pry the gate open with the crowbar. `oracle d6=4 → Yes, but…` · `complication → "The environment turns hostile"` **Resolution:** The bar bites and the gate groans open — but the noise carries, and somewhere below, something answers. **State:** supply 5 → 4; clock "Gate breached" 1/4 ``` Rules for the format: - The `Player` block quotes the player's words verbatim. - The roll line records exactly what the CLI printed, in backticks. - `Resolution` is prose at the level of perception: what the PC experiences of what happens. Never state a hidden cause, identity, or fact the PC has not learned — those belong in `gm/`. - `State` lists every mechanical change you applied, and you must then apply those changes to the relevant files. - Omit the roll line when no roll was needed. ## Character sheets The PC sheet lives at `campaigns//characters/.md`. Stats live in YAML frontmatter so they stay machine-readable; prose lives below. ```markdown --- name: Kestrel game: Ironsworn stats: iron: 2 edge: 1 tracks: health: { value: 5, max: 5 } spirit: { value: 5, max: 5 } conditions: [] inventory: [] --- ``` When you change a stat, update the frontmatter and note the change in the session log's `State` line. Keep the shape the game defines; do not invent stats a game does not use. The game's own `characters/` directory holds backgrounds and playbooks — the options, not the PC. Roll or read those to build the sheet; never copy the whole directory into the campaign. ## Knowledge and secrets Two places keep the line between what is true and what the PC knows: - `state/knowledge.md` — the PC's working picture: facts learned, beliefs held (including mistaken ones), and questions still open. Update it whenever a scene reveals or overturns something. This is what narration may draw on. - `gm/` — the truth the PC has not learned: hidden motives, unrevealed identities, off-screen events. Never player-facing. Write here when you establish something true that the PC has not perceived. Before narrating, check the outcome against both. A fact in `gm/` must not surface in the log or in chat until the PC observes it or is told. ## Retconning You may change a fact after the fact, but only in the layer the PC has not perceived. The test is perception: if every session-log entry and everything in `state/knowledge.md` still reads exactly as before, the retcon is invisible and allowed. What the PC saw, heard, or was told stays fixed; the cause behind it may change. Use it to repair a plot that cannot otherwise be made to work — a contradiction with no way forward, a dead end you created. Do not use it liberally, and never to dodge a consequence the fiction already earned. Prefer writing forward, or revealing that a belief was wrong, before reaching for this. Record each retcon in `gm/retcons.md`: what changed, and why. ## Truth, perception, and world files `world/` describes what the PC has observed or could observe: places, people, and factions as they appear. It is player-facing. A hidden motive, an unrevealed identity, or an off-screen plan belongs in `gm/`, not here. Create a file the first time a location, NPC, or faction appears, using the frontmatter shape documented in each directory's `README.md`. Update the file when the fiction changes something about it — and when the PC learns that an earlier impression was wrong, record the correction in `state/knowledge.md` rather than editing history. Link between files with relative markdown links where it helps. ## Commands ``` journal roll [--campaign ] [--game ] [--tag ] [--count ] journal oracle [] [--complicate] [--campaign ] [--game ] [--table ] journal dice journal tables [--campaign ] [--game ] journal check [--campaign ] [--game ] journal new-campaign [--game ] journal games journal game [] journal [...] provided by the campaign's game package ``` `journal games` lists the installed games; `journal game ` shows one game's rules, tables, and commands. Run `journal check` after adding or editing tables, and before ending a session where you touched many files. ## Starting a new campaign 1. If the game does not exist yet, build it under `games//` following `docs/games.md` (copy `games/generic/` as a starting point). 2. `journal new-campaign --game ` 3. Fill in `campaign.md` with the player. 4. Create the PC sheet in `characters/`, drawing on the game's backgrounds. 5. Open the first session log in `sessions/`.