ML Architecture

Linguistic State Machines

August 19, 2026llmagentsabilitiesstate machinesharness design

On why capability had to stop being prose.

I spent most of a year building software around language models, and the single idea that changed what I built was not about models at all. It was a reclassification. Somewhere between the third and fourth rewrite of Bonnie's capability system I stopped thinking of the model as an agent I was instructing and started thinking of it as a machine I was failing to program.

A language model is a linguistic state machine: its state is a sequence of tokens, its transition function is inference, and its alphabet is natural language. It has no other state, no other input, and no privileged channel.

Every word there is doing work, but the last clause is the one that costs you. There is no privileged channel. A state machine over natural language accepts any string as a legal input — that is exactly the property that makes it useful, and exactly the property that makes it unprogrammable by the means we usually reach for. You cannot hand it a configuration, because it has nowhere to put one. You can only hand it more alphabet.

The context window is the tape

Follow the framing one step and something uncomfortable falls out.

If the model is the machine and language is the alphabet, then the context window is the input tape, and everything on the tape has the same type. The system prompt is a string. The user's message is a string. A document retrieved from somewhere else is a string. And a SKILL.md loaded because the router thought it was relevant is a string.

They are not the same in intent — the author of the system prompt meant it as law and the retrieved document meant nothing at all. But intent is not a property the machine can read. The machine reads position and content. So the practical status of a skill file is not "configuration the model runs under"; it is an input symbol that happens to be phrased imperatively, competing for attention with every other symbol on the tape, including symbols written by people who are not you.

That is the whole critique, and it is structural rather than qualitative. A better-written skill file is a better input symbol. It is still an input symbol.

Credit where it is due

I want to be careful here, because the design being critiqued is genuinely good design.

Progressive disclosure — preload names and descriptions cheaply, load the body when it becomes relevant, read the deeper files on demand — is the right shape for the problem it solves. A well-written skill file measurably focuses a model. It is portable in the sense that matters most day to day: it is a folder, you can read it, you can diff it, you can email it to someone. Compared to the alternative most teams were shipping in 2024 — one enormous system prompt accreting rules like sediment — it is a real advance.

So when I say SKILL.md was a demo, I mean it in the honest sense of the word. A demo proves the intent is legible. It showed that you can express "here is a domain and how to work in it" in a form the model reliably picks up, and that you can do it without a build step or a runtime. That is a genuine result, and it is the result I needed before I could see what was missing.

What it is not is a harness. And the difference only becomes visible when you stop asking the model to do a task and start asking it to operate a machine that belongs to someone else.

Four things a symbol on the tape cannot be

Each of these is a consequence of the framing, not a complaint about markdown.

It cannot be removed. A state machine's transition function consumes what is on the tape; there is no operation that un-reads a symbol. Once a skill body has entered the conversation, only lossy compaction gets rid of it, and compaction is not a control surface — it is pressure relief. Which means capability, in that model, is monotonic: you can add, never subtract. That is a strange property for anything you would call an installation.

It cannot resolve a dependency. A skill file can say "use the calendar" but it cannot ask whether a calendar exists, activate when one appears, or stand down when one is removed. Composition happens because the model happened to read two files and drew the connection. That is not resolution; that is coincidence with good odds. And coincidence with good odds is exactly the kind of thing that works in every demo and fails in the long tail.

It cannot enforce. This is the sharpest one. A symbol on the tape influences the next transition — it does not constrain the set of legal transitions. The distinction sounds academic until the day the model attends elsewhere and does the thing the file said not to do, at which point you discover that your safety property was a sentence. The ecosystem knows this, which is why the guidance for anything that must happen points you at a different mechanism entirely.

It cannot be bounded. If capability arrives as prose, then whoever authors the capability writes directly onto the tape — and now the trust question is not "is this package well-behaved" but "is this text persuasive." Free-form prose from a third party, mixed into the same channel as your instructions, is an authority laundering machine. There is no amount of review that turns arbitrary text into a contract.

The ambient book walks this same territory mechanism by mechanism, against Bonnie's implementation. What I want here is the derivation, because the derivation is what tells you the fix cannot be "write better skill files."

What the framing forced

Bonnie's answer is the Ability,1 and I did not arrive at its design by taste. Each decision is what remains once you accept that the model is a state machine you cannot configure through its alphabet.

The first move is the one everything else hangs on: if you cannot put configuration on the tape, put it somewhere the tape cannot reach. Capability lives outside the model entirely — as a validated package of typed, bounded data. Not prose that argues for behavior, but declarations a validator can accept or refuse before a conversation ever starts. Bonnie's architecture docs state the rule flatly: "Schemas are data, never executable extensions." An Ability declares what it needs, what effects it may have, and under what limits; it does not get to write a sentence the model will read as law.

The second move is that the runtime decides what is executable, not the model. Routing happens before inference: what capability is even in play this turn is resolved against what is actually installed and ready, and the model is handed a roster it did not assemble and cannot rewrite. This inverts the usual arrangement. The model is no longer a decision-maker persuaded by documents — it is, to borrow the phrasing from Bonnie's own design notes, closer to "a schema-conditioned routine compiler, not a miniature conversational assistant." It proposes moves within a set that was bounded before it spoke.

The third move follows from removability. If capability is data resolved per turn rather than text accumulated in a conversation, then unloading is just the absence of a declaration next turn. Remove the package and the Skill is gone — not compacted away, not lingering in a summary. And an unmet dependency is not an error but a dormancy: the capability exists and is simply not available right now, which is the behavior every other composable system converged on decades ago.

The fourth is subtler and is the one I am most attached to. Abilities declare a paradigm — whether they encode a portable craft or expertise in one specific application. The schema puts it plainly: one can be good at design and an expert in Sketch, while being good at design and an amateur in Figma. The split matters because it decides what personalization is a fact about. How you write is a fact about your writing, not about the editor you happened to write in — so it travels to an application that did not exist when the system learned it. You only get that if capability is structured. Prose cannot be keyed by anything, because prose has no keys.

Diagram
Rendering diagram

The part that is not a critique

None of this says the skill-file idea was wrong. It says it was answering a different question — how do I give one model deep reference material on demand — and answering it well. The question I ended up with was how do I build a computational harness around a machine whose only input is language, such that the machine's non-determinism is bounded rather than trusted.

Those questions have different answers, and conflating them is how you end up shipping something that demos beautifully and cannot be operated. The tell is always the same: if the thing that stops a bad outcome is a sentence, you do not have a harness. You have a well-phrased hope.

The reclassification is what I would keep if I could keep only one thing from the past year. Treat the model as a linguistic state machine and the architecture questions answer themselves in the right order — what is state, what is input, who owns the transition function, and which of those a package author is allowed to touch. The answer to the last one, it turns out, is none of them.

You cannot program a state machine by writing to its alphabet or you just end up arguing with it.

Footnotes

  1. Three nouns, three jobs: an Ability is what Bonnie knows how to do, a Skill is one machine-readable instruction inside it, and a Capability is the contract — effect, permissions, limits — that makes the Skill safe to run. The full treatment, including the per-turn snapshot and a six-pair comparison against SKILL.md, is chapter 7 of the ambient book: Abilities: bounded data, frozen turns. ↩