# CLAUDE.md Architecture: A Hub-and-Spoke Pattern for Autonomous Codebases

> Your CLAUDE.md is the highest-leverage file in your codebase. It survives compaction, loads in every session, and accumulates the rules that turn a generic Claude into your codebase's senior engineer. Here's the full architecture, root file, directory hub-and-spoke, scar-tissue practice, auto-load tables, and the anti-patterns that wreck it.

`CLAUDE.md` is the most important file in any Claude Code project.

I mean that literally. There's no other file that touches every session, survives every compaction, and accumulates value over months of use. Your `package.json` doesn't. Your README doesn't. Your tests don't. `CLAUDE.md` does.

And yet most teams I've worked with treat it as a write-once afterthought. They generated it with `claude /init` six months ago, never opened it again, and now wonder why their agents keep making the same five mistakes.

This post is the full architecture of `CLAUDE.md` as we run it at Chipp. Root file, hub-and-spoke directory loading, scar-tissue practice, auto-load tables, sub-agent definitions, and the specific anti-patterns that turn a useful `CLAUDE.md` into a useless one.

If you only have time to internalize one thing from the [autonomous development series](/blog/autonomous-development), make it this one.

## What `CLAUDE.md` actually is

`CLAUDE.md` is a markdown file in your project root. Claude Code finds it automatically and prepends its contents to the system prompt of every session in that project.

That's the whole mechanism. There's no magic. There's no plugin. The file is just *there*, and Claude reads it.

Three properties make it special.

**Property 1: It loads in every session.** Whether you start an interactive session, run `claude -p` headless, spawn a sub-agent, or dispatch a session from a webhook, `CLAUDE.md` is part of the system prompt every time. There is no opt-out.

**Property 2: It survives compaction.** When the context window fills and the model summarizes everything else, `CLAUDE.md` is one of the few things that stays intact. The post-compaction agent has lost the file contents you read, the grep results you ran, the reasoning that led to the current state, but it still has `CLAUDE.md`. ([Why compaction matters →](/blog/context-engineering#the-compaction-trap))

**Property 3: It's the only training data you fully own.** The model is trained on the public internet. The MCP servers you use are someone else's tools. The Claude Code CLI is Anthropic's product. `CLAUDE.md` is *yours*. It's the one piece of context the agent loads that nobody else can see, replicate, or take away.

These three properties make `CLAUDE.md` the *highest-leverage file in your codebase*. Every line in it pays compounding dividends. Every line you neglect to add costs you the same mistake, repeated, every time the agent runs.

## The scar-tissue practice

The fundamental discipline of `CLAUDE.md` is treating it as a *scar tissue document*, not an aspiration document.

An aspiration document says things you wish were true. *"Always write clean code." "Prefer composition over inheritance." "Use semantic HTML."* The agent ignores most of it because the rules are too vague to act on and too unmotivated to take seriously.

A scar tissue document says things that have actually bitten you. *"Don't use lodash; we removed it in v4 and the bundle size went up 30KB last time someone re-added it." "Database migrations have to be backward-compatible because we deploy without taking the API down." "The `useUser` hook returns null during the auth bootstrap; check for it."*

Each of those sentences is a real bug we hit. Each one is a rule we wrote into `CLAUDE.md` after the third or fourth occurrence. Each one prevents the agent from making the same mistake again. The aspiration version of those rules would have been ignored. The scar tissue version is treated as load-bearing.

The mechanic for building scar tissue:

1. The agent makes a mistake. Notice it.
2. Don't fix it yet. First, prompt the agent: *"Add a rule to `CLAUDE.md` that prevents this exact mistake. Cite the failure mode you just hit. Make the rule specific enough to act on."*
3. Let the agent write the rule. The model knows what kind of rule will register on its own future inference better than you do.
4. Read the rule. Tighten it if needed. Commit it.
5. Now fix the original mistake.

After six months of doing this, your `CLAUDE.md` is a textbook of your codebase's hidden rules. Your agents stop making the mistakes you've already paid for.

> "I have my autonomous AI cluster updating its own `CLAUDE.md`. I honestly barely know what's in there these days."
> — Hunter Hodnett, Chipp CTPO

## The three-strikes-then-rule heuristic

Don't add a rule for every mistake. If you do, your `CLAUDE.md` becomes 5,000 lines of one-off lessons and the truly important rules get diluted.

The heuristic we use: wait for the same class of mistake to happen *three times* before promoting it to a `CLAUDE.md` rule.

Once is an outlier. Twice is suspicious. Three times is a pattern. Patterns are what `CLAUDE.md` is for.

There are exceptions. If a single mistake costs real money, real customer trust, or real production downtime, it goes in the file the first time. But for the everyday small mistakes, the agent typed `useState` when it should have used our custom `useStableState`, the agent imported from `@/components/old/Button` when the new one is at `@/components/Button`, wait for the third strike.

This heuristic also keeps the file *legible*. A 200-line `CLAUDE.md` of hard-won rules is more useful than a 5,000-line `CLAUDE.md` of every observation. The agent reads the entire file every session. Make every line earn its place.

## Hub-and-spoke: directory-scoped CLAUDE.md

Your root `CLAUDE.md` should not contain rules that only apply to part of your codebase.

If a rule applies only to your billing system, it shouldn't load when the agent is editing your CSS. Loading it anyway costs context budget the agent could be using to think.

The fix is a feature most people don't know exists: **Claude Code automatically loads any `CLAUDE.md` it finds in or above the directory of any file it reads.**

That means you can put a `CLAUDE.md` at any level of your file tree, and it will load *only* when the agent is working in that area:

- `src/db/CLAUDE.md`, loads when the agent reads any file in `src/db/`
- `src/api/auth/CLAUDE.md`, loads when the agent is in the auth subsystem
- `src/components/CLAUDE.md`, loads when the agent is in any component

We have something like fifteen `CLAUDE.md` files sprinkled throughout the Chipp codebase. Each one is small, usually 20–80 lines, and *very* specific to its directory.

The result is that the agent always has *exactly* the context it needs and very little it doesn't. Hub-and-spoke is the difference between an agent that runs out of context budget on every task and one that finishes with 70% to spare.

A practical layout looks like:

```
.
├── CLAUDE.md                          # root: tech stack, conventions, top-level rules
├── src
│   ├── api
│   │   ├── CLAUDE.md                  # API conventions, error handling, route patterns
│   │   ├── auth
│   │   │   └── CLAUDE.md              # auth-specific gotchas
│   │   └── billing
│   │       └── CLAUDE.md              # billing invariants, Stripe quirks
│   ├── db
│   │   └── CLAUDE.md                  # ORM rules, migration patterns, schema gotchas
│   ├── components
│   │   └── CLAUDE.md                  # design system rules, prop conventions
│   └── services
│       └── CLAUDE.md                  # service layer conventions
└── tests
    └── CLAUDE.md                      # test framework, fixture patterns
```

Each subdirectory `CLAUDE.md` should answer the question *"What would I tell a senior engineer who's never worked in this directory before, on day one?"*, and nothing more. If a rule is universal, push it up to the root. If it's universal *within a subdirectory*, push it down. Hub-and-spoke is a structure for keeping rules at the right level.

## The auto-load table

Hub-and-spoke handles location-based context. But sometimes you want context to load based on *what the agent is doing*, not *where in the codebase it is*.

For example: if a ticket mentions "billing," the agent should load our billing playbook before it starts work, even if it doesn't yet know which files it's going to touch. Static `CLAUDE.md` placement can't handle that, because the relevant docs aren't *in* a billing directory; they're in `/docs/billing.md`.

We solve this with an auto-load table. At the top of our root `CLAUDE.md`, we have a small markdown table:

```markdown
## Auto-load table

| Mention | Read |
|---|---|
| billing, stripe, payment, subscription | docs/billing.md |
| auth, login, session, oauth | docs/auth.md |
| websocket, realtime, streaming | docs/realtime.md |
| voice, livekit, transfer | docs/voice-agents.md |
| migration, schema, kysely | docs/db-migrations.md |
| feature flag, rollout, kill switch | docs/feature-flags.md |
```

The pattern: when a prompt mentions any of these keywords, the agent reads the corresponding doc into context before starting work.

We don't load the docs in `CLAUDE.md` itself, that would burn the budget on every session, even sessions that don't need them. We load them dynamically, only when relevant.

This is how I keep my root `CLAUDE.md` lean (around 25k tokens) while still giving the agent rich context for any specific subsystem (5k–15k of additional context, only when needed).

The auto-load table is the part of the architecture that keeps the system *learning*. Every time a successful autonomous run produces a useful insight about a subsystem, that insight goes into a markdown file in `/docs/`, and a row in the auto-load table makes it available for future runs that touch the same area.

## Sub-agent definitions

Your `CLAUDE.md` should also define your sub-agents.

A [sub-agent](/blog/skills-vs-sub-agents) is a separate Claude Code session your main agent can spawn to do bounded work in its own context window. They live in `.claude/agents/` as their own markdown files, and your root `CLAUDE.md` should reference them.

Our root `CLAUDE.md` has a section like:

```markdown
## Sub-agents

When the work calls for a deep investigation that would otherwise burn the
main context window, dispatch one of these sub-agents instead:

- `infra-ops` — for Kubernetes, deploys, networking, log investigation.
  Has the runbooks. Has the kubectl tools. Returns one-paragraph summaries.
- `feature-deep-dive` — for understanding how an existing feature works
  before modifying it. Returns an architecture summary.
- `feature-dependency-mapper` — for refactor planning. Returns the call
  graph and files affected.
- `db-investigator` — for debugging data issues. Has read access to the
  production database with safe-column allowlisting. Returns the
  smoking-gun query results.

When in doubt, prefer a sub-agent over filling the main context. The main
context belongs to the work, not the investigation.
```

The agent reads this in every session and knows when to dispatch what. We rely on it heavily, most of our autonomous tickets dispatch at least one sub-agent in the research phase.

## Anti-patterns that wreck a `CLAUDE.md`

Six failure modes I've seen on real teams. Avoid them.

### The aspiration document

Rules like *"Always write clean code"* and *"Prefer composition over inheritance"*. These are too vague to act on. The agent acknowledges them and ignores them. Replace with specific scar-tissue rules.

### The bloat

A 5,000-line `CLAUDE.md` that includes everything anyone ever thought was important. Every session pays for the bloat in context budget. The truly important rules get diluted into noise. Apply three-strikes-then-rule. Push directory-specific stuff into hub-and-spoke files.

### The freeze

A `CLAUDE.md` that hasn't been edited in three months. Either your codebase has stopped evolving (it hasn't) or your agent is making the same mistakes over and over and you're not bothering to write them down. The latter is the diagnosis 95% of the time.

### The wishlist

Rules describing what you *wish* the codebase were like, not what it actually is. The agent reads these, dutifully writes code that matches the wish, and breaks the codebase. Document the codebase as it exists. Migrate the codebase first, then update the rule.

### The TODO ledger

`CLAUDE.md` used as a personal scratch pad: *"TODO: refactor the user service. NOTE: ask Hunter about the billing thing."* This pollutes the system prompt with irrelevant content. Use a tasks file or your issue tracker for this. `CLAUDE.md` is for rules.

### The single source

Trying to put everything in one file at the root. The hub-and-spoke pattern exists precisely because not everything belongs in the root. If your root `CLAUDE.md` is over 1,000 lines, you're failing to use the directory mechanism.

## How to start one if you don't have one

For a fresh project: run `claude /init` to generate a starter file. Then immediately delete most of what it generates. The generated `CLAUDE.md` is too generic to be useful, it's a placeholder for the scar tissue you'll write yourself.

Replace the boilerplate with three things:

1. **Your tech stack.** One-line summary of what you're using. *"Deno + Hono on the server, Svelte 5 on the client, Cloudflare Workers for delivery."*
2. **The two or three most important rules.** Things you already know will trip the agent up. *"We use Kysely, not Prisma. Migrations are expand-then-contract; never both at once."*
3. **An empty auto-load table.** Just the header. You'll fill it in as you generate `/docs/` files.

That's the whole starter. Resist the urge to write more. The remaining content has to be earned through actual scar tissue.

## How to fix one that's a mess

If you have a `CLAUDE.md` that's already 3,000 lines of garbage, the cleanup pattern is:

1. **Audit for the three-strikes-then-rule violation.** Any rule that hasn't paid for itself by preventing a real bug? Cut it.
2. **Push location-specific rules into hub-and-spoke.** A rule about your auth system goes in `src/api/auth/CLAUDE.md`. A rule about your CSS goes in `src/components/CLAUDE.md`. The root file should only have rules that apply everywhere.
3. **Convert aspirations to scar tissue.** *"Always validate input"* becomes *"Use the `assertValidUuid()` helper before any DB query against an id column. We've shipped four 500s from this exact mistake."*
4. **Build the auto-load table.** Group related rules into `/docs/` files. Reference them in the auto-load table. Cut them from the root file.

This audit is itself a great task to hand to an agent. Open an interactive session, share the current `CLAUDE.md`, and ask the agent to apply the audit pattern. It'll do most of the work for you.

## The compounding asset

The reason `CLAUDE.md` matters more than any other file in your codebase is that it's the only artifact whose value compounds with every successful autonomous run.

Every line of code you write decays, frameworks change, requirements shift, tests need updating. Every line in `CLAUDE.md` becomes more valuable, because it's preventing a class of mistake across all future sessions.

After three years of running this discipline, your `CLAUDE.md` is the most important asset in your codebase, more valuable than any individual feature you've shipped, because it's the thing that lets you ship the *next* feature reliably.

Treat it accordingly. Read it monthly. Edit it weekly. Audit it quarterly. The teams who run autonomous development at scale all have this in common: they take their `CLAUDE.md` seriously.

The teams that don't end up wondering why their agents are still making mistakes after six months. They are. The mistakes are documented in your bug tracker. They aren't documented in `CLAUDE.md`. That's the gap.

**[Join the Alchemist waitlist →](/#waitlist)**

---

If you want the full discipline of context engineering, read [Context Engineering: The Skill That Turns Claude Into a Production Co-Developer](/blog/context-engineering).

If you want to see how `CLAUDE.md` fits into a real autonomous pipeline, read [Building a Self-Healing Bug Bot](/blog/self-healing-bug-bot).

If you want to know when to use a skill versus a sub-agent (the next layer up from `CLAUDE.md`), read [Skills vs Sub-Agents](/blog/skills-vs-sub-agents).
