Harnessimo
Spec-driven development, and the harness that makes it stick.
Two halves that need each other. SDD: work is a lane — a numbered spec whose acceptance criteria can actually run. The harness: eleven checks that refuse to call that lane finished until they do. Specs without enforcement are a filing system; enforcement without specs has nothing to check against.
harnessimo track new <slug> opens a lane, harnessimo check decides whether it is done.
It works on an empty repository and on one with fifteen years of history — nothing has to be
rewritten to start, and one check is a real improvement.
Zero dependencies, one config file, any language — it reads your files, runs your commands, walks your git history.
Nobody scripted that: npm run demo runs those commands in a throwaway repository and
records what they print.
pnpm add -D harnessimo
pnpm exec harnessimo init # scans your repo, writes a config that already passes
pnpm exec harnessimo check # run this in CI
npm i -D harnessimo
npx harnessimo init # scans your repo, writes a config that already passes
npx harnessimo check # run this in CI
yarn add -D harnessimo
yarn harnessimo init # scans your repo, writes a config that already passes
yarn harnessimo check # run this in CI
bun add -d harnessimo
bunx harnessimo init # scans your repo, writes a config that already passes
bunx harnessimo check # run this in CI
Who this is for
You, if an agent writes a meaningful share of your code and you are the only one checking its work. One person with three agents has the review load of a team lead and none of the team. These checks are the part of a reviewer's job that a command can do.
Concretely:
| What changes | |
|---|---|
| Solo developer, agent-assisted | You stop re-reading diffs to find out whether the thing it said it finished is finished |
| Vibe coding a real project | The README stays true as the project moves, so the next session — yours or the agent's — is not working from fiction |
| A team running an agentic SDLC | "Done" becomes a command's exit code instead of a status somebody typed, and it means the same thing for every person and every agent |
| A long-running codebase with agents in it | Work survives session boundaries: tracks and handoffs are checked, not hoped for |
Not for you if the project is a weekend script, if you write everything yourself and review it yourself, or if nobody will write the one-line proof markers — they are the only manual part, and a repository where nobody writes them ends up with a gate that enforces nothing.
Why this, when Kiro and Spec Kit exist
Because they solve a different half. Kiro, Spec Kit, BMAD, Copilot's coding agent and the agent CLIs are about producing work: context, specs, planning, tools, sandboxes. Their answer to "is it actually done" is the one everybody already has — run the tests, ask a human.
This is the other half, and it is the half nobody ships: the arbiter. Documentation that fails the build when it stops being true. A work queue whose state only a passing command can write. Scoring files an agent's own commit may not touch.
It is also deliberately not a platform. No runtime, no daemon, no dependencies, no lock-in: one npm package and a JSON file that work the same under Claude Code, Cursor, Codex, Kiro or a person with a keyboard — and keep working when you switch.
The full comparison, layer by layer, is Why this exists.
What it catches
Three real failures from the repos this came out of.
A README that lies. It said infrastructure was "stood up through a single Pulumi program
in infra/". There was no infra/. Ten claims like that turned up in one audit.
FAIL proof markers
README.md:14 make deploy
no make command named "deploy"
Every claim in your docs names the file, test or command behind it. Delete that, and the build breaks.
A task marked done that nobody re-ran. It sat at passing with made-up evidence.
FAIL queue
"checkout-totals" claims passing but its verification fails now
command: npm test -- checkout
fix: fix the regression, or the claim was never true
Only the tool writes passing, and only after the task's own command exits 0. CI re-runs
every one of them.
A session that starts blind. The agent reopens half the repo to work out where the last one stopped. Now it gets handed the answer at startup:
$ harnessimo brief
== specs/TRACKS.md (live work tracks — load a track's handoff first) ==
- Checkout totals — [handoff](specs/0007-checkout/handoff.md) — active, next: T3 currency rounding
== work queue ==
active: checkout-totals — an order total matches the sum of its lines, in every currency
verify with: harnessimo queue verify checkout-totals
== enforced here ==
proof, tracks, tasks, queue, coldStart, cleanExit
not enforced: locked, instructions
One command wires that into your agent: harnessimo hooks install --agent.
All eleven checks
| Command | Fails when |
|---|---|
harnessimo proof |
a documented claim's file, test or command is gone |
harnessimo queue |
a task claiming passing fails when re-run |
harnessimo tracks |
a work track links a handoff that was deleted |
harnessimo tasks |
a ticked checkbox names no check |
harnessimo locked |
an agent commit touched the files that grade it |
harnessimo cold-start |
a fresh clone can't install and verify itself |
harnessimo clean-exit |
a session left TODO, debugger, .only( behind |
harnessimo instructions |
your AGENTS.md grew past the line limit you set |
harnessimo boundaries |
a pattern you banned appears where you banned it |
harnessimo thresholds |
a scored metric fell below the floor you declared |
harnessimo release |
the version in the manifest, the changelog and the tags disagree |
harnessimo doctor prints which of these are on — and which are off. Nothing is switched on
that you didn't ask for.
Starting a new project
pnpm exec harnessimo init && pnpm exec harnessimo check
init looks at what you already have — Makefile or Taskfile, source layout, migrations, CI
— and writes a config from it. The first run is green, so the first red one means
something.
You also get .harness/ (rules, tools, environment, state, feedback) and specs/ (work
tracks and handoffs) scaffolded.
Adding it to an existing project
Turn on one check, make it green, commit. Then the next one.
| What's going wrong | Turn on |
|---|---|
| The README describes things that no longer exist | docs |
| Every session starts over from nothing | tracks |
| Ticked boxes nobody can trace to anything | tracks.gateTasks |
| "Done" that turns out not to be | queue |
| It only works on the machine that built it | coldStart |
| Debug leftovers, stale notes | cleanExit |
| The agent file is a 600-line manual | instructions |
| An agent editing what grades it | locked |
| A key, a colour or an import that belongs elsewhere | boundaries |
| A quality number that quietly slipped | thresholds |
Details: Adopting an existing repo.
Any agent, any model
Nothing here knows which model wrote the code. The checks read files, run your commands and walk your git history — so they work the same under Claude Code, Codex, Cursor, Gemini CLI, a self-hosted DeepSeek, two of them at once, or nobody at all.
One piece is tool-specific, and only because tools differ: the automatic session briefing.
harnessimo hooks install --agent writes it as a SessionStart hook for Claude Code, which
has an API for that. Every other tool gets the same thing in one line — harnessimo agent
prints the contract to paste into whatever instruction file it reads, be that AGENTS.md,
CLAUDE.md, GEMINI.md or a Cursor rule:
$ harnessimo agent
## Harness
- Run `harnessimo brief` at the start of a session: it prints the live tracks, the
head of each handoff and what is in flight. Read it before touching anything.
- Run `harnessimo check` before saying anything is done. Green is the claim; your
summary is not.
- Never edit state in the queue file. `harnessimo queue verify <id>` runs the item's
own command and records the outcome — that is the only way something becomes passing.
That is the whole integration surface. There is no plugin to install, no model to configure and nothing to migrate when you switch — which is the point of keeping the rules in files rather than in a vendor's format.
Using it, by hand and by agent
Same checks, two ways in.
A person runs harnessimo check before pushing — or lets the pre-commit hook do it —
and harnessimo doctor when they want to know what this repository actually guarantees.
Nothing else is required: the checks read files and run commands, so they work in a
repository with no agents anywhere near it.
An agent gets three things it cannot get from an instruction file. At session start a
hook hands it the live tracks, the head of each handoff and what is in flight, so it does
not re-derive them. During the work, harnessimo queue verify <id> is the only way an item
becomes passing — the agent runs the command, the tool records the outcome. At commit, the
same gate a person gets.
harnessimo hooks install --agent # SessionStart briefing, merged into .claude/settings.json
harnessimo hooks install # the fast gates, before every commit
Both flows in detail: Use cases.
Why you can trust it
Every line here is checkable, which is the only kind of trust argument this project is entitled to make:
- Published by a workflow, not a person. Releases are built and signed in GitHub Actions
and authenticated by OIDC — there is no npm token in this repository or in its secrets to
steal. Each version carries a provenance statement naming the commit and workflow that
produced it;
npm audit signaturesverifies it. - Zero runtime dependencies, by a rule its own CI enforces. Nothing it pulls in can break the project it is guarding, and there is no supply chain under it to audit but this one.
- It is held to its own standard. Ten of the eleven run against this repository, including a cold start that clones it into an empty directory and runs the documented commands, and a re-verification of every passing claim. The badge above is that.
- Every rule has a test that proves it fires on bad input — a rule that has only ever passed is an assumption wearing a rule's clothes.
- Used in production, not only demonstrated. Two repositories deleted their own versions of these checks to adopt it; both are linked below and both are public.
- MIT, and small enough to read. About three thousand lines. If it disappeared tomorrow you could vendor it in an afternoon.
Who runs it
Two production repos, both of which deleted their own versions of these checks:
ledger-lens— Next.js, Supabase, Python. Swapped its documentation gates for this package; all 38 of its own unit tests passed without edits, and the counts matched exactly (183 markers across 71 documents).code-knowledge-base— dropped four local scripts, picked up proof markers, work tracks and the task gate.
This repo runs ten of its eleven checks on itself, from a fresh clone. The eleventh,
thresholds, needs a scored metric, and a tool with no metrics to score has nothing to hold
to a floor — harnessimo doctor says so rather than implying otherwise.
What it isn't
- Not a sandbox.
lockedcatches an agent editing its own scoring in CI. It won't stop someone determined to work around it. - Not a code reviewer. It doesn't judge correctness, security or style.
- Not a test-quality checker. A test that asserts nothing passes every rule here.
- Not a context tool. Pair it with a code-graph or codebase-memory MCP — those answer "what should I read", this answers "is it done".
Docs
https://atamaniuc.github.io/Harnessimo/ — every page is also in Russian: по-русски, or the language switcher in the header.
Every page answers one question. Find yours:
| I want to… | Read |
|---|---|
| decide whether this is worth adopting | Why this exists |
| see what a check catches, and what it prints | Reference |
| get to a first green check | Guide |
| turn on one more check, or turn one off | Guide → turn on what hurts |
| look up a config key | Configuration |
| put this into a repo that already has its own scripts | Guide → adopting |
| run several agents against one repository | More than one agent |
| understand why a rule exists at all | The standard |
| ask something short that is not a bug | FAQ |
| fix a run that just went red | Troubleshooting |
| know what was taken from OpenSpec, Spec Kit, BMAD and the rest | SDD |
| contribute a change | Contributing |
For an agent: every page above, as one file — llms.txt.
Development
npm test # the whole suite, no install — Node runs the TypeScript directly
npm run check # tests, then this repo's own checks
npm run typecheck # tsc, strict, over src and test (needs npm i first)
npm run build # what a consumer installs: dist/, with declarations
TypeScript, strict, ESM, no runtime dependencies. Rules live in src/ as pure functions
over strings and in-memory trees; src/resolver.ts and src/cli.ts are the only files that
touch the disk.
There is no build step in the way of running it: sources import each other as .ts, so
Node's own type stripping runs them as they are — which is why npm test needs nothing
installed and the cold-start check still measures the repository rather than npm. tsc
emits dist/ (rewriting those specifiers to .js) and that is what gets published. Build
output is not committed.
License
MIT. Fork it, vendor it, ship it commercially. If you improve a rule, send a PR — one copy is the whole point.