leek.io leek.io
contact
#ai #claude-code #tooling

My Global CLAUDE.md: The Rules I've Built Up Over Time

CJ
Chris Jones · @leek
Jun 17, 2026 · 11 min read · 2,095 words
My Global CLAUDE.md: The Rules I've Built Up Over Time

Claude Code does something that annoys me. I correct it. Next session (fresh context, no memory of the last one) it does the exact same thing again. The third time it happens, I stop re-typing the correction into the chat and write it down once, permanently, in a file that every session reads before it does anything.

That file is ~/.claude/CLAUDE.md, and over months it has quietly become the most useful thing in my setup: a record of every way an AI agent has burned me, turned into a standing instruction so it can’t burn me the same way twice.

This is the whole file, rule by rule, with the scar behind each one. Steal what’s useful.

What this file actually is

There are three places agent rules can live, and people conflate them constantly:

  • Project root (./CLAUDE.md): facts about this codebase. Its conventions, its stack, how to run its tests.
  • Subdirectory rule files (app/Models/CLAUDE.md, tests/CLAUDE.md): rules scoped to the kind of code in that folder. I wrote a whole post on why these beat one giant root file.
  • Global (~/.claude/CLAUDE.md): me. How I want any agent to work, on any project, forever.

This post is about the last one. Nothing in it is specific to a single repo. It’s my working style, the habits I’d want from any collaborator, encoded once and applied everywhere I open Claude Code.

Project files describe the code. The global file describes how you want to be worked with. Don’t mix them.

The one rule about writing rules

The global file loads into context on every session, before a single useful token is spent. That makes it expensive in the only currency that matters: attention. A 600-line global file is a 600-line tax on every task, and most of it gets skimmed.

So the bar for adding a rule is high. Each line in mine earned its place by something going wrong at least twice. Never a hypothetical, never “this seems like good practice.” If I can’t point to the specific session where its absence cost me, it doesn’t go in.

A good rule is a scar. If nothing actually went wrong, you don’t need the rule yet.

With that said, here’s what’s in there.

The working relationship

These three set the default posture: do the work, think for yourself, but don’t wander.

## Ask when unclear
- If the request is genuinely ambiguous or you're materially uncertain,
  ask one sharp question instead of guessing or hedging.

## Execute directives fully
- Do exactly what was asked, cleanly and completely. Don't substitute a
  scoped-down "safer alternative."
- Build in real safety mechanics (transactions, ordering, expand/contract
  migrations); skip generic "this is dangerous" hedging.
- State concrete blockers as facts and handle them. Push back only on real
  correctness problems, not taste or deploy nerves.

## Don't chase unrelated test failures
- Don't expand scope to fix pre-existing failures unrelated to your change.
  Once proven pre-existing: verify only what you touched, commit, note the
  failure plainly.

The one that earns its keep most often is “don’t substitute a scoped-down safer alternative.” Ask an agent to do something with real consequences (a migration, a bulk update, a refactor across many files) and its instinct is to quietly do a smaller, safer-looking version and present that as if it were what you asked. I don’t want the timid version. I want the actual thing, built with actual safety mechanics. The difference between “this is dangerous, are you sure?” and a real transaction with a rollback path is the difference between a hedge and an engineer.

“Don’t chase unrelated test failures” exists because agents are compulsive tidiers. You ask for one change, the suite has three pre-existing reds, and now your one-line fix is a 40-file diff touching things you never meant to touch. Prove the failure predates you, note it, move on.

Don’t let it near git carelessly

This is the section I’d hand to anyone, untouched.

## Git: stage explicitly
- Stage only files you touched, by explicit path. Never `git add -A` /
  `git add .`.
- Check `git status --porcelain` before every commit; unstage any foreign file.
- Re-check `git rev-parse HEAD` vs `origin/main` before history surgery —
  session-start HEAD may have moved.
- Prefer `rm`/Edit over `git rm` for files you're replacing, so deletions
  stay unstaged. Stage at your own commit time.
- Recover a tangled graph by branching from current HEAD, not rewriting commits.

git add -A is the single most dangerous habit an agent has. It sweeps up whatever happens to be in your working tree (a half-finished experiment, a .env, a debug script) and commits it alongside the intended change. Stage by explicit path, every time. Everything else here is downstream of one principle: the agent should only ever commit the exact files it knowingly touched, and it should recover from mistakes by moving forward (a new branch) rather than rewriting history under your feet.

Don’t let it destroy anything

## No destructive DB ops without approval
- Never run `migrate:fresh`, `Schema::drop`, `migrate:rollback` on create
  migrations, or any destructive DB op without explicit approval.
- Missing column that exists in the create migration → just
  `php artisan migrate`; don't drop/recreate.
- `make -n` / `--dry-run` is NOT safe for recipes referencing `$(MAKE)` —
  GNU make runs those lines for real even under `-n`. Read the Makefile to
  inspect; don't dry-run it.

## One-time operations
- One-time backfills/migrations leave no permanent infra (no audit tables, no
  `*:revert` commands). Capture pre-op state as a disposable snapshot (e.g.
  JSON dumped + downloaded locally); write a throwaway restore script only if
  a revert is ever needed.

migrate:fresh drops every table. An agent reaching for it to fix a missing column is the kind of thing you only need to witness once. The fix is almost always smaller than the agent thinks. A missing column that’s already in the create migration just needs migrate, not a teardown.

The make --dry-run line is the most specific scar in the file, and the most satisfying to have written down. make -n is supposed to print commands without running them — except recursive make ($(MAKE)) executes those sub-make lines for real even under -n. I learned that the expensive way. Now the agent reads the Makefile instead of trusting a dry run that isn’t dry.

“One-time operations leave no permanent infra” is about taste, not safety. When I ask for a backfill, I don’t want a permanent audit_log table and a backfill:revert command cluttering the codebase forever. Snapshot the before-state to a disposable JSON file, run the thing, delete the scaffolding.

Don’t trust, verify

## Verify before relying
- Verify an identifier exists before using it — icon names, enum values,
  library/API symbols, route names. Don't assume from convention.
- A package's presence in the manifest (composer.json/package.json) is not
  proof it's used. Confirm it's registered/referenced before recommending or
  relying on it.

## Investigate in the right place
- Investigate live issues against the environment where they occur (usually
  production), not the local DB of seeded/fake data. Confirm the target env
  before querying.

This is the antidote to confident hallucination. Models are superb at producing a plausible icon name (heroicon-o-sparkles, surely that exists?) or assuming a package in composer.json is wired up just because it’s installed. Plausible is not the same as present. Check that the symbol actually exists before building on it.

“Investigate in the right place” catches a subtler failure: an agent debugging a production issue against the local database full of seeded fake data, then confidently declaring the bug fixed because the fake data doesn’t reproduce it. Confirm which environment you’re actually looking at first.

Testing taste

## Testing taste
- Don't test framework behavior. Only test non-trivial branching, business
  rules, and error-prone edge cases.
- Test functionality, never presentation. Don't assert on layout, displayed
  copy, labels, nav items, headings, element order, or CSS classes — those
  are change-detectors. Assert behavior, persisted data, validation,
  record-level scoping/authorization, and side effects.
- Trivial label/copy/wording rename → edit, update any assertion referencing
  the old string, commit. No test-suite run.

Left alone, agents write tons of tests, and most of them are change-detectors: assert the button says “Save”, assert the heading is an <h1>, assert the nav has five items. The moment you rename anything, they all break, and they never caught a real bug. I want tests that assert behavior (what got persisted, who’s allowed to see it, what happens at the edges), not tests that screenshot the current copy and call it coverage.

Make it reuse before it builds

The newest section is also the longest, and the one exception to the “every rule is a scar” test, because it’s as much a standing design philosophy as a guardrail. But it grew out of a real, repeated frustration: left alone, an agent’s instinct is always to build. Ask for something that rhymes with code you already have, and it will cheerfully write a brand-new class, a parallel workflow, a second near-identical job, rather than notice the abstraction it should have extended. A few sessions of that and you’ve got LeadWorkflow, ClientWorkflow, and VendorWorkflow sitting side by side, 90% the same file.

# Reuse Before Build

Before writing code:
- Search for similar implementations.
- Reuse existing patterns when possible.
- Explain why reuse is not possible before creating a new abstraction.

Decision rules:
- Same lifecycle, different entity → build/extend a generic engine.
- Same interface, different behavior → use Strategy/Plugin/Adapter patterns.
- Same boilerplate, different configuration → use configuration, schemas,
  factories, or generators.

Duplication threshold:
- If implementation requires copying >20% of an existing file:
  - Stop.
  - Evaluate a shared abstraction first.
  - Justify any remaining duplication.

Architectural smells:
- Parallel implementations (LeadWorkflow, ClientWorkflow, etc.)
- Repeated state machines
- Repeated orchestration logic
- Repeated validation flows
- Repeated job patterns
- Repeated API handlers
- Repeated service classes
- Repeated test suites
- Parallel directory structures
- Copy-paste feature development

When a smell is detected:
1. Reuse existing implementation.
2. Extend existing abstraction.
3. Extract shared abstraction.
4. Use configuration.
5. Use plugin/strategy architecture.
6. Create a new implementation.

New implementations are the last option, not the first.

For significant features, include a Reuse Analysis:
- Existing patterns reviewed
- Chosen approach (Reuse / Extend / Extract / New)
- Reasoning
- Duplication Risk (Low / Medium / High)

The heart of it is the escalation ladder. Reuse, extend, extract, configure, plug in, and only then, as the sixth and last option, write something new. The agent’s natural ranking is exactly inverted: new implementation first, because a blank file is easier to reason about than someone else’s abstraction. Numbering the moves forces it to earn that blank file by ruling out the five cheaper ones above it.

The >20% threshold and the Reuse Analysis are there to make “I checked” verifiable. Did you look for an existing pattern? gets a confident yes every time; a one-line analysis naming the patterns reviewed and the approach chosen is something I can actually audit. It’s the same move as the rest of the file: turn a vague good intention into a concrete step the agent has to show its work on.

An agent’s default answer to “where should this go?” is “a new file.” This section makes that the last answer, not the first.

Build your own, don’t copy mine

You’re welcome to take any of these. But the real value isn’t my list. It’s the habit that produced it.

The next time you correct the agent on something you’ve corrected before, don’t just fix it and move on. Write the rule.

Start empty. Every time you catch yourself typing the same correction a second time, promote it to a line in your global file. Keep each rule to the general principle. Prune ruthlessly. If a rule hasn’t earned its keep in a month, it’s costing you attention it isn’t repaying. In a few weeks you’ll have a file that makes every agent, on every project, work the way you already wish they did, without you having to say it again.

The best part: it compounds silently. You stop noticing the mistakes that used to cost you ten minutes a session, because they simply stopped happening.

CJ
Reply by email
I read everything.
$ reply