Agents are reinventing the operating system
Agent orchestrators are repeating the history of operating systems, mechanism by mechanism. Today they resemble it; tomorrow they will be a copy. Parallels, differences and predictions.
I recently opened the code of Symphony, the coding agent orchestrator OpenAI released in 2026. It is an Elixir service that reads an issue board, starts an agent for each eligible ticket and lets it work in its own directory until the ticket reaches human review. I went straight to the configuration schema and found this:
field(:max_concurrent_agents, :integer, default: 10)
field(:max_turns, :integer, default: 20)
field(:max_retry_backoff_ms, :integer, default: 300_000)
field(:max_concurrent_agents_by_state, :map, default: %{})
A global concurrency limit, a per-queue limit, a maximum number of turns before giving up the spot and exponential backoff for jobs that fail. A few lines further down are the polling interval (30 seconds by default), a stall timeout that kills any worker that stops showing signs of life, and a list of SSH hosts with their own cap of agents per machine.
Strip the names and that is the configuration of a process scheduler. The SPEC.md describes itself the same way: “Symphony is a scheduler/runner and tracker reader”.
This is not a Symphony quirk. Whenever someone tries to put many agents to work at once, they end up building the same pieces that operating systems built over sixty years, for the same reasons, though not in the same order. This post walks through that history era by era, marks where the analogy does not hold yet and closes with concrete predictions.
The thesis: a resemblance today, a copy tomorrow
There are two ways to read the resemblance. The first is as a metaphor: “agents are like processes”, a handy line for a talk and not much more. The second is as an engineering convergence: when you have an expensive shared resource, many jobs competing for it and jobs that fail or misbehave, there are few possible solutions, and computing already found them.
My reading is that we are halfway there today: the mechanisms look alike (there is a scheduler, isolation, memory paging, supervision), but there are still deep differences that rule out calling it a copy. Further down I explain why I think that gap is going to close.
Looking at LLMs through an operating system lens is not a new idea. Andrej Karpathy popularized the “LLM OS” image in late 2023, an operating system built around the model. MemGPT (Packer et al., 2023) took virtual memory as the model for managing context, and AIOS (Mei et al., 2024) proposed an operating system for agents with its own scheduler and context manager. This post does not propose a new system: it looks at orchestrators already running in production and follows OS history era by era to see which mechanisms come back. I use Symphony as the main case because its specification is public and says precisely what it does; when other systems show the same thing, I mention them.
Laying the two histories on top of each other reveals another difference: speed. Operating systems went through their stages one after another, over sixty years. Agent systems are going through them in a few years and out of order: context paging became common before parallel agents, and the standard interface to tools arrived before capabilities.
Era 1: scarcity and batch
In the early years of commercial computing, the machine was extremely expensive and did one thing at a time. A programmer handed in their job on punched cards, a human operator loaded it, the machine ran it from start to finish and the result came back printed hours later. The first resident monitors automated the switch from one job to the next, but the logic stayed the same: one job, the whole machine, and wait.
The first stage of LLMs felt similar, at least from the user’s side. You wrote a prompt, sent it, waited for the full answer and, if the result fed the next step, copied it by hand into the next prompt. You were the operator. Working memory was a context window of 4K or 8K tokens, as scarce as the magnetic core memory of an IBM 7094: every token you added pushed another one out.
The economics, however, ran the other way. In the fifties, the machine was so expensive that leaving it idle while a human loaded the next job was an unacceptable waste. With the first LLMs, the model waited for nobody: the provider shared it among millions of users. What was wasted was the person’s time, acting as the operator by copying results from one prompt to the next. The work pattern was batch; the resource being lost was a different one.
Era 2: multiprogramming and time-sharing
In 1959, Christopher Strachey proposed that a large computer could serve several users at once if it divided its time among them. In 1961, Fernando Corbató’s team at MIT got CTSS running, one of the first time-sharing systems, and published it in 1962. The central idea was simple: while a program waits (for a disk, a tape, a person), the CPU can move ahead with another one. To keep that from degenerating, each program gets a time quantum and, when it runs out, goes back to the queue. In 1968, Dijkstra published the structure of the THE system and, with it, semaphores to coordinate processes that share resources, a problem that shows up again in Era 5.
Now look at Symphony again. The SPEC describes each tick like this: reconcile running work, validate the configuration, fetch candidate issues, sort them by priority and dispatch while slots remain. The number of slots is computed as max(max_concurrent_agents - running_count, 0).
The word “agent” hides two different things, and separating them puts the whole analogy in order. The CPU is the model: it keeps nothing between one call and the next, thousands of customers share it, and its capacity is measured in tokens per second. The agent is the process: it has a program (its prompt and its tools), its own state (the history and the plan) and a lifecycle, and it takes turns using the model. Each call is a slice of CPU time. The ticket resembles a UNIX job: the unit of work the system admits and assigns a process to.
The part that caught my attention most is max_turns. A worker can run at most 20 agent turns in one session. When it uses them up, it exits cleanly and the orchestrator schedules a “continuation” one second later: it checks again whether the issue is still active and, if a slot is free, dispatches it again. If there is no slot, it stays queued with the error no available orchestrator slots. The agent does not decide when to yield; the scheduler evicts it by quota and puts it back in the queue, as in round-robin. With one difference: the unit is not a time slice but a full agent turn, which can include many calls to the model and to tools, and when it is dispatched again the worker starts a new session on the same workspace.
Priority is there too: issues are sorted by priority from 1 to 4, then by age and then by identifier. And max_concurrent_agents_by_state limits how many agents work in each board state, which amounts to having queues with their own limits.
Symphony is not the only case. Anthropic’s multi-agent research system follows the orchestrator-worker pattern: a lead agent plans and launches subagents that search in parallel, each with its own context window, and then combines their results.
Strachey’s idea holds, with a curious detail. When an agent runs the tests or waits for a build within its turn, it is not using the model, but it still takes up its slot, because slots are counted per running worker and not per model use. The model stays free for the provider’s other customers; the orchestrator’s concurrency limit does not.
Era 3: virtual memory and the working set
Main memory was the other scarce resource. In 1962, Tom Kilburn’s team in Manchester presented the Atlas one-level storage system: the program saw a large, uniform address space, and the hardware and the supervisor moved pages between core memory and the magnetic drum without the programmer noticing. It was the birth of virtual memory.
Virtual memory brought its own pathology. In 1968, Peter Denning formalized the working set: the set of pages a program actively uses within a time window. That same year he explained thrashing: if the system cannot keep each process’s working set in memory, processes spend more time fetching pages than executing. In his 1970 survey he showed why raising the degree of multiprogramming beyond a certain point makes total throughput collapse.
LLMs repeated this chapter, and it is worth separating the layers:
- MemGPT (Packer et al., 2023) proposed treating the context window as main memory and external storage as disk, with the model itself deciding what to load and what to evict through function calls. The paper’s title is Towards LLMs as Operating Systems. This is paging at the agent layer.
- PagedAttention (Kwon et al., SOSP 2023), the basis of vLLM, took paging literally, but inside the inference server: it splits the KV cache into fixed-size blocks that need not be contiguous, with a table that maps logical blocks to physical ones. It solved memory fragmentation in inference and multiplied throughput by 2 to 4 over previous systems. Following the analogy, this paging happens inside the CPU, not in the process’s memory.
- Context rot (Chroma, 2025) measured across 18 models that performance degrades unevenly as context grows, even when the task does not change. Here the analogy with Denning flips: thrashing appears when there is too little memory for the working set, and context rot appears when the window holds too much. What repeats is the underlying lesson: a process that works with what it actually needs does better than one that loads everything it has.
The compaction that coding agents do today (summarizing the conversation when the window fills up and carrying on with the summary) is lossy swapping. And delegating a search to a subagent so it returns only the conclusion is, in Denning’s terms, a way of protecting the main agent’s working set.
Era 4: protection and isolation
When several programs share a machine, the next problem is keeping one from reading or breaking another’s data. Multics (Corbató and Vyssotsky, 1965) put protection at the center of the design, with per-segment access control and, later, protection rings. In 1973, Butler Lampson described the confinement problem: how to guarantee that a program you lend data to does not leak it through some side channel. In 1974, Popek and Goldberg formalized what an architecture needs to be safely virtualizable, the theoretical basis of the virtual machines used today to isolate coding agents. And in 1975, Saltzer and Schroeder summarized the design principles still taught today: least privilege, fail-safe defaults, complete mediation.
Symphony implements the basic version of all this. The SPEC requires each issue to have its own workspace and the agent’s commands to run inside that directory, and leaves the sandbox and approval policy to each implementation. The Elixir reference implementation defaults to workspace-write and rejects requests to escalate the sandbox. There are after_create and before_remove hooks that work like process creation and teardown: clone the repo, install dependencies, clean up at the end. And the tracker credentials live on the host: the SPEC notes that the agent’s child process does not need to see the raw secret.
In 1988, Norm Hardy published The Confused Deputy: a compiler with permission to write a billing file was tricked by a user into overwriting it, because the compiler could not tell the authority it held on its own from the authority the user was asking it to use. Hardy argued that this kind of error is the reason capabilities exist: permissions that travel with the request instead of belonging to the program.
Indirect prompt injection (Greshake et al., 2023) is the confused deputy under another name. An agent with access to your email reads a message that contains instructions, and carries them out with your authority. Simon Willison summed it up as the lethal trifecta: access to private data, exposure to untrusted content and the ability to communicate externally. With all three together, the agent can be turned into an exfiltration channel, a direct version of Lampson’s confinement problem.
The most solid answer so far came with CaMeL (Debenedetti et al., 2025), which separates control flow from data flow and attaches capabilities to each value to decide which tools may receive it. Thirty-seven years later, Hardy’s proposal returns applied to agents, at a cost: on the AgentDojo benchmark, CaMeL solves fewer tasks than an undefended agent in exchange for its guarantees.
Era 5: IPC, microkernels and the system interface
For processes to collaborate, they need a way to communicate. In 1970, Per Brinch Hansen described the RC 4000 nucleus: a minimal kernel that only offered process creation and message passing, leaving scheduling and resource policies to replaceable parent processes. Mach (Accetta et al., 1986) turned message passing into a foundation for UNIX, and Jochen Liedtke (1995) showed that a microkernel could be fast if designed with discipline. The idea that a small kernel beats one that tries to do everything comes back in prediction 5.
Brinch Hansen’s separation of mechanism and policy shows up again in Symphony: the service implements the mechanism (polling, slots, retries, workspaces) and the policy lives in a versioned WORKFLOW.md inside the repository, with the agent’s prompt and the run parameters.
For the outward interface, the parallel is the Model Context Protocol (Anthropic, 2024). MCP defines how an application exposes tools and data sources to a model, regardless of who implements them. It works as a mix of a syscall interface and a driver model: the agent does not know how access to GitHub or the database is built; it knows there is an operation with a contract. Agent-to-agent protocols, such as A2A, take the place of inter-process communication.
Toward tools, MCP already works as a de facto standard. For coordination between agents there is still no equivalent of POSIX. In operating systems, getting from the first versions of UNIX to a common standard took about twenty years, with the wars between variants in the late eighties along the way.
When processes communicate and share resources, the risk of blocking each other appears too. In 1971, Coffman, Elphick and Shoshani described the four necessary conditions for a deadlock: mutual exclusion, hold and wait, no preemption and circular wait. All four already show up in multi-agent systems: two agents each waiting for the other’s review, or an agent holding a lock on a branch while waiting for a result another agent cannot produce without that branch. The classic recipe is to break one of the four conditions. Symphony breaks circular wait by design, because each agent works in its own workspace and does not wait for other agents; and if one stops making progress, the stall timeout stops it.
Era 6: failure and supervision
When there are many processes, some will fail. The most complete study so far of how multi-agent systems fail is MAST (Cemri et al., 2025), which classifies 14 failure modes into three categories: system design issues, inter-agent misalignment and verification failures. Several of those modes have proper names in the concurrency literature: losing state between steps resembles a lost update, and waits that never resolve resemble livelock or starvation.
Symphony’s answer to failure is the most literal part of the whole analogy, because it did not reinvent it: it inherited it. It is written in Elixir on the Erlang virtual machine. The root supervisor uses the one_for_one strategy; below it, an AgentRuntimeSupervisor with the one_for_all strategy groups the orchestrator and the Task.Supervisor that starts the workers. OTP does not restart the workers: the orchestrator monitors them and, when one goes down, schedules the retry with exponential backoff. All of this comes from Joe Armstrong’s thesis (2003), which formalized how Ericsson built reliable telecom systems out of components that fail: isolated processes, no shared memory, supervised by other processes whose only job is to restart them. The philosophy is summed up as let it crash: do not try to make the process defend itself against everything; let it fail fast and let someone outside bring it back to a known state.
For agents, that philosophy fits very well. Past a certain point, an agent that drifts does not fix itself from the inside with more prompting. Symphony gives it some room, because each continuation turn sends guidance to the same thread until it reaches max_turns; when that is not enough, the agent is killed, the workspace is cleaned if needed and it is retried with backoff. Symphony’s stall_timeout_ms (5 minutes by default) is a watchdog: if the agent emits no events for that long, the orchestrator terminates the worker and queues a retry.
Era 7: from the OS to the cluster
The last stage of OS history that is already repeating is the jump from one machine to many. Borg (Verma et al., 2015) described how Google scheduled hundreds of thousands of jobs across tens of thousands of machines, with quotas, priorities and preemption. Kubernetes inherited from Borg and Omega its most lasting idea, which Burns et al. explained in 2016: the reconciliation loop. Instead of executing commands, the system continuously compares the desired state with the observed state and acts to close the difference.
Symphony uses the same word and the same pattern, as the tick diagram in Era 2 shows. On every tick, before dispatching anything, it reconciles: it checks again the state of every issue that has a running agent and, if the ticket moved to a terminal state or stopped being eligible, it stops the worker. The desired state lives on the issue board; the observed state, in the running agents. And with ssh_hosts and max_concurrent_agents_per_host, the orchestrator already spreads agents across several machines. It works as a small cluster scheduler, still without Borg’s bin packing or preemption.
The balance, era by era
If I put each era next to its counterpart and ask how close it is to being a copy, this is the result:
- Batch One job at a time, a human as operatorResident monitor ~1955 Single-turn chat 2022Similar
- Multiprogramming Quantum, round-robin, priority queuesCTSS 1962 Symphony 2026Similar
- Virtual memory Paging with a block tableAtlas 1962 PagedAttention 2023Identical
- Working set Keeping only what is needed loadedDenning 1968 Context rot 2025Similar
- Protection Capabilities, least privilegeMultics 1965 · Hardy 1988 CaMeL 2025Similar
- Tool interface Syscalls and a driver modelUNIX 1974 MCP 2024Identical
- Coordination standard A common contract between processesPOSIX 1988 A2A 2025Not yet
- Supervision OTP supervisors, let it crashErlang 1986 Symphony 2026Inherited
- Cluster Reconciliation loop across hostsBorg 2015 Symphony 2026Similar
- Identical
- same mechanism, different name
- Inherited
- not even reimplemented: same runtime
- Similar
- the problem is named and solved in print, not yet the norm
- Not yet
- candidates exist, no standard
Almost every row lands on “similar”: the mechanism is there, but with differences that still matter. The predictions at the end come from those differences.
Where it does not match yet
The map has limits. There are four differences that, today, rule out calling it a copy.
The CPU is not deterministic. A UNIX process run twice with the same input does the same thing, because the processor executes each instruction the same way every time. The model does not: the same agent, with the same prompt, can take a different path. Paradoxically, this fits Armstrong’s philosophy instead of breaking it. Jim Gray observed in 1985 that most production failures are transient, Heisenbugs that do not reproduce on retry, and let it crash works precisely because the second run can go differently. The difference is that, with agents, that variability is no longer only in the environment: it is in the CPU itself, and retrying also means rolling the dice again.
The scarce resource is different. Operating systems optimized CPU cycles and memory pages. Agent orchestrators optimize tokens, money and, above all, human attention. Anthropic reported that its multi-agent research system uses about 15 times more tokens than a regular chat. And the final state of a successful Symphony run is often Human Review, not Done: the work ends up in a person’s queue.
The process can be talked into things. A malicious process in an operating system is code written by someone with bad intentions, or legitimate code into which an attacker injected instructions by exploiting a bug, such as a buffer overflow. An agent can turn hostile by reading an issue, a README or a web page, without anyone exploiting any bug: in an LLM, data and instructions travel over the same channel by design. Prompt injection takes the place code injection once held, with the difference that there is no bug to fix.
The program is written in natural language. An agent’s “specification” is a prompt, and the scheduler is sometimes an LLM too, deciding how to split the work. That blurs the line between kernel and application that Dijkstra and Brinch Hansen drew so carefully.
Why I think it will converge
These four differences are real, but none of them is being solved with new ideas. They are being solved with OS mechanisms:
- Non-determinism is contained the way unreliable hardware was: with supervision, checkpoints, idempotency and external verification (tests, CI, review).
- Token cost is managed the way CPU time was: with quotas, concurrency limits and priorities.
- The mix of data and instructions is tackled the way Hardy proposed in 1988: separating authority from request with capabilities, which is what CaMeL does.
- The confusion between kernel and application is sorted out by separating mechanism and policy, which is what Symphony does by keeping the scheduler in code and the policy in
WORKFLOW.md.
Every time a gap closes, the architecture of an agent system looks a bit more like an operating system, and the distance shrinks in one direction only.
Predictions
These are the predictions that follow from the analogy. Each has a date and a criterion for calling it fulfilled.
1. cgroups-style token quotas (before the end of 2027). Orchestrators will stop limiting only the number of concurrent agents and will limit budget: tokens per task, per team and per priority, with low-priority agents preempted when the quota runs out. Model gateways already offer per-team or per-key budgets; what is missing is for the orchestrator to use them to decide whom to pause. max_concurrent_agents limits how many processes run at once; the next step in history was limiting how much each one consumes. I’ll call it fulfilled if one of the most widely used coding agent orchestrators lets you set a per-task token budget and pauses or preempts lower-priority agents when it runs out.
2. Degradation from excess context will get a name and a metric (2027). Today we talk about context rot as a phenomenon we observe. My bet is that frameworks will expose a metric along the lines of “context tokens per unit of useful progress” and an admission control that refuses to load more tools or more history when that metric degrades. What carries over from Denning is not the mechanism, which works the other way around here, but the idea of measuring how much of what is loaded actually gets used. I’ll call it fulfilled if a widely used agent framework or harness exposes that metric and uses it to decide what to load into context.
3. Capabilities by default (2027-2028). Per-agent permissions (“this agent can use GitHub”) will give way to per-task and per-datum permissions (“this value, which came from an external issue, cannot reach a tool that writes outward”). In operating systems, capabilities were the research proposal that only some systems adopted (KeyKOS, seL4, Capsicum, Fuchsia), while most stayed with access control lists. With agents, the cost of not adopting them is far more visible, and CaMeL already showed they are viable, though at a cost in tasks solved. I’ll call it fulfilled if at least one widely used agent framework ships per-datum or per-task permissions by default, not just per-tool ones.
4. A fight over the POSIX of agents (2027-2029). MCP won the first round as the interface to tools. The coming fight is over the standard for coordination between agents and over the format of the “work contract” (what WORKFLOW.md is in Symphony). There will be incompatible variants, as there were between System V and BSD, and the standard that wins will not be the most complete one. I’ll call it fulfilled if before 2029 at least two incompatible standards for coordinating agents coexist, each backed by a major vendor.
5. Unix beats Multics again (2028). Multics tried to solve everything and UNIX won by being small and composable. I think the orchestrators that prevail will be the ones that do little and do it well, like Symphony, which defines itself as a scheduler and ticket reader, over the multi-agent platforms that try to solve planning, memory, evaluation and governance in a single product. I’ll call it fulfilled if in 2028 the most adopted coding agent orchestrators delegate memory, evaluation and governance to external tools instead of building them in.
6. Human review will get its own scheduler (2027). In operating systems, once the CPU got fast, the bottleneck moved to the disk and processes started spending most of their time waiting for I/O. The same is happening with agents: producing code is cheap and reviewing it is expensive, and it already shows in the runs that end in Human Review. I expect the next wave of tools to be not more capable agents, but scheduling of human review: grouping changes, ranking them by risk, deciding what does not need review. They would be the equivalent of the disk schedulers that reordered requests to minimize head movement. I’ll call it fulfilled if in 2027 tools appear whose main product is ordering, grouping or filtering human review of agent work.
Closing
Symphony shows what you gain by knowing the history: instead of inventing a concurrency model, it chose a platform that already brought almost forty years of supervision proven in telecom. That decision, more than any prompt, is what makes the system operable. Anyone who builds an agent orchestrator without knowing that history will rediscover thrashing, the confused deputy and deadlocks in production.
If you are designing a system with several agents working in parallel, or trying to stop the one you have from failing in strange ways, that is the kind of problem I am interested in. You can write to me.
References
Operating systems history
- Christopher Strachey, Time Sharing in Large Fast Computers, International Conference on Information Processing (UNESCO), 1959.
- F. J. Corbató, M. Merwin-Daggett, R. C. Daley, An Experimental Time-Sharing System, AFIPS Spring Joint Computer Conference, 1962.
- T. Kilburn, D. B. G. Edwards, M. J. Lanigan, F. H. Sumner, One-Level Storage System, IRE Transactions on Electronic Computers, 1962.
- F. J. Corbató, V. A. Vyssotsky, Introduction and Overview of the Multics System, AFIPS Fall Joint Computer Conference, 1965.
- Edsger W. Dijkstra, The Structure of the “THE”-Multiprogramming System, Communications of the ACM, 1968.
- Peter J. Denning, The Working Set Model for Program Behavior, Communications of the ACM, 1968.
- Peter J. Denning, Thrashing: Its Causes and Prevention, AFIPS Fall Joint Computer Conference, 1968.
- Peter J. Denning, Virtual Memory, ACM Computing Surveys, 1970.
- Per Brinch Hansen, The Nucleus of a Multiprogramming System, Communications of the ACM, 1970.
- E. G. Coffman, M. Elphick, A. Shoshani, System Deadlocks, ACM Computing Surveys, 1971.
- Butler W. Lampson, A Note on the Confinement Problem, Communications of the ACM, 1973.
- Dennis M. Ritchie, Ken Thompson, The UNIX Time-Sharing System, Communications of the ACM, 1974.
- Gerald J. Popek, Robert P. Goldberg, Formal Requirements for Virtualizable Third Generation Architectures, Communications of the ACM, 1974.
- Jerome H. Saltzer, Michael D. Schroeder, The Protection of Information in Computer Systems, Proceedings of the IEEE, 1975.
- Jim Gray, Why Do Computers Stop and What Can Be Done About It?, Tandem Technical Report 85.7, 1985.
- Mike Accetta et al., Mach: A New Kernel Foundation for UNIX Development, USENIX Summer Conference, 1986.
- Norm Hardy, The Confused Deputy (or why capabilities might have been invented), ACM SIGOPS Operating Systems Review, 1988.
- Jochen Liedtke, On Micro-Kernel Construction, SOSP, 1995.
- Joe Armstrong, Making Reliable Distributed Systems in the Presence of Software Errors, PhD thesis, KTH, 2003.
- Abhishek Verma et al., Large-Scale Cluster Management at Google with Borg, EuroSys, 2015.
- Brendan Burns, Brian Grant, David Oppenheimer, Eric Brewer, John Wilkes, Borg, Omega, and Kubernetes, Communications of the ACM, 2016.
LLMs and agents
- Kai Greshake et al., Not What You’ve Signed Up For: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection, 2023.
- Charles Packer et al., MemGPT: Towards LLMs as Operating Systems, 2023.
- Woosuk Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention, SOSP, 2023.
- Yingqiang Ge et al., LLM as OS, Agents as Apps: Envisioning AIOS, Agents and the AIOS-Agent Ecosystem, 2023.
- Kai Mei et al., AIOS: LLM Agent Operating System, 2024.
- Mert Cemri et al., Why Do Multi-Agent LLM Systems Fail?, 2025.
- Edoardo Debenedetti et al., Defeating Prompt Injections by Design, 2025.
Non-academic sources
- OpenAI, Symphony: README and SPEC.md, 2026.
- Andrej Karpathy, Intro to Large Language Models, 2023.
- Anthropic, Introducing the Model Context Protocol, 2024.
- Anthropic, How we built our multi-agent research system, 2025.
- Kelly Hong, Anton Troynikov, Jeff Huber (Chroma), Context Rot: How Increasing Input Tokens Impacts LLM Performance, 2025.
- Simon Willison, The lethal trifecta for AI agents, 2025.