The Fix

You set up Claude Code wrong: the four boundaries that stop it rewriting your code

Your instinct when the model does something dumb is to add another rule. Mine was too. The file got to 180 lines and the behaviour got worse. Here's what happened when I cut it to four boundaries.

E
Endi
Engineer · Buka.labs
8 min read

Here's the pattern. The model refactors a file you didn't ask it to touch. You add a line to CLAUDE.md: “do not refactor unrelated files.” Next session it rewrites your tests. Another line. Then it invents a helper that already exists. Another line.

Six weeks in, my file was 180 lines and the model was less predictable than when it was empty. That's the part that took me too long to understand.

Why long instruction files get worse, not better

Every line in that file is read on every single turn. It isn't a config that gets compiled once. It's text competing for attention with your actual request, the files in context, and the tool output. Three things go wrong as it grows:

  • Rules start contradicting each other. “Always add tests” and “don't touch files outside the request” are in direct conflict the moment a change needs a new test file. The model picks one. You don't get to know which.
  • Specific beats general, and you wrote the general one first. A narrow rule you added in week five will quietly override the principle you set in week one.
  • Instructions about style crowd out instructions about safety. The line that actually matters (don't touch the migrations folder) is sitting between two paragraphs about comment formatting.
A rule you add because the model did something wrong once is a patch. A boundary is a thing that is true on every task. Patches accumulate. Boundaries don't.

The four boundaries

Every line I kept answers one of four questions. If a line doesn't, it's a patch and it goes.

1. Where may it write? Not a vibe. Actual paths. The model is very good at respecting an explicit allowlist and very bad at inferring one from your project structure.

2. What must it never touch? Migrations, generated files, lockfiles, anything with credentials. This is the line that saves you a bad afternoon.

3. How does it know it worked? Give it the command. If it can verify its own work it will iterate to something correct instead of handing you something plausible.

4. When must it stop and ask? Models are trained to be helpful, which means they will guess rather than block. Naming the cases where guessing is unacceptable is the highest-leverage line in the file.

The whole file

This is the real one, from a production Next.js project:

CLAUDE.md
# Boundaries

## Write
Only in `src/`, `tests/`, and `docs/`.

## Never touch
`migrations/`, `*.generated.ts`, `package-lock.json`, `.env*`

## Verify
Run `npm run check` (types + lint + tests) before saying a task is done.
Paste the failing output if it doesn't pass. Don't describe it.

## Stop and ask
- The change needs a schema or migration
- The change needs a new dependency
- Two reasonable implementations exist and they'd be hard to swap later

Twelve lines. That is the entire file. Everything else I had written was me trying to make the model have taste, and you cannot get taste from an instruction file. You get it from the constraints in a DESIGN.md, which is a different job.

What I deleted, and why it didn't matter

“Write clear comments.” “Prefer functional patterns.” “Use descriptive variable names.” “Keep functions small.” All gone. Modern models already do these by default at roughly the level those lines were asking for. You are spending context to buy something you already have.

The one category worth keeping is where your project genuinely disagrees with the default. If you use tabs, or your test runner is unusual, say so. That's information, not instruction.

The test

Delete your CLAUDE.md (keep a copy) and work for a day without it. Write down every moment you actually wanted a rule. Almost nothing on that list will be a style preference. What's left is your real file, and it'll be short.

The FixClaude CodeBuka.labs