Covers the per-turn procedure: bootstrap, intent, deciding to roll, the CLI, appending a scene, and applying state, with a session template.
7.2 KiB
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
- Never invent dice results. All randomness comes from the
journalCLI. Run it and use its output verbatim. If you did not run the CLI, you did not roll. - The player only talks. Record their intent verbatim in the session log.
Do not paraphrase inside the
Playerblock. - 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.
- Markdown is the source of truth. Current state lives in YAML frontmatter; narrative lives in prose. Keep them consistent.
- The game package is authoritative. Its rules override generic
assumptions. A campaign's
house-rules.mdoverrides the game, for that campaign only. - 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/<id>/ 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/<name>/ 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/<pc>.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/clocks.md ticking pressures
state/threads.md open questions
sessions/NNNN-slug.md append-only 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.
The session loop
- Identify the campaign. The campaign's
campaign.mdfrontmatter names its game. Use--campaign <name>on every CLI call. If it is unclear, ask. - Load context. Read
campaign.md, the game'sgame.md,house-rules.md, the PC sheet,state/, and the tail of the most recent session log. Read only what you need; pull arules/chapter only when the session touches it. - Read the player's intent. Treat it as what the PC attempts, not what happens.
- Decide whether to roll. See "When to roll" below.
- Roll. Call the CLI. Use the result exactly as printed.
- Narrate. Resolve the intent into a concrete outcome in the fiction.
- Append to the session log. Add a new scene using the format below.
- Update state. Apply stat, clock, thread, and world changes to their files. Create world files for anything newly introduced.
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-themesonand/butresults, or whenever the fiction needs a twist. Pass--complicatetojournal oracle, orjournal 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 <game-command> 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.
# 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
Playerblock quotes the player's words verbatim. - The roll line records exactly what the CLI printed, in backticks.
Resolutionis prose: what actually happens, in the fiction.Statelists 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/<name>/characters/<pc>.md. Stats live in YAML
frontmatter so they stay machine-readable; prose lives below.
---
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.
World files
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. Link between files with relative
markdown links where it helps.
Commands
journal roll <table> [--campaign <name>] [--game <id>] [--tag <tag>] [--count <n>]
journal oracle [<question>] [--complicate] [--campaign <name>] [--game <id>] [--table <name>]
journal dice <expr>
journal tables [--campaign <name>] [--game <id>]
journal check [--campaign <name>] [--game <id>]
journal new-campaign <name> [--game <id>]
journal games
journal game [<id>]
journal <game-command> [...] provided by the campaign's game package
journal games lists the installed games; journal game <id> 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
- If the game does not exist yet, build it under
games/<id>/followingdocs/games.md(copygames/generic/as a starting point). journal new-campaign <name> --game <id>- Fill in
campaign.mdwith the player. - Create the PC sheet in
characters/, drawing on the game's backgrounds. - Open the first session log in
sessions/.