Development
Development
Section titled “Development”Prerequisites
Section titled “Prerequisites”- Node.js >= 18.0.0 (check with
node --version) - npm >= 8 (bundled with Node; check with
npm --version) - git (for cloning and commit hooks)
- An LLM API key — the default provider is Anthropic; set
ANTHROPIC_API_KEYin your environment. Other providers require their own key (seesrc/providers/presets.tsfor theapiKeyEnvfield of each provider). Integration tests require a real key.
git clone https://github.com/farce1/handover.gitcd handovernpm installnpm run buildnpm run build compiles TypeScript via tsup into dist/. If the build passes, your environment is set up correctly.
To verify the CLI is working end-to-end:
ANTHROPIC_API_KEY=your-key node dist/index.js --helpDevelopment workflow
Section titled “Development workflow”For iterative development, use tsx to run TypeScript directly without a build step:
npm run dev -- generate --helpnpm run dev invokes tsx src/cli/index.ts. You can pass any CLI arguments after --:
# Run generate against the repo itself (requires API key)ANTHROPIC_API_KEY=your-key npm run dev -- generate
# Run static analysis only (no API key needed)npm run dev -- generate --static-only
# Run with a different providerOPENAI_API_KEY=your-key npm run dev -- generate --provider openai --model gpt-4oTypical inner loop:
- Edit source files in
src/ - Run
npm run dev -- generate --static-onlyto verify static analysis changes (instant, no API cost) - Run
npm testto run the unit test suite - For changes touching AI rounds or renderers, run the full pipeline with a real API key to verify output
Testing
Section titled “Testing”Unit tests:
npm testRuns all *.test.ts files under src/ using Vitest. No API key required.
Run a specific test file:
npm test -- src/analyzers/coordinator.test.tsnpm test -- src/orchestrator/dag.test.tsIntegration tests:
Integration tests call real LLM APIs and cost money. Gate them with the environment variable:
HANDOVER_INTEGRATION=1 ANTHROPIC_API_KEY=your-key npm testIntegration tests are skipped automatically when HANDOVER_INTEGRATION is not set.
Coverage:
npm test -- --coverageCoverage reports are written to coverage/ (which is gitignored). The CI pipeline reports to Codecov on Node 20.
Linting and formatting
Section titled “Linting and formatting”Lint:
npm run lintUses ESLint with flat config (eslint.config.js). The --max-warnings 0 flag means any warning fails the check. Fix auto-fixable issues with:
npm run lint:fixFormat:
npm run formatRuns Prettier across all files. To check without writing:
npm run format:checkPre-commit hooks:
Husky installs git hooks on npm install. The pre-commit hook runs lint-staged, which automatically lints and formats staged TypeScript/JavaScript files before every commit. This means you rarely need to run lint/format manually — it happens automatically.
Commit messages:
commitlint enforces Conventional Commits format. Every commit message must start with a type: feat, fix, test, refactor, chore, docs, ci, perf, or revert. Example:
feat(providers): add Mistral provider presetfix(dag): skip dependents when step is skipped, not just failedThe commit hook rejects messages that do not match.
Building
Section titled “Building”Compile to dist/:
npm run buildUses tsup to bundle TypeScript into dist/index.js (ESM, with type declarations). The bin field in package.json points to this file.
Type check only (no emit):
npm run typecheckRuns tsc --noEmit against the project. Type errors appear here but not necessarily in tsup (tsup transpiles without type-checking). Run this before submitting a PR.
Submitting a PR
Section titled “Submitting a PR”-
Branch from
main:Terminal window git checkout -b feat/your-feature -
Make your changes, committing atomically with conventional commit messages.
-
Verify locally before pushing:
Terminal window npm run typechecknpm run lintnpm testnpm run build -
Push and open a PR. The CI pipeline runs on Node 20 and 22:
- Lint (
npm run lint) - Type check (
npm run typecheck) - Unit tests (
npm test) - Build (
npm run build) - CodeQL security scan
- OpenSSF Scorecard (on main branch pushes)
- Lint (
-
PR template checklist — fill out the description, check that tests cover your change, and note if the PR changes any public API or config schema.
Releases are now managed manually. Keep CHANGELOG.md updated before each publish and follow RELEASE.md to ship.
Debugging
Section titled “Debugging”Run with verbose logging:
npm run dev -- generate -vThe -v / --verbose flag enables logger.setVerbose(true), which prints additional trace messages from the config loader, provider initialization, and context packing.
Run with tsx for fast iteration (no build):
# Inspect what the static analysis findsnpm run dev -- analyze --json | jq '.fileTree.filesByExtension'
# Estimate tokens and cost before running the full pipelineANTHROPIC_API_KEY=your-key npm run dev -- estimate
# Run only specific documents to save API cost during renderer developmentANTHROPIC_API_KEY=your-key npm run dev -- generate --only 01-PROJECT-OVERVIEW,03-ARCHITECTUREInspect cached round results:
Round results are cached in .handover-cache/ in your working directory. To discard the cache and force fresh API calls:
ANTHROPIC_API_KEY=your-key npm run dev -- generate --no-cacheDebug a specific analyzer:
Each analyzer is a standalone async function. You can call it directly in a one-off script using tsx:
tsx -e " import { analyzeFileTree } from './src/analyzers/file-tree.ts'; import { buildAnalysisContext } from './src/analyzers/context.ts'; const ctx = await buildAnalysisContext(process.cwd(), {}); const result = await analyzeFileTree(ctx); console.log(JSON.stringify(result, null, 2));"