Thanks for contributing! This file covers how this repository is set up, how to run the verification bar, and what a merge-ready change looks like.
headlesscode is a standalone Node/TypeScript CLI that runs a headless
coding-agent loop, ported from a VS Code extension (vendored verbatim under
src/vendor/zoo-code/, Apache-2.0 — see ATTRIBUTION.md). There is no
build step: everything runs directly via tsx. Read the docs in docs/
before diving into a subsystem.
This agent executes arbitrary shell commands as the invoking user — that
is its core function. Read SECURITY.md before running it
unattended or pointing it at untrusted repositories, and never weaken the
permission layer without a very explicit reason. If you are adding a feature
that executes commands or reads secrets, think about the least-privilege
story as part of the design, not after.
npm install # tsx + typescript + deps; no build step needed
npm test # full suite (see "Test conventions" below)
npm run typecheck # npx tsc --noEmitnode >= 18 is required (see engines in package.json).
Optional: the browser_action tool's tests. src/tools/__tests__/browser-action.test.ts
launches a real headless Chromium via Playwright. npm install only installs
the playwright npm package, not the browser binary itself — run
npx playwright install chromium once to enable those tests. Without it, the
suite detects the missing binary, prints a clear skip message, and exits 0
(this is treated as an environment gap, not a test failure — the rest of
npm test still runs and still gates your change).
- No test framework. The project deliberately uses no jest/mocha/vitest.
Tests are plain
.test.tsfiles run directly viatsxwith hand-rolled assertions, and the file ends with anAll N tests passedtrailer line. Look at any existing file undersrc/*/__tests__/for the exact style before writing a new one. - Discovery is automatic.
npm testrunsscripts/run-tests.mjs, which globs every*.test.tsundersrc/(plus a short explicit list of non-test-suffixed check scripts) and runs them sequentially, fail-fast. A new test file needs zero edits outside the file itself — do not add it topackage.jsonby hand. - Verification bar for any change to
src/:npx tsc --noEmitis clean (respect the strictnesstsconfig.jsonactually configures — noany,@ts-ignore, or!escapes).npm testpasses in full. A targeted run (npm test -- <substring>ornpx tsx <test-file>) is fine while iterating, but the full suite is the gate.
- Orchestrator / watcher / spawn / worker changes also re-run the
relevant suites under
scripts/e2e*/run.sh— these exercise real spawn/watch/review flows against a local mock LLM server, not just unit-level logic.
- No new runtime dependencies without a real reason. The project
deliberately avoids frameworks and schema libraries for its own
state/JSON handling (plain
node:fs/node:http, loose JSON validation). Prefer the smallest dependency footprint that does the job; ask in the issue/PR if you think a dependency is genuinely warranted. - Non-fatal failure pattern for auxiliary subsystems. Memory recording, checkpoint saving, and usage/cost recording all follow the same idiom: wrap in try/catch, log a warning via the session's logger, and never let a failure in an auxiliary subsystem abort or corrupt the coding session. Match that pattern when adding a new auxiliary write path.
- Vendoring convention. Code ported from the upstream VS Code extension
lives under
src/vendor/zoo-code/, copied verbatim wherever practical, with a corresponding entry inATTRIBUTION.md. VS Code API calls the vendored code makes are satisfied by no-op shims undersrc/vendor/zoo-code/shim/, wired viatsconfig.json'spaths— check there before assuming something needs a new shim. - Comments are minimal. Only when the WHY is genuinely non-obvious.
- Docs vs. plans.
docs/*.mddescribes how a shipped subsystem works.plans/*.mdare standalone work orders for an external agent to execute — each must be fully self-contained and must not reference internal-only planning artifacts. - Plan docs cite verified locations. Every code reference in a
plans/*.mddoc must include the real file path AND line number/range (e.g.src/checkpoints/cli.ts:12-30), verified by actually reading or grepping the file at writing time — never recalled from memory.
- This repo is developed primarily through headless workers in parallel git
worktrees (see
scripts/spawn-parallel-worktrees.sh). If you're submitting a PR the normal way, the same conventions apply: one logical change per commit, reference the issue number in the commit message and PR body. - Commit before you're done. Real, working changes should be committed in logical units; a PR is a series of reviewed, individually sensible commits, not one giant diff.
All contributors and maintainers are expected to follow our Code of Conduct. Be respectful, be constructive, and assume good faith — this project is small and every contribution matters.