All sections

15In practice

Gotchas and anti-patterns

The failure modes that cost the most time, grouped by the subsystem that causes them. Most of them present identically, as "Claude is ignoring my configuration".

Configuration

Gotcha Symptom Fix
// comments in a settings file “Settings Error” at startup; the entire file ignored Strict JSON only. Annotate in a sibling .md
Committed env not applied for a teammate Builds fail on a fresh clone They must accept the workspace trust prompt
Secrets in committed settings.json In git history permanently Use settings.local.json
Trying to unset an inherited env var No mechanism exists Set it to ""
settings.local.json not gitignored Your tokens get pushed Add it to .gitignore on day one
A hook path committed but the script isn’t Every teammate’s tool calls fail Commit .claude/hooks/ and keep it executable
permissions.deny written as a bare path Never matches Rules are Tool(pattern), e.g. Write(**/generated/**)

Memory

Anti-pattern Why it hurts
A 900-line CLAUDE.md Adherence degrades sharply. Paid on every turn
Language style guides in CLAUDE.md Loaded during sessions where they are irrelevant. Use paths: rules
Relying on “local overrides project” There is no override. Both load. See conflicts
Never pruning #-added lines Stale instructions actively mislead
CLAUDE.local.md plus git worktrees Exists only in the worktree that created it. Import from ~ instead
Forking a repo and keeping its AGENTS.md / CLAUDE.md You inherit someone else’s project instructions invisibly
Documenting what the code already says Pure cost. Document the non-obvious and the invariants
A global preference phrased as an absolute Guarantees a conflict with some repository eventually. Phrase it as a conditional

Rules

Gotcha Detail
paths: ["*.go"] Matches only the repository root. You want ["**/*.go"]. The most common cause of a rule that “does nothing”
Rule not in /context yet Rules load on first matching file, not at startup. Open a matching file first
A personal rule contradicting a project rule Both load. Delete the personal one; it should never have been global
Too many unscoped rules An unscoped rule is CLAUDE.md with extra steps. Keep the always-on set tiny

Skills and agents

Gotcha Detail
Personal skill shadows the project’s Opposite direction to agents. Rename or use a plugin
A generically named personal skill /deploy, /review, /test will collide with someone’s repository. Prefix yours
Side-effecting skill invoked autonomously Set disable-model-invocation: true on /deploy, /commit, /release
Weak skill description Claude never auto-loads it. Front-load the use case; it is truncated at 1,536 chars
New top-level skills/ directory not picked up Restart once. Subsequent edits hot-reload
Explore ignoring project conventions By design; it skips CLAUDE.md. Put constraints in the prompt
Subagent given Write access “just in case” Defeats the isolation. Restrict tools: deliberately
Spawning a subagent for a task that needs the conversation It starts cold and re-derives everything. Use /subtask instead
Expecting the command name to come from name: It comes from the directory name

Plugins

Gotcha Detail
skills/ placed inside .claude-plugin/ The single most common plugin error. Only plugin.json goes there
Packaging too early Iterate in .claude/ first. Package when a second repo needs it
Plugin hooks firing unexpectedly Enabled plugins contribute hooks you did not write. Check them when debugging a block
Forgetting /reload-plugins Edits to a local plugin are not hot-reloaded the way a skill is

Output styles

Gotcha Detail
Custom style silently removes engineering instructions keep-coding-instructions defaults to false. Set it to true
Change appears to do nothing Takes effect after /clear or a new session
Style not applying inside a subagent Expected. Subagents run their own system prompt. Forks are the exception
Reaching for /output-style Removed in v2.1.91. Use /config

Hooks

Gotcha Detail
A hook that exits non-zero on unhandled input Blocks unrelated work. Always exit 0 on anything you do not handle
Blocking with no message on stderr Claude cannot route around it and the block looks like a bug. Exit 2 and explain
Two PostToolUse formatters on one path They fight. Order between hooks is not guaranteed
A slow Stop hook Every turn gains its runtime. Keep it to the fast suite
Assuming hook order There is none. Never chain two hooks that depend on sequence

The meta-gotcha

Almost every entry above presents identically: Claude does something you did not ask for, and it is not obvious why. Before theorising about the model, run the conflict checklist. The first step alone — /context — resolves roughly half of them, because the instruction was never loaded in the first place.