Everything as Code: Source a Runtime Can Reject
On a Linux box, you can ask the kernel how much memory is free by reading a file:
$ cat /proc/meminfo
MemTotal: 16316200 kB
MemFree: 2451128 kB
Buffers: 198412 kB
Cached: 6104884 kB
There is no file. /proc is a virtual filesystem: the kernel rendering its own internal state as text, on demand, because text is the interface every tool already speaks. grep works on it. awk works on it. A shell script written in 1994 works on it.
That trick is the whole of Everything as Code, and it is the most useful thing we know about connecting language models to systems that already exist.
A model cannot operate your CRM, your Kubernetes cluster, or your deployment pipeline. It can operate a representation of them, and if that representation is text with a grammar, the model is on ground it knows well. But rendering the system as text is only half the job. The half that matters is the return trip. When the model proposes a change, something has to be able to look at that change and say no.
That is the bar we hold integration work to. Not "can the model read this," but "what rejects a bad answer before it lands."
Why rejection is the load-bearing part
The obvious way to connect a model to a system is to hand it an API and hope. This fails in a specific and frustrating way: a wrong API call is indistinguishable from a right one until after it has happened. The model returns something plausible, the call succeeds, and you find out three hours later that plausible was not the same as correct.
Source code is different, and the difference is not that code is tidier. It is that code has a rejecter. Compilers, schema validators, type checkers, linters, terraform plan, a failing test — these are all machines whose entire job is to look at a proposed artifact and refuse it. They turn a class of wrong answers into an error message instead of an outage.
So the validation step is not a safety feature bolted onto the pattern. It is the reason the pattern works at all. Everything as Code means: put the system into a form that has a rejecter, then let the model work in that form.
The same move, three times
Once you are looking for it, you see the same structure everywhere. Take the system, express its state as source, and keep a rejecter between the model and reality.
| System | Source | Rejecter |
|---|---|---|
| Cloud infrastructure | Terraform HCL | terraform validate, then terraform plan |
| Browser behavior | Playwright specs | The test run |
| A slide deck | Marp Markdown | The Marp compiler |
Terraform is the clearest case, because the rejecter is a first-class part of the workflow rather than an afterthought. terraform plan exists to show you exactly what would change before anything does. When a model edits infrastructure through HCL, the plan output is the review surface. Nobody has to trust the model; they have to read a diff.
Playwright works the same way at a different altitude. A browser interaction is stateful, messy, and nearly impossible to describe reliably in prose. As a spec file, it is source, and running it is the rejecter. The test either passes or it does not.
The third one looks trivial and is the most instructive.
The compression is real, but it is not the point
Here is a security group as the AWS API describes it:
{
"SecurityGroups": [{
"Description": "web tier",
"GroupName": "web-sg",
"GroupId": "sg-0a1b2c3d4e5f67890",
"OwnerId": "123456789012",
"VpcId": "vpc-0abc1234def567890",
"IpPermissions": [{
"FromPort": 443,
"ToPort": 443,
"IpProtocol": "tcp",
"IpRanges": [{ "CidrIp": "0.0.0.0/0" }],
"Ipv6Ranges": [],
"PrefixListIds": [],
"UserIdGroupPairs": []
}],
"IpPermissionsEgress": [{
"IpProtocol": "-1",
"IpRanges": [{ "CidrIp": "0.0.0.0/0" }],
"Ipv6Ranges": [],
"PrefixListIds": [],
"UserIdGroupPairs": []
}],
"Tags": [{ "Key": "tier", "Value": "web" }]
}]
}
And here is the same thing as source:
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = var.vpc_id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
The second is a quarter the size, and the token savings are worth having. But that is the smaller benefit, and leading with it misses what actually changed.
Type "protocol": "tpc" into the JSON and the API will take it. You get a runtime error from a service, somewhere downstream, phrased in that service's vocabulary. Type protocol = "tpc" into the HCL and terraform validate refuses it before anything is sent. Same typo, two entirely different failure modes: one is an incident, the other is a red line in a terminal.
That is the difference we are buying. Not brevity. A place for wrong answers to die cheaply.
The virtualization layer
Most real systems do not arrive with a rejecter attached, which means the integration work is building one. In practice that is a layer that:
- Reads the system's actual state
- Encodes it into a grammar you control
- Exposes that encoding to the model
- Accepts proposed edits
- Validates them against a schema, interpreter, or test suite
- Applies only what survives
This is /proc again, built deliberately. The system stays untouched until a validated diff has been approved. Most of our integration projects spend their early weeks here, before a single agent exists, because the agent is the easy part once there is something for it to push against.
Custom grammars help — implemented with ANTLR, YACC, or Lark, you get sharper semantics than YAML gives you. But YAML and JSON with a real schema are lightweight DSLs and they are usually enough to start.
DeckBot: the same pattern, pointed at slides

A presentation is close to the worst case for this pattern. It is a binary blob in a proprietary format, edited through a GUI, with no text representation and nothing resembling a compiler.
DeckBot is what happens when you apply the pattern anyway. Marp turns slides into Markdown, which makes them source: diffable, version-controlled, and readable by a model without any special affordance. The Marp CLI compiles that Markdown to HTML or PDF, and the compile is the rejecter. An agent can restructure a deck, and the build either succeeds or it does not.
That is the whole architecture. The rest is tooling — a REPL for talking to the agent, Nano Banana for generating images, a live preview. The interesting part is that once slides became source, the ordinary agent pattern from Give an Agent a Tool applied without modification. File editing, image generation, compilation. Nothing bespoke.
It is worth being precise about what this buys, because tools like NotebookLM will generate a deck faster. They also hand you a finished artifact you cannot meaningfully revise. When the source is Markdown in a repo, you can open it and change one line, or ask the agent to refactor three sections, and both work because they are the same operation on the same file.
DeckBot uses Behavior Driven Development, and this is less of a tangent than it looks. A .feature file is a plain-English description of what the software should do — and behave is a program that reads that description and refuses it when the implementation disagrees. The spec is source. The test runner is the rejecter. It is the same shape as everything above, applied to the project's own behavior rather than to slides.

Where this goes wrong
The pattern is easy to misapply, usually in one of five ways.
Representation drift. If your encoding falls out of sync with the real system, the model is optimizing a fiction. Every improvement it makes is to a world that does not exist. Make the virtualization layer authoritative and refresh it on demand rather than caching it.
Overpowered grammars. A DSL that can express any operation can express the destructive ones. Restrict the grammar to the operations you are willing to have executed, and let the parser enforce that boundary rather than a prompt.
Confusing valid with correct. This is the one that catches people, and it is worth stating plainly: a grammar constrains form, not truth. A model can emit perfectly valid HCL that references a subnet that does not exist, or a flawless SQL query against a table that was renamed last quarter. The parser will pass it. Schema validation is a floor, not a ceiling, and anything that matters needs a check against reality — existence, permissions, referential integrity — beyond the one the parser gives you for free.
Unreadable representations. A DSL humans cannot read will fail for social reasons long before it fails for technical ones. If reviewers cannot skim a diff, they will stop reviewing diffs. Keep the semantics small and the output diff-friendly.
Assuming validation is free. Someone has to write the schema, maintain the test suite, and keep the plan output meaningful. The rejecter is the deliverable. Underfunding it is the same as not having one.
Across the platform
The Anthus Platform is built this way throughout. Agent definitions are YAML. Scorecard configurations are declarative JSON. Evaluation harnesses are typed config objects rather than scripts. Human feedback loops are state machines with explicit transitions.
None of that is for elegance. It is so that each of those things can be validated, diffed, reviewed, and — when a model proposes a change to one of them — refused.
The first question
When we start an integration project, the question is not how to get a model talking to the system. That part has gotten easy and keeps getting easier.
The question is: what will say no?
If there is an answer — a compiler, a schema, a plan step, a test suite — the rest of the work is tractable, and the model becomes a fast, tireless contributor working inside a boundary that holds. If there is no answer, you do not have an integration strategy. You have a model making changes to production and a hope that they were the right ones.
Build the rejecter first.