Guidance for coding agents (and humans) working in this repo. For project context, contribution process, and security policy, see CONTRIBUTING.md.
- All changes must be tested. If you didn't add or update a test, you're not done. Bug fixes get a regression test that fails before the fix and passes after.
- Run the tests. If you didn't run them, the code does not work. A change is
finished only when
pnpm testandpnpm typecheckboth pass locally — the same checks CI enforces. - Type-check the whole repo, not just src.
pnpm typecheckcoverssrc/andtests/(viatsconfig.test.json). Keep it green; noas anyto silence the checker — fix the type at its source. - Match the surrounding code. Check neighboring files for naming, structure, and comment style before introducing your own. Prefer the existing pattern over a new one.
- The session format is a contract. Consumers read one schema whatever agent
produced a capture. Agent-specific shapes — tool names, input keys, patch
blobs — are resolved in the agent's own adapter (
src/hooks/*.tsplus its map insrc/tool-actions.ts), never pushed onto a reader. Adding an agent, or a tool for an existing one, means extending that map: if a consumer would have to check two property names, the mapping is in the wrong place.
- Do not default to committing unless the user explicitly asks. Do not default to committing when a task looks done, when tests pass, or to "save progress." Finishing a change typically means the edits are made and verified (typecheck/test) and left in the working tree. Wait for an explicit "commit".
- Same rule for
git push, branch creation, and PRs — git actions need an explicit request. - Write Conventional Commits:
<type>: <description>, where<type>is one offeat,fix,docs,refactor,perf,test,ci,build, orchore(append!or aBREAKING CHANGE:footer for a breaking change). The release workflow runs git-cliff (seecliff.toml) over these to group the GitHub Release notes by type, so an unprefixed subject lands the change under "Other" or mis-groups it;chore|ci|build|test|styleandbump versionare omitted from the notes.
pnpm test only proves the adapters match our own assumptions about what an
agent sends. It can't catch an agent changing its payload.
pnpm test:live drives the real agent binaries headlessly against a throwaway
repo and asserts on what lands in .sessions/. It needs each agent installed
and authenticated, spends tokens, and takes minutes, so it's not part of
pnpm test or CI. Run it before releasing anything that touches src/hooks/
or src/tool-actions.ts. pnpm test:live -t cursor runs a single agent, and
agents that aren't installed or signed in are skipped rather than failed.
If an agent's payload turns out to differ from what an adapter assumed, record
a real payload under tests/fixtures/ and replay it in that adapter's tests
(see tests/fixtures/cursor-payloads.json). Raw payloads bypass the sanitizer,
so scrub them before committing.
Put new tests in the existing file that covers the area before creating a new
one. Tests live under tests/, mirroring the src/ layout — one file per
src/ module at the matching path (e.g. tests/session-writer.test.ts for
src/session-writer.ts, tests/hooks/codex.test.ts for
src/hooks/codex.ts). Tests use Vitest; import the unit under test with the
matching relative depth (../src/... at the top level, ../../src/... under
tests/hooks/).
pnpm install # install deps (CI uses --frozen-lockfile)
pnpm typecheck # tsc over src + tests, no emit
pnpm test # vitest run (single pass)
pnpm test:live # drive real agents headlessly (see "Testing against real agents")
pnpm test:watch # vitest in watch mode
pnpm build # esbuild bundle -> dist/cli.js (ESM)
pnpm build:sea # CJS bundle for the single-executable (SEA) release
pnpm dev -- <args> # run the CLI from source via tsxRun pnpm typecheck, pnpm test, and pnpm build, and make sure CI is green.
This is your product — assert init so your session data lands in
.sessions/. When you do commit (only once asked — see Committing), generally keep
the session data in the PR unless specifically asked otherwise.