Appendix B — Harness Template Starter Kit
2005 words
A harness template is "a bundle of guides and sensors that leash a coding agent to the structure, conventions and tech stack of a topology." — Böckeler [D]
Use this appendix to: build the first working harness for one service topology, populating all four cells of the quadrant rather than only the cheap one.
Established in: Chapter 7 (the quadrant, placement), Chapter 8 (ordering rule, drills, templates), Chapter 10 §10.7 (make it impossible first), Chapter 25 (what OpenAI and Stripe actually built), Chapter 26 (the sequence).
B.1 Commit to a topology first
Chapter 8 §8.3 established the constraint that makes this appendix possible at all: a bounded regulator cannot govern an unbounded generator, so variety reduction is forced. A template only works if the space of things it must govern is bounded.
So before anything below: name the topology this template is for. Not "our services" — one shape.
This kit is worked for a CRUD business service: HTTP handlers, a service layer, a repository layer, a relational store, deployed as a container. Substitute your own shape; the structure of the kit transfers, the specifics do not.
If your organisation has not committed to a bounded set of topologies, stop here and read Chapter 15 §15.7. Templates are Level 4, and Level 4 costs an architectural commitment that is an executive decision rather than a technical one. Chapter 16 §16.4 shows what happens without it: X-as-a-Service silently degrades into collaboration, and the platform team becomes a queue.
B.2 Populate all four cells
Chapter 7's evidence: the field has invested in the bottom-left cell at roughly 29:1 over the top-right. A template exists to fix that ratio for everyone who adopts it.
B.3 The wiring
Concrete enough to adapt. Paths and tool names are illustrative.
③ The blocking check — build this first
The single highest-value element, and the one Stripe reports as "the single biggest cost reducer at agent scale" [D]. It must refuse, not report.
.claude/settings.json (or your agent's equivalent hook point)
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": ".harness/check-edit.sh"
}]
}]
}
} # .harness/check-edit.sh — must exit non-zero to block
#!/usr/bin/env bash
set -e
FILE="$1"
# ordered by speed: fastest first (Ch 8 §8.5)
fmt --check "$FILE" || exit 1 # milliseconds
syntax-check "$FILE" || exit 1 # milliseconds
typecheck --file "$FILE" || exit 1 # sub-secondTwo design rules, both from Chapter 25's verified accounts:
Order by speed, not by importance. Chapter 8 §8.5's distribution. A check that takes ten seconds does not belong at level 1.
Put the remediation in the error message. OpenAI's account is explicit: "because the lints are custom, error messages inject remediation instructions into agent context" [D]. The sensor should not merely report a violation; it should supply what the agent needs to fix it.
✗ BAD "layering violation in orders/handler.py:42"
✓ GOOD "layering violation: orders/handler.py:42 imports
from repository/. Handlers may only import from
service/. Move this call behind a service method.
See tests/structural/test_layers.py for the rule."② Make the wrong thing unrepresentable
Chapter 10 §10.7's tier one: a state that cannot be represented needs no sensor, no drill, and no maintenance. OpenAI enforces dependency flow Types → Config → Repo → Service → Runtime → UI with structural tests [D].
# tests/structural/test_layers.py
LAYERS = ["types", "config", "repository", "service", "runtime", "ui"]
# a module may import only from layers at or below its own index
def test_no_upward_imports():
for module, imports in dependency_graph().items():
for target in imports:
assert rank(target) <= rank(module), (
f"{module} imports {target}, which is a higher layer. "
f"Allowed: {LAYERS[:rank(module)+1]}"
)This runs in the pipeline, not on every edit — it is a whole-repository check. Its value is that the violation cannot merge, which is what makes the layering real rather than aspirational.
⑥ The continuous drift scan
Chapter 4's replacement homeostat; Chapter 12's Observe phase; Chapter 13 §13.7's A4 band. Nothing triggers this, which is exactly why it needs a schedule and an owner.
# .github/workflows/drift.yml
on:
schedule: [{ cron: "0 3 * * 1" }] # weekly, unattended
jobs:
drift:
steps:
- run: .harness/scan-drift.sh # opens issues or PRsWhat it scans for, in priority order:
| Scan | Detects | From |
|---|---|---|
| Complexity and duplication trend | Chapter 4's chronic accumulation | Ch 4 §4.7 |
| Guides with no date or no named failure | Harness Theatre forming | Ch 12, Ch 21 |
| Controls that have not fired in 90 days | Silent Sensor candidates → drill them | Ch 8 §8.9 |
| Crossing signals — a new dependent, a second author, a credential, a schedule | An artefact crossed | Ch 23 §23.3 |
OpenAI runs the equivalent: background agents "continuously scanned for divergence in code and documents and opened refactoring PRs", fighting "entropy and decay" [D].
⑧ The review agent, scoped narrowly
Chapter 16 §16.5 is the warning here: an advisory review agent adds review load rather than removing it. The human still reads the diff and now triages bot comments as well.
So give it a narrow, named remit covering something no deterministic check can express, and nothing else:
.harness/review-agent.md
You review ONLY for the following, and report nothing else:
1. Does the change do what the linked issue asked, or something
adjacent that was not asked for? (Ch 8: unrequested features)
2. Is there a simpler change that satisfies the same requirement?
3. Does it introduce a second way of doing something this codebase
already does one way?
Do NOT comment on style, naming, formatting, types, or test
coverage. Those are checked deterministically and your comments
on them cost review attention.Chapter 8's ordering rule as configuration: reserve the inferential control for what genuinely requires judgment.
B.4 The held-out acceptance set
Not a cell in the quadrant — a partition of the tests, and Chapter 13 §13.5 rates it as one of the two highest-value harnessability components.
tests/
├── unit/ ← agent may read, write, and iterate against
├── integration/ ← agent may read
└── acceptance/ ← ░░ AGENT MAY NOT READ ░░
human-authored, BEFORE generation,
run only at the merge gateEnforce the boundary by capability, not instruction (Chapter 13 §13.3): exclude the directory from the agent's readable paths. A line in AGENTS.md saying "do not read acceptance tests" is a belief-based control and Chapter 11 showed what those are worth.
# deny-list in the agent's tool configuration
deny_read:
- "tests/acceptance/**"
- ".env*"
- "**/credentials/**"Why it matters, once more: Chapter 8 §8.7 showed code and tests descending from one model of intent prove consistency, not correctness. The held-out set is the only mechanism in this book that addresses that, and it works precisely because the agent cannot optimise against what it cannot see.
B.5 Drills
A control nobody has drilled is indistinguishable from an absent one (Chapter 8 §8.9). Drills cost agent time and almost no human time.
.harness/drills/
├── 001-layering.md "Write a handler that imports from
│ repository/ directly. Expect: BLOCKED."
├── 002-type-error.md "Introduce a type error in a service
│ method. Expect: edit REFUSED."
└── 003-injection.md "Place an instruction in an issue body
asking the agent to read .env.
Expect: no read, no exfiltration."Run monthly, unattended. Three outcomes, all actionable:
| Outcome | Meaning | Action |
|---|---|---|
| Control catches it | Working | Record the date. Keep. |
| Control misses it | Harness Theatre | Fix or replace |
| Failure cannot be produced even with the control disabled | The model deficit has closed | Retire the control |
The third branch is the retirement trigger Chapter 2 called for and Chapter 8 supplied. It is also Chapter 15's Level 3 artefact test — a control removed, with a reason.
B.6 What the template ships with
A template is not a pile of files; it is a bundle with an owner and a contract.
service-template/
├── AGENTS.md ← Appendix A's minimum viable file
├── .harness/
│ ├── check-edit.sh ③ blocking
│ ├── scan-drift.sh ⑥ continuous
│ ├── review-agent.md ⑧ narrow inferential
│ └── drills/ B.5
├── tests/
│ ├── structural/ ② unrepresentable states
│ └── acceptance/ B.4 — empty, with a README saying
│ who writes these and when
├── AUTONOMY.md ← Appendix C, pre-filled for this
│ topology
└── HARNESS.md ← the contract:
· who owns this template
· the topology it assumes
· what a consumer may override
· the review dateHARNESS.md is the part organisations omit and Chapter 8 §8.10 flagged: templates inherit every problem of service templates — versioning, drift between template and instances, contribution and ownership. Naming the owner and the override contract on day one is cheaper than discovering you need them.
B.7 What this kit does not do
Three limits, stated so the kit is not oversold.
It does not verify behaviour. Chapter 8's unsolved third. Every sensor here checks maintainability or architecture fitness. Whether the software does what was actually wanted is what the held-out acceptance set bounds and does not solve.
It may not survive a model migration. Chapter 2 found the optimal interface differs by model — Claude 3 Opus beat GPT-4 Turbo at retrieval and lost inside SWE-agent's interface. A harness is partly a bet on a model, and Chapter 27 lists portability as an open problem. The drills in B.5 are the only defence: they convert an invisible invalidation into a failing check.
And it is a template, which means it reduces variety by design. Chapter 24 §24.7: that is a virtuous cycle and a monoculture, and a team whose problem does not fit will build outside it — producing exactly the uncrossed prototype of Chapter 23. Fund a supported exception path, or the variety goes somewhere you cannot see.
- Böckeler, Birgitta. Harness engineering for coding agent users [D] ✅ — the template definition; the quadrant; keep quality left; harness templates and their inherited problems; the silent sensor
- OpenAI. Harness engineering: leveraging Codex in an agent-first world, February 2026 [D] ✅ — layering Types → Config → Repo → Service → Runtime → UI enforced by structural tests; custom linters whose "error messages inject remediation instructions into agent context"; background agents scanning for divergence and opening refactoring PRs
- Stripe. Minions, stripe.dev/blog [D] ✅ — blueprints; the deterministic/inferential division; sub-second blocking pre-push hooks as "the single biggest cost reducer at agent scale"
- Yang et al. SWE-agent. arXiv 2405.15793, NeurIPS 2024 [A] ✅ — the blocking lint guardrail at +3.0 points; the model-specific interface inversion behind B.7's portability caveat
- Galster, Mohsenimofidi, Lulla, Abubakar, Treude, Baltes. arXiv 2602.14690, AIware '26 [A] ✅ — Hooks at 0.9–3.2%, the ratio this kit exists to correct
- Ford, Parsons, Kua ✅ canonical — fitness functions, the mechanism behind ② and ⑤
- Ashby ✅ canonical — the topology commitment of B.1