development

Entropy at Velocity: Keeping Your Codebase Coherent When AI Writes Most of the Code

The Coherence Problem

AI coding tools removed the writing bottleneck. Congratulations. Now you have a different problem.

The bottleneck was never really writing code — it was thinking about code. Deciding what goes where, how things connect, what the conventions are. Writing was just slow enough to give you time to think while you typed. Every variable name, every file path, every function signature — the mechanical friction of typing forced a pace that let your brain keep up.

Claude Code and its siblings removed that friction. You describe what you want. Code appears. You describe more. More code appears. In an afternoon you can generate what used to take a sprint. The codebase grows at a pace that would have been physically impossible six months ago.

And somewhere around day three, you notice something: the code doesn’t agree with itself.

Not bugs. Not crashes. Something subtler. The API endpoint you built Monday uses camelCase. The one from Wednesday uses snake_case. The authentication module passes user objects. The authorization module expects user IDs. The service layer has three different patterns for error handling, each perfectly reasonable, none compatible with the others.

Your codebase has developed entropy. And it happened so fast you didn’t see it coming.


Two Kinds of Drift

I’ve seen this pattern in my own work and in teams I’ve consulted for. The entropy manifests in two distinct forms, and confusing them leads to wrong solutions.

Structural Drift

Structural drift is when your code diverges from your documented architecture. You write a spec that says user data flows through a validation layer. Three prompting sessions later, someone — you, a colleague, the AI — adds a shortcut that bypasses it. The spec says one thing. The code does another. Neither is wrong in isolation. Together, they’re a trap waiting for the next person who reads the spec and trusts it.

Every team that has tried to maintain architecture decision records knows this pain. The decision gets recorded. The code evolves. The ADR becomes historical fiction.

When I built Injectionator — a security tool for AI applications — I documented a dual-LLM scanning pipeline with specific data flow patterns. Within two weeks of AI-assisted development, the implementation had drifted from the architecture doc in eight places. Not because the AI was careless, but because each individual change made sense in context. The drift was invisible until I went looking for it.

Stylistic Drift

Stylistic drift is when the code works but doesn’t cohere. Different naming conventions in different modules. Three approaches to dependency injection. Config files that mix YAML, JSON, and environment variables for no discernible reason.

LLMs accelerate this because they have no memory of their previous sessions’ conventions. Each prompt gets a fresh context window. Ask Claude to build a REST endpoint at 9am, then ask it to build another at 2pm, and you might get two perfectly functional endpoints that look like they were written by different teams.

This isn’t a Claude problem — it’s any LLM. They write confidently and consistently within a session, and inconsistently between sessions. They’ll use three different error handling patterns in the same project and never flinch, because each pattern was reasonable given the context they could see.

Both kinds of drift are real. Both compound. And the velocity that AI gives you makes both worse, because you’re generating more code faster than your ability to review it for coherence.


What Entropy Actually Costs

The cost doesn’t show up as bugs. It shows up as friction.

Rework. You build a feature on Monday. On Thursday you discover it conflicts with a pattern established elsewhere in the codebase. You rewrite it. Or worse — you don’t, and now you have two patterns, and next month someone has to figure out which one is “right.”

Surprise complexity. A change that should take an hour takes a day because the codebase has three different ways of doing the same thing and you need to understand all of them before you can safely modify any of them.

Reluctance to touch your own code. This is the one that should alarm you. When a solo developer — or a small team that built the whole thing — becomes afraid to modify their own codebase, something has gone structurally wrong. I’ve seen it in my own work. I’ve seen it with clients. The code grew so fast that nobody can hold the full picture in their head anymore, and every change feels like it might break something unexpected.

Onboarding drag. Try handing an entropy-laden codebase to a new team member. Or to a new AI context window. The inconsistencies that you’ve learned to navigate are invisible walls for anyone who didn’t watch them form.

These costs compound. A codebase with mild entropy is manageable. A codebase with six months of unmanaged entropy at AI-assisted velocity is a rewrite candidate. I’ve watched it happen in real time — teams that shipped faster than anyone thought possible, then ground to a halt because the codebase had become a patchwork of locally-sensible, globally-incoherent decisions.


Why the Obvious Solutions Fail

The natural instinct is to reach for existing tools.

“We’ll write better documentation.” You will. And it will drift from reality within a week, because documentation that isn’t verified against code is documentation on a countdown timer.

“We’ll do more code review.” Review catches bugs. It catches security issues. But it’s remarkably bad at catching entropy, because each individual PR looks fine. The drift is in the aggregate — in the relationship between files that were never modified in the same PR. A reviewer would need the whole codebase in their head to catch stylistic drift, and nobody has the whole codebase in their head anymore.

“We’ll add linting rules.” Linting catches syntax-level consistency. It cannot catch architectural drift. It cannot catch the decision to use callbacks in one module and promises in another. It cannot catch the fact that your data access layer has two competing patterns.

All three solutions share the same flaw: they’re post-hoc. They try to catch entropy after it’s been introduced. By that point, it’s already in the codebase, already shaping the AI’s next suggestions (because the AI reads your existing code as context), already compounding.

You need something that works at the point of generation — that shapes the code as it’s being written, not after.


The Four-Layer System

Here’s what I’ve built and refined, first for my own projects, then adapted for client teams. It’s four layers, each catching different problems at different scales.

Layer 1: Hooks — Automatic, Real-Time Correction

Hooks are scripts that fire every time the AI edits a file. They run before the edit is applied. The AI sees the warning and self-corrects mid-generation.

In practice, this means:

  • Terminology enforcement. Product names, technical terms, naming conventions. The AI starts writing user_data in a codebase that uses userData — the hook flags it, the AI corrects.
  • Style boundaries. Patterns your codebase shouldn’t use. Blocked imports. Deprecated APIs. The AI reaches for moment.js when your project uses date-fns — the hook catches it.
  • Relationship awareness. Edit a database schema? The hook reminds the AI to check the migration files. Modify an API endpoint? It nudges: “Check the client-side types.”

The user experience is nearly invisible. A brief status message — “Checking conventions…” — and the output comes out right. No review step. No manual correction. The guardrails run in the background while you focus on what to build.

For the Viewyonder website, we run three hook scripts on every edit: terminology checking (15 regex patterns), style guarding (13 anti-patterns), and change suggestions (7 file-watching rules). They fire as PreToolUse hooks in Claude Code — before the edit is applied, giving the AI a chance to self-correct.

Layer 2: Specs — The Source of Truth

Specs are the documents that define how your system is supposed to work. Architecture specs describe your URL structure, data flow, and component patterns. Content specs describe your naming conventions, frontmatter schemas, and editorial rules.

The critical difference from regular documentation: specs are machine-verifiable. They’re written specifically so that an automated tool can compare them against reality and report mismatches.

A useful spec isn’t prose — it’s a contract. “The API returns errors in this shape. The database schema has these fields. The design tokens use these values.” Concrete, checkable, falsifiable.

Most teams have something like this already — scattered across READMEs, wiki pages, onboarding docs. The work is consolidating it into a format that can be automatically verified.

Layer 3: Agents — Specialist Reviewers

Agents are AI personas with specific review expertise. A drift-detection agent knows how to compare specs against code. A consistency agent knows how to evaluate editorial quality. A security agent knows what patterns to flag.

They’re not doing anything magical — they’re structured prompts that direct the AI’s attention to specific concerns. But the structure matters. An undirected “review this code” produces generic feedback. A targeted “compare this implementation against the architecture spec and report any divergence” produces actionable findings.

In Claude Code, agents live as markdown files that define the review persona, its domain of expertise, and its evaluation criteria. Other tools have equivalent mechanisms — system prompts, custom instructions, role definitions. But agents need knowledge to be effective — a topic I explore in a companion piece.

Layer 4: Skills — On-Demand Comprehensive Checks

Skills are the commands you run deliberately at key moments. Before committing. Before a release. When onboarding a new team member. When you haven’t touched the codebase in a month and want to know what drifted while you were away.

We use two primary skills:

/coherence check-drift compares spec documents against the actual codebase. It answers: “Has reality diverged from what we documented?” The output is binary per item — aligned or drifted — with specific file references and remediation suggestions.

/coherence check-principles reviews code and content against your documented architectural and editorial principles. You can scope it to specific directories or just your staged changes — the pre-commit check that catches what the hooks missed. (Terminology and style consistency enforcement has moved to automatic hooks, running continuously rather than on demand.)

Three touch points emerge from this system: automatic correction on every edit (hooks), pre-commit review of staged changes (skills), and pre-release verification against specs (skills + agents). Each catches different problems at different scales.


What This Changes (and Doesn’t)

Let me be honest about the limits.

This system catches mechanical entropy. Naming inconsistencies, architectural drift, pattern violations, terminology errors — the stuff that compounds silently and costs you later. It’s very good at this. It catches things humans miss because humans can’t hold an entire codebase in their working memory.

This system does not solve design quality. It won’t tell you that your architecture is wrong, only that your code doesn’t match your documented architecture. It won’t tell you that your API design is confusing, only that it’s inconsistently confusing. Garbage in, consistent garbage out.

This system requires investment. Writing good specs takes time. Configuring hooks takes iteration. Defining agents takes domain knowledge. This isn’t a drop-in solution — it’s infrastructure that pays for itself over weeks and months, not hours.

The payoff is compounding. The teams I’ve worked with report the same trajectory: initial setup takes a few days. The first week feels like overhead. By week three, they’re catching drift they didn’t know existed. By month two, new team members are productive faster because the conventions are enforced, not just documented. By month three, they can’t imagine working without it.

The honest assessment: this is not a silver bullet. It’s a system that trades upfront effort for long-term coherence. If you’re building a weekend prototype, you don’t need it. If you’re building something that has to survive contact with a team, with time, with the relentless accumulation of AI-generated code — you do.


Where to Start

If you’re feeling the drift — if your codebase has that patchwork quality where every file works but nothing quite fits together — here’s the minimum viable version:

  1. Write one spec. Pick the area that hurts most. Document how it’s supposed to work. Be concrete enough that a tool could verify it.
  2. Add one hook. Start with terminology or naming conventions. A simple regex-based check that fires on every edit. Get used to the feedback loop.
  3. Run a manual check. Before your next commit, ask the AI to compare your staged changes against the spec. See what it catches.

That’s enough to feel the difference. The full four-layer system can come later, built incrementally as you learn what your codebase needs.

This is the kind of work we do at Viewyonder. We help teams build coherence systems tailored to their stack, their conventions, and their workflow — because the framework is general, but the implementation is always specific. If your team is shipping fast with AI but feeling the drift, get in touch. We’ve been through the entropy and come out the other side.


Steve Chambers is the founder of Viewyonder, a GenAI consultancy that helps teams work effectively with AI coding tools. He built the coherence system described here while developing Injectionator, a security tool for AI applications — and learned most of these lessons the hard way.

← All writing