docs(skills): add run-session skill

Covers the per-turn procedure: bootstrap, intent, deciding to roll, the
CLI, appending a scene, and applying state, with a session template.
This commit is contained in:
2026-09-13 16:43:17 +08:00
parent 9fdce335c2
commit b524e5f0cf
3 changed files with 158 additions and 1 deletions
+133
View File
@@ -0,0 +1,133 @@
---
name: run-session
description: Run a turn or a full session of a solo journaling campaign. Use when the player describes what their character does, asks to start or continue a session, or asks what happens next. Interprets the message as in-fiction intent, rolls through the journal CLI, narrates the outcome in chat, appends it to the session log, and updates the PC sheet, clocks, threads, and world files.
---
# Running a session
The player types their intent into chat, exactly as they would request a code
change. Everything else is your job: resolve it with dice, narrate, and persist
the result to the campaign's files. `AGENTS.md` holds the contract; this skill
is the procedure for a single turn.
The player never edits files. If you narrated it, write it down.
## 1. Bootstrap the session
Do this once, before the first turn.
1. **Identify the campaign.** `journal games` lists games; the campaign is
`campaigns/<name>/`. If the player named one, use it. If several exist and
they did not, ask — do not guess. Only `campaigns/` directories without a
leading `_` count.
2. **Read the campaign's game** from `campaigns/<name>/campaign.md` frontmatter
(`game: <id>`). Read `games/<id>/game.md` — it is authoritative — plus
`campaigns/<name>/house-rules.md`.
3. **Load state.** Read the PC sheet(s) in `characters/`, `state/clocks.md`,
`state/threads.md`, and the tail of the newest `sessions/NNNN-*.md`.
4. **No PC yet?** Build one from the game's `characters/` options (roll them
with `journal <command>` where the game provides one), write the sheet to
`campaigns/<name>/characters/<pc>.md`, and say what you created.
5. **Pick the session file.** Continue the newest one, or start the next:
`NNNN` is the previous number plus one, zero-padded to four digits, with a
kebab-case slug from the opening situation. Use `templates/session.md`.
## 2. Read the player's message
- **In-fiction intent** — the player describing what the PC does, tries, or
asks. This is the main case: go to step 3. Record their words *verbatim* in
the `Player` block.
- **Meta request** — a rules question, a recap, "what are my stats?", "start a
session". Answer from the files. Do not roll, do not append a scene, and do
not treat it as intent.
When a message is ambiguous, answer the meta part and ask whether they want the
action attempted.
## 3. Decide whether to roll
Roll only when the outcome is genuinely uncertain *and* both results would be
interesting. Do not roll for trivial actions, for what the fiction already
settles, or to decide what the PC wants.
- **Oracle** — a yes/no question about the world: "Is the gate locked?" Ask one
question at a time, phrased so either answer is interesting.
- **Spark table** — generating content: a location detail, an NPC's trait, what
happens next.
- **Complication** — on `and`/`but` results, or when the fiction needs a twist.
- **The game's own resolution** — if `game.md` defines one, follow it and use
`journal dice` for its rolls, or the game command it provides.
If the game ships a command for what you are about to do, use the command
rather than reimplementing it by hand.
## 4. Roll
Always pass `--campaign <name>`. Use the CLI's output exactly as printed — it
already renders the oracle's label, so relay that rather than re-deriving it.
```sh
journal oracle "Is the gate locked?" --complicate --campaign ashfall
journal roll sparks --campaign ashfall
journal dice 2d6+1
journal <game-command> --campaign ashfall
```
Never invent, reroll, or adjust a result. If a roll is not interesting, the
mistake was calling for one — narrate from the fiction instead.
## 5. Narrate and append
Resolve the intent into a concrete outcome, then append one scene to the
current session log using the format in `AGENTS.md`. Copy
`templates/session.md` for a new file.
- If you rolled, put the CLI output in backticks, verbatim.
- Omit the roll line when no roll was needed.
- List every mechanical change on the `State` line.
- **Reply in chat with the same resolution prose**, so the player can read it
without opening the file. Keep chat and file consistent.
## 6. Apply state changes
The scene is not finished until the files match the `State` line.
| Change | File |
|--------|------|
| Stat, track, condition, inventory | `campaigns/<name>/characters/<pc>.md` frontmatter |
| A clock filled or advanced | `campaigns/<name>/state/clocks.md` |
| A thread opened, resolved, abandoned | `campaigns/<name>/state/threads.md` |
| A place, person, or faction first appears | new file under `world/` |
| Something changes about an existing one | that file |
| A rule shape that emerged in play | `campaigns/<name>/house-rules.md` |
Never invent stats the game does not use. Keep the frontmatter shape the game
defines.
## Continuity rules
- **Append only.** Never edit a past scene except to fix a typo the player
points out.
- **Do not decide what the PC wants.** The oracle answers the world; the player
answers the character.
- **Never copy game content into a campaign.** Reference the game package.
- **Keep frontmatter and prose consistent.** If the log says a stat changed,
the sheet must show it.
## Closing a session
When the player stops for the night:
1. Run `journal check --campaign <name>` and fix anything it reports.
2. Make sure every `State` line has been applied.
3. Leave `state/threads.md` reflecting what is unresolved.
## Common failures
- Inventing a dice result, or rolling without calling the CLI.
- Rolling when the fiction already answers the question.
- Paraphrasing the player in the `Player` block instead of quoting them.
- Writing a `State` line but not applying it to the files.
- Editing an earlier scene to "fix" continuity instead of writing the fix
forward.
- Acting on the wrong campaign when several exist — ask first.
@@ -0,0 +1,24 @@
# Session NNNN — <title>
- **Campaign:** <name>
- **Game:** <game>
- **Date:** <YYYY-MM-DD>
- **PC:** <pc>
## Scene 1 — <title>
> **Player:** <the player's words, verbatim>
`<cli output, verbatim, in backticks>` · `<complication, if any>`
**Resolution:** <what actually happens, in the fiction>
**State:** <every mechanical change, e.g. supply 5 → 4; clock "Gate breached" 1/4>
## Scene 2 — <title>
> **Player:** <the player's words, verbatim>
**Resolution:** <what actually happens, in the fiction>
**State:** <mechanical changes, or omit the line if there were none>