The thesis
An application is not written; it is assembled. Strip a real program down and something like 99% of it is pre-existing software recombined — storage, transport, serialization, scheduling, retries, auth, state. The part that is genuinely yours is thin, and it sits on top of a very large pile of things somebody has already built many times.
Because that pile is common, the industry keeps arriving at the same answer: the framework. Gather the recurring pieces, wire them together, hand the developer the assembled whole. It is a good instinct, and it has one structural defect that no amount of engineering removes.
A framework is a language prison
A framework composes inside a programming language. Its units are objects, modules and imports, and they can only be combined with other units written in the same language, for the same runtime, against the same conventions. Nothing crosses out.
So the duplication a framework promises to kill does not die. It relocates and multiplies — once per language, then once per framework within each language. Every ecosystem re-solves state, sessions, memory, tool dispatch, retries and credentials, and the results cannot be reused by anyone standing one language over. The pile is common; the solutions to it are not.
The AI generation of software made this loud rather than new. Each application vendors a provider SDK, holds a credential in its own environment, and reinvents session, memory and durable state for itself. Swapping a vendor is a refactor. Wiring two programs from different ecosystems together is a rewrite of one of them.
Drop the locus of composition
There are two places where pieces become an application, and the choice between them is architecture, not implementation detail.
In-language composition puts the joint inside the runtime. OS-level composition puts it beneath the language: the units are processes and system services, wired through the operating system’s own facilities — the shape of a microservices architecture kept local, which is also the Unix philosophy at its root.
Two consequences fall out immediately, and they are the whole argument:
- The composable blocks are language-free. The operating system composes processes, not objects. A block written in Rust and a block written in Python are the same kind of thing to it, and neither knows the other exists.
- The shared infrastructure lives once, offered from beneath rather than shipped inside every application. That is the platform effect, and it is not available to anything that composes in-language.
Which means the framework does not need to be built. The framework is the operating system, and what is missing is not a runtime but a userland — the commands, the durable shapes, and the services that a machine of this kind should have offered all along.
The three couplings
Wiring at this altitude is not one mechanism. It is three, and a real solution normally uses all of them.
Data now — the pipe. A byte stream from one stage’s output to the next’s input, between processes that both exist at that instant. Sockets, shared files and signals are the same coupling in other clothes. Each capability is one orthogonal command, so it composes with every other program on the machine, AI or not:
$ cat incident.log | llm --output-format typed --output-encoding json | chat-render
Nothing there is an integration. It is a pipeline, and the pieces do not know one another — llm emits a stream of typed events, chat-render is an ordinary filter that has never heard of a model, and either side can be replaced without telling the other.
State over time — the entity. What outlives the processes: a named thing of the application’s ontology, physically one Git repository, its branches being its instances. Composition between programs that never coexist — one run writes, a later run reads and extends, and versioning comes from the substrate rather than from a library:
$ entity create acme.note
$ entity new acme.note n1
$ entity act acme.note:n1 write -- /usr/local/bin/append-outline
The RAM is the disk. The developer’s object model survives intact while the object becomes durable, addressable and versioned — and the platform never reads inside it, which is exactly why a third party’s tooling can compose with state it has never seen. And because the thing on disk is a Git repository, publishing it to another machine is the substrate’s own operation rather than a feature somebody has to design.
Occurrence — the event. The publish/subscribe coupling, between parties who need not know one another. One program announces that something happened; whoever cares reacts. Subscribing is arming a command line at a coordinate, and the act that lands there runs it:
$ entity on acme.note:n1 write.landed -- /usr/local/bin/reindex
The body of an act runs in the act’s own private area rather than in the directory you typed from, so the command is named by absolute path.
This is the coupling that starts the other two, and it is the reason components may be transient rather than resident. A program is free to not exist between events only because something universal can wake it — a world of transient processes without a way to be woken is not lean, it is inert.
A component picks its coupling from its own logic. Nothing is forced into plumbing, and a piece may be ephemeral or long-lived as it needs.
The loop was never yours to give away
An agent is one wiring, not a new kind of component: reason, act, observe, repeat is a while around a single-turn filter, with the transcript on disk as memory. Every agent harness on offer is a chatbot runtime — a loop, tools, a context, a session store — and the operating system has been all four for fifty years. The shell is the loop, every program is a tool, the pipe is the context wire, the filesystem is the store.
The difference that decides everything: your script owns the while; the capability is a filter it calls. A framework inverts precisely this — it owns the loop and calls your code — and that inversion is the entire line between an SDK and a framework. Sophistication then lives in the wiring, not in a more complicated component. The full argument, with the code, is in the model.
Intelligence as a service of the machine
Everything above is older than AI, and it is what makes the AI part small.
Today a capability that lives outside the machine is consumed as a foreign cloud API: each application integrates an SDK, manages keys, calls remote endpoints. Intelligence is a dependency of each app, which is another way of saying there is no platform — there are N one-off integrations, each of them a driver wearing the wrong costume.
Model the capability as what it ontologically is — a device — and it stops being an integration. Vendors and models are device paths under a namespace the kernel owns, and a consumer opens one by name:
$ llm models
$ echo 'name the root cause' | llm -d /dev/llm/openai/gpt-4o-mini
The device path is a kernel namespace today, not a node in the host filesystem; enumerating it with ls and opening it with a raw POSIX open() is the canonical form and is not built designed. What the shape already buys is the part that matters: the consumer names a device instead of an endpoint, and it holds no credential, because the credential lives in the driver, below the surface it can reach — a device it is not entitled to fails at open, with eacces, rather than failing inside the application. It cannot leak what it never saw. Swapping a vendor swaps a driver, and the application does not change. The hard work — modelling a class of device well enough to survive three vendor generations — is done once, per class, rather than once per application by everyone. One subsystem per device class. Never per vendor, never per app.
The deepest consequence is for software that is not about AI at all. A turnstile never became an electronics product; it stayed a turnstile and gained a fifty-cent brain, because microcontrollers became shelf commodities. When intelligence costs one device away rather than an SDK decision, a key-management policy and an architecture review, an archiver or a package manager or a form validator can spend a little of it where it pays — a genuinely useful error message, a --help that understands what you meant. None of those justify integrating an AI SDK. All of them justify one open device.
And inference is one class among many. Speech in and speech out are subsystems beside it; vision, embeddings, and then out of AI entirely — messaging, mail, telephony designed. Each is a per-application SDK swamp today. Each is a device class with drivers, and the same subsystem is written once for the class rather than once per vendor.
This is what BentOS is for: a kernel and a userland, installed onto the operating system you already run, that put the joint beneath the language and hold external capability as devices. What of it runs today, what is designed, and what is still open is set out plainly in status.