5 months. 100% Claude Code. Zero architectural drift. A developer reports that after five months of using Claude Code to write 100% of the code for two projects, the architecture has not drifted. The key to preventing architectural drift is a system of locked files that agents cannot modify without human approval, enforced via GitHub push rulesets. The developer found that while AI agents propose changes to locked files frequently, only about two-thirds of those proposals are accepted, and the human gate prevents self-reinforcing drift. 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. 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: 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. The system has three parts working together: 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. 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. 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. 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. 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. 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 https://dev.to/teppana88/how-i-validate-quality-when-ai-agents-write-my-code-481c . The two-category model in this article and the validation pipeline in that one are halves of the same system. 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.