lockstep

How do I stop AI agents from violating our architecture decisions?

Two moves: put decisions in the agent's context before generation, and check its output after. Write constraints as imperative rules the agent reads at task start (via AGENTS.md or an MCP tool) and enforce the checkable ones with automated tests at PR time. Agents don't rebel; they just never heard the rule.

By Naman Jain

An agent that violates your architecture isn't being disobedient. It's being statistical: asked to add a feature, it reaches for the most common pattern in its training data (a direct DB call, a new REST endpoint, a fresh utility class), unaware your team ruled that pattern out a year ago. The fix has a before half and an after half.

Why this happens

Your architecture decisions live in three places: ADRs nobody rereads, code patterns that only imply the rule, and people's heads. An agent sees none of them by default. A human engineer who missed a decision asks in Slack; an agent that missed one ships code against it at machine speed, and it can do so in ten repos at once.

The deeper problem is documented in our ADR guide: decision records were designed for a human reader with time and curiosity. Agents have neither. They read what's in the context window at generation time, and nothing else exists.

What actually works

Before generation: make decisions reach the agent.

Write constraints as imperative, checkable sentences ("all cross-service calls go through the event bus; no synchronous HTTP between services"), not as narrative ADR prose. An agent can follow a rule; it cannot infer one from a six-paragraph context section.

Put the few permanent, always-relevant rules in your repo's agent instructions file (AGENTS.md, CLAUDE.md). Keep it under a page: this file is loaded on every task, and stale rules in it are actively harmful.

For everything else (the decisions that change monthly, the ones that bind only some tasks), use a live tool instead of a static file. An MCP tool the agent calls at task start ("fetch approved decisions relevant to this change") keeps the constraint set current without bloating every prompt.

After generation: check the output.

Encode what's mechanically checkable as what Ford, Parsons, and Kua call fitness functions in Building Evolutionary Architectures: automated checks that verify an architectural property stays true as code changes. Dependency direction, module boundaries, forbidden imports: tools like ArchUnit or a custom lint rule catch these in CI regardless of whether a human or an agent wrote the code.

Accept that most decisions don't compile to a lint rule. "We're migrating off this ORM, don't extend it" is real architecture and no test catches it. For that class, the check is at PR review: a diff compared against the current decision list, by a human or by tooling built for it.

And underneath both: write the decisions down at all. Most teams discover, via an agent's confident mistake, that their architecture lived in the hallway. The one-question test (will this constrain how someone builds later?) tells you what to log.

Where Lockstep fits

Lockstep covers the loop: decisions get captured from Slack and Notion where they're made, the owner ratifies them in one click, an MCP server briefs agents on the ratified set before they write code, and PRs that drift from a decision get flagged with the decision quoted. Design-partner stage, Apache-2.0, self-hostable. See how it works.

Related questions

Why do AI agents ignore our ADRs?
They don't ignore them; they never see them. ADRs typically live in a docs folder or wiki the agent has no reason to read for a given task. The agent fills the gap with the most common pattern from its training data, which is often exactly what your ADR decided against.
Can I enforce architecture decisions with tests alone?
Partly. Dependency rules, layering, and naming can be encoded as fitness functions: automated checks in CI. But many real decisions ('don't call the billing service synchronously,' 'this module is being deprecated') resist cheap encoding. Those need to reach the agent as context before generation and a reviewer at PR time.
Does a bigger context window solve this?
No. A bigger window means you can include more, not that the right things get included. The problem is selection and freshness: knowing which decisions bind this task, and keeping them current. That's a retrieval-and-tooling problem, not a window-size problem.

Keep reading