Chapters
← Claude Code 101

Project setup: a repo agents work well in

Turn a repo into a place agents work well in. Write a contract that's actually true, encode conventions as mechanical checks, and prune permissions instead of hoarding them.

You will learn

  • What belongs in CLAUDE.md, and why a stale contract is worse than none
  • How tokens-only conventions turn vague review into checks an agent can self-apply
  • How permission allowlists sprawl, and why periodic consolidation beats hoarding
  • Why my file reads run roughly 1:1 with edits
  • Which recurring failure modes are worth codifying as standing rules

You've run a few sessions. The agent is useful but inconsistent, great on one task and confidently wrong on the next. Usually the difference isn't the model. It's the repo. A codebase set up for agent work states its own rules, makes those rules checkable, and scopes what the agent is allowed to do. This chapter is how you get there.

CLAUDE.md is the contract#

CLAUDE.md is the first thing an agent reads and the closest thing it has to onboarding. It should carry what a new senior hire would need on day one: the locked stack, the conventions, the explicit "don't do this" list, and the data policies that keep the agent from inventing what it should be looking up. This repo's own file is a worked example. Its stack table is a hard contract:

markdown
## 3. Tech stack — locked, do not deviate

| Concern   | Choice                          |
| --------- | ------------------------------- |
| Framework | Next.js 15 (App Router)         |
| Rendering | Static (SSG) — no runtime fetch |
| Styling   | Tailwind CSS v3 from tokens.ts  |
| Layout    | Flexbox throughout. No CSS Grid.|
| Hosting   | Vercel                          |

Now the failure mode I own up to: that last row lied for weeks. The site had already moved to a Cloudflare static export, but the contract still said Hosting | Vercel, so agents kept planning against Vercel and I kept correcting them by hand, until eventually I wrote a memory file whose entire job is to say "overrides CLAUDE.md §3." This is CLAUDE.md drift. The document keeps its authority long after it stops being true, and the agent follows it straight into the wrong decision. A stale contract is worse than no contract, because a missing rule makes the agent ask while a wrong rule makes it act. Treat CLAUDE.md as code: when the stack changes, the contract changes in the same commit.

Conventions as guardrails#

The most useful lines in a CLAUDE.md convert a vague preference into a mechanical check. "Use the design system" is a judgment call an agent will interpret loosely. This repo instead says, in its non-negotiables: no hardcoded colors, fonts, font sizes, spacing, or motion timings in components. Every such value lives in src/design/tokens.ts, and components only use classes that resolve from it.

The strictness isn't the point. Checkability is. Reviewing "does this look right?" is slow and subjective. Reviewing "does this diff contain a hex code?" is a grep. Constraints like tokens-only, flexbox-only, or a single normalization choke-point give the agent a rule it can self-apply while writing, and give you a rule you can verify at a glance.

Permissions: modes, allowlists, and sprawl#

Claude Code gates tool calls through a permission system. Broadly there's an interactive mode that asks before acting, an accept-edits mode that auto-applies file changes, a plan-only mode that proposes without touching anything, and a full-bypass mode best reserved for throwaway sandboxes. Underneath the mode sits an allowlist in settings.json:

json
{
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test:*)",
      "Read(~/.zshrc)"
    ],
    "deny": ["Bash(curl:*)", "Read(./.env)", "Read(./secrets/**)"],
    "defaultMode": "default"
  }
}

Here's what actually happened to mine. When you approve prompts ad hoc, each "yes, just this once" can write a hyper-specific entry back to your project allowlist: an individual curl URL, one exact kill PID, a single one-off path. Over a month my project settings accumulated more than 50 of these one-off entries. None were wrong on their own. Collectively they were noise that no longer matched how I work. The fix isn't to stop approving. Periodically consolidate instead: ten Bash(npm run test:foo), Bash(npm run test:bar) lines collapse into one Bash(npm run test:*). A short list of broad, intentional rules can be audited. A long list of accidents can't.

Verify, don't trust#

The habit that makes all of this safe is boring. You read what the agent did. In a month of my own usage, file reads ran at 3,107 against 3,020 edits, roughly one read for every edit. The agent's "done" is a claim, and a claim gets checked. In practice that means reading the diff before you accept it (what changed, not merely that a file changed) and then running the thing: the test, the build, the actual page in a browser. Errors caught here are cheap. The same errors caught in production are not. Active supervision is the reason high agent volume doesn't turn into a high defect rate.

Rules worth writing down#

Some mistakes recur often enough that you shouldn't re-catch them by attention. Encode them. Here's what a month of my session history said I should codify:

  • Never push to main without an explicit ask. Default to opening a PR. Agents drift toward committing straight to main and using git add -A. The standing rule is branch first, stage files explicitly.
  • Subagents never push or merge autonomously. A spawned agent does its slice, leaves a status note, and stops. Integration is a supervised step, not something five parallel agents each decide to do on their own.
  • Cleanup rm never touches tracked files. Check git status before any delete. A subagent once rm -rf'd a real directory, which is why this is a written rule and not a hope.
  • Long outputs go to a file, not the terminal. Dumping a huge log into the conversation burns context for no benefit. Write it to disk and read the part that matters.

All four are the same move: take a recurring failure and turn it into a line an agent can't misread, the same way you'd handle a junior engineer's recurring habits.

A repo set up this way is honest with the agent about the rules. The next problem is keeping the agent honest with itself across long work. That's context discipline, chapter 3.

Recap

  • CLAUDE.md is a contract: stack, conventions, what-not-to-do lists, data policies. Keep it current or agents confidently do the wrong thing.
  • Encode conventions as mechanical constraints ("tokens only, no hardcoded colors") so review becomes a check instead of a judgment call.
  • Permission allowlists accrete one-off entries. Consolidate periodically rather than hoarding hyper-specific approvals.
  • Read the diff and run the thing. My reads track edits roughly 1:1 because agent output gets checked, not assumed.
  • Write down the rules a month of your own mistakes keeps re-teaching: no push to main without a PR, subagents never merge, cleanup never touches tracked files.