Context Is a Budget, Not a Backpack

A mud-caked tactical backpack sitting on wet ground in a dark forest.

As a codebase grows, Claude Code can start to feel less sharp. Early prototypes fly; then complexity sets in, and suggestions begin missing context or editing the wrong file.

The instinct is to give Claude more — more rules, more background, all crammed into CLAUDE.md. That’s the exact move that makes it worse.

Here’s the core truth:

The context window is a budget, not a backpack.

Everything you load costs you twice — once in space, and once in attention. Cram everything into CLAUDE.md and it gets read on every task. Fixing a button label? Claude is also wading through your migration policy and commit-message preferences. That blows up your budget and buries the rules that matter for this task under the ones that don’t. More context isn’t more help. Relevant context is.

What this looks like from Claude’s side

To see why structure matters, it helps to look at the problem from the model’s perspective.

Every Claude Code session begins with a fresh context window. Nothing carries over on its own — so anything you want Claude to know has to be re-loaded at the start of each session, spending budget before you’ve typed a word. Worse, those instructions aren’t enforced configuration. Claude reads your CLAUDE.md, treats it as context, and tries to follow it — but there’s no guarantee of strict compliance, and when two instructions conflict, Claude may pick one arbitrarily. The more you pile in, the more often the rule that mattered gets drowned out by the fifty that didn’t. A model’s attention is a real, finite thing, and you’re the one deciding how it gets spent.

The good news is that Claude Code now meets you halfway. Alongside the CLAUDE.md files you write, there’s a second, complementary system called auto memory — notes Claude writes for itself. As you work, Claude saves the things worth remembering: the build command it had to discover, a debugging insight, the fact that you keep correcting it toward pnpm. Those land in a per-repo MEMORY.md index that loads at the start of each session, with longer notes spilling into topic files it reads only on demand. You write the rules; Claude accumulates the learnings. Both are designed to carry knowledge across that fresh-every-time context window — without you re-explaining yourself.

Fixing it by hand

You don’t need anything exotic to fix this — just a layout that loads only what each task needs. Here’s the structure:

your-project/
├── CLAUDE.md              # lean map: orientation + pointers, nothing more
├── .claude/
│   └── rules/             # how we do things — each loads ONLY when its paths match
│       ├── database.md       # paths: migrations, *.sql, src/db/**
│       ├── api-design.md     # paths: src/api/**, routes, handlers
│       ├── testing.md        # paths: *.test.*, *.spec.*, tests/**
│       └── security.md       # paths: auth, api, webhooks, middleware
└── documentation/        # how the system works — read on demand
    ├── auth-flow.md
    ├── ingestion-pipeline.md
    └── billing-webhooks.md

Keep CLAUDE.md lean. It loads in full, every session, so it should stay a table of contents, not an encyclopedia — orientation, pointers to your docs, and only the handful of standards universal enough to belong in every task. Aim for under 200 lines; past that, adherence actually drops.

Put your standards in .claude/rules/ — and scope them. This is the load-bearing trick most “split your CLAUDE.md” advice misses. Each rule file carries a paths: glob in its YAML frontmatter, and Claude Code loads that file automatically and only when Claude touches a file matching the glob. Open a migration and database.md arrives on its own. Fix a typo and nothing extra loads. You don’t reference these from CLAUDE.md; the glob does the work.

That precision is the whole point, because the alternatives both fail in opposite directions. Simply mentioning a file in your CLAUDE.md loads nothing automatically — Claude has to decide to go read it. An @import loads the file eagerly at every startup — back to carrying the backpack. A paths:-scoped rule is the only mechanism that’s both automatic and relevance-gated. (A rule file with no paths: block loads every session, same as CLAUDE.md — so give every rule a glob on purpose.)

Put system knowledge in documentation/. Rules say how you want things done; docs say how the system already works — the auth flow, the ingestion pipeline, the billing webhooks. There’s no auto-load here, which is correct for reference material you reach for occasionally; CLAUDE.md simply points the way. When Claude (or a new engineer, or you at 11pm) needs to understand a subsystem, it reads one doc instead of grepping the whole repo. Good documentation is cached understanding.

The one catch: docs rot. The moment code and docs drift, the docs become a trap. So the maintenance has to be cheap enough that it actually happens — which is exactly where tooling earns its keep.

The repo: well-actually

I packaged this whole layout into a starter template so you don’t have to assemble it by hand: github.com/BanyanOutcomes/well-actually.

It ships the structure above plus four skills that keep it from becoming a chore:

  • well-actually-get-started seeds both trees at once — splits an existing CLAUDE.md into path-scoped .claude/rules/ files and reads your code into documentation/.
  • well-actually-create-rules does just the rules half: decomposes a fat CLAUDE.md into concern-scoped files, each with the right paths: glob, and proposes a slimmed CLAUDE.md you approve before anything is overwritten.
  • well-actually-documentation-full documents the whole repo from scratch, one doc per subsystem, in parallel.
  • well-actually-documentation-recent is the maintenance loop that solves doc rot: it reads every commit since the last sync — tracked by a .last-synced commit marker, not a calendar window — and updates only the affected docs. Run it after each feature lands and your documentation keeps itself honest.

Clone it fresh, or copy just the skills into an app you already have and let them regenerate the rules and docs from your real code. The README has a quickstart for both paths and a worked example/ showing a path-scoped rule loading itself mid-task.

The point

Bigger projects don’t need bigger context. They need better-managed context. Treat the window like the budget it is — a lean map, rules that load only when they’re relevant, docs that stay current, and Claude’s own memory filling in the rest — and the model stays sharp exactly when your codebase gets complex enough to need it.