You’re deep in a coding session with Claude. It just implemented a feature exactly the way you wanted. Nice. Now you type “commit that.” It commits. “Push it.” It pushes. Then in the next response, it opens with “That’s a great question!” when you asked something straightforward. You sigh. A few exchanges later, you ask it to fix a small bug, and it returns with the fix plus a refactored function, new error handling for edge cases that don’t exist, and a helper utility you didn’t ask for.
None of these are deal-breakers. Each correction takes a few seconds. But they add up. Over an eight-hour session, you might make dozens of these micro-corrections without even noticing. It’s cognitive overhead that operates below the level of conscious attention — like background noise you’ve tuned out. You don’t realize how loud it was until it stops.
The most effective “plugin” I’ve found for Claude Code isn’t a plugin at all. It’s a plain text file called CLAUDE.md that lives in my home directory. It contains my preferences, my workflow expectations, and my list of antipatterns to avoid. Claude reads it at the start of every conversation. No code to maintain, no dependencies to break, no debugging sessions when something goes wrong — just instructions that work.
This applies to any AI coding agent, not just Claude. Codex has similar instruction mechanisms. So does Gemini. The principle is the same: persistent context beats repeated prompting. I’ll use Claude as the concrete example because that’s what I use daily, but the patterns transfer.
Let me show you how to build one from scratch, section by section. By the end, you’ll have a file tailored to your own workflow and frustrations.
The Global CLAUDE.md
Your global CLAUDE.md lives at ~/.claude/CLAUDE.md. Claude reads this file at the start of every conversation, regardless of what project you’re working in. Think of it as your personal preferences — the baseline behavior you want everywhere.
This is where you put instructions that aren’t project-specific. How you like Claude to communicate. Your git workflow expectations. The coding patterns you prefer and the antipatterns you want to avoid. Anything that reflects you rather than the particular codebase you’re in.
Start with an empty file and add sections as you notice friction. There’s no perfect template because everyone’s frustrations are different. What matters is that you capture your patterns.
mkdir -p ~/.claude
touch ~/.claude/CLAUDE.md
Now let’s fill it in.
Fixing Communication Antipatterns
Let’s start with the most universally relatable annoyance: sycophancy.
“You’re absolutely right!” “That’s a fantastic idea!” “Great question!” These phrases feel polite, but they’re noise. Worse, they can mask disagreement. If Claude always starts with “You’re absolutely right!” before explaining why you’re actually wrong, the signal gets buried.
Here’s what I put in my global CLAUDE.md:
## Communication Style
- Be concise. Skip preamble and get to the point.
- Don't narrate what you're about to do - just do it.
- **No sycophancy.** Don't flatter, don't say "great question",
don't start with "absolutely". If I'm wrong, say so directly.
Honest disagreement is more valuable than false agreement.
Let me explain each one.
“Be concise.” You’re reading Claude’s output in a terminal. Space is limited. Every unnecessary sentence is visual noise that pushes the actual content further down. You want the answer, not an essay about the answer.
“Don’t narrate what you’re about to do.” Without this instruction, Claude will say things like “Let me read that file for you” before calling the read tool. But you can see the tool call. The narration adds nothing. It’s like a chef announcing “I’m going to chop the onion now” before each knife stroke.
“No sycophancy.” This is the big one. I want Claude to be a collaborator, not a yes-man. If my approach has problems, I want to hear about them directly. False agreement wastes time — I go down the wrong path and only discover the issue later. Honest pushback saves time.
Here’s the difference in practice:
Without the instruction:
“That’s a great approach! You’re absolutely right that we should cache those results. Let me implement that for you…”
With the instruction:
“Caching would help, but the real bottleneck is the N+1 query in the loop. Let’s fix that first.”
The second response might feel blunter, but it’s more useful. It identifies the actual problem instead of validating my guess.
One note: you can tune this. Some people genuinely prefer a bit of acknowledgment before Claude dives into the answer. The point isn’t that acknowledgment is always bad — it’s that the default should be intentional, not automatic. Write the instructions that match what you want.
Fixing Workflow Antipatterns
Here’s a pattern I noticed repeatedly: Claude would write code all day, but it wouldn’t take the final step. It would implement a feature perfectly, then… wait. For me to say “commit that.” Then wait again for “push it.” Then wait for “run the tests.”
I became a human Enter key. Each individual prompt was trivial — two words — but the cumulative effect was constant low-grade friction. I was the bottleneck in a workflow that could have been continuous.
The fix is simple: redefine what “done” means.
## Git Workflow
- Always make frequent, small commits with clear messages.
- Prefer feature branches with worktrees for all non-trivial work.
- Always check `git status` before finishing work.
## Verification Requirements
- **Before finishing any branch or significant work:** Verify clean git state
(no uncommitted changes, no unpushed commits).
- **Before merging/PRs:** Confirm I've had a chance to do manual verification.
- **Don't assume automated tests are sufficient** - always offer a manual
verification checkpoint for user-facing changes.
The key insight is the difference between “do this when asked” and “do this by default.” I’m not asking Claude to commit when I tell it to. I’m telling Claude that committing is part of the definition of done. If there are uncommitted changes, the work isn’t finished.
The verification requirements section adds nuance. I want Claude to commit and push automatically for regular work, but I also want a checkpoint before major milestones. Merging to main or creating a PR should wait for my explicit approval. This gives me automation for the routine parts while preserving control over the important decisions.
You might also include workflow-specific instructions. I have this in my global file:
## Working Style
- For non-trivial tasks, outline the approach before diving in.
- Use todo lists to track multi-step work.
- When debugging, be systematic - don't shotgun random fixes.
These aren’t strictly necessary — Claude will often do these things anyway — but making them explicit means I don’t have to wonder whether it will or prompt for them when it doesn’t. The instruction cost is low; the consistency benefit is high.
Think about your own workflow. What steps do you find yourself prompting for repeatedly? Those are candidates for your CLAUDE.md. Each micro-task you eliminate is mental energy freed up for the actual work.
Fixing Over-Engineering Antipatterns
This category is sneakier than the others. Sycophancy is obvious; you notice it immediately. Missing commits are easy to spot; either there’s a commit or there isn’t. But over-engineering creeps in gradually.
You ask for a bug fix. Claude returns with the fix, and also a refactored version of the surrounding function “while it was in there.” Plus new error handling for an edge case you’ve never encountered. Plus a helper utility that makes the pattern “reusable.” Each addition seems reasonable in isolation. Together, they mean your two-line bug fix became a fifty-line changeset touching four files.
Here’s my antipatterns section:
## Anti-Patterns to Avoid
- Don't add features beyond what was asked.
- Don't refactor surrounding code when fixing a bug.
- Don't add error handling for impossible cases.
- Don't create helper utilities for one-time operations.
- Don't add backwards-compatibility shims - just change the code.
And the related coding preferences:
## Coding Preferences
- Favor simplicity over cleverness.
- Don't add abstractions until there's a clear need.
- Match existing code style in the project.
- Minimal comments - code should be self-documenting. Only comment
non-obvious "why".
Why does this matter?
Every “improvement” is code you now maintain. That helper utility Claude added? You’re responsible for it now. If it has a bug, you fix it. If requirements change, you update it. The cost of code isn’t just writing it — it’s living with it.
Unrequested features aren’t tested against your actual requirements. Claude might add error handling for an edge case, but does that edge case actually matter in your context? Often it’s handling something that can’t happen given your system’s constraints. Now you have code that runs never, but you have to read past it every time you’re in that file.
The “helpful” instinct compounds. One refactored function is fine. A hundred of them across a codebase means the codebase no longer reflects deliberate architectural decisions — it reflects Claude’s in-the-moment opinions about what would be cleaner. Those opinions might be good individually, but they’re not coherent collectively.
Here’s a concrete example. Say you ask Claude to “add a logout button to the settings page.” Without antipattern guardrails, you might get:
- The logout button (what you asked for)
- A confirmation modal (“Are you sure you want to log out?”)
- A session timeout handler
- A “remember me” checkbox that persists login state
- Refactored authentication state management to support the new features
With guardrails, you get: the logout button.
If you want the confirmation modal, ask for it. If you need session timeout handling, that’s a separate task. The point is that you decide what’s in scope, not Claude’s imagination about what would be nice to have.
The mindset shift is training Claude to ask before expanding scope rather than assuming you want everything it can think of. “Should I also add a confirmation modal?” is a much better response than silently adding one.
Project-Level CLAUDE.md
Your global CLAUDE.md is your baseline, but different projects have different needs. A Python API has different checks than an Astro static site. A personal project might want aggressive auto-commits; a team repository might require more careful staging.
This is where project-level CLAUDE.md comes in. Claude reads both files — global first, then project — and the project file can augment or override global settings.
Here’s my blog’s project-level CLAUDE.md:
## Ground Rules
1. **Nothing is done until it passes type checking.** Run `npx astro check`
before considering any task complete.
2. **Commit every change automatically.** Do not wait to be asked.
3. **Push committed changes automatically.** Do not wait to be asked.
## Commands
npm run dev # Start dev server
npm run build # Production build
npx astro check # Type check (REQUIRED before any commit)
Notice what’s project-specific here:
npx astro check is meaningless in a Python project. It’s the Astro framework’s type checker. But for this blog, it’s the gate that every change must pass. Making it explicit means Claude never forgets to run it.
Auto-commit and auto-push make sense for a personal blog where I’m the only contributor. I wouldn’t put this in a team repository’s CLAUDE.md — there, I’d want manual control over what gets pushed to shared branches.
The commands section teaches Claude the vocabulary of this specific project. It doesn’t have to guess whether it’s npm run build or yarn build or something else. The correct commands are right there.
When should you add project-level instructions?
- Specific tech stack: Different frameworks have different linting, testing, and building commands
- Team conventions: Commit message formats, branch naming, PR templates
- Risk tolerance: Personal projects can be more aggressive; production systems need more guardrails
The layering system means you don’t have to repeat yourself. Put your universal preferences in global, put project-specific details in the project file, and Claude composes them correctly.
The Relief You Didn’t Know You Needed
The first week after I set up my CLAUDE.md, I kept noticing moments where I didn’t have to correct Claude. Moments that used to require a nudge now just… worked. It’s a strange thing to notice the absence of friction, but that’s exactly what happened.
The cognitive load was always there, but it was invisible — like a background process consuming resources without appearing in any dashboard. Removing it freed up attention I didn’t realize was being spent.
Why does plain text work better than complex plugins for this?
- No dependencies to break. It’s markdown. Nothing to install, nothing to update, nothing that stops working when a library changes.
- No code to debug. When something isn’t working, you read the file. The failure mode is always “the instruction wasn’t clear enough,” which you fix by editing the instruction.
- Version controlled. Your
CLAUDE.mdcan live in your dotfiles repo, versioned and portable across machines. - Readable by anyone. Including Claude itself. There’s no layer of abstraction between what you wrote and what Claude reads.
Start small. Don’t try to write the perfect CLAUDE.md on day one. Start with the one thing that annoys you most. Add another when you notice the next pattern. Let your file grow organically from actual friction rather than imagined needs.
Start with one instruction. Maybe it’s “no sycophancy.” Maybe it’s “commit without asking.” Whatever friction you notice most — write it down. Then notice how it feels when that friction disappears.
If you’ve found patterns that work for you, I’d love to hear about them. The best configurations come from shared experience.