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.
CLAUDE.md, a rules directory, or a system promptThe 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.
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
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.
A billing team, three years in, after roughly a dozen incidents. The deletions took everything else.
# 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.
The rule text is the part everyone writes and the least important of the four.
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
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.
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.
Same charter, three enforcement strengths, and the choice is not about how much the team cares. The shape of the failure decides it.
| Rule | Altitude | Why not lower | Why 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. |
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.
"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.
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.
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.
The omissions define a charter. Every line you add dilutes the ones that matter, so argue the omissions as hard as the inclusions.
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.
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.
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.
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.
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.
| Rule | Fired | Blocked | Last block | Verdict |
|---|---|---|---|---|
| money.integer-cents | 1,204 | 31 | 6 days ago | keep · load-bearing |
| payments.no-retry | 890 | 4 | 3 months ago | keep · rare and catastrophic |
| scope.allowed-paths | 1,204 | 147 | today | keep · but 147 is a smell, investigate |
| test.must-fail-when-reverted | 1,204 | 0 | never | demote to check-only, revisit next year |
| logging.structured-only | 1,204 | 0 | never | delete · 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.
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.
Nothing but the header that says how the file works.
# 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.
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.