agent-harness GitHub

Agent Harness Blueprint

Last Updated: 2026-10-03 · Applies to: every repo, every machine, every model tier Concrete schemas, skeletons, and literal file drafts live in SPECS.md.

Thesis. A repo’s harness is defined by its blast radius — what can irreversibly break there. Everything else follows: how much standing context it may cost, which gates exist, what authority agents hold, and what the repo is allowed to grow for itself. The harness assumes the model may be weak, wrong, or cheaper next year: judgment gets encoded into structure (hooks, budgets, region maps, restricted toolsets) that a weaker model inherits for free.

The harness guards catastrophe, not capability. Hard walls exist only for the irreversible — secret exposure, destroyed or unowned work, rewritten shared history, public leaks, production data. Everything reversible stays within agent autonomy at every tier: tiers scale verification with blast radius, and they never subtract autonomy (ratified in issue #92).

Every mechanism here was either proven in the estate or is the missing half of something that half-worked. Nothing is speculative.


0. Design principles P1-P12 (cross-cutting, all tiers)

P1 through P12 name this blueprint’s design principles, not another global law set. Global laws are canonical in claude-config; SPECS §1 identifies their source. Use P<N> or global law <N> explicitly in operational text. Historical records using BLUEPRINT law N retain their original numbering as PN; those records are not new operational instructions.

P1. Enforcement ladder

memory → CLAUDE.md → skill → hook → CI → structure (restricted toolset, branch protection, sandbox). Every rule lives at exactly ONE layer — the cheapest that actually enforces it. Prose is promoted to a hook only when violation is objectively machine-detectable AND has recurred. (Formalizes Options workflow_enforcement.md.)

P2. One home per policy

Every policy has exactly one file; everything else links, never restates. (Taskdeck’s review policy lived in 7 files; #1220 took 14 review rounds partly reconciling copies.)

P3. Second-occurrence rule + pruning symmetry

Nothing is built speculatively — structure arrives with the second item (second correction → rule; third bulk-read → region map; second repo needing a skill → hoist it global). Every growth trigger has a decay twin: session logs expire in 14 days, memories uncited 90 days fold to one line, skills uninvoked a quarter get archived, superseded strategies collapse to one SUPERSEDED line. Growth without decay produced olb’s 1,251-file memory swamp.

P4. Budgets with rotation

Every standing artifact has a hard line cap (table in SPECS §3). Overflow ROTATES to archive/ — never deleted, never accumulates in the routed path. A mandate that cannot be literally obeyed (Taskdeck’s ~80k-token required-reading chain) teaches agents to ignore mandates — the most corrosive failure mode found in the estate.

P5. Tripwires are not walls

Regex deny hooks, stamp checks, and token-presence checks are tripwires: cheap, worth keeping, never counted as safety. Walls are branch protection that requires named checks, toolset-restricted subagents, and hermetic runtimes. (The old prefix deny list missed git push -f; Taskdeck’s branch protection “required nothing.”)

P6. The weaker the model, the harder the harness

Spend the top model writing structure and reviewing; run cheap models only inside mapped regions with skills, stop conditions, and PR-only output. A weak model + tight region + stop-hook verification beats a strong model + an 80k-token read mandate.

P7. Capture is automatic; promotion must be scheduled

Any ledger/memory/inbox without a scheduled consumer degrades into noise (314/314 failure-ledger entries unclassified after 8 weeks; nightly lane red 5/5 days unnoticed). The Gardener (§4) is that consumer.

P8. Authority is declared, not negotiated

Push/merge autonomy is a written per-repo setting in .agent-harness/tier.json — the same developer currently runs opposite git postures in different repos, discoverable only by tripping hooks.

P9. Tracked-issue-or-it-doesn’t-exist

Plans living only in prose lose to tracked issues every time (Taskdeck’s only archive plan sat in a gitignored file while agents worked the tracker). Any doc-resident plan gets mirrored into the tracker or it will not happen.

P10. Misleading authority is worse than nothing

Dead repos get 3-line tombstones; stale authoritative docs (metricalgo’s 245-line AGENTS.md for a path that no longer exists) get deleted, not maintained; superseded docs leave the routed path.

P11. Every loop terminates

Review and termination are defined by global laws 2 and 11, not a separate local round count. See SPECS §1 for the canonical source and review-and-ship for the operational procedure.

P12. Mission first

Global law 12 defines mission scope; global law 11 defines termination. No new gates whose subject is other gates or doc consistency. The existing grandfathered set remains: already-built gates, §3 stale-map stamps, the T3 docs-stamp/budget lane, §7 vendor parity-diffs and SPECS §7 stop-hook states. The Gardener may propose retiring gates whose upkeep exceeds what they catch. Closeouts retain the finished / parked / rounds-used scoreboard described in §9; this is not a new review gate.


1. The Tier Ladder

Tiers add verification, never permission. Every tier ships autonomously on its own authority behind global law 2’s risk-calibrated gate (green proving checks; a clean connector outcome for documentation-only or very-low-risk work, otherwise one fresh-context adversarial review); what rises with blast radius is the extra verification — a second distinct lens for genuinely high-risk work at T3, the full declared gate at T4. A tier is never a reason to wait, ask, or leave finished work unmerged — within the repo’s declared authority: .agent-harness/tier.json binds over these defaults, and merge: gated/human-only means exactly that at any tier.

Tier Name Defined by (blast radius) Standing context CI Authority (default) Estate examples
T0 Tombstone Nothing runs here ≤200 tokens none none home-directory wrapper folders, stale product clones, one-off fix checkouts, junk wrappers
T1 Sandbox Only irreversible loss matters (secrets, privacy, money) ≤1k none push+merge free behind global law 2’s gate hq-private (+sensitive_data), LeetCode, CV-builder, new prototypes
T2 Daily driver Lost work / lost context costs real hours ≤3k none (optional fast pre-commit) push+merge free behind global law 2’s gate extract-api (reference implementation), NavSentinel
T3 Workshop Regressions are expensive; sole stakeholder ≤6k required lane, single-OS, <10 min push+merge free behind global law 2’s gate, plus a second lens for high-risk work Taskdeck (after diet), wealthlens-hq
T4 Live wire Other people, money, or production data ≤8k full gate + branch protection push/merge behind the full declared gate (two independent reviews + green CI) olb/series_tools_python, staticprofit (if revived)

Overlay flags (orthogonal to tier, set in tier.json):

T0 — Tombstone

3-line CLAUDE.md: FROZEN <date>. Do not develop here. Live repo: <path>. Delete any other scaffold — stale config actively misleads. Tombstone junk 1-commit wrappers at the wrapper level so git -C at the wrong depth self-identifies. One row in ~/.claude/ESTATE.md. Gardener skips these dirs entirely. Exit: human revives → harness seed --tier N removes the tombstone in the same commit that installs the floor.

T1 — Sandbox

The lightest posture. Bypass comes only from user settings or a launch flag; the repo commits no defaultMode (global laws, “Claude Code runtime facts”). A deny floor (§2) rides along only where a host or the repo wires one. CLAUDE.md ≤40 lines: what this is, how to run it, any hard data rule. No CI, no STATUS, no skills beyond the global process three, no repo review policy beyond global law 2, no read-first list. Start inline; a read-only review subagent is always allowed (global law 2’s independent review). Promote to T2 on evidence of durable use: 3rd+ return session, something consuming its output, or the first “wish I had a test” moment.

T2 — Daily driver (template: extract-api, the estate’s cleanest instance)

T3 — Workshop

Everything in T2, plus:

T4 — Live wire

Everything in T3, plus:


2. The floor: analyzer contract, posture and wiring

One logical, argv-aware PreToolUse deny floor (dispatcher spec in SPECS §5), with a shared analyzer and explicit runtime adapters. Effective rendering depends on posture, tier and overlays; wiring is declared separately. The invariant is the bounded analyzer contract, not an identical runtime refusal at every tier. The floor addresses the IRREVERSIBLE wherever it is wired. Claude wires the shared dispatcher at user scope on hosts that keep one (the primary workstation runs none by owner decision; a repository can declare floor_wiring: none); each active Codex repo owns one project adapter carrying an audit-only normalized dispatcher marker — a declaration the runtime never verifies, so a dispatcher change obliges refreshing every consumer marker and re-trusting each adapter in a fresh /hooks session (SPECS §5). Never stack a global and project Codex floor:

Work-loss guards are tier-dependent, not floor: reset --hard, clean -fd, checkout -- ., worktree remove --force are allowed at T1–T2 (solo relaxed-git posture — wealthlens proved blocking them causes merge-gymnastics workarounds), warn at T3, deny at T4 and under wave_mode (another agent’s work is then in the blast radius). A T3 repo whose relaxed posture is declared (tier.json flag relaxed_work_loss_guards, per SPECS §2) keeps them allow below T4/wave_mode — the flag is ignored where guards are walls.

Plain worktree remove allows at EVERY tier, wave_mode included (owner ruling 2026-07-27; issues #41/#117/#123). Git refuses it on a tree with tracked modifications or untracked files and a checked-out branch survives it — but its clean check ignores gitignored content, which removal then deletes, so a .env living only in that worktree is gone; and a detached worktree’s commits are held only by its own HEAD and die with the removal (global law 7’s git switch -c mandate exists for exactly this). Allowed because git checks the part that matters, never because the plain form is harmless. What DOES stay on the work-loss ladder is every spelling that can carry --force or disable git’s check without showing it in argv: a runtime-computed action word, a dynamic option/separator-free operand token, and -c status.showUntrackedFiles=no-class config — an opaque spelling never scores better than the literal form it might be.

Never scan commit-message or PR-body text at any tier. Proven repeatedly to block the agent’s own descriptions and train --body-file workarounds. Secrets-in-content is CI gitleaks’ job (diff-scoped); command safety is the argv parser’s job.

The floor is a defense-in-depth tripwire by P5, not an exhaustive shell sandbox. Its bounded parser and bypass matrix cover the explicitly tested command forms; the walls at T3+ remain branch protection and restricted toolsets. A change to the floor is T4-class work (top model + review) no matter which repo it runs in.

Current posture and feature freeze

The default below T4/wave_mode for a non-sensitive repository is floor_posture: core. Destructive deletes outside the project, secret-file mutation, downloaded program text run directly, privilege elevation and the tag guard remain double-checks (FLOOR_ACK); git-config execution, work-loss and launcher verdicts proceed. A sensitive_data repository never runs core: a declared core renders as guide. T4, wave_mode and the default sensitive posture retain walls; an eligible repository can declare guide or wall. SPECS §5.4 defines precedence and rendering, including guide’s opacity handling. Since floor 1.8.0 the analyzer itself no longer flags branch history at any tier or posture, sensitive_data included: every floored repository protects its default branch with a server-side ruleset, and the client keeps only what that ruleset does not cover, tags and --mirror (SPECS §6). The sensitive_data public-remote privacy guard is unchanged. A repository declaring floor_wiring: none has no client-floor runtime claim.

FEATURE-FROZEN. Only false-positive fixes that blocked real work, the ratified #21 slice sequence, and repairs to a SPECS §6 charter regression as literally written may change dispatch.py. A newly discovered bypass family is recorded in FLOOR_LIMITATIONS.md, not implemented. The owner-authorized Developer Lens exact-route publication contract is the separately ratified, bounded exception; it does not reopen general parser work. A second owner-ratified exception (#356 step 2, owner decision 2026-10-04) deleted the branch-history families in floor 1.8.0 and kept the narrow tag guard; it is a removal, not new parser surface. For that rollout only, the owner chose to re-pin the consumers before the deployed 1.7.x was canaried, so each re-pinned root’s 1.8.0 re-trust and canaries replace the older canary it still owed (HUMAN_TODO H-22). Permitted source fixes may merge and bump FLOOR_VERSION, but no new version is deployed until the currently deployed one is re-trusted and canaried. Current operator gates live in HUMAN_TODO.md; a source merge is not permission to run sync-global --apply or refresh consumer markers.

The dated measurements and decisions behind these rules are preserved verbatim in BOOK’s historical appendix. They are provenance, not a report of current installations or a second active plan.


3. Regions — the context-economy primitive (T3+; embryo at T2)

The mechanism that makes “work in a self-contained region without digging into others” real:

  1. AGENT_MAP.md at repo root, ≤100 lines: seam table (domain → entry points → invariants → verification command) + an explicit Do-Not-Read-By-Default negative index (archives, generated artifacts, node_modules, dead dirs) + the 6-line Minimum Handoff Shape.
  2. Directory-scoped CLAUDE.md (≤30 lines) in each region root — harness-native: it auto-loads only when files there are touched. Region-local rules live here, nowhere else.
  3. Optional detail maps docs/regions/<domain>.md (≤100 lines), loaded on demand.
  4. The write path: updating the map is part of Definition of Done when a seam moves — enforced by the DoD checklist, not memory. This is what makes the repo SELF-EXPANDING without a crawler or scheduled re-scan burning credits.
  5. Task prompts name a region. Worker agents log a one-line reason before reading outside it. Subagents receive a region map, never “the repo”.

Fan-out economics: stay INLINE when a task touches ≤2 files in one mapped region. Fan out when regions are disjoint, required context exceeds ~20k tokens, or an independent lens is structurally required (review). T0/T1 never fan out. Heuristics, not laws — deep coupling makes “disjoint” illusory (worktree waves leaked 5/6 despite protocols); when a fan-out produces merge conflicts, that’s evidence the regions aren’t real yet. Right-size the fleet: default ≤3–5 subagents, a broad sweep/audit ≤8–12, never a reflexive fleet; put wide mechanical fan-out on the cheap tier at medium/high effort (never low — a cheap model at low effort compounds two handicaps) and reserve the top tier at high/xhigh for the narrow judgment core. Subagents that still need judgment go on the default tier at low effort, not the cheap one. This is what stops a top-model session from spawning a subagent fleet that drains the budget before finishing — the model-effort-routing skill (§6) is the home for the sizing rules.

Stale-map risk: a wrong map misroutes — worse than no map. Maps carry Last-Verified: stamps; the budget script flags >90 days; human edits outside the harness are the known hole (the weekly sitting is the backstop).


4. Self-expansion — the Gardener loop (T2+)

capture (hooks, zero inline tokens) → triage (scheduled agent) → promote/prune (ONE ≤100-line PR) → ratify (human merges).


5. Model & effort routing

Route by JUDGMENT vs MECHANICAL, never by size. Effort level is the cheaper dial — use it before switching models. Full table in SPECS §8; the shape:

Model tiers below (top / default / cheap) are ROUTING tiers — unrelated to the T0–T4 blast-radius ladder in §1.

Work Model tier Effort
Harness growth: deny floor/dispatcher, region maps, skills, hooks, ADRs, global laws; promotion/demotion audits; anything irreversible top xhigh
Merge decisions; second lens on high-risk work top high (xhigh when irreversible or wide blast radius)
Adversarial review gate default high
Code implementation, debugging, feature slices inside mapped regions, routine PRs default high
Gardener triage, tombstone classification, routing/promotion calls, judgment-bearing subagent work, lookups default low
Doc rotation, formatting sweeps, mechanical transforms that are hard to get wrong — including wide mechanical fan-out (§3) cheap medium–high, never low

Delegation is not a task class. Route a subagent by what it is DOING, never by the fact that it is a subagent: a mechanical sweep handed to eight workers is still mechanical (cheap tier, medium/high effort, §3), and a single worker asked for an independent judgment is still judgment.

Triage and classification sit on the default tier, not the cheap one: deciding what matters is judgment wearing mechanical clothes. That misclassification is what kept the Gardener definition (~/.claude/agents/gardener.md — the one canonical path this doc set uses for it) pinned to a cheap model through three separate prose bans.


6. Global & machine layers

~/.claude/ becomes a versioned repo (config, CLAUDE.md, hooks/, agents/, skills/, selected scripts — NOT caches/history) with a private remote, plus scheduled backup of projects/*/memory/. Today the entire meta-system and 139 memory files are one disk failure from gone.


7. Multi-vendor policy

Single-runtime by default. No .codex/ mirror unless a second vendor genuinely runs sessions in that repo (decision recorded in ESTATE.md per repo).


8. Estate migration routing

The original July estate migration sequence is preserved in BOOK’s historical appendix. It is a historical plan, not current instructions to mutate those repositories, and moving it here does not mark any step complete.

For current work, inspect the target repository’s declared authority and live issue/PR state. Use the existing tracker rather than creating a parallel plan (P9). This repository’s ROADMAP.md and plans/ACTIVE.md carry current work routing; HUMAN_TODO.md carries operator-only gates. Executable CLI behavior is in README.md and SPECS §9. No estate-wide migration or runtime activation is implied by these pointers.


9. How this blueprint fails (watch for these)