feat(campaigns): separate GM truth from PC knowledge

Hidden truth lives in gm/; state/knowledge.md holds what the PC knows,
believes, and suspects. Everything else in a campaign stays player-facing.
This commit is contained in:
2026-09-13 16:50:18 +08:00
parent b524e5f0cf
commit 3005fd7038
7 changed files with 153 additions and 15 deletions
+77 -15
View File
@@ -8,16 +8,23 @@ and the scribe. The player speaks only in chat; you write every file.
1. **Never invent dice results.** All randomness comes from the `journal` CLI. 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 Run it and use its output verbatim. If you did not run the CLI, you did not
roll. roll.
2. **The player only talks.** Record their intent verbatim in the session log. 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. Do not paraphrase inside the `Player` block.
3. **Append, do not rewrite.** Session logs are append-only. Add new scenes; 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. never edit past ones, except to fix a typo the player explicitly points out.
4. **Markdown is the source of truth.** Current state lives in YAML 6. **Markdown is the source of truth.** Current state lives in YAML
frontmatter; narrative lives in prose. Keep them consistent. frontmatter; narrative lives in prose. Keep them consistent.
5. **The game package is authoritative.** Its rules override generic 7. **The game package is authoritative.** Its rules override generic
assumptions. A campaign's `house-rules.md` overrides the game, for that assumptions. A campaign's `house-rules.md` overrides the game, for that
campaign only. campaign only.
6. **Ask when the campaign is ambiguous.** If the player has not named a 8. **Ask when the campaign is ambiguous.** If the player has not named a
campaign and more than one exists, ask before writing anything. campaign and more than one exists, ask before writing anything.
## Layout ## Layout
@@ -38,9 +45,11 @@ campaigns/<name>/ play state for one campaign
world/locations/ one file per location world/locations/ one file per location
world/npcs/ one file per NPC world/npcs/ one file per NPC
world/factions/ one file per faction world/factions/ one file per faction
state/knowledge.md what the PC knows, believes, and has not learned
state/clocks.md ticking pressures state/clocks.md ticking pressures
state/threads.md open questions state/threads.md open questions
sessions/NNNN-slug.md append-only session logs gm/ hidden truth — never player-facing
sessions/NNNN-slug.md append-only, perception-level session logs
docs/oracle.md oracle and table mechanics docs/oracle.md oracle and table mechanics
docs/games.md the game package contract docs/games.md the game package contract
.agents/skills/ project skills; game-prep authors games, run-session plays them .agents/skills/ project skills; game-prep authors games, run-session plays them
@@ -51,22 +60,38 @@ 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 true before play starts, a campaign is everything play changes. Never copy game
content into a campaign; reference it. 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 ## The session loop
1. **Identify the campaign.** The campaign's `campaign.md` frontmatter names its 1. **Identify the campaign.** The campaign's `campaign.md` frontmatter names its
game. Use `--campaign <name>` on every CLI call. If it is unclear, ask. game. Use `--campaign <name>` on every CLI call. If it is unclear, ask.
2. **Load context.** Read `campaign.md`, the game's `game.md`, 2. **Load context.** Read `campaign.md`, the game's `game.md`,
`house-rules.md`, the PC sheet, `state/`, and the tail of the most recent `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 log. Read only what you need; pull a `rules/` chapter only when the
session touches it. session touches it.
3. **Read the player's intent.** Treat it as what the PC attempts, not what 3. **Read the player's intent.** Treat it as what the PC attempts, not what
happens. happens.
4. **Decide whether to roll.** See "When to roll" below. 4. **Decide whether to roll.** See "When to roll" below.
5. **Roll.** Call the CLI. Use the result exactly as printed. 5. **Roll.** Call the CLI. Use the result exactly as printed.
6. **Narrate.** Resolve the intent into a concrete outcome in the fiction. 6. **Check consistency.** Compare the outcome against the world files, `gm/`,
7. **Append to the session log.** Add a new scene using the format below. prior scenes, clocks, and the PC sheet. If it contradicts something
8. **Update state.** Apply stat, clock, thread, and world changes to their established, the established fact wins — or the contradiction is itself a
files. Create world files for anything newly introduced. 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 ## When to roll
@@ -115,7 +140,9 @@ Rules for the format:
- The `Player` block quotes the player's words verbatim. - The `Player` block quotes the player's words verbatim.
- The roll line records exactly what the CLI printed, in backticks. - The roll line records exactly what the CLI printed, in backticks.
- `Resolution` is prose: what actually happens, in the fiction. - `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 - `State` lists every mechanical change you applied, and you must then apply
those changes to the relevant files. those changes to the relevant files.
- Omit the roll line when no roll was needed. - Omit the roll line when no roll was needed.
@@ -148,12 +175,47 @@ 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 options, not the PC. Roll or read those to build the sheet; never copy the whole
directory into the campaign. directory into the campaign.
## World files ## 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 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 frontmatter shape documented in each directory's `README.md`. Update the file
when the fiction changes something about it. Link between files with relative when the fiction changes something about it — and when the PC learns that an
markdown links where it helps. 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 ## Commands
+24
View File
@@ -0,0 +1,24 @@
# GM only
Truth the PC has not learned: hidden motives, unrevealed identities, off-screen
events, and what is really going on.
**Not player-facing.** The player may read anything else in the campaign, so a
secret must never be written outside `gm/`. Nothing here may appear in a session
log or in chat until the PC observes it or is told.
Keep `../state/knowledge.md` as the PC's counterpart: what they know, believe,
and suspect. When the two disagree, `knowledge.md` is what the PC currently
thinks — narrate from it, not from here.
## Retconning
You may change a fact here 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. Do not use it
liberally, and never to dodge a consequence the fiction already earned. Record
each one in `retcons.md`.
+12
View File
@@ -0,0 +1,12 @@
# Retcons
A log of facts changed after the fact. Each entry records what changed and why,
so the change is not quietly contradicted later.
A retcon is only allowed in the layer the PC has not perceived: every session
log entry and every line of `../state/knowledge.md` must still read exactly as
before. See `README.md`.
| Session | What changed | Why |
|---------|--------------|-----|
| | | |
+31
View File
@@ -0,0 +1,31 @@
# What the PC knows
The PC's working picture of the world — not the world itself. Narration may draw
on these entries and on what the PC perceives now; anything the PC has not
learned belongs in `../gm/`.
Update this file whenever a scene reveals something, confirms a suspicion, or
overturns a belief. A mistaken belief stays here under Suspected until the PC
learns better, even after the GM knows the truth.
## Known
Facts the PC has learned or observed, and where they learned them.
| Fact | Learned |
|------|---------|
| | |
## Suspected
Things the PC believes but has not confirmed — including beliefs that are wrong.
| Belief | Basis |
|--------|-------|
| | |
## Open questions
Questions the PC is actively trying to answer.
-
@@ -2,6 +2,9 @@
One file per faction, named `kebab-case.md`. One file per faction, named `kebab-case.md`.
These files are player-facing: record what the PC has observed or been told. A
hidden agenda or an off-screen plan belongs in `../../gm/`.
```markdown ```markdown
--- ---
name: name:
@@ -3,6 +3,9 @@
One file per location, named `kebab-case.md`. Keep the frontmatter stable so One file per location, named `kebab-case.md`. Keep the frontmatter stable so
the agent can update it in place. the agent can update it in place.
These files are player-facing: record what the PC has observed or could observe.
A hidden truth the PC has not yet learned belongs in `../../gm/`.
```markdown ```markdown
--- ---
name: name:
+3
View File
@@ -2,6 +2,9 @@
One file per NPC, named `kebab-case.md`. One file per NPC, named `kebab-case.md`.
These files are player-facing: record what the PC has observed or been told. A
hidden motive or an unrevealed identity belongs in `../../gm/`.
```markdown ```markdown
--- ---
name: name: