Conventions
Code
- TypeScript with
strict, ESM ("type": "module", NodeNext). Import local files with the.jsextension. - Keep
src/corefree of transport concerns. It must not import fromdaemon,cliormcp. - Dependencies come in through parameters (
Deps,RunFn,now) so behaviour is testable without spawning processes or waiting on clocks. - Spawn agents without a shell and pass the prompt as a single argument.
- Anything that varies between CLI releases belongs in config, not code: flags, error patterns, cooldowns.
- Prefer returning a
TaskResultwith astatusover throwing for expected failures. Throw only for programmer or configuration errors, and make the message say how to fix it. - Keep dependencies minimal. Runtime:
yaml,zod,@modelcontextprotocol/sdk.
Tests
- Test first, one behaviour per test, named after the behaviour.
- No real
claudeorcodexin automated tests. - Use real temp directories and repositories instead of mocking the filesystem or git.
Commits and branches
- One branch per change, merged into
mainwhennpm testandnpm run buildpass. - Commit messages use a type prefix:
feat:,fix:,docs:,chore:,refactor:,test:. - Each commit should leave the tests green.
Documentation
Code and docs change together. See Documentation policy.
Extending
A new config key
- Add it to the types in
src/core/types.tsand, if it has a default, toDEFAULT_CONFIG. - Validate it in
src/core/config.tsand add tests inconfig.test.ts. - Document it in
docs/guide/configuration.mdanddocs/th/guide/configuration.md.docs-coverage.test.tsenforces this for agent and rule keys.
A new CLI command
- Add it to
parseArgs(src/cli/args.ts) with a test, toUSAGE(src/cli/usage.ts), and to the switch insrc/cli/index.ts. - Document it in both
guide/usage.mdpages. The coverage test fails until you do.
A new rate-limit or login pattern
Add the regex to LIMIT_PATTERNS or AUTH_PATTERNS in src/core/config.ts and a case to detector.test.ts using the real message. Users can also add patterns in their own config.
A third agent
Not supported yet: AgentName has two members and otherAgent assumes exactly two. Adding one means generalizing the failover choice in src/core/router.ts and orchestrator.ts first.