--- name: game-prep description: Prepare or validate a game package under games/ for this solo journaling workspace. Use when adding a new game system, porting one from games/generic/, reviewing whether a game package is complete, or checking that its rules, tables, character backgrounds, and commands are wired up correctly before starting a campaign. --- # Preparing a game package A game package is a directory under `games//` that holds everything true about a game *before* play starts: its rules, spark tables, character options, and tool scripts. Campaigns own the play state and reference a game by id from `campaigns//campaign.md` frontmatter (`game: `). Read `docs/games.md` for the full contract. `games/generic/` is the reference implementation — copy it as a starting point. Rule of thumb: a game is what is true before play, a campaign is what play changes. Never copy game content into a campaign; reference it. ## Required contents | Path | Required | Purpose | |------|----------|---------| | `package.json` | yes | `@solo/game-`, `"type": "module"`, `main`/`exports`; depend on `@solo/oracle` if scripts use dice or tables | | `index.js` | yes | default-export manifest: `id`, `title`, `description`, `rules`, `commands` | | `game.md` | yes | authoritative rules the agent reads each session | | `tables/*.csv` | yes | spark and complication tables, header `min,max,text[,tags]` | | `characters/` | yes | backgrounds, playbooks, starting options — the character *options*, not the PC | | `rules/` | recommended | longer rulebook chapters, read on demand | | `scripts/` | optional | standalone tool scripts for one-off jobs | Details that trip people up: - **The directory name is the game id.** Keep the manifest's `id` and the package name `@solo/game-` in sync with it. - **Ship a `complication-themes.csv`.** `journal oracle --complicate` resolves that table name, and without it on either the campaign or the game the roll fails. There is no cross-game fallback. - **Tables must be contiguous and non-overlapping.** `min`/`max` are inclusive integers and define the die range; every integer in the table's span should be covered exactly once. Quote any `text` containing a comma. - **Commands** are declared in `index.js` as `commands: { name: { description, run } }` and exposed as `journal `. Handlers receive `(args, ctx)` where `args` is `{ positional, flags }` and `ctx` carries `findTable` plus the shared helpers. - **Run `pnpm install`** after adding the `@solo/oracle` dependency or creating a new package, so the workspace symlink exists. ## Preparation workflow 1. Copy the reference: `games/generic/` → `games//`. 2. Edit `package.json`: set `name` to `@solo/game-` and a real description. 3. Edit `index.js`: set `id`, `title`, `description`; replace or remove the example command. 4. Write `game.md`: resolution, stats, tracks and conditions, character creation, and the tables the game provides. 5. Add tables to `tables/`, one CSV per table, ranges contiguous. 6. Add character options to `characters/` — rollable ones as CSV, prose as markdown. 7. Add `rules/` chapters for anything too long for `game.md`. 8. Add tooling: preferred path is a `commands` entry in `index.js` for anything the agent calls during play; standalone one-off scripts go in `scripts/`. 9. `pnpm install`. 10. Validate (below) before starting a campaign. ## Validation Run all of these. Each proves something the others do not. | Command | Proves | |---------|--------| | `pnpm install` | the `@solo/oracle` workspace link resolves | | `pnpm journal check --game ` | `package.json` parses and is named right, `index.js` loads, the rules file exists, tables parse and are contiguous, `tables/` and `characters/` exist | | `pnpm journal games` | the game appears in the catalog; a manifest that throws shows as `ERROR:` | | `pnpm journal game ` | rules path, table count, characters path, and the command list all resolve | | `pnpm journal roll --game ` | each table rolls and its range resolves | | `pnpm journal --game ` | each game command runs | `journal check` exits non-zero on errors. It reports: - **errors** — overlapping table ranges, CSV parse failures, invalid or missing `package.json`, missing game. - **warnings** — range gaps, package name mismatch, missing `"type": "module"`, missing `index.js`/`tables/`/`characters/`, missing rules file. Fix every error, then work the warnings down to zero. The checks live in `packages/cli/src/cli.js` (`checkGamePackage`, `checkTablesDir`). ## Definition of done - [ ] `games//` exists; directory name, manifest `id`, and package name agree. - [ ] `pnpm journal check --game ` exits 0 with no errors. - [ ] `pnpm journal games` lists it without `ERROR`. - [ ] `pnpm journal game ` shows the rules path and every intended command. - [ ] Every table rolls cleanly and its ranges are contiguous. - [ ] `game.md` covers resolution, stats, tracks, character creation, and the game's tables. - [ ] `characters/` holds the character options. - [ ] A complication table is present if the game uses `--complicate`. - [ ] `pnpm journal new-campaign scratch --game ` succeeds (then remove the scratch campaign). ## Common failures - **Overlapping ranges** — e.g. rows `1-3` and `3-6` both cover 3. Error. - **Gaps** — e.g. rows `1-2` and `4-6` leave 3 uncovered. Warning. - **Unquoted comma** in a table's `text` shifts the columns; wrap it in quotes. - **`ERR_MODULE_NOT_FOUND: @solo/oracle`** — the dependency was added but `pnpm install` was not run. - **Manifest id drifting** from the directory name — `journal game ` still works (the directory wins), but the package is inconsistent and the docs become misleading.