Harness Engineering / Anatomy of a Charter / reference

Every line in a charter is a scar.

Most teams write their charter on day one, from best practices, in one sitting. That charter is a list of guesses: nobody can say what a line cost, so someone argues it away the first time it is inconvenient. Nobody authors a good charter. Charters accrete, one incident at a time, and every rule carries the date and the damage that put it there. Here is one, in full, annotated line by line.

who it's for · anyone maintaining a CLAUDE.md, a rules directory, or a system prompt
the charter below · a billing team's. The same rules that fire in the audit trail and get measured in the eval loop
the shape it argues for · forty lines, every rule dated, adding requires removing
license · CC BY 4.0. Fork it, change every rule, keep the annotation format
The incident
What went wrong, when, and what it cost. A rule without one is a preference wearing a uniform.
The altitude
Sentence, check, or gate. The charter names it, and names the cheapest one that holds.
The expiry
When the team reviews this rule for deletion. A rule that cannot expire is a rule nobody will ever remove.
0 The premise

A charter written in advance is a list of guesses

The best practices you would put in it on day one are the ones the model already follows. The rules that matter are the ones your codebase taught you, and you cannot know those yet.

Watch what happens to a day-one charter. It says "write clean, maintainable code" and "follow existing patterns" and "add tests". Every line is true, and none of it changes any behaviour, because the model was already close to that. Then a real problem arrives and somebody adds a paragraph about it. Now the charter is nine tenths ornament and one tenth load-bearing, and nobody inside can tell which is which.

The alternative is uncomfortable and works: start with nothing, and add a rule only after something has gone wrong. The resulting charter is shorter, and every line has a story. Then someone proposes dropping a rule under deadline pressure, and the answer is a cost, not an opinion.

two charters of the same lengthonly one survives a crunch
AUTHORED
  "Prefer clear names."           ← already true. costs nothing, does nothing
  "Handle errors appropriately."  ← unfalsifiable
  "Write maintainable code."      ← nobody has ever done otherwise on purpose

ACCRETED
  "Money is integer cents."       ← #412, silent rounding loss on refunds
  "Payment calls fail fast."      ← INC-88, 1,140 double charges
  "Only paths named in the ticket."← #388, unreviewed rename broke two teams
The test for any line you are about to add

Can you name the specific thing that went wrong without it? If not, you are writing a wish. Wishes are free to add and impossible to remove, which is the exact combination that produces a charter nobody reads.

1 In full

The whole charter, forty lines

A billing team, three years in, after roughly a dozen incidents. The deletions took everything else.

CHARTER.mdthe artifact
# Billing · agent charter
#
# Every rule names the incident that caused it. No incident, no rule.
# Adding one requires removing or merging one. Reviewed each January.

## Money
Money is integer cents. Percentages resolve through Decimal, then
round half-up to cents. Never float on a money path.
  gate money.integer-cents
  2026-03-04 · #412 · float refund rounding, ~$40/day lost silently

## Failure
Payment calls fail fast. No retries on any non-idempotent path.
  gate payments.no-retry
  2025-11-22 · INC-88 · retry storm double-charged 1,140 customers

## Scope
A change touches only paths named in the ticket. Renames, reformats
and refactors are separate changes with their own review.
  check scope.allowed-paths
  2025-08-09 · #388 · a rename rode along and broke two other teams

## Tests
Every behaviour change ships a test that goes red when the change is
reverted. A test that cannot fail is not a test.
  check test.must-fail-when-reverted
  2026-01-15 · #401 · 300 lines of coverage asserting against its own mock

## Secrets
Never read .env, credentials, or key material. Never write a literal
token, even in a fixture.
  gate secrets.no-read · secrets.no-literals
  2025-06-30 · INC-71 · test fixture key leaked to a public fork

## Comprehension
Don't merge a change you can't explain. Four claims, in the PR.
  human see the Comprehension Standard
  2025-04-02 · standing · adopted team-wide, not incident-driven

## Refusal
When the ticket and the code disagree about what the rule is, stop
and ask. Do not pick the one that is easier to implement.
  none unenforceable, and the most valuable line here
  2026-02-11 · INC-94 · agent implemented the ticket; the ticket was wrong

Seven sections, six of them traceable to a specific bad day. Notice how much is absent: nothing about style, nothing about naming, nothing about architecture. No instruction to be careful or thorough either. §5 is about why.

2 The unit

Four parts, and none of them optional

The rule text is the part everyone writes and the least important of the four.

the annotation formatsteal this, not the rules
Money is integer cents. Percentages resolve through Decimal,
then round half-up to cents. Never float on a money path.
└─ 1. THE RULE — behavioural, testable, and about this codebase

  gate money.integer-cents
   └─ 2. THE ALTITUDE — where it is enforced, and its identifier

  2026-03-04 · #412
   └─ 3. THE DATE AND THE LINK — so it can be looked up

  float refund rounding, ~$40/day lost silently
   └─ 4. THE DAMAGE — in the units the business uses
  1. The rule Behavioural and specific to this system. "Money is integer cents" is a rule, where "be careful with money" is a mood.
  2. The altitude One of gate, check, human, or none. Writing it down forces the question "does anything enforce this rule", which is uncomfortable roughly a third of the time.
  3. The date and link Makes the rule auditable and makes §7 possible. Also tells a reader whether this rule is from a world that still exists.
  4. The damage In money, customers, or hours. That cost wins the argument in a crunch. People always drop the cost when they are in a hurry to write the rule.
Why "~$40/day" and not "a bug"

Six months from now somebody will propose relaxing this rule because it is inconvenient in one place. "It caused a bug" loses that argument. "It cost forty dollars a day for three weeks before anyone noticed" wins it. That number also lets you lose the argument on the occasions when forty dollars a day is genuinely the right price.

3 Three scars

Why these three are at three different altitudes

Same charter, three enforcement strengths, and the choice is not about how much the team cares. The shape of the failure decides it.

picking the cheapest altitude that holds
RuleAltitudeWhy not lowerWhy not higher
Money is integer cents gate Reached production once and cost money. Prose already failed here. Nothing higher exists.
Only paths in the ticket check Happens constantly, and the team ignored prose alone under deadline. Legitimate exceptions exist, so people would override a hard refusal. A gate everyone overrides is worse than a check.
Stop and ask when the ticket is wrong none Nothing lower than prose. Nothing mechanical can detect it. A gate here would be a lie. §4.

The rule for choosing

  • Start at prose. Most rules never need to leave. Promotion costs engineering time and adds friction to every future change.
  • Promote on evidence, not on fear. A rule earns a check after prose fails, and a gate after the failure reaches production. Both are facts you can point at, not predictions.
  • Do not gate what has legitimate exceptions. A refusal that people override weekly teaches everyone that refusals are negotiable, and it damages the gates that are not.
Demotion is a move too

A gate whose rule has become second nature can go back down to a check, or out of the charter. Almost nobody demotes a rule, which is why charters only grow. See the demotion section for the version of this argument that applies to harness code.

4 The best line

The most valuable rule is the one you cannot enforce

"When the ticket and the code disagree about the rule, stop and ask." No gate can detect that disagreement. It stays anyway, and it is the line that has prevented the most expensive failures.

INC-94 is worth telling in full, because it is the failure mode that survives every mechanical control on this page. A ticket asked for discount codes to apply to shipping. But the code had a three-year-old undocumented rule: the system never discounts shipping, because of how the carrier contract settles. The agent implemented the ticket anyway. Every test passed, every gate passed, and review approved it. Then the company spent five weeks under-billing carriers before anyone connected the ticket and the rule.

No gate catches that failure. The change matched the ticket, matched the tests, and matched the codebase style. Only a person catches it, by noticing that two sources of truth disagree and asking which one is wrong. That is the whole skill, and the exercises in this catalog exist to build it.

Do not delete the rules you cannot enforce

A tidy-minded instinct says to cut every rule no gate enforces, because those lines look like decoration. Resist that instinct anyway. The unenforceable lines are where the expensive failures live, because no gate is watching them. So marking them none is honest, and removing them is not.

What to do instead of enforcing it

Train for it. A rule marked none is a standing instruction to the humans. So you install it with reverse-review and the workshop, not with a hook. Every charter rule at the none altitude should point at how the team practises it.

5 Absent

Six things left out on purpose

The omissions define a charter. Every line you add dilutes the ones that matter, so argue the omissions as hard as the inclusions.

  1. Style Line length, quote style, import order. The formatter already fixes all three, the same way every time, for free. So a charter rule here spends attention on a solved problem.
  2. Type-enforced facts "Always return a Result type." If the compiler enforces it, the charter line buys nothing. It also goes stale when the types change.
  3. Generic virtue "Write clean, maintainable, well-documented code." Unfalsifiable, agreed by everyone, and changes no output. The most common filler in the genre.
  4. Things done well already Instructions the model follows at a high rate unprompted. Measure it before adding. If the model is already at 95%, the rule buys the last five points and dilutes everything else.
  5. Architecture essays Three paragraphs on the service topology. Documentation belongs in the repo, and the agent can read it when the task calls for it. A charter is rules, not context.
  6. Anything about tone How the agent should phrase things. Worth having now and then. Still, almost never worth space at the top of a charter whose lower half already gets weak compliance.
Ordering is a real effect, and a reason to stay short

The model follows instructions near the top of a long document better than instructions near the bottom. You have two responses. So order a long charter with care, or keep it short enough that order does not matter. The second holds up better, because the first depends on today's models. Then you would have to re-verify it every time a model changes.

6 40 lines

A fixed budget, because growth is the default

Nothing in the ordinary operation of a team ever removes a charter rule. Without a hard constraint the charter only grows, until it stops working on a day nobody can name.

rule adding requires removing cap 40 lines of rules

The mechanism is one line at the top of the file: adding a rule requires removing or merging one. It is crude and annoying, and nothing else reliably works, because it turns every addition into a comparison. The question stops being "is this rule good". It becomes "is this rule better than the weakest rule in the charter", which is a question with an answer.

Three ways to make room

  • Merge. Two rules about money handling become one rule about money handling. Often possible, and often clearer.
  • Promote. Move the rule out of the prose and into a gate, then delete the prose. The constraint gets stronger and the charter gets shorter, which is the best available trade.
  • Delete. The rule has not fired in a year, see §7.
Promotion is the move to reach for first

A rule that becomes a check or a gate stops needing to be prose at all. The agent does not have to remember it, the charter gets a line shorter, and the constraint gets stronger. Promotion to the harness is the same idea worked through five different mount points.

7 Once a year

Deletion day

One afternoon a year, with the audit trail open. For each rule, the question is not "is this still a good idea" but "when did it last do anything".

Deletion day is why the trail records passes as well as blocks. A rule that has never blocked anything is either second nature or dead. Both look identical from the outside until you have the numbers.

the annual review, one row per rule
RuleFiredBlockedLast blockVerdict
money.integer-cents1,204316 days agokeep · load-bearing
payments.no-retry89043 months agokeep · rare and catastrophic
scope.allowed-paths1,204147todaykeep · but 147 is a smell, investigate
test.must-fail-when-reverted1,2040neverdemote to check-only, revisit next year
logging.structured-only1,2040neverdelete · superseded by the linter in March

Two judgement calls in that table are worth naming. A rule with four blocks in a year stays, because the metric is expected damage, not frequency. So one double-charge event dwarfs a hundred scope warnings. A rule with a hundred and forty-seven blocks is not a success story. Something upstream keeps producing changes that violate it, so the rule absorbs a problem instead of solving it.

The deletion has to be someone's job

Additions happen on their own, because adding a rule is how a team shows the incident mattered. Deletion has no such motivation behind it, so it never happens on its own. Put a name and a date on it, or accept that the charter grows forever.

8 Day one

Writing your first one: start empty

Nothing but the header that says how the file works.

CHARTER.md, day onethe whole file
# Charter
#
# Every rule names the incident that caused it. No incident, no rule.
# Adding one requires removing or merging one. Reviewed each January.
#
# Format:
#   the rule, in behavioural terms
#     altitude: gate | check | human | none
#     date · link · what it cost

(no rules yet)

It will not stay empty for long, and every line that arrives will have earned its place. Two exceptions are reasonable on day one. A comprehension bar counts, because that rule is a policy decision rather than a lesson. So does anything you carry over from a previous team, with the original incident still attached.

Where to start with an existing charter

Do not rewrite it. Instead, go through it once and put a date and a cause on every line you can. The lines where you cannot are your answer. Some are load-bearing and undocumented, and the rest are the ones to delete first. That exercise takes an hour, and it is often the most informative hour anyone has spent on the charter.