In one web service project I have been building and maintaining for 5 months, every line of code has been written by Claude Code. In a second project, a macOS app in Swift built over 3 months, the same is true with Claude Code.
The architecture has not drifted.
What drift actually is with AI
AI failures usually get described as catastrophic. The agent broke the build. Shipped a bug. Those happen, but they are not what wears down a long project.
The failure that does is much smaller:
- An error swallowed with a try/catch, where the rest of the codebase returns a Result.
- The same problem solved one way here, a different way three files over.
- A helper rewritten from scratch, where one already existed a folder away.
Each change is locally justified. None of them are globally correct. After five months, the codebase looks "almost right everywhere", and the architecture I started with is no longer what I have.
Better CLAUDE.md does not fix this. It works for one session, not five months.
How the setup works: three components
The system has three parts working together:
- Locked Claude Code rules. The files that define how the agents themselves operate.
- Locked architecture and code style. The files that define what the agents produce.
- Independent validators. Separate agents that check every implementation against the rules in 1 and 2.
The first two share the same enforcement mechanism: a file lock at the server. The third is a different kind of layer that runs after every implementation. The rest of this article covers each.
Locked files: who is allowed to change what
The model that has worked, on both projects, is to separate every piece of agent instruction into two categories based on who is allowed to change them. Everything outside these two categories is left to the agents.
1. Claude Code rules
The files that define how the agents themselves operate:
CLAUDE.md # project-level Claude Code config
.claude/agents/ # subagent definitions (architect, developer, validator)
Agents can read these and propose changes. They cannot push changes. Every modification goes through me.
The reason this category is locked is recursive. If AI can change the rules that constrain it, drift becomes self-reinforcing. The agent that is drifting becomes the agent that rewrites the rules to permit the drift. The human gate breaks the loop.
The system still has to improve. Agents propose changes to their own rules when they notice friction or a repeated mistake. The improvements that survive my review become permanent.
2. Architecture and code style
The files that define what the agents produce:
docs/code-documentation/
architecture-overview.md # system map, tech stack, data flow
architecture-backend.md # service patterns, REST boundaries
architecture-frontend.md # React structure, state boundaries
architecture-shared-types.md # cross-package contracts
testing-guidelines.md # test patterns, anti-patterns
git-workflow.md # branch rules, commit conventions
Same mechanism. Agents read and propose. They cannot push.
I enforce both categories with a single GitHub push ruleset. It restricts pushes to these paths:
CLAUDE.md
.claude/agents/**
docs/code-documentation/architecture-*.md
docs/code-documentation/testing-guidelines.md
docs/code-documentation/git-workflow.md
Only the repository admin role is on the bypass list. The AI agent pushes with its own token, tied to a non-admin identity, so it is not a bypass actor. Any push it attempts to a locked file is rejected at the server.
When the agent wants to change a locked file, it surfaces the proposal as a Product Decision: situation, options, trade-offs, recommendation. I decide. If I approve, I make the file change myself.
The naming prefix matters. architecture-* is not only an organizational hint. It is also part of the access rule. A new architecture document added later inherits the lock by name.
What this looks like in practice
Across both projects, the agents have proposed changes to locked files dozens of times. Reasonable proposals. About one in three I decline. Those implementations get rewritten within the existing rules, and the codebase does not gain the new pattern. The rest are genuine improvements, and I make those file changes myself.
The reason the architecture has not drifted is not that the agents stopped trying. It is that they cannot apply their proposals without going through me first.
My memory file currently has 50+ pitfall entries in each project. Many of them come from a drift attempt that was caught in review, recorded so the agent does not repeat it.
Validation has to be independent
The whole setup works because of a final layer: independent validator agents that check every implementation against the locked architecture and code style documents. The validator sub-agents do not see the implementation reasoning. They get a fresh context, the code and the locked docs, and they verify the code conforms. Nothing else. If the validator reads the implementation's reasoning, it starts agreeing with it. That is rubber-stamping, not validation.
But not all of that validation is a judgment call, and that is on purpose. Before an implementation is even eligible for review, the compiler has to pass in strict mode, the test suite has to be green, and coverage has to clear an 80% threshold. A deterministic check cannot be talked into agreeing with the code the way an LLM can. The agent validators sit on top of that floor. They catch what the machine cannot: whether the code conforms to the locked architecture, not just whether it runs.
I have written about the validator setup in more detail in an earlier article: How I validate quality when AI agents write my code. The two-category model in this article and the validation pipeline in that one are halves of the same system.
Setting up a model that holds
- Identify the files in your project that define the agent rules, the architecture, and the code style.
- Add a GitHub push ruleset that restricts pushes to those paths. Put only the repository admin role on the bypass list and keep yourself as the only admin.
- Tell your planning agent to propose changes to those files as a Product Decision instead of editing them directly.
- Add independent validator agents that check each implementation against the locked files. Give them in context the code and the docs only. No planning, no reasoning.
- Decide on each proposal yourself. When you approve, you make the file change.
AI will not destroy your architecture in one mistake. It will replace it with a better one, one reasonable change at a time. Preventing that is the developer's job. Our skill matters most when we know how to set up the system that does it. This is one model that worked.
Top comments (0)