>
Software

What I learned writing CLAUDE.md files for my Python projects

I burned about three hours one Saturday trying to get Claude Code to stop making the same AWS Bedrock mistake. Every session, it would prefix my model ID with the local region instead of global. (the prefix AWS uses to enable cross-region inference, where a single model endpoint can route requests across multiple geographic regions). Every session I would correct it. Every session it would forget. The mistake was minor, the correction was trivial, and I was paying for the same teaching moment over and over.

The fix was not a better prompt. The fix was a file called CLAUDE.md (a Markdown file Claude Code reads automatically as project context, named for the Claude model family it serves). CLAUDE.md is the instruction surface Claude Code treats as authoritative context. Anything you put in it becomes part of the model’s working memory for the session. After I added a single line about Bedrock region prefixes, the mistake stopped happening.

That is the entire pitch for this article. CLAUDE.md files are how you stop re-teaching Claude Code the same lesson. The rest of this is the version I wish I had read first: the three layers, what belongs where, and the auditing process that tells you whether the file is earning its keep.

What CLAUDE.md actually is

CLAUDE.md is a Markdown file Claude Code reads at session start. Its contents become part of the context the model sees before it answers anything. The model does not treat CLAUDE.md as enforced configuration the way a linter (a tool that automatically checks code for style and error patterns) treats a config file. It treats it as guidance, weighted like any other text the model has read. A clear, concrete instruction in CLAUDE.md will usually win. A vague aspirational sentence will usually lose.

There are three layers, in order of how broadly they apply.

The global file lives at ~/.claude/CLAUDE.md (your home directory). It applies to every project you open with Claude Code. Personal workflow preferences, communication style, coding defaults that you want across the board: this is the right place.

A project-level file lives at the root of the repository, usually ./CLAUDE.md. It applies only when you are working in that project. Project-specific commands, repo conventions, deployment gotchas: this is the right place.

A local file lives at ./CLAUDE.local.md and is conventionally gitignored. It applies only to you on your machine, not to anyone else. Personal scratchpad notes that should not be committed: this is the right place.

The mistake I keep making and seeing others make is collapsing the three layers into one. People dump everything into the global file because it is the easiest to set up, and then wonder why their project-specific guidance never fires. The layers exist for a reason. Use them.

The auditing habit

The single most useful thing I do with CLAUDE.md is run a short audit before I write any of it. The workflow is: temporarily rename or move any existing CLAUDE.md and CLAUDE.local.md out of the way, then open a fresh Claude Code session and ask it to make a small change in the project. Watch for the repeated mistakes. Note each one.

This sounds backwards. The instinct is to write down all the rules you think the model needs in advance. The audit tells you which rules actually matter, based on what the model actually gets wrong in your specific project. A short audit almost always produces better instructions than a long checklist.

I keep a table for this, with three columns: the correction I had to give, the instruction I want Claude Code to follow, and the scope (global, project, or local). The table gets read once a month, and any rule that did not fire in the last month gets deleted. This sounds ruthless. It is also why my CLAUDE.md files stay short enough to scroll through quickly.

A recent audit produced these corrections for a Python repo I work on regularly:

  • Claude Code installed packages imperatively with pip install instead of using the project’s dependency tool. Instruction: add project dependencies with uv add (a fast Python package and project manager). Use uv pip install only for ad-hoc env installs. Scope: global or project.
  • Claude Code skipped the test command before opening the pull request. Instruction: run uv run pytest (the standard Python testing framework) before finishing a task. Scope: project.
  • Claude Code added print() debugging in places that should have used the configured logger. Instruction: use the configured logger, not print statements. Scope: project.
  • Claude Code touched files unrelated to the requested change. Instruction: edit only files needed for the current task. Scope: global.

The audit catches the corrections that repeat. The corrections that happen once are not worth a line in CLAUDE.md.

A global file that earns its keep

My current ~/.claude/CLAUDE.md has five sections, totaling about thirty lines. It is short on purpose. Long CLAUDE.md files get ignored, edited out of sync, or replaced with the auto-generated /init (Claude Code’s built-in command that scaffolds a starter CLAUDE.md for a new project) output, which is bloated.

Working style is the section I check first when I add a rule. Three lines I never delete: state assumptions before editing, prefer the smallest change that solves the problem, and verify with the narrowest relevant test before finishing. These three lines have saved me more hours than every other rule combined.

Context and tool use is the section that changes the most. Anything specific to the tools I actually have installed lives here. Right now it has six lines for rg (ripgrep, a fast command-line text search tool), git diff, ast-grep (a structural code search tool that understands syntax), and fastmod (a safe bulk string replacement tool). If I uninstall ast-grep tomorrow, I delete the line. Stale references produce wasted tokens and confused output.

Python defaults is the section that gets trimmed the hardest. The temptation is to write a Python style guide into CLAUDE.md. Don’t. Anthropic models are already good at Python. Style rules waste tokens. Keep only the preferences that differ from what a competent Python developer would write by default: uv for dependency commands, the configured logger over print(), and explicit exception handling. Three lines.

Code quality and communication are the last two sections, both deliberately thin. “Keep functions focused and small” and “be concise” are the kind of guidance that sounds helpful and produces nothing. I keep one line in each that actually changed my output: remove imports made unused by your own changes, and push back if a safer or smaller approach would meet the goal. The pushback rule has produced more useful refactors than anything else in the file.

Project-level files that scale

The project-level CLAUDE.md is where the audit pays off. Most of the corrections a real audit produces are project-specific, not personal defaults. Repo conventions, test commands, deployment steps, environment variables, the quirks of a particular framework: these go in the project file, not the global one.

The mistake I made early on was writing project-level guidance that was too abstract. “This is a Python project using FastAPI” tells the model nothing it cannot infer by reading the repo. “Run uv run pytest tests/ before opening a PR, and add new tests for any handler you touch” tells the model exactly what to do.

Concrete commands and concrete behaviors are what scale. Vague descriptions of the project’s architecture do not.

The Bedrock example I started with belongs in the project file, not the global one, because the correction only applies when the project uses AWS Bedrock. A global rule that says “always use global. prefix for Bedrock” would be wrong for the dozen other repos where I do not use Bedrock at all. The rule belongs where it is relevant.

Local notes that never get committed

CLAUDE.local.md is the scratchpad. The convention is to gitignore it, which means the contents stay on your machine only. I use this for things that are true for me but might be wrong for someone else. My local notes tend to include scratch reminders about a tricky bug I am mid-debug, or a note to myself about a recent breaking change in a dependency.

The discipline that helps me is to delete the local file every Monday. Anything in it that I actually need will get re-added within the week. Anything that does not get re-added was not earning its keep.

Trade-offs

A CLAUDE.md file that is too long costs you tokens on every session. Every line in the file is context the model sees before it answers. A thousand-line CLAUDE.md will eat into your context window (the model’s working memory limit, after which earlier content gets dropped) before the model reads a single line of your code. The longer the file, the more you pay in latency (response delay) and cost, and the more the rules blur into noise.

A CLAUDE.md file that is too short leaves the model guessing. The first session you run after deleting CLAUDE.md entirely is always worse than the session after a tight 30-line file. The model will invent defaults that match common cases but not your case.

The audit discipline is the highest-value habit I have built around CLAUDE.md. Without it, the file grows stale and the model starts ignoring it. With it, the file stays short and accurate, and the model actually reads it.

The three-layer split is genuinely useful and genuinely annoying. Three files to maintain instead of one. The annoyance is real. The benefit is that you can ship a global file across all your projects without dragging project-specific cruft into every session.

What I would tell past me

Three things, in order of importance.

Audit before you write any rules. Run Claude Code on a small task in the project and watch for the mistakes that repeat. Those are your rules. Everything else is decoration.

Keep the global file under fifty lines. Anything beyond that is a style guide, and style guides do not belong in CLAUDE.md.

Split rules across the three layers by scope, not by topic. Things true across every project go in global. Things true in one repo go in project. Things true only for you go in local.

Bottom line: CLAUDE.md is the file that turns repeated corrections into permanent rules. The three layers (global, project, local) keep the rules scoped correctly. The audit habit keeps the file short and earning its keep. None of this is complicated. All of it is the difference between re-teaching the model the same lesson every session and never having to bring it up again.

Leave a comment