Contributing
How to run the code, and what a change has to clear before it is merged.
Getting started
nvm use # or otherwise match .nvmrc
npm install
npm run dev
Use the Node version in .nvmrc; CI pins the same one. It is not cosmetic —
npm versions disagree about which transitive optional/wasm packages belong in
package-lock.json, so an npm install on a different Node writes a lockfile
that your machine accepts and CI rejects with Missing: ... from lock file.
If you bump .nvmrc, bump NODE_VERSION in .github/workflows/ci.yml too and
regenerate the lockfile with the matching npm.
After creating a linked worktree, run npm run worktree:bootstrap inside it.
On APFS this validates and copy-on-write clones the shared checkout's install;
elsewhere it uses npm ci --prefer-offline. If its lockfile later changes,
rerun it with -- --refresh.
The repo ships with a demo journal at /example, committed under
content/example/, so the app works end to end with no real trip data. Real
configuration lives in site/config.json, read by lib/config.ts — don't
put personal data or secrets in code; see AGENTS.md for the
ground rules the codebase follows (feature flags default off, secrets stay
in the environment, and so on).
Working with an agent
Start the agent in this checkout. AGENTS.md is the shared instruction file; CLAUDE.md imports it for Claude Code. Read the complete file from disk — it is short by design, but still worth reading in full rather than trusting an automatic summary.
No global install, Claude account, or personal plugin configuration is needed to follow it. If your agent supports repository skills and one seems to apply to your task, use it; a fresh clone of this repository alone has no skills of its own to discover.
Codex's skill discovery documentation
describes .agents/skills/ and symlink support; its
instruction documentation
describes the default 32 KiB limit. Repository instructions make files
available each session; they cannot force a harness to load or obey them.
Before you open a PR
Run all of these — CI runs the same five checks, as separate parallel jobs
rather than one sequential gate (npm run verify runs them locally in this
order and stops at the first failure, and is the easier way to run them):
npm run build # first — it writes .next/types, which tsc reads
npx tsc --noEmit
npx eslint .
npx vitest run
npm run unused # knip — is anything here for nothing
The build goes first because Next writes the typed-route definitions in
.next/types while it builds, and PageProps, LayoutProps and
RouteContext resolve against them. Run tsc on a checkout that has never
been built and it reports errors in every route file, none of which are yours.
npm run verify -- --quick skips that build only when a checked stamp proves
the route inputs and generated types still match its last successful build.
A PR that fails any of these won't be merged as-is. If a check is failing for a reason unrelated to your change, say so in the PR description rather than silently working around it.
Workbenches
For the parts this software draws rather than writes — the mark, the travel scene, the travellers, the day card and the print pieces. Each bench isolates one of them so a fault can be seen and traced to its file. Not indexed.
/docs/brandingThe whole file, and the licence terms, are in the repository.