A pattern shows up in almost every team that adopts a coding agent. The first week is impressive. By the third week, review comments start repeating: "we don't use that logger here," "this should follow the orders service," "don't call the payments API directly." The agent writes good code. It just keeps writing it the way most projects do, not the way yours does.
That isn't a bug in the model. It is the predictable result of where conventions live.
Why it happens
A model learns its defaults from an enormous amount of public code. It knows how most Python projects name things, how most React apps lay out components, which HTTP client most people reach for.
Your team's conventions are, almost by definition, the places where you decided to do something different from the default. And those decisions rarely live in the code itself. They live in:
- review comments from two years ago
- a wiki page nobody opens
- the head of the engineer who set up the service
When a coding agent starts a session, it sees the files it reads and the instructions it loads. If a convention isn't in either, the agent falls back to the average choice. Which is exactly the choice your team decided against.
Five fixes, in order of payoff
1. Write the rules where the agent reads them
Claude Code loads the repository's CLAUDE.md file at the start of every session. That file is the single highest-leverage place to put conventions, because every developer's agent reads the same one.
Write rules as short imperatives:
## Rules
- Log with `lib/log`. Never use `console.log` or the standard logging module.
- New endpoints copy the structure of `api/orders/`.
- Never call the payments API directly. Go through `services/billing`.
- Schema changes: write the migration and open a PR. Never apply it.
A paragraph about your logging philosophy changes nothing. "Log with lib/log" does.
If one part of the codebase has its own rules, put a CLAUDE.md in that folder. Claude Code picks it up when working there, and the root file stays short.
2. Point to an example instead of describing it
"New endpoints copy the structure of api/orders/" beats a page describing your architecture. Models copy examples far more reliably than they follow descriptions, and the example stays accurate as the code evolves.
Pick one reference implementation per kind of thing you build often: an endpoint, a component, a background job. Name it in the rules.
3. Name the banned alternatives
The agent's default is the popular choice, so a rule that only says what to use is half a rule. Say what not to use, too:
- "Use
httpx. Notrequests." - "Dates are stored in UTC. Never store local time."
- "Use the
Customermodel. NotClientorAccountHolder."
The last one matters more than it looks. Without a glossary, an agent will invent its own names for your domain concepts, and the codebase slowly fills with three words for the same thing.
4. Enforce what you can mechanically
Anything a linter, formatter, type checker, or architecture test can catch should be caught there, not in review. These checks don't care whether a human or an agent wrote the code, and they don't get tired.
Claude Code can also run commands automatically after it edits files (hooks, configured in the project's .claude/settings.json). Running the formatter or linter there means convention problems get fixed before anyone sees the diff.
5. Treat every repeated correction as a missing line
This is the habit that makes the other four stick. If you correct the agent on the same thing twice, the problem is not the prompt. It is a missing rule.
Add the line to CLAUDE.md in the same PR as the fix. Review changes to that file the way you review code, because it shapes every change the agent makes afterward.
What good looks like
After a few weeks of this, two things change:
- Review comments shift from conventions ("wrong logger") to substance ("is this the right behavior?").
- The
CLAUDE.mdfile becomes the most accurate written description of how your team actually works. New hires read it. So does every agent.
Starting from the docs you already have
Most teams already have their conventions written down somewhere: an engineering handbook, an onboarding guide, a style guide, a page about who owns what. The slow part is turning that prose into short rules an agent will follow.
That is what we built AI Workspace Builder for. You upload the docs your team already has, and it generates the CLAUDE.md, a profile for each role, and an install script in 15 to 30 seconds, using your own Anthropic API key. There's one free trial workspace, no card required.
Either way, start with the three corrections you made most often this week. Write them down where the agent reads them, and watch how many review comments disappear.
Top comments (9)
Good write-up. The “name the banned alternative” tip is the one I’d underline. Agents drift back to whatever is most common on GitHub unless you tell them what not to use.
One thing we kept hitting: CLAUDE.md is context, so it gets weaker as a session grows or the agent compacts. What held up better for us was splitting rules into two tiers. Taste and examples stay in CLAUDE.md. Anything you’d reject a PR for becomes a check the agent has to run on each file before it says it’s done, with the result fed back so it fixes its own violation.
Disclosure: I work on Norma at Quality Clouds, which does that second tier through an MCP server (free tier at portal.qualityclouds.ai). A post-edit hook running your linter gets you a long way too.
One more layer we use on AI Workspace Builder itself: a review council. Before Claude Code implements a change, our root CLAUDE.md sends it to role profiles picked by the type of change. A web page goes to the frontend engineer and the product designer, anything touching credentials to the security analyst and the architect, and every completed build to QA and a penetration tester. Each profile records its concerns in its own words, disagreements get named as trade-offs, and a CTO profile approves, modifies or blocks before any code is written.
It catches a different class of problem than your second tier. A check tells you a file breaks a rule; the council tells you the change itself is the wrong one. Critical findings block deployment, same as a failed check.
Agreed on the two tiers, and on the hook. That's the split we use too: if you'd reject a PR for it, it becomes a check, and CLAUDE.md keeps the taste and the examples. One detail on compaction: in Claude Code the project-root CLAUDE.md is re-read from disk and re-injected after /compact, so the file itself doesn't fade. What gets lost is anything said only in the conversation, plus nested CLAUDE.md files until Claude works in that folder again. So "put it in the file, not the chat" fixes part of it, and the check covers the rest.
Conventions written as prose in a prompt are a hope, not a rule. The ones that hold are checked in code, by a linter or a test that fails the build. Keep the prompt for judgment and move what the agent can break into a check.
Agreed. The test we use: if a reviewer would block the PR over it, it belongs in a linter, a test or a hook. If it's a judgment call, like which pattern to copy or when to ask, it belongs in the instructions. Most teams need both, and the mistake is putting the first kind in prose.
'Review comments from two years ago' is the real source, agreed. One habit that helps: when a review comment states a convention, add it to CLAUDE.md in the same PR, with the date and the reason, so the next agent reads the decision and not just the rule.
That's a great habit. The date and the reason do two jobs: the agent applies the rule with the right intent, and the next person doesn't delete a rule that looks unnecessary because nobody remembers why it's there. Doing it in the same PR is the key part, before the context is gone.
@aiworkspacebuilder The failure message does most of the work: a check that names the line to change is easier to act on than a red build with no reason. So the wording of the check matters as much as the rule behind it.
Agreed. A good failure message reads like a review comment: the rule, the line, and what to change it to. With an agent it matters even more, because the agent reads that message and fixes the line itself. A vague message costs you a few blind retries instead of one confused human.