Harness Engineering Spec → build → QA → Goal Review
GitHub Get started

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).

Harness Engineering banner

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/.

Stable contractObservable Acceptance Checks decide what done means — not vibes.
Independent QAThe coding tool does not approve its own work when another tool is available.
Integrated proofChecks run again after merging into the plan integration branch.
Durable stateClaims, attempts, evidence, repairs, and input requests survive sessions.

Framework

One workflow, replaceable tools

Only the workflow pipeline is required. Everything else is optional packaging or control.

HarnessSpecification, scheduler, QA loop, integration policy, durable state, and Goal Review.

Context map

Four contexts matter. Only the workflow pipeline is required to deliver software; the others are optional packaging or control surfaces.

ContextWhat lives hereYou interact through
Plugin marketplaceinstall.sh, manifests, host configurationInstaller checklist
Workflow pipelineproject_specs.xml, feature_list.json (catalog), Execution Ledger, orchestrator.mjs, claim-lease.mjsSkills + files in your repo
Supervisor controlharness-control.mjs, host-wide Resource Governor, Control Journal/harness:supervisor
Optional routing.harness/roles.json, MCP serversconfig/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…SkillAgent (automatic)
Describe observable behavior/harness:planner
Map an existing repo/harness:setupinitializer (scaffold only)
Build or resume work/harness:generatorcoding-agent → qa-agent
Run overnight with progress every ~20 min/harness:supervisororchestrator workers via harness-control
Re-audit an already-integrated plan branch/harness:evaluatorGoal Review agent

Core terms

Project GoalWhat “done” means — written in project_specs.xml.
Acceptance CheckOne observable behavior with an ID (e.g. AC-001).
Work ItemCatalog entry in immutable feature_list.json; progress lives in the Execution Ledger.
ContextWork Items built together in one branch/worktree.
Claim LeaseProof that only one worker owns a context.
AttemptOne code → QA → (maybe) integrate cycle.
Repair PlanDiagnosis + instructions after a QA defect.
Goal ReviewFinal independent audit of the whole spec on the plan integration branch.
Input RequestDurable “need your decision” with evidence and choices.

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.

Verifynode --versionclaude --versioncodex --versionopencode --versionpi --version

Step 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.

TaskClaude Code / CodexOpenCodeCursor AgentPi
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.

  1. 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.

  2. Create or open a Git repository

    You git init a folder (or clone an existing repo).

  3. 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 writes project_specs.xml - the append-only contract.

  4. 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.

  5. Start the build

    You type /harness:generator and choose All contexts.

    Initializer agent maps checks → feature_list.json, creates init.sh (start|stop|restart|status|help), scaffolds the repo, and makes the first commit. It never implements features.

  6. 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.

  7. Delegate implementation

    Orchestrator spawns coding-agent per Work Item (up to 3 Attempts).

    Coding happens in the worktree — not on main directly.

  8. 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.

  9. Integrate on the plan branch

    Orchestrator merges the worktree branch into the plan integration branch and reruns checks there (Integrated Verification).

  10. 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.

1

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

2

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

3

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

4

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

5

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

  1. 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).
  2. Reconcile: generator maps every check into the immutable Work Item catalog, copies planning_decision_ids onto each item, and verifies dependency order.
  3. 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.
  4. Build and inspect: coding implements; independent QA exercises a real boundary.
  5. Repair: failures produce evidence and a Repair Plan before a bounded retry.
  6. Integrate: passing work merges into the plan integration branch, then its checks run again there.
  7. 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.

PathPurposeWho writes it
project_specs.xmlProject Goal, direction, stable Acceptance Checks.Planner / setup
.harness-technology-inventory.jsonSetup evidence for material technologies and contradictions.Setup
feature_list.jsonImmutable 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.shPORT-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.jsonLive Claim Leases for all contexts.claim-lease.mjs
.git/harness-control/Control Journal, supervisor lease, Resource Governor quota.harness-control.mjs
.harness/roles.jsonOptional per-role tool/model routing.You (optional)
.harness/projects.jsonOptional monorepo project registry.Setup / planner finalize

Execution Ledger proofs are separate:

  • implementation means coding completed.
  • qa means isolated QA passed.
  • integration means 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

ElementRole
<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.
Minimal example— notes app 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_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.

Work Item shape
[
  {
    "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

FieldMeaning
contextBuild boundary — items in the same context share one worktree.
acceptance_checksWhich spec IDs this item proves.
planning_decision_idsGrilled decisions (ambiguity / trade-off / edge case) linked to those checks.
depends_onOther Work Item IDs that must be integrated first.
verify_firstAudit existing code before changing it (existing-codebase mode).
implementation / qa / integrationThree separate proofs — defaults in the catalog; live values in the Execution Ledger.
retriesGoal 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

Typical fields
{
  "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/

FileContents
state.jsonDerived supervisor status, active workers, retry queue, crash counts.
events.jsonlAppend-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.

A
If the note survives reload

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.

B
If the note disappears

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.

1
Supervisor finished

status: complete and supervisorPid: null.

2
Ledger integrated

Every item has Execution Ledger proofs for implementation, qa, and integration.

3
Goal reviewed

Goal Review has status: complete and phase: complete.

4
Completion persisted

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).

SymptomAction
Build says blockedThree 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 completeThe 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 leaseRecovery 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 upContext-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 deadGhost 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-loop after substantial or repetitive work.

Further help

Reference documentation