# The rules my agents run with

> The global rules every Claude Code and Codex session starts with: how they are written, what stays out of them, what the main ones say and how they reach this site.

- Canonical page: https://rob-knight.com/articles/the-rules-my-agents-run-with/
- Kind: Article
- Published: 2026-10-13
- Updated: 2026-10-19
- Topics: agents

Every Claude Code session starts with these rules already loaded. They are the files in the home's `rules/` directory, which [Claude Code reads at startup](https://code.claude.com/docs/en/memory) along with `CLAUDE.md`, and they are in context on every turn of every session, in every repository. The agents run on more than one harness, so Codex gets the same operating model through its global [`AGENTS.md`](https://developers.openai.com/codex/guides/agents-md), rendered from a parallel policy set. Thirteen of the Claude rules are published under [/reference/](/reference/), each a copy of the file the agents load, stamped with the commit it came from.

They are written for agents, not for people, so they talk about me in the third person and don't explain themselves much. [One agent context is not enough](/articles/one-agent-context-is-not-enough/) covers how these files get from one source repository into each home; this is about what's in them, and how a private file ends up as a public page.

<figure class="diagram figure-breakout">
  <img class="on-light" src="/diagrams/50-tldr-the-rules-my-agents-run-with-v2-light.svg" alt="At a glance. Every rule is paid for on every turn, so each is a short instruction, task detail waits behind a named trigger, and only a scanned copy is published. One rule written for an agent: keep, use --append-notes; the bare flag silently replaces the section. Cut, struck through: three paragraphs on how that was found. Three columns under a cost line that is heavy over the first, thin over the second and absent over the third. Paid every turn, highlighted: rules/, short imperative instructions; one clause for a tempting wrong belief; a reason only if it changes the action. Paid when a trigger fires: reference/ beside rules/, named by an exact trigger; full text on a matching path; skills, a one-line description until called. Never loaded: dates and changelogs; what the harness already says; cached inventory, where the rule names the live command instead. How one reaches this site: just sync-rules, then the allowlist and denylist, then a scan where any finding writes nothing, ending at /reference/rules/&lt;name&gt;/, stamped with its source commit. The same scan runs again in just check." width="1440" height="1104" loading="lazy" decoding="async">
  <img class="on-dark" src="/diagrams/50-tldr-the-rules-my-agents-run-with-v2-dark.svg" alt="" aria-hidden="true" width="1440" height="1104" loading="lazy" decoding="async">
  <figcaption>Only the left column costs context on every turn of every session. The middle one costs only when its trigger fires, and the right one never reaches an agent.</figcaption>
</figure>

## Rules are paid for on every turn

Everything in `rules/` is sent before the user has said anything, and sent again on every turn. [claude-md-and-memory](/reference/rules/claude-md-and-memory/) opens with that cost and builds the house style on it. It sets out how to write a rule, a `CLAUDE.md` or a memory file, and its first instruction is that a rule is an instruction to an agent and does not justify itself.

In practice that means:

- Imperative, not narrative. "Use `--append-notes`; the bare flag silently replaces the section", and not three paragraphs on how that was found.
- No dates, no changelog, no "an earlier version of this rule said". Where a wrong belief is tempting enough to come back, one clause names the truth.
- No rationale unless it changes what the agent would do.

Some reasons pass that test. In [archive-never-delete](/reference/rules/archive-never-delete/) the reason is the instruction: say what you intend to delete and wait, because "a wrong 'before' costs one message; a wrong 'after' is unrecoverable." [full-prompts-never-deltas](/reference/rules/full-prompts-never-deltas/) keeps one sentence saying I paste prompts into terminal harnesses with no editor and no diff view, which is why length is never a reason to send only the changed lines.

claude-md-and-memory also lists what never goes into an always-loaded file: generic agent behaviour the harness prompt already covers ("dry-run first", "present a plan and wait"), commands a model writes unprompted, anything a parent `CLAUDE.md` already says, and cached inventory. A table of devices or versions or "current health as of" a date rots silently and is then trusted, so the rule says to name the command that fetches it live instead.

## The progressive disclosure seam

Material that only matters for some tasks goes behind what claude-md-and-memory calls the progressive disclosure seam: a separate `reference/` directory, with each rule naming the exact condition that calls for its reference file. [coderabbit-review](/reference/rules/coderabbit-review/) opens with one:

> Read [`reference/coderabbit.md`](/reference/rules/references/coderabbit/) before diagnosing a failed or partial review, splitting a large one, or applying CodeRabbit's PR review threads.

Two details make the seam work. The trigger has to be specific enough to decide from: "read before granting the service account org-level IAM", not "more on IAM". And the reference directory has to sit beside `rules/`, not inside it, because `rules/` is loaded recursively. A file at `rules/reference/foo.md` lands in every session exactly like `rules/foo.md`, so a seam built there costs as much as no seam at all. The rule's own summary is that an unindexed reference file is dead weight.

There are two other places to put something. A few rules load their full text only when the session touches matching files: [github-actions-oss](/reference/rules/github-actions-oss/) is a short summary until a session edits something under `.github/workflows/` or `.github/actions/`, and [justfile-task-surface](/reference/rules/justfile-task-surface/) does the same for a `justfile` or `Makefile`. A runbook for one kind of task becomes a skill instead, since only a skill's one-line description is always loaded.

<figure class="diagram figure-breakout">
<img class="on-light" src="/diagrams/39-the-progressive-disclosure-seam-light.svg" alt="Four layers of instruction file in one agent home, ordered from always loaded to loaded only on demand. Every turn: rules, short and imperative, sent on every turn of every session, for example ~/.claude/rules/operating-model.md. A heavier rule below this layer is labelled the seam. Matching paths: full text that loads when the session touches matching files, such as .github/workflows/**. When a trigger fires: reference files a rule names, read before a specific task, such as ~/.claude/reference/coderabbit.md. When invoked: skills, of which only the one-line description is always loaded, at skills/&lt;name&gt;/SKILL.md. An arrow down the right edge reads loaded less often. Below the four layers, a warning: ~/.claude/rules/reference/foo.md is inside rules/, so it loads every turn like any other rule." width="1440" height="691" loading="lazy" decoding="async">
<img class="on-dark" src="/diagrams/39-the-progressive-disclosure-seam-dark.svg" alt="" aria-hidden="true" width="1440" height="691" loading="lazy" decoding="async">
<figcaption>Only the top layer is paid for on every turn. Everything below it loads on a path match, a rule's trigger or an explicit call, and a reference folder nested inside <code>rules/</code> quietly moves itself to the top.</figcaption>
</figure>

Seven of the reference files are published too, the generic ones the published rules point at, under [/reference/](/reference/). A rule's link to one of them goes to its page; a link to any other reference file stays a path you can't open.

## The operating model

[operating-model](/reference/rules/operating-model/) keeps the guidance every session needs. Planning, delegation, testing and review, and knowledge work each have a reference file with a specific read trigger. The always-loaded Claude text is under 9 KB, and Codex has the equivalent split.

Its first line sets the precedence: a project's own `CLAUDE.md` or `AGENTS.md`, and my direct instructions, override everything in it. Global rules describe the default, and the repository describes itself. The one exception is written down in [git-push-bypass](/reference/rules/git-push-bypass/), which says that committing finished work straight to `main` on my own repositories overrides any in-repo file that says to push only when asked. Where a global rule beats a local one, the global rule says so explicitly.

Some of what the rule and its references say:

- Investigate means read-only: "Research", "assess", "investigate", "diagnose", "review" or "make no changes" means no edits, commits, pushes, deploys or tracker writes, and the session ends with the proposed actions as a question to me. Logging an incidental finding as a task needs the same approval.
- Proof integrity: a check that passes on its first run against unchanged code has probably asserted nothing, so a new check has to be seen failing for the right reason first. A weaker proof never stands in for the one asked for: a component test is not browser evidence and a type check is not a run.
- Prove behaviour where it is used: run the CLI on a fixture, drive the local dev server, load the page. Green unit tests over a broken real path is, in the rule's words, the commonest miss.
- Which tests not to write: a test per permutation, assertions on implementation details, snapshots that only record current output and tautological tests are listed as defects, not diligence. Before adding a test, the agent has to be able to name in one sentence the bug it would catch.
- Never cite a tracker ID bare: every task ID in text I read carries its meaning in brackets, in lists and ranges too, and a batch or lane label never stands in for the ID.

The delegation reference routes on one question: can the acceptance check be stated now? If yes, a Sonnet lane can do it; if the agent has to decide what "done" means, it goes to Opus or isn't delegated at all. A loop routes by role instead. [The loop contract](/reference/loop-contract/#3-dispatch) sends a task to a `worker` lane by default, to `senior` only when the brief says why (an unknown cause, a frozen seam, a data-model call or composing a batch) and read-only work to `scout`, and every brief carries a `Done when:` check that fails on the base and passes on the candidate. [The machinery around the loop](/articles/the-machinery-around-the-loop/) covers the pinned subagents. The rule adds a second test for interactive work: how much output will the lane throw away? A subagent re-reads what the main session already had, so a job whose answer is a line or two is cheaper done inline.

## Dispatching subagents

[subagent-dispatch](/reference/rules/subagent-dispatch/) is mostly about traps in Claude Code's agent tooling. Naming a background agent keeps it resident as a teammate, and its final text then arrives late through a different channel, so one-shot work is dispatched unnamed. Every brief tells the agent that its last message is the whole deliverable, because the dispatcher never sees its transcript.

Two parts apply beyond Claude Code. The first is "verify the artifacts yourself", which cuts both ways. In the rule's words, every agent that failed to return a brief had still done correct work, so a missing brief is a reason to go and look. A returned brief isn't evidence of correct work either, so the claims that matter get checked against the source.

The second is about auto mode. A subagent can't clear a soft block, because it clears only on the user's own message naming the action and a subagent's transcript has no user message in it. A dispatch brief claiming consent is refused as permission laundering, and re-dispatching a blocked lane looks like bad faith to the classifier. So SSH, deploys, cloud mutations, secret-store writes and destructive git stay on the main thread.

## Small rules about handoffs

Three short rules cover what an agent hands back to me.

[full-prompts-never-deltas](/reference/rules/full-prompts-never-deltas/) says a prompt is always re-emitted whole, however small the change. It is careful about scope: files on disk are edited in place as normal, and a loop's launch message is a file beside its charter, not a chat block.

[compaction-cycle](/reference/rules/compaction-cycle/) defines what "give me a compaction cycle" means: the exact `/compact` argument text and a launch prompt for the fresh context, both in one reply. The arguments are a pointer, not the record. Anything that exists only in the transcript gets written somewhere durable first. A decision needs its reason attached or it gets argued again, and a correction has to say "X was WRONG; the truth is Y" or the next context goes back down the same dead end.

[archive-never-delete](/reference/rules/archive-never-delete/) says "clean up" and "tidy" never mean delete. Superseded files move into `backups/`. The only files an agent may delete unasked are ones it created in the same session and has checked are byte-identical to a copy being kept.

## Tooling rules

The rest are about specific tools. [justfile-task-surface](/reference/rules/justfile-task-surface/) makes a top-level justfile the only task runner on my repositories, and [github-actions-oss](/reference/rules/github-actions-oss/) covers the shared workflows and how they're pinned. [coderabbit-review](/reference/rules/coderabbit-review/) is covered in [one agent context is not enough](/articles/one-agent-context-is-not-enough/#the-review-before-main).

[firecrawl](/reference/rules/firecrawl/) tells the agent to look up how a library, SDK, API or CLI works even when it is a well-known one, instead of answering from training data, and gives the order of surfaces to try. It also limits itself: ordinary web lookups stay on the free search and fetch tools, because Firecrawl bills every call against one shared 5,000-credit month, and that line explicitly overrides the vendor skill's claim to "any live-web task".

[code-navigation](/reference/rules/code-navigation/) splits code search three ways: a question about a symbol goes to the language server where the harness has one, a question about how or why something behaves starts with `jg`, which ranks files by meaning, and grep is kept for literal text. [gate-runner](/reference/rules/gate-runner/) sends a repository's heavy gate to a remote runner, a fresh container on a pool of gate hosts, instead of running it on the laptop. [Just as the only task surface](/articles/just-as-the-only-task-surface/#where-check-runs) covers how that fits the `check` recipe.

## What the published copies leave out

Nine rules are never published. They sit on a denylist in the site's source next to the allowlist of thirteen, and a name on both lists fails the build. Most of the nine are about my own infrastructure: credentials and tokens, telemetry accounts, backups and particular hosts. Codex homes get their own policy set from the same repository, and none of it is published here.

There is no public repository of them. This site is the public copy, cleaned on the way out.

## How a rule reaches this site

The rules live in `rob/agents`, a private repository, so `just sync-rules` runs on my machine and its output is committed like any other content. It's manual, and the site repo's own instructions tell an agent to nag me when the last sync is more than three days old. The sync refuses to write anything if a single check fails:

- It reads only the allowlisted rules and reference files and refuses any with uncommitted changes, since publishing uncommitted text under the last commit's hash would stamp the page with a revision that doesn't contain what it shows.
- It stamps each copy with the short hash and date of the last commit to touch that file, which is what the rule page and [/reference/](/reference/) show.
- It rewrites links the reader couldn't follow. A cross-reference to another rule becomes a link to that rule's page when it's published and plain text when it isn't, and the home placeholder becomes `~/.claude`.
- A short list of exact substitutions replaces the phrases that name one of my contexts or the local user, with wording that names neither. The same list drops or generalises anything that maps my own setup: tracker IDs, machine and host names, private repository names and credential paths. Public repository names stay.
- A scan for sensitive content fails the sync on private domains and addresses, cluster hostnames, local user paths, long hex identifiers and UUIDs, credential and bearer-token shapes and long numeric identifiers, a second check fails it on any context name the substitutions missed, and a third on any tracker ID, machine name or private repository name they missed.
- A rule dropped from the allowlist is deleted from the site on the next sync rather than lingering.

<figure class="diagram figure-breakout">
  <img class="on-light" src="/diagrams/40-how-a-rule-reaches-the-site-v2-light.svg" alt="One rule's publication path, left to right through six numbered stations. Under just sync-rules: 1, the private policy repository, committed rules only; 2, the allowlist and denylist; 3, rewrite: rule links, the home placeholder, context and user phrases, titles included; 4, scan: hostnames, addresses, identifiers, credentials, context names, tracker IDs; 5, src/content/rules/, a committed copy stamped with its source commit. Under just check: 6, scan-reference, the same scan again, so a hand edit fails the gate. The line ends at OK, /reference/rules/&lt;name&gt;/. Drops from stations 1 to 4 lead to one shared FAIL: nothing is written, on an uncommitted source, a name on both lists, an unresolved placeholder or any scan finding. A separate drop from station 6 leads to FAIL: the gate fails and nothing deploys." width="1440" height="720" loading="lazy" decoding="async">
  <img class="on-dark" src="/diagrams/40-how-a-rule-reaches-the-site-v2-dark.svg" alt="" aria-hidden="true" width="1440" height="720" loading="lazy" decoding="async">
  <figcaption>Every check in the sync runs before anything is written, so a bad rule never leaves a half-updated copy behind, and the gate is left to catch a hand edit.</figcaption>
</figure>

The same scan runs again as `just scan-reference` inside `just check`, so a hand-edited copy fails the pre-commit gate even though it never went through the sync. When the scan flags something, the fix is in the source rule, not a looser pattern.

Apart from those substitutions and link rewrites, each page is the file my agents load. If a rule changes, the page changes on the next sync and its stamp moves with it.
