Three Annoying Coding-Agent Habits, and the One File That Fixed Them
# Three things that kept going wrong
My coding agent of daily use is Claude Code, Anthropic’s terminal coding agent. Most of the friction isn’t with the hard problems—those it handles well. The friction is a handful of small, repetitive failures that happen because the agent doesn’t know things about my environment that I’ve never told it. Three of them kept coming back:
1. It bypasses my git hooks. The project has a pre-commit hook that runs linting. When the lint fails, a well-meaning agent often concludes the hook is in its way and does this:
$ git commit -m "fix: handle empty input"
✖ husky - pre-commit hook failed (eslint found 2 problems)
# the agent's next move:
$ git commit --no-verify -m "fix: handle empty input"
✓ Committed
Technically successful. The hooks I put there on purpose never ran.
2. It ignores my virtualenv. In a Python project with a .venv/ directory, the agent writes perfectly fine scripts and then executes them:
$ python scripts/migrate.py
ModuleNotFoundError: No module named 'sqlalchemy'
System Python, not the venv. Or worse: pip install happily installs into the system environment, and the dependencies now exist in two places, one of which is wrong. Every session, the same fight.
3. It dies on my network. I’m in China. npm install, pip install, go mod download—any of these can hang or reset without a proxy. The agent’s response is to wait patiently, retry the identical command, and report a timeout. The workaround (a local proxy at 127.0.0.1:1080) is trivial if you know about it. The agent has no way to know.
Notice what these three have in common: each one is a piece of information that lives in my head, applies to every session, and breaks something the moment it goes unsaid. Telling the agent once doesn’t help—the next session forgets. So for a while, I repeated myself. Every. Single. Session.
# The common shape of the problem
All three failures have the same shape: information the agent cannot discover on its own, which must be present at every session.
Not “the codebase uses Flask”—it can read the code and figure that out. Not “how to architect this feature”—that’s the job. Just the small, local, unguessable facts: these hooks must not be bypassed, this Python is the right Python, this network needs this proxy.
Claude Code has a place specifically for that kind of information: CLAUDE.md.
# What CLAUDE.md is
A plain markdown file that Claude Code automatically loads into context at the start of every session. Whatever is in it is treated as standing instructions for working in this environment—like the onboarding doc you’d hand a new colleague on day one, except this colleague actually reads it every morning.
And you don’t need to get it perfect on the first try. Once the file exists, Claude can audit it for you: run /doctor prompt-audit ~/.claude/CLAUDE.md, and Claude checks that file for outdated or conflicting content—instructions written for older models, references to files or commands that no longer exist, rules that contradict each other—and hands you a report with proposed edits. Nothing changes until you say so (Audit your instruction files in the official docs).
Mine (the user-level one, more on that below) is short enough to show in full:
# Global Coding Agent Rules
## Git hooks
- Never bypass hooks: no `git commit --no-verify`, no `git push --no-verify`,
no `HUSKY=0`-style env escapes.
- If a hook fails, report the exact failure output, then fix it or ask
for instructions.
## Python environment
- When a project contains a `.venv/` directory, use it for all project commands:
`.venv/bin/python`, `.venv/bin/pytest`, `.venv/bin/pip`, etc. — never the
system Python or pip.
## Network proxy
- If a network request fails (timeout, reset), retry through the local proxy
at 127.0.0.1:1080 (it speaks HTTP proxy):
- env vars: `http_proxy=http://127.0.0.1:1080 https_proxy=http://127.0.0.1:1080 <command>`
- curl: `curl -x http://127.0.0.1:1080 …`
- If the tool ignores proxy env vars (git over SSH, ssh, Go binaries, …),
force it with `proxychains4 <command>`.
Three rules, three annoyances. Since I wrote this file, all three problems essentially disappeared from my daily work—not because the agent got smarter, but because it stopped being ignorant of my setup.
# How it actually works
A few mechanical details worth knowing, because they shape how you should use the file (this is all from the official memory docs):
It’s loaded at the start of every conversation, and it survives compaction. CLAUDE.md content is delivered into context as part of session setup—not as part of the system prompt—and stays in the context window for the whole session. After /compact, the project-root CLAUDE.md is re-read from disk and re-injected, so project rules keep working even in long sessions. That staying power is also why you pay for it continuously (more on that below).
There’s a hierarchy. Claude Code loads memory files from several locations, ordered broadest to most specific:
Organization-managed — a centrally managed CLAUDE.md deployed at a managed policy location:
- macOS:
/Library/Application Support/ClaudeCode/CLAUDE.md - Linux and WSL:
/etc/claude-code/CLAUDE.md - Windows:
C:\Program Files\ClaudeCode\CLAUDE.md
Alternatively, the content can live inline as the
claudeMdkey insidemanaged-settings.json. It loads before user and project files, and individuals can’t exclude it.- macOS:
User-level (
~/.claude/CLAUDE.md) — your personal defaults, every projectProject-level (
./CLAUDE.mdor./.claude/CLAUDE.mdin the repo root) — checked into git, shared by the team; plus a gitignoredCLAUDE.local.mdfor personal notes about one repo that shouldn’t be committedSubdirectory-level — a
CLAUDE.mddeeper in the tree isn’t loaded at launch. It loads on demand, the first time Claude reads or edits a file in that subdirectory.
These files are concatenated, not overridden: user rules load first, project rules appear later in context, closer to the conversation. When two levels conflict, Claude may follow either one—so keep them consistent rather than relying on “the closer file wins.” My three rules are cross-project facts about me and my machine, so they live at the user level. “This repo uses pnpm, never npm” belongs at the project level, where teammates inherit it.
It supports imports. A line like @docs/conventions.md pulls in another file (up to four levels of nesting). This keeps the main file organized, but note it doesn’t reduce context cost—imported files also load at launch.
/init bootstraps one. Run /init in a project and Claude Code analyzes the repo and generates a starter project-level CLAUDE.md (build commands, architecture notes). It’s a decent first draft; edit it down afterward.
# What CLAUDE.md is not
Two limits matter, and pretending they don’t exist is how people end up disappointed.
It’s a soft constraint. Instructions in CLAUDE.md steer the model strongly, but they are not a security boundary. On a long enough timeline, some rule gets ignored in some session—that’s a known, chronic community complaint (search “Claude ignores CLAUDE.md” and you’ll find GitHub issues with that exact title). When a rule must hold—hooks must never be bypassed, no force-pushes to main—the right tool is a hard one: deny rules in .claude/settings.json permissions, or a PreToolUse hook that rejects the command outright. Use CLAUDE.md for the 95% case; use enforcement for the rules where 95% isn’t acceptable.
It’s not free. The file sits in the context window for the entire session, competing with code and conversation for room (and a file larger than 4 MiB is skipped outright). The official guidance is to keep each file under ~200 lines, and /context shows you exactly which memory files loaded and what they cost. This constraint is also a useful editorial filter: if a line isn’t worth holding in context for the whole session, it doesn’t belong in the file—put it in a doc the agent can read when needed instead.
Both limits point to the same rule of thumb for what deserves a line in CLAUDE.md:
Only write what the agent cannot discover from the codebase, and what is worth holding in context for the whole session.
My proxy config passes both tests. A description of the project’s architecture fails the first (it’s derivable from the code). Notes on a one-off migration fail the second.
# Quick FAQ
CLAUDE.md vs. AGENTS.md? AGENTS.md is a cross-tool convention—Codex, Gemini CLI, and others read it. Claude Code reads it natively too (v2.1.277+): by default, when a repository has no project-level CLAUDE.md, Claude Code loads its AGENTS.md instead, while your ~/.claude/CLAUDE.md still applies. If you want both files to load, set the “Project instructions” option to CLAUDE.md and AGENTS.md. And /init can even convert existing Cursor rules into a starter CLAUDE.md.
What about auto memory? Claude Code also has an auto memory system: notes Claude writes itself under ~/.claude/projects/<project>/memory/, with a MEMORY.md index whose first 200 lines load at the start of each conversation. Rough split: CLAUDE.md is what you deliberately prescribe; auto memory is what Claude learns from your corrections. Rules and conventions belong in CLAUDE.md, where you control them.
Project CLAUDE.md is checked into git—won’t my proxy config leak? Don’t put machine-specific config in the project file. Personal and local facts (proxies, editor quirks, preferred workflows) belong in ~/.claude/CLAUDE.md, which is yours alone.
Does it slow the agent down? Marginally, via context weight. In practice a lean CLAUDE.md saves far more than it costs, because it prevents wasted work—wrong interpreters, failed installs, bypassed hooks, redoing commits.
It seems like my CLAUDE.md isn’t loading. First figure out whether the file loaded at all, or loaded and is being ignored—those are different problems. Run /context: it lists every memory file that made it into context. If yours isn’t there, check the mechanical causes: the file is in the wrong location, it exceeds the size limit and got skipped, or an @import points at a path that doesn’t exist. If it is listed but the rules still get ignored, that’s the soft-constraint problem from above (troubleshooting steps in the docs).
# The takeaway
You don’t need a long CLAUDE.md. Mine is three rules, ~20 lines, and it eliminated three recurring daily failures. Start from the other direction: keep a mental note of every time you type the same correction to your agent twice. After a week, you’ll have your file—and unlike repeating yourself, you’ll only ever have to write it once.