Open-source harness for AI coding
Checked delivery for long runs.
You describe a goal once. The harness keeps the contract, splits coding from QA, merges safely, and proves completion on the plan integration branch — even if you close the chat overnight.
Think of it as hiring a project manager (deterministic orchestrator) who delegates to specialists (agents) while you stay the product owner (skills in chat).
Why
Completion needs evidence, not confidence
Short coding tasks fit in one conversation. Long work does not. Context resets, parallel edits, retries, and self-approved implementations make chat state an unreliable source of truth.
The harness externalizes truth into files you can inspect: a specification, a queue, journals, and machine-readable run state under .git/.
Framework
One workflow, replaceable tools
Only the workflow pipeline is required. Everything else is optional packaging or control.
Context map
Four contexts matter. Only the workflow pipeline is required to deliver software; the others are optional packaging or control surfaces.
| Context | What lives here | You interact through |
|---|---|---|
| Plugin marketplace | install.sh, manifests, host configuration | Installer checklist |
| Workflow pipeline | project_specs.xml, feature_list.json (catalog), Execution Ledger, orchestrator.mjs, claim-lease.mjs | Skills + files in your repo |
| Supervisor control | harness-control.mjs, host-wide Resource Governor, Control Journal | /harness:supervisor |
| Optional routing | .harness/roles.json, MCP servers | config/roles.example.json |
flowchart TB
subgraph MKT["Plugin marketplace"]
INS[install.sh / manifests]
end
subgraph PIPE["Workflow pipeline"]
DRAFT[spec draft]
REVIEW[localhost spec review]
SPEC[project_specs.xml]
QUEUE[feature_list.json]
ORCH[orchestrator.mjs]
ATT[attempt-machine.mjs]
CLAIM[claim-lease.mjs]
end
subgraph SUP["Supervisor control"]
HC[harness-control.mjs]
end
subgraph RT["Optional routing"]
ROLES[roles.json]
end
INS --> PIPE
DRAFT --> REVIEW
REVIEW --> SPEC
HC --> ORCH
ORCH --> ATT
ORCH --> CLAIM
HC --> CLAIM
ROLES -.-> ORCH
Who does what
flowchart LR
subgraph You["You"]
SK[Skills in chat]
end
subgraph Engine["Deterministic engine"]
HC[harness-control]
OR[orchestrator]
end
subgraph Workers["LLM workers"]
C[coding-agent]
Q[qa-agent]
I[initializer]
end
SK -->|drafts| DRAFT[(spec draft)]
DRAFT -->|localhost review submit| SPEC[(project_specs.xml)]
SK --> HC
SK --> OR
HC --> OR
OR --> C
OR --> Q
OR -.-> I
The orchestrator has no LLM. It sequences phases, owns retries, and spawns agents. Its state machine was inspired by the harness patterns Anthropic documents for long-running agents and by the Dynamic Workflows pattern in Claude Code — deterministic control with LLM workers at phase boundaries. The supervisor admits parallel workers and relays progress — it does not own Attempt policy.
Ubiquitous language
Skills vs agents
Skills are chat commands you type (/harness:planner, /harness:generator, …).
They live under skills/ and prepare specs or start runs.
Agents are workers the orchestrator spawns per phase (coding-agent, qa-agent, initializer).
You never invoke agents directly.
| You want to… | Skill | Agent (automatic) |
|---|---|---|
| Describe observable behavior | /harness:planner | — |
| Map an existing repo | /harness:setup | initializer (scaffold only) |
| Build or resume work | /harness:generator | coding-agent → qa-agent |
| Run overnight with progress every ~20 min | /harness:supervisor | orchestrator workers via harness-control |
| Re-audit an already-integrated plan branch | /harness:evaluator | Goal Review agent |
Core terms
project_specs.xml.AC-001).feature_list.json; progress lives in the Execution Ledger.Full glossary: CONTEXT.md on GitHub.
Before installation
Install the runtime and one coding tool
The repository machine needs Git, Bash, Node.js 18 or newer, and one authenticated tool: Claude Code, Codex, OpenCode, Cursor Agent, or Pi. Node.js runs setup inventory, reconciliation, orchestration, and supervisor commands.
git --version
bash --version
node --version
claude --version # or: codex --version / opencode --version / pi --version
Optional: project-local .harness/roles.json for tool/model routing. Workers always run in the background. The installer requires jq (it does not auto-install it).
Step 1
Install the harness
Run once in a terminal on the machine that holds the Git repository.
v3.0 is a clean break from 2.x: remove the previous plugin/skills install, then install fresh. There is no mid-flight migration. Control modules live only under skills/supervisor/lib/.
curl -sSL https://raw.githubusercontent.com/vinicius91carvalho/harness-engineering/main/install.sh | sh
The curl one-liner fetches the installer from main, then stages the latest GitHub Release tag.
Override with VERSION=vX.Y.Z, --version vX.Y.Z, or HARNESS_INSTALL_REF=vX.Y.Z (for example v3.0.0).
A local checkout of this repository installs from the working tree.
Interactively the installer asks for install scope first (user global vs project folder; local when Claude is detected), then offers only detected hosts compatible with that scope, then an arrow-key checklist of modules compatible with the selected scope and host (harness pre-checked, toggleable). --scope / --project-dir skip the scope menu; --cli skips the host menu; --yes / --no select all compatible modules or harness only when non-interactive. User-only modules (status-line, shared-config, treehouse) are skipped for project scope. Requires jq (not auto-installed).
For Cursor, harness lands under .cursor/plugins/local/harness/ and copies each skill into .cursor/skills/harness-* so the Agent CLI discovers slash commands.
Native Windows users can run install.ps1. Re-running either installer refreshes installed content safely.
node --versionclaude --versioncodex --versionopencode --versionpi --versionStep 2
Use the command name for your tool
Default harness form is /harness:<command> (Claude Code / Codex). OpenCode and Cursor Agent use /harness-<command> because those hosts disallow : in skill names. Pi registers each skill's own name as a /skill: command.
| Task | Claude Code / Codex | OpenCode | Cursor Agent | Pi |
|---|---|---|---|---|
| Set up existing code | /harness:setup | /harness-setup | /harness-setup | /skill:setup |
| Plan a new goal | /harness:planner | /harness-planner | /harness-planner | /skill:planner |
| Build or resume | /harness:generator | /harness-generator | /harness-generator | /skill:generator |
| Review the goal | /harness:evaluator | /harness-evaluator | /harness-evaluator | /skill:evaluator |
| Operate supervisor | /harness:supervisor | /harness-supervisor | /harness-supervisor | /skill:supervisor |
| Capture lessons | /harness:learning-loop | /harness-learning-loop | /harness-learning-loop | /skill:learning-loop |
| Back up configuration | /harness:update-project | /harness-update-project | /harness-update-project | /skill:update-project |
Grilling (before generator): the planner asks one product question at a time - not a separate command.
It covers three topics: ambiguous requirements (two readers could disagree, for example soft-delete vs hard-delete),
architectural trade-offs (two viable approaches, for example SQLite vs Postgres),
and edge cases (empty input, expired session, not-found).
Answers land in <planning_decisions> inside the spec draft and are proved by Acceptance Checks.
After reconcile, Work Items list planning_decision_ids.
Spec review does not open until the grilling Ready Gate passes; project_specs.xml is written only after you submit.
You can also activate grilling directly by asking “grill me.”
Step 3
Choose the new-project or existing-code path
| You have… | Start with |
|---|---|
| A new idea / new product goal | /harness:planner <goal> |
| An existing repo + a new goal to build | /harness:planner <goal> (existing-codebase mode) |
| An existing working app, just adopting the harness (no new goal) | /harness:setup (no args) |
A reviewed project_specs.xml, ready to build/resume | /harness:generator |
| A long unattended run with monitoring/pause/resume | /harness:supervisor |
| To independently re-audit an already-integrated integration branch | /harness:evaluator |
Type each /harness:... skill command below into your coding tool's chat session, not a terminal. (Install above is terminal-only.)
New project or new goal
Give the planner behavior that can be observed and tested.
/harness:planner Build a notes app where a user can publish a note and find it after reloading.
Review the specification, then build it:
/harness:generator
Generator asks whether to build 1 task, a set, or All — answer All for a new project. It is done when the Goal Review passes and every check is marked complete.
Existing codebase
Run setup from the Git root with no goal, feature, scope, or other text. It derives scope from the repository and never changes application code.
/harness:setup
Review the specification. Setup is complete; it does not validate every feature. To request an audit, run generator and select one task, a set, or all.
/harness:generator
Setup inventories technologies, reports code/docs contradictions, creates the Work Item catalog, and stops before implementation. An optional audit uses verify-first mode for only the selected work, so passing checks are recorded without a rewrite.
OpenCode / Cursor: substitute /harness-planner, /harness-setup, or /harness-generator using the command table above. Pi: substitute /skill:planner, /skill:setup, or /skill:generator.
From zero
Create a project and delegate the entire build
This is the story of a brand-new notes app — the same path works for any greenfield goal. You make product decisions; the harness handles scheduling, isolation, and proof.
-
Install the plugin marketplace
You run the installer once on the machine that holds Git.
Harness registers skills for your coding tool. No project files yet.
-
Create or open a Git repository
You
git inita folder (or clone an existing repo). -
Describe the product goal
You type
/harness:planner Build a notes app where…Planner skill grills you one question at a time, records answers in
<planning_decisions>, opens the blocking localhost spec review until you submit, then writesproject_specs.xml- the append-only contract. -
Review the specification
You confirm grilled decisions and Acceptance Checks in the localhost spec review page (opens only after the Ready Gate passes, then blocks until you submit).
Each check must be observable in a browser or via real HTTP. Comments return to the planner in chat until you are satisfied.
-
Start the build
You type
/harness:generatorand choose All contexts.Initializer agent maps checks →
feature_list.json, createsinit.sh(start|stop|restart|status|help), scaffolds the repo, and makes the first commit. It never implements features. -
Claim isolated workspaces
Claim lease gives each context its own branch, worktree, port, and Run State file.
Parallel contexts do not step on each other.
-
Delegate implementation
Orchestrator spawns coding-agent per Work Item (up to 3 Attempts).
Coding happens in the worktree — not on
maindirectly. -
Independent QA
qa-agent exercises the same Acceptance Checks at a real boundary.
On defect: Defect Report → Repair Plan → next Attempt. On pass: ready to integrate.
-
Integrate on the plan branch
Orchestrator merges the worktree branch into the plan integration branch and reruns checks there (Integrated Verification).
-
Goal Review
When every Work Item is integrated, Goal Review agent audits the whole Project Goal on the integrated plan branch.
You get a durable completion record — or defects reopen specific items.
sequenceDiagram
participant U as You
participant P as planner skill
participant G as generator skill
participant I as initializer
participant O as orchestrator
participant C as coding-agent
participant Q as qa-agent
U->>P: /harness:planner goal
P->>P: draft specification
P-->>U: localhost spec review
U-->>P: Submit and continue
P->>P: finalize project_specs.xml
U->>G: /harness:generator All
G->>I: scaffold (once)
I->>I: feature_list.json + init.sh
loop each Work Item, up to 3 Attempts
O->>C: implement in worktree
C->>Q: isolated QA
alt defect
Q-->>O: Repair Plan
else pass
O->>O: merge + Integrated Verification
end
end
O->>Q: Goal Review on plan branch
Delegation model
You stay the product owner; the harness manages execution
You never micromanage agents. You issue intent through skills; the deterministic engine decides when each specialist runs.
You → Planner skill
Natural-language goal becomes stable Acceptance Checks plus grilled <planning_decisions>. Planner asks one decision at a time until the Ready Gate passes.
You decide product behavior · Planner blocks on spec review before project_specs.xml
You → Generator skill
You pick scope: one task, a set, or all contexts. Generator reconciles spec ↔ queue and starts orchestrator workers.
You choose scope · Initializer scaffolds once · Orchestrator schedules work
Orchestrator → Coding agent
Each Attempt sends a bounded prompt with Work Item steps, Repair Plan (if any), and evidence paths. Coding agent returns structured JSON verdict.
Orchestrator owns retries · Coding agent implements in worktree only
Orchestrator → QA agent
QA never shares the coding session. It reruns Acceptance Checks independently and files Defect Reports with evidence.
QA agent approves or rejects · Repair planning diagnoses root cause
Orchestrator → Merge + Goal Review
Integration merges to the plan integration branch and reruns checks. Goal Review is a separate mandatory pass over the whole spec. When the plan ships, merge that branch to main in one deliberate PR.
You answer Input Requests when blocked · Supervisor runs overnight with progress events
For long runs, /harness:supervisor wraps the same orchestrator workers with a host-wide Resource Governor (memory, quota, concurrency), an append-only fail-closed Control Journal, and durable progress events every ~20 minutes.
How the workflow runs
Seven stages, idea to reviewed
- Specify: planner grills ambiguities, trade-offs, and edge cases, blocks on localhost spec review, then writes the Project Goal, Acceptance Checks, and
<planning_decisions>(setup maps an existing repo without grilling a new goal). - Reconcile: generator maps every check into the immutable Work Item catalog, copies
planning_decision_idsonto each item, and verifies dependency order. - Claim: a ready context receives a lease, its own Git branch and worktree, a port (so parallel dev servers don't clash), and Run State.
- Build and inspect: coding implements; independent QA exercises a real boundary.
- Repair: failures produce evidence and a Repair Plan before a bounded retry.
- Integrate: passing work merges into the plan integration branch, then its checks run again there.
- Review the goal: an independent Goal Review verifies the complete specification.
Multiple sessions may claim independent contexts. Closing a session does not erase work: the next generator resumes durable state. Large goals pin .harness/integration-branch (for example plan/opensource-docker); Work Item branches merge there, not to main, until the plan ships.
Terminology: see Skills vs agents and CONTEXT.md.
Deep dive
Each phase explained
1. Specify (planner / setup)
Planner turns your goal into a reviewed project_specs.xml: Project Goal, technology stack, core features, stable Acceptance Check IDs (AC-001, …), and <planning_decisions> that record grilled answers.
Grilling: before generator runs, the planner asks one question at a time about (1) ambiguous requirements - two readers could disagree; (2) architectural trade-offs - two viable approaches; (3) edge cases - empty input, auth expiry, not-found, and similar. Each resolution is written under <planning_decisions> and proved by Acceptance Checks. Spec review does not open until the Ready Gate passes; project_specs.xml is written only after submit.
The file is append-only after first build - new work adds checks and decisions; old IDs never change.
Setup does the same for an existing codebase: inventories tech, records contradictions, sets <mode>existing-codebase</mode> for verify-first audits. Setup does not require a generator run and does not validate every feature.
2. Reconcile
reconcile.mjs verifies every Acceptance Check maps to at least one Work Item, copies linked planning_decision_ids from the spec onto each catalog entry, and checks dependency order is acyclic. Reconciliation runs before every orchestrator start - a missing mapping blocks execution immediately.
3. Scaffold (initializer, once)
If feature_list.json is empty, the initializer creates the Work Item catalog, init.sh (PORT-parameterized lifecycle: start|stop|restart|status|help), and project structure, then commits. Idempotent: a second run skips scaffolding.
4. Claim lease
claim-lease.mjs atomically assigns a context: dedicated branch (gen/<context>), git worktree, free port, heartbeat, and .git/harness-runs/<context>.json. Only one live owner per context.
5. Attempt loop (coding → QA → integrate)
attempt-machine.mjs runs up to 3 Attempts per Work Item. Each Attempt: coding agent → QA agent → (if QA passed) merge + Integrated Verification. Operational failures (rate limits, crashes) backoff and retry without consuming the defect budget.
flowchart TB
Coding[Coding] -->|"implementation"| QA[QA]
QA -->|"qa pass"| Integrate[Integrate]
QA -->|defect| Repair[Repair]
Integrate -->|"checks pass"| Passed([Work Item done])
Integrate -->|defect| Repair
Repair -->|"attempts remain"| Coding
Repair -->|"3 attempts"| Blocked([Needs guidance])
6. Repair
QA or integration defects produce a Defect Report (expected vs observed + evidence). Repair planning writes a bounded Repair Plan for the next coding Attempt. After 3 failed Attempts the context blocks for your guidance — it never auto-guesses.
7. Goal Review
After all Work Items show integration: true, Goal Review exercises every Acceptance Check and primary user journeys on the integrated plan branch. Defects can reopen linked Work Items (up to 2 reopenings per item).
flowchart LR
Integrated[All Work Items integrated] --> Review[Goal Review on plan branch]
Review -->|pass| Complete[Project Goal complete]
Review -->|defect| Reopen[Reopen linked Work Items]
Reopen --> Retry[Repair and re-integrate]
Retry --> Review
Files delivered
State you can inspect and resume
Every artifact has a job. Together they let a stranger (or future you) continue exactly where the run stopped.
| Path | Purpose | Who writes it |
|---|---|---|
project_specs.xml | Project Goal, direction, stable Acceptance Checks. | Planner / setup |
.harness-technology-inventory.json | Setup evidence for material technologies and contradictions. | Setup |
feature_list.json | Immutable Work Item catalog reconciled from Acceptance Checks. | Initializer + reconcile.mjs |
.git/harness-ledger/ | Execution Ledger: mutable implementation, QA, integration, Attempt, Blocking Scope. | Orchestrator (workflow transition module) |
init.sh | PORT-parameterized app lifecycle (start|stop|restart|status|help); owns .harness/app.pid and dev.log. | Initializer |
harness-progress/ | Human-readable Workflow Journals by work context. | Orchestrator |
.git/harness-runs/ | Run State and worker results per context. | Orchestrator |
.git/harness-evidence/ | Create-only Evidence Artifacts (screenshots, HTTP, logs). | Workers + orchestrator references |
.git/generator-claims.json | Live Claim Leases for all contexts. | claim-lease.mjs |
.git/harness-control/ | Control Journal, supervisor lease, Resource Governor quota. | harness-control.mjs |
.harness/roles.json | Optional per-role tool/model routing. | You (optional) |
.harness/projects.json | Optional monorepo project registry. | Setup / planner finalize |
Execution Ledger proofs are separate:
implementationmeans coding completed.qameans isolated QA passed.integrationmeans the behavior passed after merging.
This table is state written inside a project you ran the harness on. Running /harness:update-project on this repository instead writes config/settings.json and config/home/ — see Backup for their format.
Format
project_specs.xml — the completion contract
The specification is the source of truth for what done means. Work Items are derived from it; they never replace it. Grilled product choices live in <planning_decisions> so a fresh agent does not re-open settled questions.
Key sections
| Element | Role |
|---|---|
<project_goal> | One observable system-level outcome Goal Review evaluates directly. |
<mode> | existing-codebase enables verify-first audits; omit for greenfield. |
<core_features> | Named areas — each area name becomes a context for parallel builds. |
<acceptance_checks> | Stable IDs, observable descriptions, depends_on graph (include in-scope edge cases). |
<planning_decisions> | Grilled answers (ambiguity, trade-off, or edge case) with question, choice, rationale, and linked Acceptance Check IDs. |
<technology_stack> | Ports, frameworks, conventions agents must follow. |
<project_specification>
<project_name>Notes</project_name>
<mode>existing-codebase</mode>
<project_goal>
Published notes remain available after reload.
</project_goal>
<acceptance_checks>
<acceptance_check
id="AC-001"
context="notes"
category="functional"
depends_on="">
<description>
Publish a note, reload, and observe the same title and text.
</description>
</acceptance_check>
<acceptance_check
id="AC-002"
context="notes"
category="edge-case"
depends_on="AC-001">
<description>
Submit an empty title and observe a validation error with no note created.
</description>
</acceptance_check>
</acceptance_checks>
<planning_decisions>
<decision id="D-001" topic="ambiguous-requirement">
<question>Are deleted notes soft-deleted or hard-deleted?</question>
<options>Soft-delete with restore; hard-delete</options>
<choice>Soft-delete with restore</choice>
<rationale>Matches user expectation for accidental deletes.</rationale>
<acceptance_checks>AC-001</acceptance_checks>
</decision>
<decision id="D-002" topic="architectural-tradeoff">
<question>SQLite vs Postgres for local MVP?</question>
<options>SQLite file; Postgres container</options>
<choice>SQLite file</choice>
<rationale>Zero-ops local smoke path.</rationale>
<acceptance_checks>AC-001</acceptance_checks>
</decision>
<decision id="D-003" topic="edge-case">
<question>Empty title on publish?</question>
<options>Reject with validation; allow untitled</options>
<choice>Reject with validation</choice>
<rationale>Prevents blank notes in the list.</rationale>
<acceptance_checks>AC-002</acceptance_checks>
</decision>
</planning_decisions>
</project_specification>
Append-only rule: after the first build, never edit or delete existing Acceptance Check IDs. Add new checks for new features; generator maps only the delta.
Format
feature_list.json — the Work Item catalog
A flat JSON array. Each entry is a Work Item: the smallest vertical slice that can be coded, QA'd, and integrated independently. The catalog is reconciled from project_specs.xml and treated as immutable during execution; live progress flags are stored in the Execution Ledger and overlaid at read time.
[
{
"id": "WI-AC-001",
"context": "notes",
"category": "functional",
"description": "Publish a note and find it after reload",
"steps": [
"Start app via init.sh",
"Publish a note with title and body",
"Reload the page",
"Confirm the same title and body appear"
],
"acceptance_checks": ["AC-001"],
"planning_decision_ids": ["D-001", "D-002"],
"depends_on": [],
"verify_first": true,
"implementation": false,
"qa": false,
"integration": false,
"retries": 0
}
]
Field guide
| Field | Meaning |
|---|---|
context | Build boundary — items in the same context share one worktree. |
acceptance_checks | Which spec IDs this item proves. |
planning_decision_ids | Grilled decisions (ambiguity / trade-off / edge case) linked to those checks. |
depends_on | Other Work Item IDs that must be integrated first. |
verify_first | Audit existing code before changing it (existing-codebase mode). |
implementation / qa / integration | Three separate proofs — defaults in the catalog; live values in the Execution Ledger. |
retries | Goal Review reopen count for this item (not Attempt count). |
Important: false Execution Ledger proofs (implementation, qa, integration) mean “not yet proved,” not “the application is broken.” Setup records what could be audited; it does not schedule the audit. (Older docs called these queue flags.)
Runtime
Durable state under .git/
Machine-readable files survive chat loss. Human journals mirror the important transitions.
Run State — .git/harness-runs/<context>.json
{
"status": "running",
"phase": "qa",
"attempt": 2,
"nextAction": "qa",
"currentFeatureId": "WI-AC-001",
"ownerPid": 12345,
"heartbeatEpoch": 1710000000,
"repairPlan": { "summary": "...", "actions": ["..."] }
}
status may be running, blocked, complete, or interrupted. nextAction tells the next session exactly where to resume.
Claim registry — .git/generator-claims.json
One object keyed by <projectId>--<context>. Tracks port, worktree path, owner PID, heartbeat, and blocked/stale status.
Workflow journal — harness-progress/<context>.md
Append-only human log: Attempt outcomes, Defect Reports, Repair Plans, explicit Resumes. Read this first when something looks stuck.
Evidence — .git/harness-evidence/<project>/<run>/<context>/
Create-only screenshots, HTTP captures, and agent logs referenced by Workflow Journals and Defect Reports.
Supervisor — .git/harness-control/
| File | Contents |
|---|---|
state.json | Derived supervisor status, active workers, retry queue, crash counts. |
events.jsonl | Append-only Control Journal (run_completed, progress, input_required). Fail-closed on corrupt tails. |
responses/ | Your answers to Input Requests (idempotent ack). |
Fleet recovery (kill supervisor, release locks, kill workers) uses guarded harness-control commands with lease authorization — not raw kill/rm. See monorepo ops.
Worked example
Audit one behavior in an existing notes application
Assume the repository already contains a notes application. Users can publish notes, but you want the harness mapped before deciding whether any existing behavior needs verification.
1. Setup maps the repository without testing every feature
cd /work/notes
/harness:setup
Setup reads the application, tests, manifests, configuration, and documentation. It produces the completion contract and queue, then stops. No coding tool launches and no Acceptance Check runs.
Specification excerpt
<project_specification>
<project_name>Notes</project_name>
<mode>existing-codebase</mode>
<project_goal>
Published notes remain available after reload.
</project_goal>
<acceptance_checks>
<acceptance_check
id="AC-001"
context="notes"
category="functional"
depends_on="">
<description>
Publish a note, reload, and observe the same title and text.
</description>
</acceptance_check>
</acceptance_checks>
</project_specification>
Queue excerpt
[
{
"id": "WI-AC-001",
"context": "notes",
"acceptance_checks": ["AC-001"],
"depends_on": [],
"implementation": false,
"qa": false,
"integration": false,
"retries": 0
}
]
2. The user opts into one scoped audit
/harness:generator
When generator asks for scope, choose 1 task and select WI-AC-001. Verify-first mode exercises only that selected behavior before deciding whether code must change.
Coding records the existing implementation as proved without editing it. Independent QA repeats the journey, integration verification repeats it on the plan integration branch, and the Execution Ledger records implementation, qa, and integration as proved.
QA records the expected note, the missing result, and evidence. Repair planning identifies the persistence failure; coding fixes that root cause, then QA and integrated verification rerun the same Acceptance Check.
The journal at harness-progress/notes.md explains the attempt. Machine-readable Run State and evidence remain under .git/harness-runs/. Other mapped Work Items stay untouched.
3. New work still starts with planner
/harness:planner Add reversible note archiving.
Planner loads grilling internally and may ask one decision at a time—for example, whether archived notes disappear from the default list and whether restoring them preserves their original URL. The resulting Acceptance Checks are appended; generator then builds only the new context you select.
Add a feature
Describe it to planner, then build only the new context
Planner appends new Acceptance Checks to project_specs.xml; existing ones are never rewritten.
/harness:planner Add reversible note archiving.
Review the new Acceptance Checks, then build them:
/harness:generator
Generator lists every unbuilt context, including the new one — select it to build only the feature you just described. Existing, already-integrated contexts stay untouched.
Monorepos
Setup detects project boundaries
Run argument-free setup once from the Git root. It lists independently runnable or deployable candidates (no registry write by default), asks which projects to register, then writes .harness/projects.json for those selections only. Confirm is required before mutation (--confirm / HARNESS_CONFIRM_BOUNDARIES=1). Each selected project gets separate specifications, queues, journals, and Run State. Run later commands from the selected project directory; Git coordination stays repository-wide.
Advanced users may maintain the same registry manually before running setup:
{
"projects": [
{"id": "web", "path": "apps/web", "description": "Customer application"},
{"id": "api", "path": "services/api", "description": "HTTP API"}
]
}
Shared packages need no entry unless they run or deploy independently.
Monitor
Watch, pause, resume, and verify a run
From inside Claude Code, Codex, OpenCode, Pi, or Cursor Agent chat, run /harness:supervisor (or /harness-supervisor / host-native forms) to drive the same operations without leaving the session.
The script path below is an OpenCode namespaced install example; substitute your host's harness-control path on Claude, Codex, Pi, or Cursor.
CONTROL=~/.config/opencode/skills/harness-supervisor/scripts/harness-control.mjs
PROJECT=/absolute/path/to/project
node "$CONTROL" status --repo "$PROJECT"
node "$CONTROL" capacity --repo "$PROJECT" --host opencode
node "$CONTROL" pause --repo "$PROJECT"
node "$CONTROL" resume --repo "$PROJECT"
node "$CONTROL" stop --repo "$PROJECT"
node "$CONTROL" events --repo "$PROJECT" --consumer manual-check
Workers always run in the background. Tail logs under .git/harness-control/<project>/logs/ or use fleet-snapshot for monorepo-wide bearings. Poll Control Journal events with any opaque consumer id (default herdr-notify — a journal consumer name, not a UI).
If work blocks, answer the exact Input Request through the supervisor's respond path or any durable event consumer. Branches, worktrees, evidence, and Repair Plans remain available.
status: complete and supervisorPid: null.
Every item has Execution Ledger proofs for implementation, qa, and integration.
Goal Review has status: complete and phase: complete.
Control events contain kind: run_completed.
GEN=~/.config/opencode/skills/harness-generator
node "$GEN/reconcile.mjs" "$PROJECT" --check
jq -e '.progress | (.integrated == .total) and (.total > 0)' <(node "$CONTROL" status --repo "$PROJECT")
node "$CONTROL" events --repo "$PROJECT" --consumer manual-check
Troubleshooting
Fix strange behavior
Start with the live claims view, from the generator skill directory. As with monitoring, this path assumes OpenCode is installed; it is not the same directory Claude Code or Codex install their plugin into.
GEN=~/.config/opencode/skills/harness-generator
bash "$GEN/claim.sh" list "$PROJECT"
Each line reports a context's tasks, port, status, worktree, phase, attempt, next action, owner/child process, and heartbeat. For any context that looks stuck, read harness-progress/<context>.md (Workflow Journal), .git/harness-runs/<context>.json (Run State), and .git/harness-evidence/ (Evidence Artifacts).
| Symptom | Action |
|---|---|
Build says blocked | Three failed coding → QA → integration Attempts always stop for input — the harness never guesses past that point, and a blocked context never resumes on its own. Review the journal and evidence above, then explicitly resume with guidance: bash "$GEN/claim.sh" resume "$PROJECT" "$CONTEXT" $$ force, then rerun the orchestrator with a concise --guidance "..." describing how to proceed. |
| Looks done but won't complete | The supervisor is still draining its retry queue (up to 5 attempts per context) before it can declare the goal complete. Check node "$CONTROL" status --repo "$PROJECT" and wait, or answer any pending Input Request. |
| Worker crashed / stale lease | Recovery reclaims a stale context automatically once its heartbeat passes the lease timeout (HARNESS_LEASE_TIMEOUT_SECONDS, default 60s) — including one owned by a different host. Force only once you're sure the owning process is actually dead: bash "$GEN/claim.sh" resume "$PROJECT" "$CONTEXT" $$ force |
| No progress / pending inputs pile up | Context-scoped input_required events auto-retry each supervisor tick. If still stuck, inspect pendingInputs in status, workerHealth, and worker logs under .git/harness-control/<project>/logs/. |
status lists workers but PIDs are dead | Ghost worker row — restart supervisor; check fleetSnapshot and workerHealth. |
To abandon a context instead of resuming it:
bash "$GEN/claim.sh" release "$PROJECT" "$CONTEXT"
Advanced
Optional routing
Nothing below is required to plan, generate, validate, integrate, or review work. The harness runs completely with a single host CLI. Workers always run in the background; monitor via status, fleet-snapshot, and worker logs.
Routing priority
Ordered candidates with bounded fallback
Each array runs from highest to lowest priority. The engine advances only after a rate limit, authentication failure, unavailable model, launch failure, or timeout. A successful QA response that finds a product defect enters the Repair Plan loop instead of trying another model.
Validation, integrated QA, and Goal Review first prefer a tool different from the actual coding tool. Configured order remains stable within the independent and same-tool groups. Every route and fallback reason is persisted.
A model that fails from an infra error or a repeated QA rejection is demoted to the back of its role list for the rest of the run, so the run self-heals instead of retrying the same broken candidate, and a coder that declines a Work Item falls through to the next candidate. The optional noCredits array is a free-tier fallback tried only once paid options are exhausted by infra/credit errors. Repair retries are bounded by HARNESS_REPAIR_BUDGET (default 2).
Full source: https://github.com/vinicius91carvalho/harness-engineering/blob/main/config/roles.example.json
Why open-source volume models lead: OpenCode Go (DeepSeek V4 Flash/Pro, Minimax M3, Qwen 3.7 Plus/Max) and NVIDIA NIM carry everyday coding and validation on high-credit pools.
OpenRouter free Qwen Coder is a thin free fallback (limits are low).
When work gets hard, Cursor Agent (Composer 2.5, then Grok 4.5 High) steps in.
Claude Opus / GPT-5.5 (via Pi or native CLIs) are late rescue only for stuck bugs — not the default.
Reorder or delete entries to match your licenses; add a harness/model pair to extend a role.
{
"coding": [
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-flash" },
{ "harness": "opencode", "model": "nvidia/deepseek-ai/deepseek-v4-flash" },
{ "harness": "opencode", "model": "openrouter/qwen/qwen3-coder:free" },
{ "harness": "opencode", "model": "opencode-go/minimax-m3" },
{ "harness": "opencode", "model": "opencode-go/qwen3.7-plus" },
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-pro" },
{ "harness": "opencode", "model": "opencode-go/qwen3.7-max" },
{ "harness": "opencode", "model": "nvidia/deepseek-ai/deepseek-v4-pro" },
{ "harness": "agent", "model": "composer-2.5" },
{ "harness": "agent", "model": "grok-4.5-high" },
{ "harness": "pi", "model": "anthropic/claude-opus-4-8:xhigh" },
{ "harness": "pi", "model": "openai-codex/gpt-5.5:high" },
{ "harness": "claude", "model": "claude-opus-4-8" },
{ "harness": "codex", "model": "gpt-5.5" }
],
"validation": [
{ "harness": "agent", "model": "composer-2.5" },
{ "harness": "codex", "model": "gpt-5.5" },
{ "harness": "claude", "model": "claude-opus-4-8" },
{ "harness": "agent", "model": "grok-4.5-high" },
{ "harness": "opencode", "model": "opencode-go/minimax-m3" },
{ "harness": "opencode", "model": "opencode-go/qwen3.7-plus" },
{ "harness": "opencode", "model": "opencode-go/qwen3.7-max" },
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-pro" },
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-flash" },
{ "harness": "opencode", "model": "nvidia/deepseek-ai/deepseek-v4-flash" },
{ "harness": "opencode", "model": "openrouter/qwen/qwen3-coder:free" }
],
"repairPlanning": [
{ "harness": "agent", "model": "composer-2.5" },
{ "harness": "codex", "model": "gpt-5.5" },
{ "harness": "claude", "model": "claude-opus-4-8" },
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-pro" },
{ "harness": "opencode", "model": "opencode-go/qwen3.7-max" },
{ "harness": "opencode", "model": "opencode-go/minimax-m3" },
{ "harness": "opencode", "model": "nvidia/deepseek-ai/deepseek-v4-pro" },
{ "harness": "agent", "model": "grok-4.5-high" },
{ "harness": "pi", "model": "anthropic/claude-opus-4-8:xhigh" },
{ "harness": "pi", "model": "openai-codex/gpt-5.5:high" }
],
"goalReview": [
{ "harness": "agent", "model": "composer-2.5" },
{ "harness": "codex", "model": "gpt-5.5" },
{ "harness": "claude", "model": "claude-opus-4-8" },
{ "harness": "opencode", "model": "opencode-go/qwen3.7-max" },
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-pro" },
{ "harness": "opencode", "model": "opencode-go/minimax-m3" },
{ "harness": "opencode", "model": "nvidia/deepseek-ai/deepseek-v4-pro" },
{ "harness": "agent", "model": "grok-4.5-high" }
],
"noCredits": [
{ "harness": "agent", "model": "composer-2.5" },
{ "harness": "opencode", "model": "opencode-go/deepseek-v4-flash" },
{ "harness": "opencode", "model": "nvidia/deepseek-ai/deepseek-v4-flash" },
{ "harness": "opencode", "model": "openrouter/qwen/qwen3-coder:free" },
{ "harness": "agent", "model": "grok-4.5-medium" }
]
}
mkdir -p .harness
cp config/roles.example.json .harness/roles.json
Copy from the repository's config/roles.example.json (or your plugin install path). Configure or remove every listed provider/model before execution. Without this file, the orchestrator uses the active host CLI directly.
Maintenance
Keep the workflow current and recoverable
- Update: rerun the installer to refresh plugins.
- Inspect: use status/events plus
harness-progress/,.git/harness-runs/, and.git/harness-control/. - Pause safely: use supervisor operations so it and child processes stay consistent.
- Back up configuration: run
/harness:update-project; credentials, caches, and sessions are excluded. - Capture useful lessons: run
/harness:learning-loopafter substantial or repetitive work.
Further help