📖 New to harness? Read README.md (日本語: README.ja.md) for concepts, terminology (Tier-A / rubric / Principal Skinner / foundation-sprint / ...), and the three-skill overview before diving into implementation details.
harness-loop — Autonomous Sprint Execution Loop
Orchestrator for the GAN control loop. Consumes the sprint backlog
produced by harness-plan and runs each sprint through
Negotiation → Implementation → PR. Every state transition lands in
.harness/progress.md, .harness/_state.json, .harness/metrics.jsonl,
and git so the loop survives context compaction and session restarts.
Roles dispatched through this orchestrator:
- Planner (Claude) — stalemate arbiter and replanner
- Generator (Claude / Codex CLI / Codex via cmux / other MCP) —
writes code per
_config.yml.generator_backend - Evaluator (Claude + Playwright MCP / Playwright CLI / curl / custom-script) — scores rubric
Orchestrator responsibility (read first)
You are the Orchestrator. Your job is to dispatch Planner / Generator / Evaluator and own shared state (_state.json, progress.md, metrics.jsonl, git checkpoints, PRs). You must NOT perform their work yourself.
Do
- Render prompts by placeholder substitution only (
{{EPIC_NAME}},{{SPRINT_NUMBER}},{{ITER}},{{EVALUATOR_FB_PATH}}, etc.) - Point the agent at contract / feedback paths to read / write
- Write
_state.json/progress.md/metrics.jsonl/ git commits / PRs; raisepending_worker_exit=trueafter each turn-ending durable write sostop-guard.shcan allow natural exit (see resilience-schema) - Apply small repo hygiene fixes (
.gitignore/.editorconfig/.gitattributes1-2 line additions) when clearly needed; code / schema / migration changes remain Generator work - Work on a feature branch (see Step 1 / Step 3)
Don't
- Write code, schemas, docker-compose files, or other implementation content inline in prompts (Generator's job)
- Make design decisions — file layout, dependency picks, CLI flags, migration names (Generator's job)
- Score an agent's work or decide rubric threshold values (Evaluator / Planner / Negotiation's job)
- Commit directly on
main/master/ default branch (Step 1 refuses this) - Skip agent dispatch and do the work yourself "to save time"
Full rationale + examples: README.md §Orchestrator's responsibility.
Required Reading — Open BEFORE doing the step
Claude Code tends to skim SKILL.md. For each step below, you MUST open and read the listed reference file(s) before acting. The SKILL.md only contains the dispatch skeleton; protocol detail lives in references.
| Step | Phase | Required file(s) to open |
|---|---|---|
| Step 1 | Detect state, pin Generator backend (4-layer resolution) | references/generator-dispatch.md §4-layer resolution, references/shared-state-protocol.md §Write permissions |
| Step 3.5 | Every Generator dispatch | references/generator-dispatch.md, references/validator-protocol.md |
Step 2 (mode=autonomous-ralph) |
Supervisor / worker branching | references/supervisor-dispatch.md, references/autonomous-ralph.md |
| Step 4 | Negotiation | references/negotiation-protocol.md, references/generator-dispatch.md |
| Step 6 | Implementation | references/shared-state-protocol.md, references/validator-protocol.md |
| Step 6 (mid-impl replan) | When a contract debt trigger fires | references/negotiation-protocol.md §Mid-impl replan, references/shared-state-protocol.md §Mid-impl replan escalation |
| Steps 8–10 | PR, sprint transition, final summary | references/completion-and-transition.md, plus references/pr-creation-guide.md for Step 8 and references/generator-dispatch.md §4-layer resolution for Step 9 |
| Step 7 | Checkpoint / Principal Skinner | ../harness-init/references/resilience-schema.md, references/git-strategy.md (Orchestrator owns the atomic commit; agents must NOT) |
| Step 8 | PR creation | references/pr-creation-guide.md |
Foundation-sprint (sprint-0, type: foundation) |
Skips negotiation + G⇄E loop | references/foundation-loop-protocol.md, ../harness-init/references/templates/foundation-sprint-checklist.md |
Mode autonomous-ralph / scheduled |
Headless runs | references/autonomous-ralph.md |
| Optional: metrics export | When otlp_endpoint is set |
references/otlp-exporter.md |
Prompt templates for Generator and Evaluator invocations live under
references/prompt-templates/ (EN/JA).
Language Rules
Resolve narrative language: explicit override (in English, 日本語で) >
project mandate in CLAUDE.md / AGENTS.md > current user prompt >
fallback skill source language (English).
Never infer from machine text (git log, progress.md, JSON keys, state
enums, file paths, commands). Keep such tokens unchanged. AskUserQuestion
body uses resolved language; option labels/descriptions stay bilingual
(English / 日本語).
Reference files exist as <name>.md (EN) and <name>.ja.md (JA).
Prerequisites
- Harness initialised —
.harness/_config.yml,.harness/scripts/progress-append.sh, and.claude/agents/{planner,generator,evaluator}.mdexist. If not, instruct the user to run/harness-init. - Plan completed —
.harness/<epic>/roadmap.mdexists and_state.json.phase ∈ {ready-for-loop, negotiation, impl, evaluation, pr, done}. Otherwise instruct the user to finish/harness-plan. jqandgitavailable.- Tracker pre-flight — if
_config.yml.tracker == github, rungh auth status. Fail fast. - Fresh agent registry after
/harness-init— ifTask(subagent_type="generator"|"evaluator"|"planner")is missing or falls back to a general-purpose agent,/clearis insufficient. Fully exit Claude Code, relaunch the repo withclaude --resume, then retry/harness-loop.
Do not partially execute on failure. Surface the missing piece and exit.
Boot Sequence
Execute first on every invocation — fresh session or resume:
git log --oneline -20tail -30 .harness/progress.mdcat .harness/_state.json
Decision table:
_state.json condition |
Action |
|---|---|
completed == true |
Report "epic done" and exit |
aborted_reason != null |
Surface reason; interactive mode asks user to resolve |
pending_human == true |
Tier-A halt; surface details and stop |
phase == ready-for-loop |
Fresh epic — autonomous-ralph does a once-per-epic boot reset (keyed on start_time_epic, before the Principal Skinner gates: re-anchors start_time / cost / stagnation / iteration; see references/autonomous-ralph.md), then Step 1 |
phase ∈ {negotiation, impl, evaluation, pr} |
Resume — enter Step 1, branch by phase |
In interactive mode, confirm resume vs restart via AskUserQuestion.
In non-interactive modes, auto-resume per _state.json.
Execution Flow
Step 1: Detect State, Pin Generator Backend
Parse _state.json for current_epic, current_sprint, phase,
iteration, Principal Skinner budget. Active sprint directory:
.harness/<epic>/sprints/sprint-<n>-<feature>/.
Pin the Generator backend via 4-layer resolution per
references/generator-dispatch.md §4-layer resolution
(state → contract → roadmap → config; legacy bypass when
_config.yml.sprint_level_generator_override == false; codex_cmux
falls back to claude when cmux / CMUX_SOCKET_PATH is unavailable).
Write the resolved value to _state.json.effective_generator_backend
(atomic jq | mv) and append
[<ts>] backend pinned: <backend> (source: <source>) to progress.md.
Step 3.5 dispatch reads this cache directly; the 4-layer resolution is
re-evaluated only at Step 9.
If the resolved backend is codex_cli and mode == interactive, the
kickoff approval MUST explicitly mention danger-full-access. Do not
dispatch until the operator attests that this is acceptable for the
sprint.
Note: branch setup is unconditional in Step 3. If HEAD is on the default branch when harness-loop starts, Step 3 creates the sprint branch off the current HEAD; Step 1 only logs the starting branch.
Step 2: Execution Mode Selection
Mode is chosen once at loop start and persisted to _state.json.mode.
AskUserQuestion is permitted only in interactive mode and in the
interactive supervisor branch of autonomous-ralph.
Precedence: --mode CLI flag > existing _state.json.mode > interactive
prompt > "continuous" default.
| Mode | Loop control | AskUserQuestion |
|---|---|---|
interactive |
In-process; pause after each iter | allowed |
continuous |
In-process; run to completion | forbidden |
autonomous-ralph |
Interactive session = supervisor attach/spawn via .harness/ralph.pid; non-interactive worker = one unit via fresh claude -p --permission-mode bypassPermissions |
supervisor only |
scheduled |
Mix of continuous + Ralph at fixed cadence | forbidden |
Supervisor / worker split is mandatory:
if --stop-wrapper:
stop wrapper via .harness/ralph.pid and exit
if mode == "autonomous-ralph":
if interactive session detected:
ensure wrapper is running (attach if live, spawn if absent/stale)
watch progress.md + ralph.log and relay important events
handle pending_human / Tier-A via AskUserQuestion
remain supervisor; do not execute the worker unit inline
else:
execute exactly one worker unit and exit
Open references/supervisor-dispatch.md for lifecycle details and
references/autonomous-ralph.md for the internal wrapper contract.
Step 3: Load Current Sprint
Read .harness/<epic>/roadmap.md frontmatter; select the sprint where
n == _state.json.current_sprint. Load contract.md, shared_state.md,
and feedback/ for that sprint.
If the sprint directory is missing (roadmap drift), set
aborted_reason: "sprint-missing:<n>" and halt.
Set _state.json.phase = "negotiation" if fresh; else keep as read.
Sprint branch setup
First action per sprint: create (or check out) the sprint branch before
any commit. Run unconditionally — do NOT ask for user confirmation.
One branch per sprint; bundled peers share the primary peer's branch.
Starting HEAD does not matter (main / master / another feature branch /
the correct sprint branch all work; the checkout -b or checkout
handles every case).
harness/<epic>/sprint-<n>-<feature> (split; also foundation n=0)
harness/<epic>/sprint-<primary-n>-<primary-feature> (bundled — lowest-numbered peer)
BRANCH="harness/<epic>/sprint-<n>-<feature>" # bundle → primary peer's name
git rev-parse --verify "$BRANCH" >/dev/null 2>&1 \
&& git checkout "$BRANCH" \
|| git checkout -b "$BRANCH"
Record to _state.json.sprint_branch and append progress.md:
[<ts>] branch: <BRANCH> (created|reused) from <starting-HEAD>
sprint_branch == null is the cursor that mandates this Step run on the next worker tick — harness-init and Step 9 transition both reset it to null so a new sprint cannot inherit the previous sprint's branch. The resolved name is derived from <epic> + roadmap, not from the prior sprint_branch value.
Foundation-sprint protocol branch: if the loaded contract.md has
type: foundation, skip Steps 4–7 (negotiation / rubric iteration) and
follow references/foundation-loop-protocol.md
instead. Resume at Step 8 (PR) / Step 9 (sprint transition) on Attest.
Plan-side doctrine (why / when to insert a foundation-sprint) is in
../harness-plan/references/foundation-sprint-guide.md.
Step 3.5: Generator Dispatch (backend-aware)
Open references/generator-dispatch.md. Invoked by both Step 4 and Step 6.
Short summary (full detail in the reference):
- Render
prompt-templates/generator-<phase>.mdto a temp file with per-invocation substitutions - Invoke per backend;
clauderequires post-dispatch viaclaude-dispatch.sh,codex_cliuses.harness/scripts/codex-cli-dispatch.sh,Skill(skill="cmux-delegate", args="...")forcodex_cmux - Wait for the backend-specific completion signal defined in
generator-dispatch.md§Completion signal before consuming feedback files - Expect phase-specific feedback:
negotiation =
feedback/generator-neg-<round>.md+generator-neg-<round>-report.json, implementation =feedback/generator-<iter>.md+generator-<iter>-report.json - Fallback: claude backend = mandatory
claude-dispatch.sh --post-dispatch; others seereferences/generator-dispatch.md - Pipe report to
.harness/scripts/codex-progress-bridge.sh
Step 4: Negotiation Phase
Open references/negotiation-protocol.md.
if contract.status == "active":
skip Step 4 (resume case, already negotiated)
for round in 1..contract.max_negotiation_rounds (default 3):
Dispatch Generator (Step 3.5) with prompt-templates/generator-negotiation.md and validate per references/validator-protocol.md
Dispatch Evaluator with prompt-templates/evaluator-negotiation.md
({{ROUND}}=round, {{GENERATOR_FB_PATH}}=feedback/generator-neg-<round>.md or "(none)")
Copy round summaries to shared_state.md/Negotiation
if both agree: break
if no agreement after max rounds:
Dispatch Planner (phase=ruling); Planner writes feedback/planner-ruling.md
and overwrites contract.md rubric + max_iterations
Append one progress.md line per round:
[<ts>] negotiation: round=<r> agent=<role> signal=<accept|counter|escalate> delta=<short> file=feedback/generator-neg-<r>.md
Finalise contract frontmatter (acceptance_scenarios, rubric from
../harness-init/references/rubric-presets.md,
max_iterations). Flip status: active, record the contract commit
SHA in shared_state.md/Contract. Advance _state.json.phase = "impl".
Step 5: Contract Freeze and Commit
git add .harness/<epic>/sprints/sprint-<n>-*/
git commit -m "harness-loop: sprint-<n> contract frozen"
Before entering Step 6, explicitly reset _state.json.iteration = 0
so the first implementation turn writes generator-1.*. Keep
_state.json.negotiation_round as the frozen negotiation cursor.
Store SHA in _state.json.last_commit. Append progress.md:
decision: sprint-<n> contract frozen @ <SHA>. As the LAST durable write of this turn, atomically set _state.json.pending_worker_exit = true.
Step 6: Implementation Loop
Open references/shared-state-protocol.md for write permissions, file layout, and the report.json contract.
while iteration < contract.max_iterations:
iteration += 1
# Generator turn — see Step 3.5
_state.json.phase = "impl"
Dispatch Generator with prompt-templates/generator-implementation.md
({{ITER}}=iteration, {{EVALUATOR_FB_PATH}}=feedback/evaluator-<iter-1>.md if iter>1)
Run `.harness/scripts/validate-generator-report.sh --report ... --narrative ... --report-dir ... --phase impl`; then bridge/protocol-update progress/state from report.json.
# Evaluator turn — Task tool, Claude, always
_state.json.phase = "evaluation"
Dispatch Evaluator with prompt-templates/evaluator-implementation.md
({{ITER}}=iteration, {{GENERATOR_FB_PATH}}=feedback/generator-<iter>.md,
{{EVALUATOR_TOOLS}}=_config.yml.evaluator_tools joined by commas)
Run `.harness/scripts/validate-evaluator-report.sh --report ... --narrative ... --sprint-dir ... --report-dir ... --phase impl --strict` before reading verdict.
invalid report, missing phases, or non-zero quality gates force fail.
Copy the compliance-adjusted verdict to shared_state.md/WorkLog and /Evaluation.
# Mid-impl replan check — see references/negotiation-protocol.md §Mid-impl replan
# Triggers in priority order: Layer 1 (agent request) / Layer 2 (axis stagnation)
# / Layer 3 (supervisor --replan-contract). Gated by _config.yml.mid_impl_replan
# (enabled, min_consecutive_signals, max_per_sprint, axis_band_threshold).
if mid_impl_replan trigger fires AND not gated:
Dispatch Planner (phase=mid-impl-replan) with contract.md, all post-freeze
feedback, trigger context, cross-iter axis table. Planner writes
feedback/planner-ruling-impl-<iter>.md.
Apply ruling → contract.md delta, _state.json.contract_revisions[] append,
mid_impl_replan_count += 1, rubric_stagnation_count = 0, iteration kept.
# Decide verdict + terminal state BEFORE Step 7 checkpoint so all
# durable writes land in one atomic pass
verdict = "pass" if evaluator report is compliant and all axes >= threshold else "fail"
if verdict == "pass":
contract.status = "done"; phase = "pr"; terminate = true # final sprint included; Step 8 is never skipped
elif any Principal Skinner condition fires (see Step 7):
contract.status = "aborted"; set aborted_reason; terminate = true
else:
terminate = false
checkpoint(iteration, verdict, contract.status) # Step 7
if terminate: break
Evaluator failure feedback (input for next Generator) contains
iter, verdict: fail, failing_axes array, and a retry_hint.
Step 7: Iteration Checkpoint and Principal Skinner
Open ../harness-init/references/resilience-schema.md
for the canonical _state.json + metrics.jsonl schema.
Every iteration (pass / fail / abort) atomically persists in one pass:
contract.md— onpassor Principal Skinner fire: frontmatterstatus: done | aborted, fillSprint Outcomesection_state.jsonviajq | mv— iteration, last_agent, next_action, last_commit, phase, features_pass_fail, cumulative_cost_usd, rubric_stagnation_count, aborted_reason (if fired)metrics.jsonl— append one JSON line per schema- When a Tier-A guard caused
pending_human=true, include the latesttier_a_lastpayload so dangerous command attempts can be counted and audited across sprints
- When a Tier-A guard caused
- Commit —
git add -A && git commit -m "harness-loop: sprint-<n> iter-<iter>"(non-fatal; log any failure and continue) - Worker-exit signal — atomically set
_state.json.pending_worker_exit = trueas the last write
Principal Skinner stop-check (the five conditions, computed before
the checkpoint so aborted_reason lands in the atomic write):
| Condition | Source | Default |
|---|---|---|
iteration >= max_iterations |
contract + state | 8 |
wall_time >= max_wall_time_sec |
now - start_time |
28800 |
rubric_stagnation_count >= rubric_stagnation_n |
state + config | 3 |
cumulative_cost_usd >= max_cost_usd |
state + config | 20.0 |
pending_human == true |
Tier-A guard hook | — |
Append progress.md:
evaluation: iter=<n> verdict=<pass|fail> axes=...
and on abort: stop: reason=<condition> detail=<text>.
Principal Skinner never deletes state. The loop stops and leaves everything on disk for later resume, replan, or budget bump.
Interactive per-iteration gate
interactive mode only: after each checkpoint, offer continue /
restart (fully exit Claude Code, then relaunch with claude --resume) /
pause / abort via AskUserQuestion. Non-interactive modes skip
this gate.
Step 8: PR Creation on Sprint Pass
Read references/completion-and-transition.md
completely (.ja.md for Japanese), then execute its canonical PR creation,
sprint transition, state-reset, final-write, and summary contract in order.
Step 9: Sprint Transition
Execute Step 9 from the required completion-and-transition reference.
Step 10: Final Summary
Execute Step 10 from the same reference after its completion assertion passes.
Error Handling
Use the Error Handling table in the required completion-and-transition reference. Do not convert its halt or retry responses into silent fallbacks.
Usage
/harness-loop # start or resume
/harness-loop --mode <mode> # interactive | continuous | autonomous-ralph | scheduled
/harness-loop --mode scheduled --ralph-every 5 # hybrid
/harness-loop --from-sprint 3 # skip (confirm required)
/harness-loop --replan-current-sprint # re-enter Negotiation, iter = 0
/harness-loop --replan-contract # mid-impl Planner ruling, iter kept
What harness-loop does NOT do
- Does not change the epic plan — use
/harness-plan --replan - Does not edit rubric after contract freeze —
--replan-current-sprint - Does not refine rules from failures —
/harness-rules-updatedoes - Does not configure hooks or agents —
/harness-initowns those - Does not bypass Tier-A denials — human approval required
Observability
Four files: .harness/progress.md (human trace, append),
.harness/_state.json (machine cursor), .harness/metrics.jsonl
(per-iter metrics), git log (one commit per iter). Optional OTLP
export when hook_level == strict and otlp_endpoint is set — see
references/otlp-exporter.md.