Agent reliability work looks like infrastructure. It is domain modeling, and the object it models is a constraint. One constraint carries four independent attributes: whose rule it is, what mechanism carries it, what happens when it fires, and whether a model or a machine decides. Collapse any two and your harness stops traveling. I have no number for how much variance to accept. This page is the apparatus for holding one you pick yourself.
What a constraint is, what it is made of, where it can live, and how it moves. Twelve sections, and no machinery in any of them. Part II catalogs what you build on top.
Businesses already know how to do this. They write a risk appetite, define tolerances, build controls, and keep a register of the exceptions. Agent output needs the same apparatus, because the question is never "is this code correct". It is "how much unreviewed variance will we accept, and where do we spend to narrow it".
Call it a reliability band: the range of agent output an organization will accept without a human reading every line. A wide band is cheap to run and expensive to trust. A narrow one costs a gate at every seam, and the gates are the budget. Nobody argues about the band directly, so the merge queue settles it one pull request at a time.
Constraint engineering is my name for the work of holding that band. Making a model correct is not the goal, because nobody is offering that. The goal is to constrain the model at several layers, with a different strategy at each. You stop tightening when the output lands inside the band often enough to be worth the tokens.
I have no number for the band. Neither does anyone I have read. What follows is the apparatus for holding one once you pick it. Where a constraint goes, what makes it good there, and what evidence moves it. Treat the sections on evidence as the part that lets you set a number later, from your own runs rather than from mine.
Push the business analogy one step further, because it predicts the failure. A risk framework dies two ways. People who cannot see the work own the controls, or people who can see it handle the exceptions quietly. Both have exact analogues in a harness, and section 22 covers the role that prevents them.
Two levels sit here, and teams build only one. The conceptual level says what a constraint is, what it is made of, and how it may change. The infrastructure level runs it. Skip the model and every new repository gets a copy of your machinery instead of your design.
Start with the test that separates the two levels. Change your agent SDK tomorrow. If your rules survive the change, you have a model. If you rewrite them, you had machinery and called it a design. That is the whole distinction, and it costs a migration to learn the slow way.
The conceptual level answers four questions, and none of them mentions a process or a queue. What is the thing? What attributes does it carry? What is its consistency boundary? How does it change, and who may change it? Answer those and the runner becomes an implementation detail. Skip them and the runner becomes the design.
One more placement, because it decides who is in the room. This domain sits where DevOps sits. It spans development and platform, and it belongs to neither alone. DevOps merged two roles that could not hold a deployment between them. Constraint engineering merges the same two roles, because neither of them can hold a reliability band alone. Section 17 splits the work into sub-disciplines, and section 22 says what each side sees and what each side misses.
flowchart TD M["the model · constraint · layer · rung · policy · verdict · family · context · identity"] A["a coding agent CLI · charter files, hooks, skills"] B["an SDK loop you wrote · predicates in front of every call"] C["a delivery pipeline · stages, gates, records"] M --> A M --> B M --> C N["swap any runner and the model is unchanged"] C --- N class M pass class A warn class B warn class C warn class N dim
Below is the whole model as a graph, and every later section is one region of it. Read the arrows as relationships rather than as flow. Section 23 defines each term once, so treat that section as the dictionary and this diagram as the map.
One loop in the graph carries more weight than the rest. Firings and hatch uses become evidence, evidence argues for a move, and a move changes the rung that produces the firings. Cut that loop and the model still looks complete, and it stops learning anything.
flowchart TB CON["constraint · the entity"] LAYER["layer · whose rule"] RUNG["rung · what carries it"] POLICY["policy · what happens"] VERDICT["verdict · who decides"] PRED["predicate · the decision procedure"] ESC["escape hatch · the sanctioned deviation"] CAP["capability · what the agent can do"] SET["setting · budgets and caps"] STATE["state · memory and context"] EVID["evidence · counts, records, evals"] MOVE["promotion or demotion · a pull request"] HUMAN["a human"] CONTRACT["contract · what was asked"] CTX["charter · harness · factory"] CON -- "owned by" --> LAYER CON -- "carried at" --> RUNG CON -- "acts by" --> POLICY CON -- "decided by" --> VERDICT CON -- "asks" --> PRED CON -- "waived by" --> ESC RUNG -- "lives in one of" --> CTX VERDICT -- "inferential asks a model, deterministic asks" --> PRED POLICY -- "ask routes to" --> HUMAN CAP -- "withheld at rung 1, so it becomes" --> CON SET -- "bounds the turn and the job" --> CTX STATE -- "unowned, it becomes a rule nobody wrote" --> CON RUNG -- "firings counted as" --> EVID ESC -- "uses counted as" --> EVID CONTRACT -- "graded against" --> EVID HUMAN -- "amends" --> CONTRACT EVID -- "argues for" --> MOVE MOVE -- "approved by" --> HUMAN MOVE -- "changes" --> RUNG class CON block class RUNG warn class VERDICT warn class POLICY pass class PRED pass class EVID pass class MOVE block class HUMAN warn class LAYER dim class ESC dim class CAP dim class SET dim class STATE dim class CONTRACT dim class CTX dim
I reach for domain-driven design here because I had the machinery working and still could not say what a rule was. The vocabulary is not the point, and section 5 borrows a second frame for a second reason. Use the mapping to test your model, then throw the words away.
| In this model | In DDD | Why the mapping holds |
|---|---|---|
| a constraint | entity | it has an identity that survives a rewrite of its predicate, its rung and its prose |
| layer, rung, policy, verdict | value objects | no identity of their own. Compared by value, replaced rather than edited |
| the predicate | specification | a decision procedure written once and asked of many candidates |
| a family | aggregate | one lifecycle and one consistency boundary. You may not half-apply it |
| charter, harness, factory | bounded contexts | each names its own terms, and the dependency between them runs one way |
| the layer field | the context map | it records which context ships the rule, so the harness can travel |
locked | invariant | the one thing a downstream context may not lower |
| the rule file's fields | ubiquitous language | the same six words appear in prose, in config, and in the record |
| the contract | aggregate root of a job | everything about the work hangs off it, and nothing downstream may rewrite it |
Non-goals
Not an argument that you should adopt domain-driven design.
Not a claim that agent work is a domain the way billing is a domain.
Not a layered architecture, and not a diagram of your services.
Open your rules and look for an identity. A rule that is only a line in a file loses its history the moment you move it or reword it. Then you have no entity, so nothing can be promoted, demoted or counted. Every later section assumes a constraint you can name twice and recognize both times.
Whose rule it is, what mechanism carries it, what happens when it fires, and who decides. Those are four questions with four different answers and, often, four different owners. Model any two as one field and the harness stops traveling.
---
description: A broad except says what it is swallowing and why
why: A gate that fails silently on its own bug stops the factory invisibly.
paths: ["workers/**"]
layer: team # whose rule. Ships with the harness, not the repo
rung: [3d, 4d] # what carries it. Two boundaries, not two strictnesses
policy: refuse # what happens. refuse | ask | warn
verdict: deterministic # who decides. A predicate, not a judge
locked: false # may a project override it, or only deviate visibly
predicate: predicates/name_the_swallow.py
escape: swallow-ok
---
The four attributes answer different questions, and confusing any two causes a specific failure. Layer says who ships the rule and who may change it. Rung says which mechanism refuses. Policy says whether a firing stops the work, parks it for a human, or only leaves a record. Verdict says whether a model judged the case or code settled it.
I shipped the layer field and then read it nowhere for months. For that whole time a company standard and one repository's local opinion were the same kind of object. So the harness was something you copied rather than something you shared, which is a modeling bug rather than a coding one.
| The collapse | What it looks like | What breaks |
|---|---|---|
| layer into rung | strong rules live high, weak rules live low | authority becomes "how much I care", and nothing travels between repositories |
| policy into rung | warn is modeled as a lower rung |
a rule you wanted measured is instead unenforced, and the counts look the same |
| rung into layer | the org owns every mechanism | a project cannot carry its own rule anywhere, so it routes around all of it |
| verdict into rung | a judged check and a coded check share a rung | a rule a model decides looks as reliable as one a predicate decides, and the record cannot tell you which kind failed |
Policy deserves one note, because people leave that attribute out. A rule set to ask
parks the call and puts a human in the loop. It is honest only at a rung that can hold a call
rather than veto it. If your mechanism can only say no, ask becomes a rule that
refuses in silence, which is worse than either option.
Verdict is the attribute I added last, and section 5 is where it earns its place. Read it now as a plain fact about the mechanism. Either a model read the work and judged, or code read it and settled. Those two fail in different ways, so the record has to keep them apart.
Take any rule you enforce today and write down its four answers separately. If you cannot name a layer without naming a rung, you have one attribute where you need four. Your harness is then a thing you copy into repositories rather than a thing that governs them.
Charter is the project: what this repository is about. Harness is development: how a turn happens. Factory is delivery: how work ships. Each owns different components, and the dependency between them points one way only.
flowchart TD F["factory · delivery · stage · gate · guard · ordering · record"] H["harness · development · prompt · tool · policy · budget · context · phase"] C["charter · project · rule · hook · skill · command · agent · predicate"] F -- "hands in its own delivery rules" --> H H -- "reads what the repository declares" --> C C -- "cannot reach upward" --> X["a charter that configured the harness would be a repo governing the fleet"] class F block class H warn class C pass class X dim
The direction matters more than the contents. The factory knows about the harness, and the harness must not know about the factory. Point that arrow both ways and the harness stops running on its own. A developer can then no longer ask the only question they have: what do my charter and my rules do to a turn?
That question makes a harness a product rather than a subsystem. Someone working in a repository wants to run one turn, see which rules fired, and see what it cost. They do not want a queue, a worktree or a pull request. If your design cannot serve that, developers build their own, and you get two harnesses that disagree.
| Context | About | Components | Changes |
|---|---|---|---|
| charter | this project | rule · hook · skill · command · agent · predicate · convention | constantly |
| harness | how work is done | prompt · tool · policy · budget · context · phase | rarely |
| factory | how work is delivered | stage · gate · guard · ordering · record | very rarely |
| eval | anywhere | a measurement, for what no rule can decide | with the thing it measures |
Those change frequencies are a diagnostic, not a schedule. Proposals should thin out with distance from the project's own code. Most of what goes wrong is something the repository wanted and never said. So a cycle producing three factory changes and no charter ones tells you the distribution is wrong, not that the factory needs work.
A company standard about how code gets written belongs in the harness, because it must reach every turn including a developer's local one. A company standard about how code ships belongs in the factory, at the delivery rungs. Both are org-layer rules. They live in different contexts because they govern different things, not because different people own them.
A family is an aggregate: one lifecycle, one consistency boundary. Give every component the same lifecycle and you will spend months promoting things that have nowhere to go. You will also withhold things that were never capabilities.
| Family | Primitives | Lifecycle | Moves how |
|---|---|---|---|
| constraint | rule · hook · gate · guard · predicate · convention | add · improve · remove · migrate · promote · demote | up and down a rung |
| capability | tool · skill · command · sub-agent · phase · MCP server | add · improve · remove · migrate · encapsulate | granted or withheld, and along a second ladder |
| setting | budget · model · policy · ordering · turn cap · thinking level | add · improve · remove · migrate | a value changes, never a rung |
| evidence | eval · record · log · count · verdict · trace | add · improve · remove · migrate | recalibrated. It measures, and never refuses |
| state | memory · context · transcript · spec · checkpoint | add · improve · remove · migrate | derived, or scoped to a layer and a life |
Two of those families cause most of the confusion. A capability and a constraint look alike in a config file, because both are entries in a list. They differ in what happens when you remove the entry. Remove a capability and the agent can do less. Remove a constraint and the agent can do more.
I used to write that a capability has no ladder, because it never refuses anything. The first half of that is right and the second half hid something. A capability does not climb the constraint chain, and it has a chain of its own. Section 5 is that chain. It exists because the question came up: are commands, skills, sub-agents and tool servers the same shape as rules, hooks and gates?
Memory is the primitive teams reach for first and design last. A fact the system remembers becomes a constraint nobody wrote down. It shapes every later turn, and it has no layer, no owner, no review and no expiry. The default worth holding is derive, don't remember: rebuild what you need from the work record and the repository.
When you do need memory, give it what every other primitive has. A layer, so someone owns it. A scope, so it cannot govern work it never saw. An expiry or a re-derivation, so it cannot outlive the thing it described. Memory without those three is drift with a good reputation.
Context is the other half of this family, and the trade is direct. You pay for everything in the window on every turn, and it crowds out the rules that matter. Section 20 counts that cost as one of the five kinds of rot.
Remove the component and ask what changed. The agent can do less, so it was a capability. The agent can do more, so it was a constraint. A number moved, so it was a setting. You know less about what happened, so it was evidence. The agent forgot something, so it was state.
Constraints climb from prose to a hook to the harness to the factory. Capabilities climb from a command to a skill to a sub-agent to a tool server. Different families, different ladders, and the same underlying question at every step.
Every step on either chain moves work out of the model's reading and into something that runs the same way each time. Prose is a suggestion the model interprets, and a predicate is code it cannot argue with. A skill file is text the model may read, ignore or contradict. At the other end sits a tool server, which is a process in another language that answers a schema.
So name the axis once and use it twice: how much of this can the model reinterpret? On the constraint chain that reads as reach and authority. On the capability chain it reads as encapsulation. The mechanism differs and the direction is identical.
The four rungs below run from open to hidden. A command hides nothing, and the model sees every word of it. A tool server hides everything except a schema, because it is a separate process that may not even share a language.
| Rung | Who invokes it | Where it runs | What the caller sees | Boundary |
|---|---|---|---|---|
| command | a human types it | in the turn, as text | every word | none. It is a macro |
| skill | the model, from a description; or a human | in the turn, loaded on demand | every word, once loaded | convention. The model can read the file |
| sub-agent | the parent turn | a separate context window | a summary | context. Its tool grant is declared, not inherited by accident |
| tool server | the model, by schema | a separate process | the schema | process. Another language, another machine, if you like |
A capability carries two things: what the agent knows, and what the agent does. The chain moves weight from the first to the second. A command is knowledge with no behavior, and a tool server is behavior whose knowledge you never see. The middle two carry both, in different proportions, which is why they are the hard ones to place.
| Rung | Carries knowledge | Carries behavior | Hides its internals |
|---|---|---|---|
| command | ● | · | · |
| skill | ● | ◐ | · |
| sub-agent | ◐ | ● | ◐ |
| tool server | · | ● | ● |
The table states the boundary, and the order of events is what makes it real. Watch what crosses back to the caller in each of the three cases below. A skill returns its whole text into the same context window. A sub-agent returns a summary of work the parent never saw.
sequenceDiagram participant P as the parent turn participant S as a skill participant A as a sub-agent participant T as a tool server P->>S: load it, because the description matched S-->>P: every word, into this same context window Note over P,S: nothing is hidden, and the context grew P->>A: a task, and the grant it is allowed Note over A: its own context window, which the parent never sees A-->>P: a summary P->>T: a call that matches the schema Note over T: another process, and possibly another language T-->>P: a result, and no implementation
flowchart TD
subgraph CON["constraints · reach and authority"]
direction TB
A0["prose"] --> A1["hook"] --> A2["harness"] --> A3["factory"]
end
subgraph CAP["capabilities · encapsulation"]
direction TB
B0["command"] --> B1["skill"] --> B2["sub-agent"] --> B3["tool server"]
end
AX["the axis · how much the model can reinterpret · falling"]
CON --- AX
CAP --- AX
class A0 dim
class A1 warn
class A2 pass
class A3 block
class B0 dim
class B1 warn
class B2 pass
class B3 block
class AX dim
Knowledge and behavior bundled together, with the internals hidden, is the oldest idea in object orientation. The mapping is close enough to be useful, and the places it fails are worth more than the places it fits.
| Rung | In object terms | Why |
|---|---|---|
| command | a macro | it expands in place. No state, nothing hidden, no interface |
| skill | a module | knowledge plus optional procedures, loaded when something needs it |
| sub-agent | an object | private state in its own context window, a public interface of prompt in and summary out |
| tool server | an interface with a separate implementation | you hold the schema. The implementation lives in another process |
Three things break, and each one has a known answer. Read the table below as the design work that the analogy hands you rather than as a reason to drop it. An object you cannot trust to return the same answer twice is still an object. It just needs different tools around it.
| The break | What it costs | What closes it | What it is not |
|---|---|---|---|
| no determinism | a method that returns something different each call. One green run proves nothing | an eval over a golden set, so you measure a distribution rather than a call · property tests that assert an invariant across many runs · a variance count, the same input judged N times · a schema, which pins the shape even when the content moves · a deterministic rung underneath for anything irreversible | not a unit test. There is no single expected value to assert |
| encapsulation is a convention | a skill's boundary is politeness. The model can read the file, and often should | move it to a real boundary, a sub-agent for a context wall or a tool server for a process wall · withhold the read for that path · a hook that refuses reads into it · treat the file as untrusted input if anything the agent runs can write to it | not private. Nothing in a prompt is private |
| inheritance is a security default | a sub-agent inherits the parent's permission mode unless you say otherwise, so forgetting to write something widens the blast radius | declare the tool grant on every sub-agent, never inherit it · assert the child's grant is a subset of the parent's · a test that runs the child under a deny-all parent and checks it still refuses · record the effective grant on the provenance row, not the declared one | not a class hierarchy. There is nothing to specialize |
| the schema types the arguments, not the meaning | a tool server can satisfy its schema and answer the wrong question after a change you never saw | contract tests against the server, run on your schedule · version the tool and treat a schema change as breaking · a golden call in the eval set, so a semantic drift shows up as a score | not a type system. It checks shape, never intent |
| no identity | two invocations of the same sub-agent are indistinguishable in the record, so you cannot attribute a failure | a run id on every invocation · a provenance record naming the prompt, the grant, the model and the inputs · counts per sub-agent, not per parent turn | not object identity. It is bookkeeping you have to add |
Move a capability up its chain when you need the boundary enforced rather than respected. A skill is the right answer for knowledge the model should read and adapt. A sub-agent is the right answer when the parent's context is the problem. A tool server is the right answer when the behavior must be identical for every caller, including the ones you did not write. Each step costs an interface, and section 14 counts what that interface buys in delivery.
A constraint climbs by crossing two boundaries. It moves from the repository to the harness to the factory. Inside each of those, it moves from a judged verdict to a coded one. That is six rungs and one path, walked in either direction.
Two words carry this section. A verdict is inferential when a model reads the work and judges it. A verdict is deterministic when code reads the work and settles it. An inferential rung can decide what no predicate can express. It costs tokens, and it can be wrong twice, by missing a violation and by inventing one.
Cross the two verdicts with the three contexts and you get the six rungs. The numbering keeps
faith with the ladder on my other pages. Rung 3 is now written 3d, and rung 4 is
now written 4d. Nothing you already reference has moved.
Two rungs sit off the chain, and both stay off it for a reason. Rung 1 is the tool grant, and it withholds a whole capability rather than deciding a case. So a rule cannot move there and stay the same rule. Rung 5 is CI. It sits outside the process that produced the work, and outside the process that checked it. Move your rules there and you spend the one rung that can tell you the others are lying.
flowchart TD R0["0 · rule · prose the model reads"] R2["2 · hook · the repository's own file"] R3i["3i · harness inferential · a judging phase in the turn"] R3d["3d · harness deterministic · a predicate at every call"] R4i["4i · factory inferential · a review stage on finished work"] R4d["4d · factory deterministic · a gate on the diff and the publish"] R0 -- "recurs, and someone can name the case" --> R2 R2 -- "other repositories need it too" --> R3i R3i -- "the judgment became a predicate" --> R3d R3d -- "the tree matters more than the call" --> R4i R4i -- "the reviewer keeps saying the same thing" --> R4d R4d -- "the gate fires on cases nobody meant" --> R4i R4i -- "the reviewer adds nothing the harness missed" --> R3d R3d -- "the predicate and the rule came apart" --> R3i R3i -- "only this repository ever cared" --> R2 R2 -- "nobody can say why it exists" --> R0 class R0 dim class R2 warn class R3i warn class R3d pass class R4i warn class R4d block
Each step does one of two things. It moves the rule further out of the agent's reach, or it makes the verdict more exact inside the same context. The second move is cheaper than the first, so take it first. Turning a judged rule into a predicate costs one function. Moving a rule from the harness to the factory costs a boundary and a new blind spot.
The reviewing phase was in my model for a long time as a capability, and I never noticed it was also a rung. That is why an older version of this page ended its promotion section with the line that undecidable rules stay prose forever. They do not. They stay undecidable, which is a different claim, and rungs 3i and 4i are where undecidable rules go.
A rule carried at both an in-harness check and a stage gate is not one rule enforced twice as hard. It is one predicate at two boundaries, because an in-harness check sees tool calls and a stage gate sees the finished tree. Moving the chain rung must not silently remove the rung that catches what the moved one cannot see.
Choosing a rung is choosing what it can see and who can remove it. Those two properties are what the design is about. Nothing else about a rung matters much, and the blind spot matters more than the reach.
| Rung | Sees | Blind to | Agent can remove | Cost per firing |
|---|---|---|---|---|
| 0 · rule | everything, weakly | nothing, and it enforces nothing | it can reinterpret it | context, on every turn |
| 1 · grant | nothing. The tool is simply absent | cases, entirely | no | nothing. It never fires |
| 2 · hook | every agent that reads the settings | an agent that does not read them | yes. It is a file in the repository | a process, per event |
| 3i · judging phase | intent, wording, and whether a claim is supported | anything outside its own context window | no | a model call, and it can be wrong twice |
| 3d · predicate | every call the model makes, including to tools you did not write | inside a shell command it does not parse | no | microseconds |
| 4i · review stage | the finished work, and whether it answers the contract | how the work was produced, and anything reverted | no | a whole extra pass |
| 4d · stage gate | the finished diff, and what is published | anything mid-turn that was reverted | no | one pipeline step |
| 5 · CI | the merged result | the whole turn | no, and nor can the factory | a build |
Six things exist for a rung to see, and no rung sees all six. Put your rungs in this grid and the empty column is the rule you believe you enforce and do not.
| Rung | Tool call | Shell write | Reverted work | Finished diff | Published text | Merged result |
|---|---|---|---|---|---|---|
| 1 · grant | ● | · | · | · | · | · |
| 2 · hook | ◐ | ◐ | ● | · | · | · |
| 3i · judging phase | ● | ● | ● | ◐ | ◐ | · |
| 3d · predicate | ● | · | ● | · | · | · |
| 4i · review stage | · | · | · | ● | ● | · |
| 4d · stage gate | · | · | · | ● | ● | · |
| 5 · CI | · | · | · | · | · | ● |
Rung 2 is the interesting cell, because a hook is charter content and mechanical at the same time. That mix makes it the cheapest mechanical rung to own, and the agent it governs can delete it. Every design decision about rung 2 follows from those two facts together.
Rung 3d taught me the reach lesson expensively. It used to sit inside three editing tools, so a turn writing through a shell heredoc walked straight past it. That happened twice in testing. It now sits in front of every call the model makes, including calls to tools nobody on my side wrote. That move is what makes reaching for stock tools safe.
No predicate had a bug, and tightening one would have fixed nothing. A rung watches a path, so ask of any rung whether the thing it governs has a second path. Ask before you tighten anything.
A stage gate sees two things: the finished diff, and what the pipeline is about to publish. No tool writes a commit message, a pull request body or a review comment, and none of them appear in a diff. Give your model no rung that sees published text, and every rule about what your organization says in public goes unenforced while looking enforced.
A rule that reaches your main turn does not automatically reach a child turn. Some rungs cross a context boundary and some cannot, and the split is not the one people expect. The deeper your graph, the less prose can hold it.
Section 5 gave a sub-agent its own context window, and that isolation is the point. It is also the problem, because a fresh context window starts without your charter. So ask three questions of every child turn. Does it see the rules? Does it inherit the grant? Which rung catches it when it breaks something?
| What | Crosses | Why |
|---|---|---|
| rung 0 · the rule | no, unless you copy it in | prose lives in a context window, and the child got a new one |
| rung 1 · the grant | yes, and it can only narrow | the parent declares what the child may call, so this is the one inheritance that works |
| rung 2 · the hook | yes | the runner fires it on an event, and it does not care which turn caused the event |
| rung 3i · the judging phase | no | judging is a phase of one turn. A child needs its own, or none |
| rung 3d · the predicate | yes, if it is mounted in the harness | it sits in front of every call from any turn. Mount it in the parent's prompt and it crosses nothing |
| rung 4i and 4d | yes, once | delivery sees the joined result, so a child's work is graded but a child is not |
| memory and context | no, and that is deliberate | isolation is what you paid for. Passing it all through buys you a slower parent |
| the budget | it partitions, and it must not copy | hand each of five children the job budget and you authorized five times the spend |
Read the first and fifth rows together, because together they are the argument. Prose does not survive a context boundary, and a predicate mounted in the harness does. So a fleet that leans on rung 0 gets weaker with every level of fan-out. One that leans on rung 3d does not.
flowchart TB H["the harness · rung 3d mounted here, in front of every call"] P["the parent turn · charter loaded, rung 0 present"] C1["child turn · a fresh context window"] C2["child turn · a fresh context window"] H --> P P -- "task and grant, never the charter" --> C1 P -- "task and grant, never the charter" --> C2 H -- "every call, from any turn" --> C1 H -- "every call, from any turn" --> C2 C1 --> J["the join"] C2 --> J J --> G["rung 4d · grades the joined result, not each child"] class H pass class P warn class C1 block class C2 block class J dim class G warn
A rule mounted once still fires many times per job, so a per-job count hides which child broke it. Record the firing against the rung and the child that caused it. Otherwise a fan-out of twenty makes one badly briefed child look like a rule that fires constantly.
The identity of the rule does not change inside a child, and neither does its layer. Only the record needs the extra field. That is a small change, and skipping it is how a healthy fleet reports a rule as noisy.
Decide how deep your graph goes before you decide where your rules live. One turn deep, prose is fine and cheap. Two or more turns deep, anything that matters belongs at rung 1, rung 2 or rung 3d. Those are the three that cross a boundary without you copying anything.
A rule that travels needs three things. A stable identity across repositories, a decision procedure that exists once, and an answer for when a repository disagrees. Get all three and teams share the harness. Miss one and they copy it.
A team standard restated in every repository is not a standard. It is a copy, and copies drift. So a shipped rule travels with the harness rather than with any repository, and its predicate travels beside it. Nobody shared a rule whose decision procedure has to exist in every repository it governs. They pasted it.
The same predicate then mounts at every rung that needs it. That means the repository's hook, the in-harness check, and the stage gate. Two implementations of one rule will disagree, and the agent finds the seam before you do. One function, several mounts, and a record of each firing against the rung that caught it.
Here sits the only genuinely interesting decision in the model, and it is a domain decision rather than a technical one. A project declares a rule with the same identity as a shipped one. Who wins?
| Shipped rule | Project declares the same id | Result |
|---|---|---|
| ordinary | a local adaptation | the project wins. The shipped layer is recorded on the surviving rule |
locked: true |
a local adaptation | the shipped rule holds. The attempt is recorded on it as an override attempt |
The order of events matters as much as the outcome, because the harness writes the record on the way through. Both branches below end with something written down. That is the property to keep if you take nothing else from this section.
sequenceDiagram
participant H as the harness
participant P as the project
participant R as the record
H->>H: load the shipped rule
P->>H: declare a rule with the same identity
alt the shipped rule is ordinary
H->>H: the project rule wins
H->>R: write the shipped layer onto the surviving rule
else the shipped rule is locked
H->>H: the shipped rule holds
H->>R: write the attempt down as an override attempt
end
H-->>P: the surviving rule, and its collision record
The project wins by default, because a repository knows things the harness does not. A layering nobody could adapt locally gets routed around within a week. That repeats the risk-appetite argument. Nobody obeys a control with no sanctioned deviation. They evade it quietly, and then you lose the register too.
locked marks the floor of the band, and it stays deliberately rare. It names the
rules an organization has closed to a project's judgment. Either way the surviving rule
carries a record of the collision, because a standard replaced in silence is worse than both
outcomes.
A predicate resolves against the tree it came from and may not leave it. A project rule cannot reach out of its repository, and a shipped rule cannot reach out of the harness package. Drop that containment and a rule file becomes a way to run arbitrary code from wherever it points. The layering you built to hold a band becomes the hole in it.
Every default in this model prefers a mistake that reads as too narrow over one that is quietly too broad. A rule that is wrong where nobody can see it does more damage than no rule. The band looks held when it is not.
| Field | Unreadable value becomes | Why that direction |
|---|---|---|
| layer | project | a mistyped org standard governs one repository, visibly too narrow, rather than silently too broad |
| rung | 0 · prose | a typo that silently became a gate is a rule nobody wrote |
| policy | refuse | warn turns a typo into an unenforced rule, and ask parks a turn waiting for a human nobody told |
| verdict | deterministic | a missing predicate fails loudly when the rule loads. An inferential default spends tokens on every turn and says nothing |
| locked | false | a rule does not become an iron law because someone typed locked: probably |
Those five apply one design decision five times. When the model cannot read what someone meant, prefer the visible failure over the quiet one. The same instinct makes a broken gate report itself and let the work through. Fail closed instead and it stops the pipeline for a reason nobody can see.
So count a broken predicate against its rule rather than only printing it. A gate that reports itself in prose nobody aggregates is how a rung rots while the table shows nothing. Counting separates a control from a control you can test.
What a rule says when it fires is a domain concern. People learn to route around a refusal that names no way out. A good refusal carries the rule's own words, its recorded reason, and its escape hatch. Then it says plainly that someone counts every use of that hatch.
The why field earns its place at one moment, years later. A rung whose reason
nobody can reconstruct is enforcing institutional memory it does not have. Section 20 turns a
missing why into a deletion signal for that reason.
Every gate here fails open on its own bug, which is the right trade and leaves one question unanswered. You cannot ask the gates whether the gates work. So at least one rung has to sit outside the process that produced the work, and outside the process that checked it.
That is the whole argument for keeping a rung in CI, or anywhere else the agent and the pipeline both cannot reach. It will be the quietest rung you own. It is also the only one that can tell you your other rungs have been reporting success into a void.
A recorded deviation beats an unsanctioned one nobody logged, which is the argument every risk function makes. So the hatch stays, and the harness counts its use per rule. A rising count does not argue for removing the hatch. It shows the rule and its predicate have come apart, which is a demotion signal.
Rung 0 is prose the model reads and applies. Injected text is prose the model reads and applies. Those are the same operation, which is why no rule that matters for security can rest on an inferential rung alone.
A model reading its charter and a model reading a poisoned file are doing one thing: turning tokens into behavior. Nothing in the context window is labeled trustworthy. So a sentence in an issue comment, a dependency README, a retrieved document or a tool result arrives with one standing. It is the standing of a rule you wrote and reviewed.
The verdict attribute makes this precise, which is the reason it is worth having. An inferential rung decides by reading, so anything that can be read can argue with it. A deterministic rung decides by running code, and code does not get persuaded.
| Rung | Injectable | What that means |
|---|---|---|
| 0 · rule | yes | prose against prose, and the newer prose is often closer to the question |
| 1 · grant | no | the tool is absent, and no sentence conjures one |
| 2 · hook | no | the runner fires it, and the model is not consulted |
| 3i · judging phase | yes | a judge that reads the work also reads whatever the work contains |
| 3d · predicate | no | it inspects the call, not the argument for the call |
| 4i · review stage | yes | the reviewer reads a diff an attacker may have written |
| 4d · stage gate | no | it runs a predicate over a tree |
| 5 · CI | no | outside the process, and outside the conversation |
The pattern is exact: every inferential rung is injectable, and every deterministic one is not. That is no coincidence. The thing that lets an inferential rung judge the undecidable is the same thing that lets an attacker address it.
Section 5 called a skill's boundary a convention rather than a wall. Here is what that convention costs. If an agent can write to its own charter, its own skill files or its own rubric, then it can author rung 0. An attacker who reaches any of those files has not bypassed your rules. They have written new ones.
So treat the rule files, the skill files and the rubrics as code rather than as content. They get a review, they get an owner, and no turn writes them without a human merging it. That is the same containment argument as section 9, pointed at a different target.
| Defense | Buys | Does not buy |
|---|---|---|
| a deterministic rung under every security rule | a decision an attacker cannot address | anything for rules code cannot settle |
| withhold the capability | a violation nobody can express, injected or not | capabilities the work genuinely needs |
| mark provenance on every token | the model can be told which text is untrusted | a guarantee it will act on the marking |
| treat tool output and retrieved text as data | a stated rule, and a testable one | enforcement, because the rule itself sits at rung 0 |
| humans own the rule and skill files | rung 0 stops being agent-writable | protection from what the agent reads elsewhere |
| a classifier on input or output | a measurable filter with a known error rate | certainty, and it is itself inferential |
Put a deterministic rung under every rule whose violation would be a security incident. Treat the inferential rung above it as a filter rather than a control. Section 24 carries this as a numbered rule, and Prompt Injection is where I work through the attacks themselves.
Every primitive the model names, then the patterns people build from them. The catalog is here so you can see what you are choosing against. Nobody runs all of it, and I do not.
About fifty things, and each one belongs to exactly one family. Place a primitive in the wrong family and you will manage it with the wrong lifecycle. That is the most common modeling error, and the table below is the fix.
Read the reaches column as the rungs a primitive can occupy, not as a rank. A tool server and a predicate are both good designs, and they answer different questions. The watch for column carries the failure I would look for first in a review.
| Primitive | What it is | Context | Reaches | Watch for |
|---|---|---|---|---|
| Constraint · it refuses, so removing it lets the agent do more | ||||
| rule | a named constraint with prose, metadata and an optional predicate | charter | 0 to 4d | a rule with no identity cannot be promoted or counted |
| hook | a repository script the runner calls on an event | charter | 2 | the agent it governs can delete the file |
| predicate | the decision procedure a rung asks | any | 2 · 3d · 4d | two implementations of one rule will disagree |
| convention | a stated pattern with no predicate under it | charter | 0 | it promotes only once someone can name the case |
| judging phase | a phase inside the turn that reads the work and refuses | harness | 3i | give it no editor, or it repairs what it should report |
| review stage | a pass that reads the finished work and returns a verdict | factory | 4i | it shares the author's blind spot if it shares the prompt |
| gate | a stop between two stages | factory | 4d | a gate that fails closed on its own bug stops the line invisibly |
| guard | a check inside a stage that stops that stage | factory | 4d | count its firings, or it rots while the table shows nothing |
| allowlist | which actions run without asking | harness | 1 · 3d | widening it is a change to the band, so record it |
| schema | the shape an output or a call must satisfy | harness | 3d | it checks shape and never intent |
| classifier | a model that scores an input or an output | harness · factory | 3i · 4i | it has a false positive rate, so measure it before you trust it |
| containment rule | a predicate resolves against its own tree and may not leave it | harness | 3d | drop it and a rule file becomes arbitrary code execution |
| Capability · it enables, so removing it lets the agent do less | ||||
| tool | a callable the model may use | harness | granted at 1 | withholding it is the cheapest enforcement there is |
| command | a named entry point a human types | charter | capability rung 1 | it hides nothing, so it is not a boundary |
| skill | instructions loaded on demand rather than at startup | charter | capability rung 2 | the model chooses it from a description, so the description is the trigger |
| sub-agent | a separate context window with its own prompt and grant | harness | capability rung 3 | declare its grant, because inheriting one widens the blast radius |
| phase | a named step of a turn with its own prompt and grants | harness | capability rung 3 | two phases that need each other's context are one phase |
| tool server | a separate process exposing tools over a protocol | harness | capability rung 4 | version it, and treat a schema change as breaking |
| retrieval index | a corpus the model may search instead of loading | harness | — | a stale index produces a confident wrong answer |
| sandbox | a bounded place a command may run | harness | 1 | a sandbox holding the production credentials is not a sandbox |
| worktree | an isolated checkout one job owns | factory | — | services outside the worktree are still shared |
| plan mode | a state in which writes are withheld until a human agrees | harness | 1 | approval becomes a reflex, so keep it rare |
| Setting · a value moves, and no rung moves | ||||
| budget | tokens, money or wall clock for one job | harness | — | exhausting it must escalate, never truncate in silence |
| turn cap | how many model calls before the loop stops | harness | — | a cap set by feel throws away correct work |
| revision cap | how many retries after a refusal | factory | — | measure the distribution before you tune the number |
| concurrency cap | how many jobs run at once | factory | — | it is your backpressure, so make it visible |
| model | which model serves this phase | harness | — | record it, or you cannot attribute a failure |
| thinking level | how much reasoning budget one call gets | harness | — | a setting, and never a constraint |
| sampling | how much the output is allowed to vary | harness | — | pin it before you measure variance, or you measure the knob |
| policy | refuse, ask or warn | any | — | an attribute of a rule, and also a default for rules that omit it |
| ordering | which stage runs when | factory | — | ordering is a constraint you cannot see in any rule file |
| timeout | how long before a step is abandoned | factory | — | a timeout with no owner escalates to nobody |
| Evidence · it measures, and it never refuses | ||||
| eval | a scored measurement over a fixed set of cases | anywhere | never a rung | it answers what no predicate can decide |
| golden set | the fixed inputs an eval runs on | anywhere | — | if the agent can edit the set, the set is not golden |
| rubric | the criteria a judging rung applies | anywhere | — | publish it, or the judge is unauditable |
| record | the durable row for one job | factory | — | one row, one job, one identity |
| log | the ordered events of one run | any | — | prose nobody aggregates is not evidence |
| trace | the timing and nesting of calls | any | — | this is where cost per job actually comes from |
| count | firings per rung, and hatch uses per rule | any | — | count per rung, never only per rule |
| verdict | a pass or a fail, with the evidence under it | any | — | a verdict with no command under it is unproven, not done |
| provenance | what produced this, from what inputs, under what grant | factory | — | record the effective grant, not the declared one |
| cost row | tokens and money for one job | factory | — | aggregate spend attributes nothing to anything |
| State · it persists, so it governs work it never saw | ||||
| context window | what the model sees on this call | harness | — | everything in it is paid for on every turn |
| charter | the standing instructions for one repository | charter | 0 | give it a fixed size, so a new rule displaces an old one |
| memory | a fact carried between sessions | harness | — | give it a layer, a scope and an expiry, or derive it instead |
| transcript | the turn so far | harness | — | compaction is where a constraint quietly falls out |
| scratchpad | a file the agent writes to think in | charter | — | unread scratch becomes memory nobody scoped |
| todo list | the agent's own plan, visible and steerable | harness | — | it drifts from the contract, so compare the two |
| checkpoint | a restorable point in the work | factory | — | nothing checkpoints the world outside the tree |
| contract | what was asked, and what done means | factory | — | the system working from it may never rewrite it |
| amendment | a human's answer to a mid-flight question | factory | — | it must travel to every later check, or reviewers grade a withdrawn requirement |
| artifact | a produced file, diff, message or comment | factory | 4d | published text is an artifact that no diff shows |
A hook looks like infrastructure and is charter content, because the repository writes it and the repository can delete it. An eval looks like a gate and is evidence, because it returns a score rather than a refusal. Get those two wrong and you will version a hook centrally, and let an eval block a merge. Those are the same mistake, pointed in opposite directions.
The harness holds a single turn. Twenty-four patterns live here, and they trade three things against each other: tokens, reach and how much the model may decide. Every one of them has a failure mode, and the failure mode is the reason to read the row.
Start with the shape of a turn, because the patterns are all edits to it. The model plans a call, a rung decides whether that call happens, the call runs, and the loop repeats until something stops it. Every harness pattern either changes what the model sees, changes which rung decides, or changes when the loop stops.
flowchart TB
P["prompt · charter, contract, context"] --> M["the model plans a call"]
M --> G1{"rung 1 · is the tool granted"}
G1 -- "absent" --> M
G1 -- "granted" --> G3{"rung 3d · does a predicate refuse"}
G3 -- "refuse" --> B["the refusal · its words, its why, its hatch"]
B --> M
G3 -- "allow" --> T["the call runs"]
T --> H["rung 2 · the repository hook"]
H --> M
M --> D["the work is done"]
D --> J{"rung 3i · a judging phase reads it"}
J -- "refuse" --> M
J -- "pass" --> O["out of the harness"]
class P dim
class M warn
class G1 pass
class G3 pass
class B block
class T dim
class H warn
class D dim
class J warn
class O pass
| Pattern | What it does | Primitives | What it costs | How it fails |
|---|---|---|---|---|
| Shaping the loop | ||||
| tool-use loop | the model calls tools until it decides it is done | tool · turn cap | tokens per step | it loops until the budget stops it, and calls that finished |
| plan then execute | write the plan first, then act on it | phase · contract | one extra call | the plan is approved and the work quietly diverges from it |
| plan mode | withhold every write until a human agrees to the plan | rung 1 · plan mode | a human's attention | approval becomes a reflex, so it stops being a gate |
| phase split | separate prompts and separate grants per step | phase · tool grant | orchestration, and lost context | two phases that need each other's context were one phase |
| budget-bounded loop | stop at a token, money or clock limit | budget · turn cap | correct work discarded at the boundary | the cap is set by feel and never measured |
| escalate on repeat failure | after N refusals, park the job for a human | revision cap · policy ask | a parked job | N is chosen by patience, not by the distribution |
| interrupt and steer | a human redirects the turn while it runs | policy ask · transcript | full attention | the steering is never written down, so it teaches nothing |
| checkpoint and rollback | restore a known point after a bad path | checkpoint · worktree | disk, and discipline | nothing checkpoints the world outside the tree |
| Shaping what the model sees | ||||
| retrieval | query an index instead of loading the corpus | retrieval index · context | an index to keep fresh | it retrieves the wrong chunk and answers with confidence |
| compaction | summarize the transcript so the turn fits | transcript · context | detail you cannot get back | the summary drops a constraint and nothing notices |
| scratchpad | the agent writes its reasoning to a file | scratchpad | a file to clean up | it becomes memory nobody gave a layer or an expiry |
| todo steering | the agent keeps a visible, editable task list | todo list | very little | the list drifts from the contract and nobody compares them |
| prompt caching | keep a stable prefix warm across calls | context · ordering | ordering constraints on your prompt | a changed prefix silently costs more and nothing reports it |
| sub-agent isolation | a fresh context window for a sub-task | sub-agent | a handoff, and a summary | the parent loses what the child learned on the way |
| model routing | a cheap model first, escalating on failure | model · record | two failure modes instead of one | the record does not say which model was wrong |
| Deciding what is allowed | ||||
| least privilege | withhold the tool rather than write the rule | rung 1 | a capability nobody has | the agent reaches the same end through a shell |
| deterministic tool wrapper | the tool refuses, so the model never gets the chance | predicate · rung 3d | writing the predicate | a second path to the same effect walks straight past it |
| sandboxed execution | run commands where the damage is bounded | sandbox | setup, and a slower loop | the sandbox holds the credentials, so it bounds nothing |
| structured output | constrain the answer to a schema | schema · rung 3d | rigidity | the schema fits perfectly and the content is wrong |
| injection defense | treat retrieved text and tool output as data, never instructions | rung 3d · classifier | false positives | the rule lives only in prose, where the injected text also lives |
| Judging the work | ||||
| reviewer with no editor | a phase that judges and cannot repair | sub-agent · rung 1 · 3i | one extra pass | nothing downstream acts on what it found |
| self-critique | the model grades its own output before returning it | phase · 3i | tokens | it agrees with itself, because it shares every assumption |
| chain of verification | restate the claims, then check each one separately | phase · predicate | tokens, and latency | it verifies the wording rather than the fact |
| generate and test | write the failing test first, then satisfy it | tool · predicate | a real test run per attempt | the agent edits the test until it passes |
Four of those rows are the same idea at different prices. Least privilege, the deterministic wrapper, the reviewer with no editor and structured output all remove the ability to express a violation. That is the cheapest enforcement in the model, and section 19 gives it a name.
The judging patterns need one warning that the table cannot carry. A model grading its own work shares every assumption that produced the work. So a judging rung earns its keep when it has a different prompt, a different context, or a published rubric. Give it none of those and you have bought agreement.
If you run one of these, run the deterministic tool wrapper. Mount it in front of every call, rather than inside the tools you wrote. No other pattern here reaches calls you did not write. That reach is what makes a stock tool safe to hand an agent. Treat the rest of the list as optional next to it.
The factory holds many turns, many agents, and everywhere work waits. Twenty-four patterns live here. They trade throughput against how much you can say afterwards about what happened. The second of those is the one teams discover they needed.
A factory is a pipeline with a record under it. Work arrives as a contract, gets an isolated place to happen, passes through stages, and stops at gates. What separates a factory from a script is the record: every stage writes what it did, so the counts in section 20 exist.
flowchart TB
I["intake · a written contract"] --> W["a worktree, one per job"]
W --> S1["plan"]
S1 --> S2["build"]
S2 --> S3["test"]
S3 --> G3{"rung 4d · the stage gate"}
G3 -- "refuse" --> R["retry, briefed with the gate's own words"]
R --> S2
G3 -- "pass" --> S4["review · rung 4i"]
S4 -- "rework" --> R
S4 -- "pass" --> HU["the human merge gate"]
HU -- "merge" --> CI["rung 5 · CI, outside all of it"]
HU -- "close" --> X["recorded, and not merged"]
R -- "revision cap reached" --> PK["parked, and visible"]
class I dim
class W dim
class S1 dim
class S2 dim
class S3 dim
class G3 pass
class R warn
class S4 warn
class HU block
class CI block
class X dim
class PK block
| Pattern | What it does | Primitives | What it costs | How it fails |
|---|---|---|---|---|
| Getting work in | ||||
| intake queue | jobs wait, and workers pull them | record · concurrency cap | a queue to watch | queue depth hides a gate that has been refusing everything |
| contract as input | nothing starts without a written statement of what done means | contract | authoring time, per job | the contract is written by the system it is supposed to govern |
| worktree per job | one isolated checkout, owned by one job | worktree | disk, and setup per job | the services outside the worktree are still shared |
| backpressure | refuse new work rather than degrade running work | concurrency cap | visible waiting | the cap is invisible, so the queue looks like a slow factory |
| Moving work through | ||||
| stage pipeline | plan, build, test, review, ship, in that order | stage · ordering | latency per stage | one stage quietly does all the work and the rest are theatre |
| gate between stages | a stop that the work must pass to continue | gate · predicate | a stopped job | it fails open on its own bug and nobody counts that |
| fan out and fan in | parallel agents, and one join at the end | concurrency cap · sub-agent | merge conflicts | the join has no arbiter, so the last writer wins |
| shard by module | split work along boundaries the code already has | ordering | uneven shards | a change that crosses shards belongs to nobody |
| map then reduce | the same operation over many files, then one summary | sub-agent · record | cost, multiplied | the summary hides the outliers, which were the point |
| supervisor | one process owns ordering, retries and escalation | ordering · record | a single point of failure | the supervisor grows until it becomes a second harness |
| blackboard | agents read and write a shared working state | state · record | contention | the shared state has no layer, no owner and no expiry |
| retry with brief | the refusal's own words become the next attempt's prompt | policy · record | a turn per attempt | the retry runs without the brief, so it repeats the failure |
| revision cap | stop after N attempts and park the job | revision cap | correct work discarded | N is tuned by patience rather than by the record |
| dead letter | a job that cannot proceed waits somewhere visible | record · policy ask | someone has to look | nobody looks, and the park becomes a bin |
| Deciding what ships | ||||
| review stage | a second pass reads the finished work against the contract | rung 4i · rubric | one whole pass | the reviewer shares the author's prompt, so it shares the blind spot |
| merge queue | integration is serialized, so nothing merges into a moving target | ordering | latency | agents race the queue and rebase over each other |
| eval gate | a scored set must not regress before work ships | eval · golden set | maintaining the set | the set becomes the thing being optimised, so it stops measuring |
| canary run | run the new configuration beside the old one | record · eval | double the cost | nobody compares the two, so it is just double the cost |
| progressive rollout | widen the blast radius in named steps | ordering · budget | slowness, on purpose | there is no defined step backwards |
| rollback | a defined and rehearsed way back | checkpoint | rehearsal nobody wants to schedule | it exists on paper and has never been run |
| kill switch | stop the fleet without shipping anything | setting | the discipline to keep it working | using it requires a deploy, which is what you cannot do |
| Knowing what happened | ||||
| provenance record | what produced this, from what input, under what grant | provenance · record | storage, and plumbing | it records the output and not the inputs that caused it |
| cost per job | tokens and money on the job's own row | cost row · trace | plumbing | cost stays aggregate, so nothing is attributable to anything |
| idempotent re-run | running a job twice does what running it once did | checkpoint · record | design effort | side effects outside the tree are not idempotent and never were |
| sampling audit | a fixed fraction of passed jobs is read by a human | record · rubric | a slice of attention, forever | the fraction drifts to zero and nobody announces it |
Three of those rows exist only to make the rest measurable. The provenance record, the cost row and the sampling audit produce nothing a customer sees. They are also the difference between a factory you can tune and one you can only restart. So build them before you need them.
The sampling audit deserves the extra sentence, because it is the pattern that decays quietest. Nothing else in the list checks the gates themselves against reality. Set the fraction, name the owner, and put the number on the same dashboard as throughput.
Almost every failure in that table is invisible rather than loud. A gate failing open, a summary hiding outliers, an audit fraction drifting to zero, a cap tuned by patience. None of them stops the line, and all of them widen the band while the dashboard stays green. That is why counting is a first-class primitive here rather than an operational nicety.
Every constraint so far governs how work happens. None of them says what the work is, or what it means for it to be done. The contract does that. The human path is what happens when an agent cannot satisfy it without a decision that is not theirs to make.
A band means nothing without a statement of what was wanted. So the contract earns first-class status: written down, kept in version control, and never rewritten by the system working from it. Acceptance criteria belong there. A rule can say how to write code, and only the contract says whether this code was the point.
That gives evidence somewhere to attach. A claim of done is worth nothing alone, so demand the criteria and the proof that something exercised each one. A verdict with no command under it is unproven rather than done. Treat those two as the same and you will report a band as held.
Twelve patterns, ordered by when they happen. The first four run inside the turn and are cheap and rare. The middle four run at delivery and cost a pass each. The last four are the ones that keep the whole apparatus honest, and they are the ones that decay when nobody owns them.
| Pattern | When | What it costs | What the answer becomes | How it fails |
|---|---|---|---|---|
| Inside the turn | ||||
| ask mid-turn | the agent is genuinely blocked | one parked turn, minutes to hours | an amendment to the contract, and the work resumes | it asks about naming, so nobody reads the questions any more |
| plan approval | before any write happens | one review, per job | a plan of record | the plan is approved and the work diverges from it |
| approval before an irreversible action | at the action, every time | attention, every time | a grant for this action only | approval fatigue, so the click stops meaning anything |
| interactive steering | a person drives the turn with the agent | full attention | tacit knowledge, in one person's head | nothing is written down, so the charter learns nothing |
| At delivery | ||||
| refusal brief | a gate said no | one revision, one turn | the gate's own words, verbatim, as the next prompt | the human fixes it by hand instead, so the rule never improves |
| review verdict | a person reads the finished diff | a review per job | a comment, or a rework | the reviewer trusts the gate that already passed it |
| merge gate | at the end. Nothing merges itself | the whole job waits | merge, close or rework | the queue length turns it into a rubber stamp |
| two-person rule | the highest blast radius only | two people, on one decision | a recorded second signature | one person holds both credentials and clicks twice |
| Keeping the apparatus honest | ||||
| escalation on budget exhaustion | the job ran out of tokens, money or clock | a parked job | more budget, or a kill | the budget is raised without anyone asking why it ran out |
| timeout to a human | a step stalled and nothing moved | an interruption, out of hours | someone owns the stall | the timeout escalates to a rota nobody staffed |
| exception register | whenever an escape hatch is used | bookkeeping only | a count per rule, and a demotion signal | hatch use is not counted, so the register does not exist |
| sampling audit | after the fact, on work that passed | a fixed slice of attention | a calibration of every gate above it | the fraction drifts to zero without an announcement |
The first row is the one worth designing carefully, because it is where a human is cheapest and rarest. An agent that guesses on a contradiction produces confident work against a requirement nobody meant. An agent that asks about naming has turned a hatch into a habit, and you will stop reading the questions.
Keep the hatch narrow by design: contradictory requirements, a missing credential, a choice that destroys data, or a direction the contract did not authorise. The agent decides preferences, naming, and anything the codebase already answers, and it reports what it decided. A resumed turn then loses the hatch, because asking the same question twice is not asking.
The sequence below is the whole pattern, and the last arrow is the one people drop. A check that sees the contract without the amendment grades correct work as wrong. Build that arrow first, because the rest of the pattern is useless without it.
sequenceDiagram participant A as the agent participant F as the factory participant U as a human participant C as the contract participant V as every later check A->>F: blocked, and here is the contradiction F->>U: park the turn, and ask U-->>F: the answer F->>C: attach an amendment, and leave the contract untouched F-->>A: resume, and this time without the hatch A->>F: the finished work F->>V: the contract and the amendment, together Note over V: grade against both, or grade a withdrawn requirement
This is the part that is easy to miss and expensive to skip. If a human answers a question mid-flight, every later check must see the contract and the answer. Otherwise a reviewer grades correct work against a requirement that was withdrawn an hour earlier. The authored contract stays untouched, and the amendment rides alongside it.
One axis decides more than any other, and almost nobody writes it down. How bad is it if this is wrong, and can you undo it? A constraint about formatting and a constraint about deleting production data are not the same kind of thing. No rung saves you if you placed them by how often they irritate you.
Irreversible actions deserve the expensive answers: withhold the capability, or ask a human. Reversible ones deserve the cheap answers: refuse and let the agent adapt, or record and look later. Sort by cost of being wrong before you sort by anything else.
Never put an inferential rung last in front of an irreversible action. A judging phase is a good rung, and it is not reproducible. So it cannot stand alone between an agent and a deletion you cannot undo. Put a predicate under it, or put a human at it, and section 5 lists what closes that gap.
Every one of these looks like diligence from the outside. That is what makes them expensive. A harness with all eighteen still reports success, still passes its gates, and still cannot tell you whether you are holding the band.
| Anti-pattern | What it looks like | Why it fails | Instead |
|---|---|---|---|
| Modeling | |||
| the copied harness | every repository holds its own copy of the rules | copies drift, and no two repositories enforce the same thing | one identity per rule, shipped with the harness |
| rung as strictness | "important rules go higher up the ladder" | authority collapses into mechanism, so nothing travels | keep layer and rung as separate fields |
| the nameless rule | a rule is a line of prose in a long file | with no identity it cannot be promoted, demoted or counted | give every constraint a stable id |
| memory as policy | a remembered fact quietly governs later work | it has no layer, no owner, no review and no expiry | derive it, or give it a scope and an expiry |
| the growing charter | every incident adds a line, and nothing removes one | the charter gets long enough that nothing in it is read | a fixed size, so a new rule displaces an old one |
| rules that apply themselves | a loop rewrites its own constraints on its own authority | it escapes the band it exists to hold | every promotion and demotion is a pull request |
| Enforcement | |||
| the second path | a rule sits at the tool, and a shell command writes anyway | it looks enforced, and it is not | mount the predicate in front of every call |
| two implementations | the same rule is written once in the hook and once in the gate | they disagree, and the agent finds the seam before you do | one predicate, many mounts |
| the unenforceable gate | a predicate that measures the wording of a claim | it reports enforcement it does not have | keep the rule as prose and put an eval beside it |
| fail closed on your own bug | a broken gate stops the pipeline | the line stops for a reason nobody can see | fail open, and count the breakage against the rule |
| reviewer with an editor | the checking phase repairs what it finds | nothing is ever refused, so nothing is ever recorded | withhold the editor at rung 1 |
| a judge as the last line | a model approves an irreversible action | it is not reproducible and it can be argued past | a deterministic rung under it, or a human at it |
| Evidence | |||
| the uncounted hatch | an escape exists and nobody totals its use | you lose the exceptions register, which was the point of the hatch | count hatch uses per rule, and read a rise as a demotion signal |
| aggregate counting | firings are totaled per rule, across every rung | you cannot tell which rung is doing the work | count per rung, always |
| idle-counting the quiet rungs | the tool grant and CI look dead in the report | your evidence argues for deleting the two backstops | exclude both by name, and say why in the report |
| the self-graded eval | the judge and the author share a prompt and a context | you measure agreement rather than correctness | a separate context, and a published rubric |
| the contract the system rewrites | the agent edits the acceptance criteria as it works | every later check grades against a target that moved | the authored contract is immutable, and amendments ride alongside |
| cost as an aggregate | spend is a number on a monthly invoice | nothing is attributable, so no change can be justified | tokens and money on each job's own row |
Six of those are the same mistake wearing different clothes. The copied harness, two implementations, aggregate counting, the uncounted hatch, cost as an aggregate and the nameless rule share one missing thing. That thing is identity, and giving a constraint one stops five of the six from being possible.
The one that cost me most was the second path. Nothing looked wrong, no predicate had a bug, and the report stayed green while a turn wrote through a shell heredoc. An anti-pattern you can see in a report is not the dangerous kind.
Do not read it as a checklist. Take the three rows whose failure you could not currently detect, and build the detection before you build the fix. A harness that cannot see an anti-pattern will grow it back after you remove it, and you will not find out for a quarter.
What the work divides into, how a constraint moves in each direction, and who holds it. This part is about people and evidence rather than about mechanisms.
Constraint engineering is one job with eleven sub-disciplines. They sort cleanly by scope, from one model call up to the whole fleet. They do not sort by team at all, which is the finding that matters and the reason section 22 argues for one role.
Scope is the honest sort order, because it says what a change can affect. A prompt change reaches one call. A graph change reaches every job in flight. Sorting by team instead tells you who is in the meeting, and it tells you nothing about the blast radius.
flowchart TB A["one call · prompt"] B["one turn · context · tool · harness · memory"] C["between turns · loop"] D["many jobs · graph"] E["the fleet · governance"] A --> B --> C --> D --> E X["eval · security · cost"] X -- "cut across every scope above" --> A X --> C X --> E class A dim class B warn class C warn class D block class E block class X pass
| Sub-discipline | What it governs | Scope | Context | Sits with | Sections |
|---|---|---|---|---|---|
| prompt | what a single call actually says, and in what order | one call | harness | development | 13 |
| context | what the model is told, and what it costs to tell it every turn | one turn | charter · harness | both | 5 · 13 · 20 |
| tool | the capability surface: grants, schemas, servers, boundaries | one turn | harness | both | 6 · 12 · 13 |
| harness | the mechanism that holds one turn, and the rungs inside it | one turn | harness | both | 7 · 9 · 13 |
| memory | what persists between turns, and what it silently governs | one turn, forever | harness | development | 5 · 12 |
| loop | what happens between turns: retries, revisions, and when to stop | between turns | factory | both | 14 · 15 |
| graph | many turns and many agents, and everywhere work waits | many jobs | factory | platform | 14 |
| governance | the band, the layers, the locked floor, the exceptions register | the fleet | all three | platform | 0 · 10 · 22 |
| eval | measuring what no rule can decide, at any scope | cuts across | anywhere | both | 12 · 19 |
| security | injection, containment, least privilege, blast radius | cuts across | all three | both | 6 · 9 · 13 · 15 |
| cost | budgets, routing, caching, and attributing spend to a job | cuts across | harness · factory | platform | 13 · 14 |
Four of those carry most of the design weight, and they are the four I would name if someone asked what the job is. Context is what the model is told and what it costs to tell it. Harness is the mechanism that holds a single turn. Loop is what happens between turns. Graph is many turns and many agents, and where work waits.
The other seven are real and they are narrower. Prompt sits inside context, and tool and memory sit inside the harness. Above all of those sits governance. Eval, security and cost refuse to sit anywhere, because each of them is a question you ask at every scope.
Read the sits with column and the point of section 22 arrives early. Two of eleven sit with platform, one sits with development, and eight sit with both. A split that leaves eight shared disciplines is not a split. It is a standing meeting.
This is DevOps territory, spanning development and platform, and owned by neither alone. The precedent is worth taking seriously rather than as a slogan. Development and operations split because deployment was somebody else's problem, and merged because a deployment nobody owned end to end failed in the gap. A reliability band fails in exactly the same gap.
Every number this page asks for already exists, unaggregated, in the logs you are already writing. Counts say what happened and evals say whether it was good. Neither one decides a promotion alone, and the interesting cases are where they disagree.
A session log holds the prompts and every tool call, with its arguments and its result. It also holds every refusal, the hook output, the phase boundaries, the tokens and the timings. That is the raw material for the entire evidence family. Nobody has to instrument anything new to start, which makes this the cheapest rung of the whole apparatus.
One warning before the table. The log format belongs to your runner, so this is the least portable part of the model. The signals below are stable and the parser you write is not, and I would keep that parser small for exactly that reason.
| Signal | Where it comes from | What it decides |
|---|---|---|
| firings per rung | every refusal event, tagged with the rule id and the rung that caught it | promotion, demotion, and whether a backstop is doing all the work |
| hatch uses per rule | the escape marker, in the diff or in the call that carried it | a rising count means the rule and its predicate have come apart |
| tool call histogram | the call stream, counted by tool | which capabilities are never used, and can therefore be withheld at rung 1 |
| second-path evidence | shell commands that wrote files, next to the edit tools that did not | whether a rung has a blind spot. This is how I found mine |
| refusal to success distance | how many turns pass between a refusal and the work continuing | whether a refusal teaches. A long distance means the message is bad, not the rule |
| repeat refusal rate | the same rule firing more than once inside one job | the rule is unteachable at that rung, or the brief is not reaching the retry |
| variance | one case, replayed N times through a judging rung, verdicts compared | whether an inferential rung is judging or guessing |
| context cost per rule | charter bytes loaded, times the turns that loaded them | context debt, which is the rot that hides because silence looks free |
| cost per job | token counts on the trace, summed to the job's record | attribution, without which no change to the model can be justified |
| phase timing | span boundaries | where the loop stalls, and which phase to split or delete |
flowchart TB L["session logs · prompts, calls, refusals, hooks, tokens, spans"] X["a small parser · one row per event"] C["counts · per rung, per rule, per child, per job"] E["evals · a score over a fixed set"] J["the join · counts beside scores"] D["the decision matrix"] P["a proposal, as a pull request"] L --> X --> C E --> J C --> J J --> D --> P class L dim class X warn class C pass class E pass class J block class D block class P warn
Counts on their own are ambiguous. A rule that stopped firing might be a rule nobody needs, or a rung that went blind. Evals on their own are worse, because a score that moved tells you nothing about which rung moved it. Put them side by side and the four cases separate cleanly.
| The eval held | The eval dropped | |
|---|---|---|
| firings fell | demote or delete, after you have ruled out a second path. The behavior improved, or the rung stopped seeing | the rung went blind. The violations still happen and something stopped catching them. Fix the mount, never demote |
| firings rose | the rule is too broad. It fires on cases the prose never meant, and quality did not need it. Narrow it | leave the rung alone. Something upstream regressed and the rung is doing its job. Go and find the regression |
The top-right cell is the expensive one, because it looks exactly like the top-left in a report that shows only counts. A team watching firings alone reads a falling number as progress and demotes the rung that was protecting them. That is the argument for the join in one sentence.
A predicate that changed is a different classifier, so firings recorded under the old one are not evidence about the new one. Stamp every count with the predicate version. Then reset the variance measurement whenever that version changes, because a variance number averaged across two predicates describes neither.
The rule's identity survives the rewrite, which is what section 1 asks for. Its evidence does not, and the distinction is easy to miss because both live in the same row.
A predicate is a classifier with a false positive rate and a false negative rate, and almost nobody measures either. Give it a fixture set: cases that must fire, and cases that must not. Run it in CI beside everything else.
This is the cheaper twin of a golden set, and the page has so far prescribed golden sets only for the inferential rungs. That is backwards. A deterministic rung is the easy one to test, so test it first and spend the expensive measurement on the judge.
I parse the logs and read the counts by hand, and nothing schedules it. So the loop in section 20 runs whenever I remember it. That is the one rule of section 24 my own factory misses. Build the parser first and the schedule second, because a parser you run monthly still beats a dashboard you never wrote.
A rule earns a mechanical rung by being consequential, recurrent and settleable. The third test used to disqualify most candidates. It no longer does, because settleable splits in two, and one half of it is what rungs 3i and 4i are for.
Consequential means being wrong costs something, and costs it quietly. Recurrent means it has been broken more than once, by more than one person. Settleable means something can decide it without a person, and that is where the test forks. Code can settle "no float in the money module", because it is a predicate over a syntax tree. Only a reader can settle whether someone genuinely exercised a thing rather than claiming it.
So a rule that a machine cannot decide is not stuck at prose. It goes to an inferential rung, where a model reads the work and judges it. That costs tokens, and it buys a verdict nobody can reproduce. Rules that neither code nor a reader can settle stay prose and get an eval, which measures without refusing.
flowchart TB
Q1{"is being wrong expensive, and quiet when it happens"}
Q1 -- "no" --> P0["prose · rung 0"]
Q1 -- "yes" --> Q2{"has more than one person broken it"}
Q2 -- "no" --> P0
Q2 -- "yes" --> Q3{"can the capability be withheld instead"}
Q3 -- "yes" --> P1["withhold the tool · rung 1"]
Q3 -- "no" --> Q4{"can code settle it"}
Q4 -- "yes" --> Q5{"does it govern this repository only"}
Q5 -- "yes" --> P2["the repository hook · rung 2"]
Q5 -- "no" --> Q6{"does the check need the finished tree"}
Q6 -- "no" --> P3d["a predicate at every call · rung 3d"]
Q6 -- "yes" --> P4d["a stage gate · rung 4d"]
Q4 -- "no" --> Q7{"can a model settle it during the turn"}
Q7 -- "yes" --> P3i["a judging phase · rung 3i"]
Q7 -- "no" --> Q8{"can a model settle it from the finished work"}
Q8 -- "yes" --> P4i["a review stage · rung 4i"]
Q8 -- "no" --> PE["prose, plus an eval · rung 0"]
class P0 dim
class P1 pass
class P2 warn
class P3d pass
class P3i warn
class P4i warn
class P4d block
class PE dim
A promotion should be one field in one file, and nothing else. If moving a rule up means rewriting it, re-registering it, or touching code, promotion costs too much and nobody does it. Keep the rung next to the prose it enforces, so there is no second place to forget.
Two properties are worth stealing. First, a promotion is a proposal rather than an act: it opens a pull request and a human merges it. Second, promoting to a mechanical rung with no predicate and no rubric should produce a task instead. Writing that predicate is the actual work, and a rung without one looks enforced from the outside.
| The rule | Where it goes | Why |
|---|---|---|
| "a check does not repair what it finds" | rung 1. Do not hand the phase an editor | no predicate, because the violation cannot be expressed at all |
| "do not commit secrets" | rung 3d and rung 4d. One predicate, two mounts | 3d catches the tool call, and 4d catches whatever the shell wrote |
| "prove it actually ran" | rung 4i, plus an eval. Never rung 4d | a reader can settle it from the finished work, and a predicate would only measure wording |
People reach for that first row last. Before you write a predicate, ask whether that phase could hold no such capability at all. A rule nothing can violate needs no gate, no escape hatch and no counting. That is the crossing where a capability becomes a constraint, and it is the best trade in the model.
An eval answers what no rule can decide, and it sits at any layer. It never refuses, so it is not a rung and competes with none. Treat it as the instrument that tells you whether you are holding the band. That includes the inferential rungs, where the verdict itself needs measuring. Without it, nobody knows whether a judging phase is judging or agreeing.
A harness ratchets on its own. Every incident argues for one more gate, and nothing ever argues for fewer, because no paragraph has ever failed a build. So demotion and deletion need machinery, and promotion does not.
Anything written down can rot, including the things written down to stop rot. It goes wrong in five distinguishable ways, and naming which one you have makes a count actionable. "Never fires and is six hundred words" and "nobody knows why this exists" look alike in a table and argue for different actions.
| Kind | What it looks like | Argues for |
|---|---|---|
| technical | a predicate that throws, or a gate mounted where it cannot see | a fix. Nothing about the rule is wrong |
| context | long, loaded into every turn, and it never fires | a deletion, or a demotion |
| comprehension | no recorded why, or a name that lies about what it does | a rewrite, or a deletion if the why does not survive |
| intent | the escape hatch doing all the work, or firing on cases the prose never meant | a demotion, or a narrowing |
| variance | an inferential rung judging the same case differently across runs | a predicate, or an honest admission that the rule is not settleable |
Variance is the kind the earlier version of this page could not name, because it only appears once you have inferential rungs. Measure it directly: run the same case through the judging rung several times and count the disagreements. A rung that cannot agree with itself is not enforcing a rule, and no amount of prompt work will hide that from a count.
Context debt hides for the opposite reason, which is that silence looks free. It is not. The harness loads charter content into every turn that touches what it is about. So you pay for a dead rule on all of them. It also dilutes the attention left for the rules that matter.
So a rule that never fires is a demotion if it still matters. It is a deletion if nobody can say why it is there. Those are different findings, and the difference is whether the recorded reason survives the evidence. Removal is half the work here rather than the failure case, and it is the half nobody does unprompted.
flowchart LR A["a rung fires, or a hatch is used"] --> B["the record counts it against that rung"] B --> C["the analysis pass reads counts, hatch use and variance"] C --> D["a proposal, as a pull request"] D --> E["a human merges it, or does not"] E --> F["the rule's rung, policy or verdict changes"] F --> A class A warn class B pass class C pass class D block class E warn class F block
Growth is the default, because every incident adds a line and nothing removes one. So set a size for the charter and hold it. When a new rule arrives and the budget is full, something else leaves, and the argument about which one is the useful part.
A budget converts an unbounded ratchet into a trade, and it puts deletion on the agenda without anyone needing to feel bad about it. It also stops the slowest failure in this whole design, which is a charter so long that nothing in it gets read.
Record every firing against the rung that caught it. Then "the in-harness check never catches this any more" stays a readable fact rather than vanishing into a rule-level total. When a backstop starts doing all the work, that tells you how turns are writing code. Ask why, not which rung to tighten.
Two rungs that fire on the same case earn their keep only as two boundaries. Two rungs that differ in how hard they push are redundancy, and they destroy your ability to tell which one works. Per-rung counting makes that distinction visible.
A tool grant never fires by construction: the capability is absent, so there is nothing to catch. CI fires outside anything the pipeline records. Count either as idle and your report argues for demoting the two rungs whose whole value is that they stay quiet. Exclude them by name, or your evidence will be confidently wrong.
Everything on this page is overhead. It produces no feature, and no customer ever sees it. Most teams should stop at the first conformance level, and a page that argued otherwise would be selling something.
The strongest objection to all of this is that it is a lot of machinery for what began as a style guide. That objection is right about levels two and three, and wrong about level one. Level one is a schema and a habit, and it costs an afternoon.
| Level | To build | To keep | Worth it when |
|---|---|---|---|
| 1 · modeled | four fields, named families, one direction on the dependency | almost nothing, because it is a schema | always. No team is small enough for this not to pay |
| 2 · enforced | predicates, their mounts, containment, one rung outside the process | predicate maintenance, and the false positives people will complain about | more than one repository, more than a few people, or one incident already |
| 3 · measured | a log parser, records, provenance, variance runs, an eval set, a sampling audit | a real slice of one person's week, forever, plus storage and eval upkeep | the cost of one bad merge exceeds the cost of the apparatus |
I cannot tell you where that last crossover sits, and the reason is worth stating plainly. It depends on the width of your band, and section 0 already admitted that nobody has a number for the band. So the crossover is a judgment. Anyone handing you a threshold for it is guessing with more confidence than I have.
| Situation | Why |
|---|---|
| a human reads every line | your band is already as narrow as it goes, so there is nothing left to hold |
| one person, one repository | the layer attribute has nothing to carry, and a shared standard has nobody to share with |
| exploratory or research work | constraints are for output you mean to keep, and the point here is finding out what to keep |
| a prototype you will throw away | the apparatus would outlive the code, which is the wrong way round |
One failure deserves naming on its own, because this page could cause it. An apparatus nobody maintains reports success into a void, which section 10 already warned about in a smaller way. A level three you cannot staff is worse than a level one you actually run, because it produces numbers that look like evidence.
Four fields on your rules. Then one predicate with two mounts. Then the log parser, because it is cheap and it tells you which rule to work on next. Then the eval set, then variance, then the audit. Anyone who starts at the dashboard builds a dashboard, and anyone who starts at the schema finds out what the dashboard should have shown.
Platform decides what ships and what a project may not lower. Development knows which rules are actually wrong. Split those across two teams that meet quarterly and nobody holds the band. Section 17 already showed why: eight of the eleven sub-disciplines belong to both.
The DevOps precedent is the argument, and it is worth stating carefully rather than as a slogan. Development and operations were split because deployment was somebody else's problem. They merged because a deployment that nobody owned end to end failed in the gap between them. That gap was invisible from either side. A reliability band fails in the same one.
So the disciplines cut across the org chart rather than along it. Whoever knows the repository writes the context, and whoever owns the budget pays for it. The loop stays a delivery concern until a revision limit throws away correct work, and then it belongs to everyone.
| Role | Owns | Cannot see alone | Alone, it fails this way |
|---|---|---|---|
| platform | what ships with the harness · the locked floor · the record and the counts | which rules are wrong in a repository it does not work in | rules nobody can override, routed around within a week |
| development | the project layer · predicates for its own code · which refusals are noise | that its local fix is a company standard three other repositories need | a standard restated per repository, which is a copy that drifts |
The two-way traffic is the point, and the layer attribute exists to carry it. Propose a local rule as a team rule once it keeps proving itself in one repository. Bring a shipped rule down when its escape hatch does all the work in three. Both moves are pull requests, and both need someone who sees the repository and the fleet at once.
Nothing in this model should apply itself. A proposal to change a rule becomes a task or a pull request, and it passes the same gate as any other work. A loop that rewrites its own constraints on its own authority is the one thing here that escapes the band it exists to hold.
I run the analysis pass by hand, and nothing schedules it. Call that a real gap rather than a design position, and the piece I would build next. A ratchet that someone inspects only when they remember is still a ratchet.
Take the rules you already enforce. Write four answers next to each: whose it is, what carries it, what happens when it fires, and who decides. Where you cannot answer the first without the second, you have found the reason your harness does not travel. Then pick the one rule with the busiest escape hatch and ask what it and its predicate have stopped agreeing about.
Every term defined once, then the normative rules and what a conformance claim requires. This part is the part you can hold a design against. The rest of the page argues for it.
One term, one meaning, one word. Every definition below is the only definition on this page, and no term has a synonym anywhere in it. A vocabulary that drifts costs the reader a lookup on every section, and a standard that drifts is a style guide.
Take the model and rename all of it if your organization already has words for these things. What must not change is the count. Four attributes, three contexts, five families, two chains. Rename a term and the model survives, and merge two terms and it does not.
| Term | Definition | Kind | Where |
|---|---|---|---|
| amendment | a human's answer to a mid-flight question, which travels beside the contract and never edits it | state | 15 |
| artifact | anything a job produces: a file, a diff, a commit message, a pull request body, a comment | state | 12 |
| band | the range of agent output an organization accepts without a human reading every line | concept | 0 |
| blast radius | how much damage a wrong decision does, and whether it can be undone | concept | 15 |
| budget | the tokens, money or wall clock one job may spend before it escalates | setting | 12 |
| capability | a component whose removal lets the agent do less | family | 4 |
| capability chain | command, then skill, then sub-agent, then tool server, ordered by how much each hides | concept | 5 |
| charter | the bounded context of one project, and the standing instructions that state what it is about | context | 3 |
| checkpoint | a point in the work that can be restored | state | 12 |
| classifier | a model that scores an input or an output rather than producing work | constraint | 12 |
| command | a named entry point a human types, which expands in place and hides nothing | capability | 5 |
| constraint | a component whose removal lets the agent do more. The entity this model is about | family | 2 · 4 |
| constraint chain | rungs 0, 2, 3i, 3d, 4i and 4d, ordered by reach and authority | concept | 6 |
| containment | the rule that a predicate resolves against the tree it came from and may not leave it | constraint | 9 |
| context | one of charter, harness or factory. Never the context window, which is a separate term | concept | 3 |
| context window | what the model sees on a single call, and what is paid for on every turn | state | 12 |
| contract | the written statement of what was asked and what done means, which no downstream system may rewrite | state | 15 |
| convention | a stated pattern with no predicate under it | constraint | 12 |
| cost row | the tokens and money attributed to one job | evidence | 12 |
| demotion | a move down the constraint chain, proposed by evidence and merged by a human | concept | 20 |
| deterministic | a verdict reached by code reading the work | attribute | 2 · 6 |
| escape hatch | the sanctioned way to deviate from a rule, whose every use is counted | constraint | 10 |
| eval | a scored measurement over a fixed set, which measures and never refuses | evidence | 19 |
| evidence | a component that measures and never refuses | family | 4 |
| factory | the bounded context of delivery: how work ships | context | 3 |
| family | one of five aggregates, each with its own lifecycle and consistency boundary | concept | 4 |
| gate | a stop between two stages in the factory | constraint | 12 |
| golden set | the fixed inputs an eval runs on, which nothing under test may edit | evidence | 12 |
| guard | a check inside a stage that stops that stage | constraint | 12 |
| harness | the bounded context of development: how a single turn happens | context | 3 |
| hook | a repository script the runner calls on an event, at rung 2 | constraint | 12 |
| identity | the name of a constraint, stable across repositories and across rewrites of its predicate | attribute | 1 · 9 |
| inferential | a verdict reached by a model reading the work and judging it | attribute | 2 · 6 |
| judging phase | a phase inside the turn that reads the work and refuses, at rung 3i | constraint | 6 |
| layer | whose constraint it is: org, team or project. It says who may change the rule | attribute | 2 |
locked | the invariant marker. It names a shipped rule a project may not lower | attribute | 9 |
| memory | a fact carried between sessions, which governs later work whether or not anyone scoped it | state | 4 |
| mount | one place a predicate is asked. One predicate has many mounts | concept | 9 |
| phase | a named step of a turn with its own prompt and its own grants | capability | 12 |
| policy | what happens when a constraint fires: refuse, ask or warn | attribute | 2 |
| predicate | the decision procedure a rung asks. Written once, mounted many times | constraint | 9 |
| promotion | a move up the constraint chain, proposed by evidence and merged by a human | concept | 19 |
| provenance | the record of what produced an artifact, from what inputs, under what effective grant | evidence | 12 |
| record | the durable row for one job | evidence | 12 |
| review stage | a factory pass that reads the finished work and returns a verdict, at rung 4i | constraint | 6 |
| rubric | the published criteria a judging rung applies | evidence | 12 |
| rule | a named constraint with prose, metadata and an optional predicate | constraint | 12 |
| rung | which mechanism carries a constraint. Rungs 0, 1, 2, 3i, 3d, 4i, 4d and 5 | attribute | 6 · 7 |
| sandbox | a bounded place a command may run, holding no credential it does not need | capability | 12 |
| setting | a component whose change moves a value and never a rung | family | 4 |
| skill | instructions loaded on demand, chosen by the model from a description | capability | 5 |
| stage gate | a factory gate over the finished diff and over what is published, at rung 4d | constraint | 6 |
| state | a component that persists, and therefore governs work it never saw | family | 4 |
| sub-agent | a separate context window with its own prompt and its own declared tool grant | capability | 5 |
| tool server | a separate process exposing tools over a protocol, of which the caller sees only a schema | capability | 5 |
| turn | one pass of the harness: a prompt, the calls it produces, and the work that results | concept | 13 |
| variance | the disagreement of an inferential rung with itself across runs of the same case | evidence | 20 |
| verdict | who decides a constraint: inferential or deterministic. Also, a pass or fail with its evidence | attribute | 2 · 6 |
| worktree | an isolated checkout one job owns | capability | 12 |
Context is one of charter, harness or factory. Context window is what the model sees on a call. Almost every confused conversation I have had about this model collapsed those two. The collapse hides a real question: does this rule belong to a repository, or to the machinery that reads it?
A standard that only describes is a style guide. This section is the part you can hold a design against. It carries the scope, twenty-nine normative rules, three conformance levels, and the evidence each level demands. My own factory does not reach level three.
This standard covers the conceptual design of agent constraints. It says what a constraint is and what it is made of. It also says which context holds it, which mechanism enforces it, and what evidence moves it. It applies to any system where a model produces work that a person did not read line by line.
Out of scope
Any specific framework, SDK, runner, queue or pipeline. The model is deliberately portable.
A number for the reliability band. Section 0 says why I will not invent one.
Model selection, prompt wording, and anything that changes with the next release.
Organizational structure. Section 22 argues for one role and does not draw your org chart.
Twenty-nine rules, each traceable to the section that argues for it. Read them as the shortest form of this page. If you disagree with one, the section behind it is where the argument lives. That argument is the part I would rather you took.
Three levels, and each one subsumes the one below it. Most teams reach the first in an afternoon and never reach the third. Calling both of those conformant would make the word useless.
| Level | What it asserts | Rules | Evidence a reviewer can ask for |
|---|---|---|---|
| 1 · modeled | the design exists and is separable from the machinery | 1 to 4 | a rule file showing four distinct fields · a named family for every component · a context map with one arrow direction |
| 2 · enforced | the model is carried by mechanisms, and it fails honestly | 1 to 15 · 23 to 26 | one predicate with more than one mount · a rung outside the harness and the factory · a broken gate that let work through and got counted · a recorded collision |
| 3 · measured | evidence moves the model, on a schedule nobody has to remember | all 29 | per-rung counts · hatch counts per rule · a variance number for one inferential rung · cost per job · a scheduled analysis pass that has opened a demotion proposal |
wipp does not reach level three. The rule it misses is the scheduled analysis pass, because I run that by hand and nothing reminds me. That is the gap I would close first, and it is the same gap section 22 names. A standard whose author quietly exempts himself is worth less than the paper it is printed on.
The counts are the stable part. Four attributes, three contexts, five families, two chains, and the rungs on each. Rename any term to match what your organization already says, and keep the counts. Merging two of them is what breaks the model.
This page changed once already in a way worth recording. It had three attributes and one chain, and it claimed that a rule a machine cannot decide stays prose forever. Verdict, the inferential rungs and the capability chain came from that being wrong. Assume the same will happen again, and treat a version of this that admits no error as the version to distrust.
Nobody has published a number for the band, and this standard cannot produce one. What it can produce is the instrumentation: per-rung counts, hatch counts, variance at the judging rungs, and cost per job. Run those for a quarter and you will have the first honest input to the number, from your own runs. If you get there before I do, I would like to read it.