00 · Start here
Sunil Tiwari· Oct 27, 2026 · 9 min
00 · Start here
A chapter-by-chapter guide to google-research/harness2 (Harness²: recursive agent harnessing). Pinned to commit 1cfe254, so every code link points at exactly the code described.
Reading order
| # | Chapter | What you'll understand | Main diagrams |
| 01 | Architecture overview | The method and the code on one page | Architecture (canvas) |
| 02 | Code structure | Packages, core types, seams | Class, package |
| 03 | One task, end to end | The run lifecycle | Sequence, flow (canvas) |
| 04 | The harness tree | The c1..c8 components and edit rules | Class, state |
| 05 | Evidence and safety | What editors see; leak tripwires | Flow, sequence |
| 06 | Budget, selection and judging | Fixed spend, blind choice, measurement | State, flow |
| 07 | Executors and benchmarks | Plug-in points and adding your own | Component, class |
| 08 | Setup and running | Install to judged report | Deployment (canvas), flow |
Depth standard (every chapter)
- Cover everything in scope: every public class, function and constant in the chapter's files, with what it does, its inputs and outputs, and why it exists.
- Link to the code at the line:
blob/<pinned commit>/path#Lstart-Lendfor each class and function named. - Clickable diagrams: every class or component box links to its definition in the code.
- Show real code: short excerpts for the key logic, with line links.
- Explain the why: design choices, invariants and failure modes, not just the what.
- Worked example: trace one concrete run or input through the chapter.
- No guessing: say "not covered by the code" rather than inventing behaviour.
Glossary
50 terms used across the guide. The last column links the chapters that explain each one.
| Term | Meaning | Chapter |
| Harness | The system around a fixed model that makes it an agent (prompts, tools, memory, skills, orchestration); in the code, a tree of text files on one framework's editable surface. | 01, 04 |
| Harnessing | Optimising the harness; in Harness² the outer level of recursion, which carries adopted harnesses and lessons from task to task. | 01 |
| Substrate | The agent framework a solver rollout runs under: OpenCode (oc) or Codex CLI (cx). Owns the surface, staging and trajectory format. | 02, 07 |
| Executor | The agent that actually does the task (the solver on a substrate); its runs are the rollouts. | 07 |
| Rollout | One execution of one harness on one task; core sees it only as a RunView. Dead rollouts are recorded, never raised. | 03 |
| Base rollouts | The k runs of the unmodified harness (base1..basek), rolled once in the agg namespace and shared by both modes. | 03 |
| Improver session | One model session that edits a harness (INV, DOM, AGG or COMPOSE); also called editor or proposer session. Run by the Proposer class. | 05 |
Channel (ChannelSpec) | How improver and selector models are reached: opencode (default) or claude_cli. Independent of the substrate. | 02, 05 |
| INV / DOM edits | The two proposal dimensions: domain-invariant edits (inv_i) and domain-specific edits (dom_i). | 03 |
| Composition | A stage that merges earlier candidates into one harness: agg1..aggk in parallel mode, c1..ck in sequential mode. | 03 |
| Probe | Running each candidate harness on the same task so its behaviour can be compared; the contrast between runs is the signal. | 01, 03 |
| Stage | One improver step including its single retry; recorded as a Stage and as one ledger session. | 03, 04 |
| Stage fallback | After two failed attempts (or a transport error) a stage inherits the harness it started from; it is still rolled and still counted. | 04 |
| KEEP_BASE | A valid proposal that changes nothing (kept_base=True); a legitimate answer when the evidence argues for no change. | 04 |
Parallel mode (agg) | Width: 2k independent proposals from the same base evidence, then k independent compositions over all of them. | 03 |
Sequential mode (seq) | Depth: k rounds; each round edits the current harness (INV + DOM) and composes c_t, which the next round builds on. | 03 |
| k | The scale: number of bases, finals and sequential rounds; sets the budget R = 4k, P = 3k. | 03, 06 |
| Finals | The mode's k compositions (agg1..aggk or c1..ck); the only candidates selection may choose from. | 06 |
| R / P | Per task and per mode: R = 4k rollouts (k bases + 2k candidates + k finals), P = 3k improver sessions (k INV + k DOM + k compositions). | 06 |
| Ledger | Per-mode record of every rollout and session; assert_identity raises BudgetError unless R = 4k, P = 3k and no label repeats. | 06 |
| Evidence tree | The folder context.build writes for a session (task, source, trajectories, deliverables, harness, pool, library): the only way evidence reaches a model. | 05 |
| MISSION.md | The mission prompt written into an OpenCode session workspace; a short pointer to context/, not the evidence itself. | 05 |
| Tripwire | A check that raises when answer-key paths (leak_globs) or grader-verdict markers would enter model context or be stored; three of them. | 05 |
leak_globs | Per-benchmark answer-key path patterns: filtered out of source copies, rejected anywhere else. | 05, 07 |
| Names-only mode | Proposers see deliverable file names but not contents (proposer_deliverables="names", WorkBuddy code). | 05 |
| Harvest | Copying the edited context/harness/ out of the throwaway session workspace; how a proposal comes back. | 05 |
| Experience library | Per-mode, per-domain store of adopted harnesses plus lessons (INDEX.md), read before each task and trimmed to earlier tasks. | 03, 06 |
| EXPERIENCE.md | A library entry's lesson: why it was chosen, what each edit did, and a transferable cue / lesson / evidence / confidence. | 06 |
| Blind selection | The selector picks one of the k finals from anonymised deliverables (ids A, B… from a SHA-1-seeded shuffle of task, k and mode), with no labels, harnesses or scores. | 06 |
| Trivial selection | At k = 1 the single final is delivered without a selector session. | 06 |
| Selector fallback | After a selector failure, the alphabetically first final is recorded with fallback=True, but the selection stays ok=False: not reflected, not stored, not judged. | 03, 06 |
| Reflection | The deliberately non-blind experience session after adoption; distils edit verdicts and at most one lesson for the library. | 06 |
| Judge | The benchmark grader, reached only through adapter.score from core/judge.py, in a separate command after selection; a failure is None, never zero. | 06, 07 |
Namespace (ns()) | <bench>-<substrate>-<mode><k>[-s<seed>][-<tag>]; with task and label it forms the run id <ns>/<task>/<label>, the cache key. | 02, 03 |
| Stream order | The seeded, per-domain order of tasks; domains run concurrently, tasks within a domain strictly in order. | 03 |
| Domain | The grouping unit (practice area, profession, category or role); one library stream per domain and mode. | 03, 07 |
summary.json | The per-task record (modes, selections, status), kept in the agg namespace and merged under a file lock. | 03 |
| Resume | Rerun the same command: tasks whose summary is ok with intact artifacts are skipped; caches replay the rest. config.json blocks a changed experiment. | 03, 08 |
| BenchSpec | Frozen value describing one (benchmark, substrate) cell: install mode, prompts, channels, leak globs, limits. | 02, 07 |
| BenchmarkAdapter | The protocol a benchmark implements (tasks, execute, trajectory, deliverables, base harness, validate_tree, score). | 02, 07 |
| BenchPrompts | The benchmark's wording for the shared prompts; may not mention benchmark, evaluation, grader, rubric or score. | 02, 07 |
| RunView | What the method knows about one rollout (label, run id, dir, ok, delivered); never carries a score, and its cost fields are never set. | 02, 07 |
| SurfaceSpec | Data describing one framework's editable surface (always-on files, caps, skill dir, plugins or hooks); all tree logic reads it. | 02, 04 |
| c1..c8 | The component slots: c1 system prompt, c2 context policy (not editable), c3 memory, c4 tool guidance, c5 subagents, c6 guardrails + skills, c7 scripts, c8 plugins/hooks. | 04 |
| Omitted-is-inherited | The edit contract: files a proposal doesn't touch are inherited unchanged; deleting a file removes the component. | 04 |
| Autotrigger | Automatic repair that appends a trigger line for any skill not named in the always-on text, within the cap. | 04 |
| Diversity | Mean pairwise line-Jaccard and distinct count over the parallel finals; makes collapse visible but nothing acts on it. | 04 |
| Install / Launcher | A staged harness with its source fingerprint / the benchmark-supplied body a substrate calls to run it. | 02, 07 |
| Run mark | The .adapt_complete marker plus harness fingerprint that makes execute idempotent by run id. | 07 |
| Preflight | Offline readiness checks (harness2-check, repeated by harness2 before spending); never proves a model is reachable. | 08 |
Known gaps and surprises in the code
Findings the chapters flagged as dead code, unused settings or behaviour the docs don't describe, at commit 1cfe254.
RunView.cost_usdandwall_sare never set, so rollout cost is 0 everywhere and the report's spend omits executor and judge cost. (03, 06, 07)- A selector fallback stays
ok=Falsealthough the docstring says it "falls back to a delivered base"; the base branch of_fallbackandrun_selection'spool_kind="mixed"default can't fire in this release. (02, 06) - The anonymisation seed uses task, k and mode, not the sweep's
--seed. (06) - The
harness2CLI defaults to--modes parallel(the Pythonrun_sweepdefaults to both) and passes no tag or task filter;harness2-judgehas no--tageither. (03, 06) .env.exampleis referenced by the README, SETUP andMANIFEST.inbut is not in the tree. (08)BenchSpec.domain_wordis set by every adapter but never read;max_charsis documented as aBenchSpecfield but is a literal in each adapter. (02)- The import rules (core never imports benchmarks or the judge) are conventions: no linter or test enforces them. (02)
- The selector-wording hooks
deliverable_assets_note/_line/_reference_onlyhave no implementer. (02, 07) - Threaded base rollouts are marked
ok=Truewithout checking the run directory exists, unlike_rolland the batched path. (03) ModeResult.errorsis never appended to inrecursion.py. (03)- No per-task wall-clock or cost cap exists in the scheduler. (03)
- Diversity is computed but nothing reads it, and there is no collapse threshold. (04)
- OpenCode plugins (
.ts) get no content check, while Codex hooks get a full schema check; Codex subagents are gated off on all three benchmarks. (04) - No caller passes a system prompt, so the
SYSTEM_ARG_MAXbranch is unused; the Claude CLI channel has no directory sandbox. (05) - Report denominators are graded rows only and are not reconciled across modes;
base_judged.jsonhas no consumer. (06, 08) - JobBench passes the profession slug as the domain, so the domain lens rarely applies. (07)
- Exported but unused:
SCOREABLE,sweep_orphans,codex.final_message,config.env_int;CodexSubstrate.preflightignoresrequire_dist. (07, 08) - The code never restricts the executor's network, and some rubrics are public; block Hugging Face and GitHub before evaluating. (08)
Was this useful?
Make a page like this. Free.Notes and diagrams side by side, written by you or by Claude Code and Codex. Publish it in one click.
Make your own, free