Writing rules, CLAUDE.md and memory files (all projects)
One of the global rules my agents load on every session, published as they load it. Links to reference files point at documents I do not publish.
- Source
- rob/agents/policy/claude/claude-md-and-memory.md
- Revision
- 8ffc462
These files load automatically — a CLAUDE.md in a session’s folder and every folder above it, a
MEMORY.md index in every session in its project, every file in <config-dir>/rules/. Those tokens
are spent before the user has said anything, and they are re-sent on every turn of the session.
Write instructions, not explanations
A rule is an instruction to an agent. It does not justify itself.
- Imperative, not narrative. “Use
--append-notes; the bare flag silently replaces the section.” Not three paragraphs on how that was discovered. - No dates, no changelog, no “an earlier version of this rule said”. State what is true now. Where a wrong belief is genuinely seductive, one clause is enough: “Tailnet Lock is off”, not the story of believing otherwise.
- No rationale unless the rationale changes what you’d do. “Keep the directory name because a repository automation matches it exactly and a rename silently stops it” earns its clause. “This was chosen after careful consideration” does not.
- A statement of fact beats a paragraph making the case for it. If a sentence could be deleted without changing any action an agent takes, delete it.
What earns a place in an always-loaded file
Gotchas and traps (“silently no-ops”, “the status command lies”, “a 2xx proves nothing”). Standing prohibitions. Decisions stated as the decision, not the debate. Deliberate omissions, marked as deliberate so they don’t get “fixed”. Non-guessable identifiers: IPs, tenant and app IDs, ports, absolute paths, credential locations, exact odd invocations.
What does not
- Generic agent-behaviour rules — “read-only first”, “confirm before mutating”, “dry-run first”, “present a plan and wait”. The harness system prompt already says this.
- “Related Context” tables restating the folder tree. Keep a line only where the relationship is non-obvious and load-bearing.
- Command blocks a model writes unprompted (
df -h,docker logs,systemctl status). Keep only non-guessable invocations: odd flags, exact API shapes, the one command that doesn’t lie. - Cached live inventory — device/user/policy tables, counts, “current health as of
”, versions stated as fact. It rots silently and is then trusted. Name the command that fetches it live. - Vendor endpoint or API reference — fetch it per
context7. - Anything a parent
CLAUDE.mdalready says. They load recursively; a child carries deltas only.
The progressive-disclosure seam
Content that is valuable but only matters for some tasks goes in a sibling .md (bulk under
reference/), indexed as the last section:
## Deeper references
- `reference/dns-dhcp.md` — read before touching DNS or DHCP on this box
The seam must sit outside the auto-loaded directory. For a repo folder that means a sibling of
CLAUDE.md. For the user-level config it means a sibling of rules/, not a subdirectory of it —
<config-dir>/rules/ is loaded recursively, so rules/reference/foo.md lands in every session’s
context exactly like rules/foo.md, while <config-dir>/reference/foo.md is loaded by neither.
Index those by their absolute ~/.claude/reference/<name>.md path so they resolve
from the work config and the Linux servers.
The trigger must be specific enough to decide from (“read before granting the service account org-level IAM”, not “more on IAM”). An unindexed reference file is dead weight.
A rule that is mostly a lookup table, a config reference or a runbook belongs behind the seam, or as a skill — a skill’s body loads only when it is used, and only its one-line description is always on.
Memory files
MEMORY.md is always-on; the memories themselves are on-demand. Terseness pays in the index,
accuracy pays in the files. One line per memory — the shortest hook that supports a decision to open
it. name: must equal the filename stem. One fact per file. Never the same fact under two project
keys. Don’t store what the repo permanently records; do store the expensive, correction-shaped and
pending-action things. A memory recording an unfinished commitment must stay loud.
When you touch any of this
Learned something expensive — a live-verified fact, a negative result, a trap? Write it down as an instruction. Found two statements that disagree? Resolve it and delete the loser; do not keep both with a note explaining which won. Adding a long-lived plan or runbook? It’s a reference file with a trigger, not a new section.