I use Claude Code every day on client work and on this site. Most of what went wrong in the first months had nothing to do with the model being wrong about code. It came from the agent doing a reasonable thing in the wrong place: editing a checkout I was using, pushing to a branch that deploys, reading a file it should never open. Below are the ten mistakes I hit most often, and the specific mechanism that now prevents each one. Every fix is a line in a CLAUDE.md, a hook, or a review step that already runs in my repos.
Which Claude Code mistakes cost the most time?
The table is the short version. The sections after it explain each row with the actual rule or config.
| Mistake | Symptom | Fix |
|---|---|---|
| Agent edits the main checkout | Your uncommitted work and the agent's changes mix | Rule: open a worktree before touching files |
| Orphaned worktrees | Stale directories and branches pile up | Lease worktrees from a tool and return them |
| Wait loop with pgrep -f | The loop never ends | Background the command or use a bracket pattern |
| No tests | Done code that breaks on the next change | TDD rule: failing test first |
| Hidden type errors | Build passes, types are broken | Run typecheck in the gate |
| Docs drift | Docs describe code that no longer exists | Docs = current state, map updated in the same diff |
| Agent reads secrets | .env contents land in the transcript | PreToolUse hook that denies the command |
| Over-engineering | Abstractions nobody asked for | YAGNI rules loaded every session |
| Unwanted PRs or pushes | PRs opened or main pushed at the wrong time | Explicit delivery rules per repo |
| Trusting 'done' | Bugs found after merge | Review agents and a gate before merge |
Why should a Claude Code agent never edit the main checkout?
When Claude Code edits the directory you are working in, its changes and yours share one working tree. You cannot tell which edit is whose, a git stash takes both, and two agents in parallel overwrite each other. A git worktree fixes this: it is a separate checkout on its own branch that shares the repository history. The official worktree docs describe the --worktree flag and explain that a session isolated in a worktree has its edits and git commands blocked when they target the main checkout.
My global CLAUDE.md makes this the default: if the task modifies files in a repo, open a worktree first, and once inside it, read and edit only there. The rule is written as an ordered list, so the agent does not have to decide which mechanism to use.
How do orphaned worktrees happen, and how do you stop them?
Isolation creates its own mess. Per the Claude Code docs, a subagent worktree with changes stays on disk until a periodic sweep can remove it without losing work, and non-interactive -p runs have no exit prompt, so their worktrees are not cleaned up at all. After a few weeks of parallel agents I had directories under .claude/worktrees/ that nobody remembered creating.
The fix in my setup is to take worktree creation away from the agent's built-in tools. The global CLAUDE.md says never to use EnterWorktree or a subagent with isolation: "worktree", because those are the ones that left orphans for me. Instead the agent leases a worktree from a small CLI, works there with absolute paths, and returns the lease when it finishes. One lease per subagent. A worktree that is returned is cleaned; one that is still leased has an owner I can see.
path=$(treehouse get --lease --lease-holder claude)
# ... work inside "$path" ...
treehouse return "$path"Why does an agent's wait loop with pgrep never finish?
Agents like to wait for a build or a server with a loop such as until ! pgrep -f "next build"; do sleep 1; done. The -f flag matches against the full command line, and the shell running that loop has "next build" in its own command line. The loop finds itself and waits forever, burning the session's time.
The rule I added is short: never wait on a process with pgrep -f inside a Bash command. Run the long command in the background and wait for the notification, use wait <pid>, or use a pattern that cannot match its own text. The bracket trick works because the regex [n]ext build matches "next build" while the literal string in the command reads "[n]ext build".
# loops forever: the shell matches itself
until ! pgrep -f "next build"; do sleep 1; done
# works: the pattern does not match its own command line
until ! pgrep -f "[n]ext build"; do sleep 1; doneHow do you make Claude Code write tests every time?
An agent asked to add a feature will add the feature. Tests come later, or never, and the next change breaks the first one quietly. The rule in this site's CLAUDE.md is the first line under Rules: TDD is non-negotiable, write a failing test before the code, and no change is complete without a test. Two skills, tdd and testing, tell the agent which layer a test belongs in and how to run it with pnpm test.
Writing the test first also changes the conversation. If the agent cannot write a failing test, it usually does not understand the requirement yet, and that shows up before any code exists.
Why can a green build still hide type errors?
This site's Next.js config sets typescript.ignoreBuildErrors: true. That keeps deploys moving, and it also means pnpm build succeeds with broken types. An agent that checks only the build will report success. The repo says it in three places: CLAUDE.md ("type errors don't fail the build, run pnpm typecheck"), the workflow doc, and the ship config, where typecheck is listed as required because next build ignores type errors. Any project with a similar escape hatch needs the same explicit check, or the agent has no way to know the build is lying.
How do you keep docs from drifting when an agent changes code?
Agents are good at writing docs and bad at deleting them. Over time you get a README that describes three versions of the same feature. Two rules fixed this for me. First, docs describe the current state only: when behavior changes, update or delete the old text in the same diff, and leave history to git. Second, the repo has a code map, a set of short cards that cite path::symbol, and updating the affected cards is part of the diff, not a follow-up task.
During delivery, a dedicated docs agent runs after the code is final, reads what the diff actually changed, and updates the map and agent docs. It is the only agent in the pipeline with write access, so reviewers cannot drift the docs either.
How do you stop Claude Code from reading .env files?
A written rule ("only read .env.example") is in the workflow doc, but a rule is a request. A hook is enforcement. The hooks reference explains that a PreToolUse hook receives the tool input as JSON on stdin and can return a permissionDecision of deny with a reason, which stops the tool call.
My user settings register a PreToolUse hook on the Bash and PowerShell tools. It reads the command from tool_input, looks for any .env file name, allows only template names such as .env.example, .env.sample, .env.template and .env.dist, and denies everything else with a message pointing the agent to the example file. The output has this shape:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Shell access to .env.local blocked: use .env.example."
}
}The matcher covers shell commands only, so the written rule still matters for the other file tools. Layering both is the point: the rule explains why, the hook catches the case where the agent forgets.
How do you stop an AI agent from over-engineering?
Ask an agent for a cache and you may get a cache class, an interface, a config file and a factory. Each piece looks defensible; together they triple the diff you have to review. I load a set of lazy-developer rules into every session: check whether the thing needs to exist, reuse what is already in the codebase, prefer the standard library and native platform features, add no dependency for what a few lines can do, and write the smallest diff that works. Shortcuts with a known limit get a comment naming the limit, so they can be found later. The repo's coding standards add the same pressure from another side: reuse the existing UI primitives before writing new ones.
How do you stop Claude Code from opening PRs or pushing to main?
The defaults of most agent tooling assume a PR flow. This site has none: Vercel deploys main, and the delivery step merges a work branch directly. So the repo says it plainly in CLAUDE.md and again in the ship config: never open a PR, no gh pr command. Pushing is allowed only when the gate is green, after a rebase on origin/main. A merge conflict or a rejected push means stop and ask, and force-pushing main is never allowed. Global rules add that the agent commits or pushes only when asked.
The lesson for any team: write down the delivery path for each repo, including what the agent must not do. An agent cannot respect a convention it has never seen.
Why shouldn't you trust an agent when it says the task is done?
"Done" from an agent means it stopped. It does not mean the tests can fail, that nothing was weakened, or that the diff follows the standards. My /ship step runs review agents in parallel on every diff before merge: a generalist reviewer and a dedicated test reviewer that checks whether the tests are truthful, can actually fail, and were not modified or deleted without authorization. The coding standards are reviewed on every diff too. Lint, typecheck and tests form the gate. If anything blocking is still open after the fix rounds, nothing is merged; the agent reports the findings and a fix plan and asks.
This is the step that catches what the other nine fixes miss. It costs a few minutes per change, which is less than one bug found in production.
What are the common mistakes when adding these guardrails?
The first is writing rules without enforcement for anything risky. Secrets and deploys need hooks or permissions. The second is writing rules in vague terms ("be careful with git"). Each rule in my files names a command, a file or a flag. The third is putting everything in one giant prompt. Global rules live in the user CLAUDE.md, repo rules in the repo's CLAUDE.md, and the detail sits in linked docs and skills the agent opens when it needs them. The last is never revisiting the list. Every rule above exists because the agent got it wrong once.
Want this setup in your team's repos?
I help teams put AI coding agents to work with the rules, hooks and review steps that keep them out of production trouble.
Let's talkFor agent work beyond coding assistants, see my AI agent development service.



