ADLCThe Agentic Development Lifecycle
Appendix B

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.

THE STARTER KIT, PLACEDGUIDES — feedforwardSENSORS — feedback① scaffold: make new-svcgenerates the layered skeleton② types + a layering rule that FAILS THE BUILD(Ch 10 §10.7, tier one)③ BLOCKING on editformat · syntax · types (Ch 7 §7.4, level 1)④ pre-integration: fast unit tests, contract⑤ pipeline: fitness functions⑥ continuous: drift scanCOMPUTATIONALdeterministiccheap to run⑦ AGENTS.md — Appendix AONLY underivable content⑨ a skill for the one recurring workflow⑧ one review agentwith a NARROW, NAMED remit —not "review this PR"INFERENTIALjudgementcostly, fallibleBuild in the order 3 → 1 → 2 → 7 → 8 → 6 → 9. Chapter 26 §26.2: the blocking check first, because it is the highest-authority control and thecheapest to retrofit.
The starter kit placed on the harness quadrant. Numbers give build order, not importance.

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-second

Two 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 PRs

What it scans for, in priority order:

ScanDetectsFrom
Complexity and duplication trendChapter 4's chronic accumulationCh 4 §4.7
Guides with no date or no named failureHarness Theatre formingCh 12, Ch 21
Controls that have not fired in 90 daysSilent Sensor candidates → drill themCh 8 §8.9
Crossing signals — a new dependent, a second author, a credential, a scheduleAn artefact crossedCh 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 gate

Enforce 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:

OutcomeMeaningAction
Control catches itWorkingRecord the date. Keep.
Control misses itHarness TheatreFix or replace
Failure cannot be produced even with the control disabledThe model deficit has closedRetire 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 date

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


Sources
  • 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