Principles
Principles under my agent setup: enforce rules with structure, give a checkable criterion first, let the model fill in the verdict, fix mistakes at the source.
The other guides cover what I set up and how. This one covers why. The principles come from the design notes (claude/docs/SKILL-PHILOSOPHY.md, HARNESS-ENGINEERING.md, MODEL-ERA-AUDIT.md) and working principles (claude/skills/_shared/principles/) in the agent config repo, and from the incident log I keep for each rule (claude/docs/RULES-EVIDENCE.md).
Structure, not requests
A sentence like "never do this" is forgotten once the context grows long; structure is not. So the first decision about a rule is which layer it lives in. The higher the layer, the less it can be broken.
| Layer | How | Example |
|---|---|---|
| No permission | The tool is never given | The explorer agent (claude/agents/explorer.md) has no Edit or Write |
| Hard block | settings.json deny and ask | Editing CLAUDE.md, RULES.md, CONTEXT.md or AGENTS.md needs approval |
| Conditional block | A hook exits 2 | Dangerous commands, force pushes to protected branches, --no-verify, broken Conventional Commits |
| Owned verdict | Gates and deterministic verifiers | A slice passes = tests green + review PASS |
| Injection and isolation | SessionStart hook, forked context | Commits and the branch go back in after a compact; reviews run in a separate context |
| Request | CLAUDE.md | Guidance only. When a line has to hold, it moves up a layer |
Where a permission cannot stop something, a verifier checks afterwards. A subagent with write access gets a list of allowed paths, and when it returns, git diff --name-only reverts any file outside that list. "Only touch your own folder" written as a sentence is not a verifier.
Bash blocking lives in one guard hook, for two reasons.
- A
settings.jsondeny matches by prefix, so it misses chained commands likecd x && <command>. - The live
~/.claude/settings.jsonis not a symlink to the repo copy. A deny added only to the repo never reached the live settings, so it blocked nothing; the hook did the blocking.
A command instead of "done"
"It works" is not a criterion. When I hand off a task, the first line states what must be true when it is finished and the command that measures it.
done: a draft PR is open · check: `pnpm check` · expect: check: okFor larger tasks the plan file's Acceptance Contract extends that line. Each criterion pairs an observable condition (WHEN … THE … SHALL …) with the command that measures it, on one line. The contract goes through three steps.
- Falsify — before implementing, run the command and confirm it is red. A criterion that is already green tells nothing apart, so the criterion gets fixed.
- Freeze — when implementation starts, the criteria are fixed by a hash. Changing one means refreezing with a reason, and the review reads that reason.
- Self-assess — the implementing model fills in only the verdict columns (status and evidence). Evidence is the command it actually ran plus the one output line the verdict rests on. "I checked" or "it is implemented" is not a pass; it is unverified. A check that ran but never hit its target (0 tests collected, a case skipped by a filter) is not a pass either.
A script then compares that self-report against the verification ledger. Before this format, plans listed success criteria as - [ ] lines. Nobody ran them, so "done" ended as the model's claim. I switched on 2026-10-15. What this stops is criteria quietly drifting. It does not stop forgery.
The reviewer never sees the passing bar
A reviewer that knows the bar aims for it. It downgrades a Critical by one level to produce a "pass". Writing "ignore the bar" in the same file is not separation. So the bar is physically removed from the reviewer's context.
- The bar lives in a separate file (
GATE.md) that only the main session reads, after all findings are in. The finder's spawn prompt does not even name it. - The finder that produces findings is a subagent that has not seen the conversation. It gets the plan, the diff and the repo's conventions, never earlier findings or verdicts. When the harness can call a finished subagent again, one finder takes three slices and their re-reviews, and the next slice starts a fresh one.
Reviews look along two axes: does it follow the repo's conventions (Standards), and did it build what the plan asked for (Spec fidelity). A diff with perfect conventions that builds the wrong thing still fails.
Loops end on a deterministic check; weak criteria go to a person
A fix-and-recheck loop ends only on a deterministic check such as tests, lint, or typecheck. No loop ends because the model says "looks done". If the same issue comes back twice in a row, or one slice goes three rounds without a pass, it stops and reports.
Design and scope have weak criteria, so they do not go in a loop. A person decides. Instead of asking every time, the agent picks the recommended option and lists it under "Auto-decided" in the draft PR body, where I review and change it. I do the merge.
Fix a mistake in the layer that caused it
A mistake an agent could have avoided is feedback on the system around the diff before it is a bad diff. Fix only the code and the next run makes the same mistake. So I fix the layer that produced it: the spec, the domain vocabulary, the repo instructions, the validation, or the structure. A diff is used once; that layer is used on every later run. Without a signal, I do not write a rule in advance.
Each rule gets a dated entry in the incident log that says why it exists. The rule files keep only short imperatives; the reasons live in the log.
Subtract before adding
The test is not line count but a deletion test. If removing something leaves the result the same, it was a duplicate; if the result changes, it was unique.
- I merged the three plan review lenses (product, design, engineering) into one, then split them again. Their personas, checklists, and verdict scales all differed, so removing one changed the result. The merged version measured a median of 46 turns and 22.4k output tokens, against 26 turns and 9.8k for a single lens.
- Call counts were weak evidence for deleting a skill. Most skills are not called by me; another skill points to them in its body. So I look at the reference graph. A skill that a live execution path points to stays; one only a catalog page points to goes.
package.jsonscripts, config files, and--helpoutput are the source of truth themselves. A document that restates them becomes a cache, and caches go stale. Docs hold only what an agent cannot look up: unwritten conventions, why a choice was made, and traps no setting reveals.
One source of truth
When the same content lives in two places, the copies drift apart. Keep one source and record only the differences elsewhere.
- The pipeline's shape lives in a shared contract (base), language differences in packs (react, ts, nodejs), and the calls in routers.
- A skill that Claude Code, pi and opencode share has one English body (
agent-skills/). The Claude Code file keeps only a table of what differs per harness, such as tool names and availability. When the policy differs, the source changes, not the delta. The parity check that kept two copies in sync was deleted on 2026-10-30; there are no two copies left to sync. - Two documents that name each other as the source mean there is no source.
- A skill body stays small and moves detail into references read on demand, one level deep. When a reference points to another reference, the agent reads the first part and moves on.
Delete steps as models improve
A step added for an older model is only cost once the model improves. Steps fall into five kinds.
| Kind | Example | Verdict |
|---|---|---|
| Making up for model limits | "one concern per pass", splitting roles | Delete or merge |
| Double evaluation | Scoring the same thing twice | Keep one |
| Unused decomposition | A mode or role an execution path points to but that is never called | Delete along the reference graph |
| Deterministic verifiers and structural separation | Tests, hooks, a separate reviewer | Keep; they do not depend on model ability |
| Specs for weak implementers | Documents a cheap worker model reads | Keep while the reader is weak |
Before deleting, three questions: what was it added to stop; does it still fire (recent logs); does deleting it change the result. If what changes is that a defect gets caught, the step is a verifier after all.
Working principles
There are 19 short principle files, each read when its situation comes up. The rule file says only when to read each one; the body is read at that moment. The ones that overlap with common advice are left out; these are the ones with a specific trigger.
| Principle | When | What |
|---|---|---|
| verify-primary-source | Before writing a fact or number into a document | Did I read the primary source myself? If I only heard it, mark it unverified |
| attack-the-premise | Two fixes on one premise failed the same check | Before the third fix, write the shared premise as one sentence and test it directly |
| explain-the-number | Reporting a measurement | Ask "why not double?" and name the limiter. Keep the run count and spread next to the number |
| subtract-before-you-add | Extending a system, prompt, or rule set | Remove complexity first. Design for observed usage, not speculative edge cases |
Sources
The design notes (SKILL-PHILOSOPHY.md) start from the engineering discipline in mattpocock/skills (MIT). Fifteen of the 19 working principles are adapted from the pstack principles in cursor/plugins (MIT). The Acceptance Contract's freeze, hard thresholds, and evidence column come from Anthropic's two posts on harnesses for long-running agents and from the Claude Code best practices ("show evidence rather than asserting success").
Check
To see whether the same principles hold in your own harness:
- Write the done criterion for your next task as one command. Run it before implementing and confirm it is red. If it is green, the criterion measures nothing.
- Look at the prompt you give the reviewer. If it contains a passing score or the verdict rules, the reviewer will aim for that bar.
- Pick a rule you added recently and find where it says why it exists. If nowhere does, the next person cannot tell whether it is safe to delete.