Blog · September 1, 2026

Get the Architecture Out of Your .md Files

AI agents need an architecture model, not more markdown.

A CLAUDE.md file of architectural prose on the left versus an architecture.calm.json graph of nodes, relationships, flows, and controls on the right.
Architecture as prose is advisory, drifting, and unverifiable. Architecture as a model can be checked.

There's a new genre of file at the root of every repository: CLAUDE.md, AGENTS.md, .cursorrules. And buried inside the build commands and style conventions, you'll find the load-bearing part: prose describing the architecture. Which services own which data. What talks to what, and through what. Which patterns are mandatory and which are forbidden.

That architectural content is doing governance work. And prose is the wrong instrument for governance.

To be clear about scope: your readme isn't going anywhere. Build commands, dev setup, naming conventions, PR etiquette — markdown is fine for all of it, because none of it needs to be enforced. The problem is the paragraphs that were pretending to be controls.

Three reasons architectural prose fails

Three panels: architecture rules dropped from an agent's context window; a markdown queue path drifted into a direct HTTPS call; a proposed change and a paragraph of prose with no deterministic check.
Deprioritized. Drifted. Unverifiable. The same three failures, every change.

Agents deprioritize it. A markdown file competes for attention with everything else in the agent's context window: the task, the code it just read, the error it's chasing. Under context pressure, your architecture rules lose. Not maliciously; probabilistically. Guidance that holds 95% of the time isn't governance. It's a coin you flip on every change, and agents make hundreds of changes a day.

It drifts. The markdown says the payment service talks to the ledger through a queue. The codebase, eighteen months and four teams later, says otherwise. Nothing flags the gap, because nothing connects the prose to the code. Every architect who has maintained a wiki knows how this ends — except the stale document is no longer misleading a new hire once a quarter. It's misleading an agent on every task.

It's unverifiable. Here's the question that breaks the whole model: given a proposed change and a paragraph of prose, is the change compliant? No procedure answers that. You can ask another LLM for an opinion — and now your governance layer has the same failure modes as the thing it governs. Non-deterministic checking of non-deterministic output isn't a control.

It's vibes reviewing vibes.

We spent two decades learning this lesson in infrastructure. Nobody governs cloud environments with a runbook that says "please keep the databases encrypted." We declare the desired state in code and let machines enforce it. Then AI agents arrived, generating changes faster than any human team ever could, and our answer was a README with rules in it.

Where the architecture should live: FINOS CALM

The right home already exists as an open standard. CALM — the Common Architecture Language Model, from FINOS — describes architecture as structured, machine-readable data: nodes, relationships, flows, and controls. Not a diagram exported to PNG. Not a paragraph of intent. A versioned artifact that lives in the repo, gets reviewed like code, and can be validated against.

That last property is the whole point. A CALM model isn't documentation about the architecture — it is the architecture, in a form a machine can check a change against.

And the checking is done by operators, not opinions. The model enforces on two levels. Topology says what may talk to what: payment reaches the ledger through a queue, and that's a declared relationship, not the sentence that drifted for eighteen months, two sections ago. Controls sit on top and assert attributes: this resource type, this field, this value, authored by your architects against your own control catalog. Both are evaluated the same way on every proposed change. The change that introduces a direct call doesn't get reviewed by opinion. It gets violation.

A RELATIONSHIP, NOT A SENTENCE

"relationships": [
  {
    "unique-id": "payment-to-settlement-queue",
    "description": "Payment service publishes settlement events",
    "protocol": "AMQP",
    "relationship-type": {
      "connects": {
        "source":      { "node": "payment-service" },
        "destination": { "node": "settlement-queue" }
      }
    }
  },
  {
    "unique-id": "settlement-queue-to-ledger",
    "description": "Ledger consumes settlement events",
    "protocol": "AMQP",
    "relationship-type": {
      "connects": {
        "source":      { "node": "settlement-queue" },
        "destination": { "node": "ledger-service" }
      }
    }
  }
]

Guidance and enforcement must derive from one model

A model alone is still just better documentation. The loop closes when two things derive from it:

Guidance. Before an agent writes a line of code, it queries the model: what does this service connect to? Which controls apply to the node that owns this file? What breaks upstream and downstream if I change it? The agent isn't skimming prose and hoping, it's reading structured context from the source of truth. Prose doesn't disappear here; it gets generated from the model instead of hand-maintained beside it. The difference is provenance, and provenance is what keeps it from rotting.

Enforcement. The change is then evaluated against the same approved model. A proposed call from payment to ledger that was never declared isn't a judgment call. It's a violation, with the control named. Not a repo-wide scan, not a quarterly review: every change to governed code, judged when it's proposed, whether an agent wrote it or a human did.

An approved CALM model feeds guidance to the agent and engineer, and enforcement to one gate, so guidance cannot drift from the check.
One source — guidance cannot drift from enforcement.

This is what ArchRails does, and the ordering matters: the context an agent receives and the gate that judges its output derive from one model, so guidance cannot drift from enforcement. When they come from different places — as they always eventually do when one is prose and the other is a linter someone bolted on — agents learn to satisfy the gate and ignore the guidance. When they share a source, complying with the guidance is passing the gate.

And when a change is blocked, the response isn't a bare failure code. The agent learns which control fired, why it matters, and what to change; so the next attempt converges instead of thrashing.

Blocking isn't the same as stopping work

The objection every engineering leader raises next:

Won't this just stall my team?

No — because blocked isn't the end of the path.

A developer can authorize the change anyway, in their own words. The code gets written. The finding still stands, and nothing is reported as approved that wasn't.

That's the difference between a guardrail and a gag. Deliberate exceptions stay possible; silent ones stop being possible. Which is precisely the trade auditors have been asking for.

The stakes are different now

Pre-AI, architectural drift happened at human speed, and architecture review boards could almost keep up. Agents drift at agent speed. If your architecture lives in advisory text, you've chosen to find out about violations after they've merged, multiplied across every repository an agent touches. For any organization where architecture is a concern — not just a preference — that's not a tooling gap. It's a control gap.

Keep the markdown for what markdown is good at. Move the architecture into a model.

Declare it in CALM. Enforce it with ArchRails.

What follows: even if the agent reads the whole tree, it still can't find what was never written down.

ArchRails is built on the FINOS CALM open standard. Learn more about CALM at the FINOS Architecture as Code community.

The product · More posts