Agent Runtimes Are Relearning Operating Systems
By wGrow Project Team ·
Step 45 of 50. The agent has been running for 22 minutes, accumulated roughly 80,000 tokens of context, queried three external APIs, and written partial results to a staging table. Then the upstream telemetry endpoint returns a 429. The retry logic fires. The rate limit holds. The loop stalls. You restart from step one, burning the same context budget and duplicating the same writes.
That is not a prompt engineering problem. That is a process management problem. Unix solved it in 1969.
The Function Call Illusion
Backend engineers tend to think about LLM-powered workflows the way they think about RPCs: send a request, get a response, handle the error code. The mental model is synchronous, stateless, and bounded. It works fine for anything that completes in under a second. It breaks catastrophically for anything that doesn’t.
A single completion is a function call. An agent loop that pulls context, selects tools, executes them, observes outputs, and iterates over several minutes is a background daemon. These are fundamentally different things with different failure modes and different operational requirements. Treating them the same way is what gets you into trouble.
How you frame the problem shapes what you build. Wire an agent into an HTTP handler with a 30-second timeout and that’s your architecture now. When it breaks, you debug the prompt. When it stalls, you restart it. When it corrupts state, you’re surprised — and you probably shouldn’t be. You built a longer function call with more side effects and less supervision, and called it a system boundary.
It isn’t.
Process Identity and Parent-Child Lineage

Early versions of our internal article-generation crew at wGrow ran as a single orchestration script. Researcher, drafter, fact-checker — all executing in sequence under one process, sharing one context. If the research step blocked on a slow web fetch, everything waited. If the drafter hit a rate limit, the whole pipeline sat idle. There was no way to inspect what was running, interrupt a stuck step, or restart selectively from a safe point.
We migrated to a parent-child model. The orchestrator acts as an init process: it spawns child agents, assigns each a unique run ID, and monitors health via heartbeat checks at configurable intervals. Every log line, tool call, and memory read carries that run ID. When a child gets stuck in a repetition loop — a genuine failure mode in long-context generation tasks — the orchestrator detects the stall and sends a termination signal. The child restarts from the last checkpoint.
This is fork() and wait(). It is also SIGKILL. None of it is novel. What is novel is that many agent frameworks require you to implement it yourself, in configuration files, if they support it at all.
One distinction worth stating plainly: a prompt asking the model to “please stop if you notice yourself repeating” is not a loop guard. It is a suggestion to a process with no obligation to comply. Hard termination signals are enforced by the runtime. They are not requested from the model.
Checkpoints and Resume Duties
Long-running agents will fail. This is not pessimism; it is a consequence of operating over networks, against rate-limited APIs, with context windows that fill up. The question is not whether they fail but what the runtime does when they do.
In the WaterDoctor diagnostic pipeline, we run agents against sensor fault data from water treatment systems. The loop runs multiple analysis passes, cross-references historical fault signatures, and produces structured findings. Early versions restarted the entire loop on failure. Two problems followed: writes to the findings table were duplicated because the agent had no record of completed passes, and token costs scaled with the frequency of upstream instability rather than diagnostic complexity. Neither of those is a prompt problem.
The fix was checkpointing at the runtime layer. Before any tool executes, the runtime writes a state snapshot to a persistent store: current step, memory contents, pending action, tool parameters. On recovery, the orchestrator reads the last valid checkpoint and rehydrates the agent from that state. The agent resumes from the next uncompleted step.
This is what a database write-ahead log does for transactions. The terminology differs; the principle is identical. The trade-off is real — every tool call now involves a write to persistent storage. For long-running pipelines with expensive steps, worth it. For short, stateless tasks, probably not.
State management is a runtime responsibility, not a model responsibility. Do not rely on the LLM’s in-context memory to reconstruct where it was. In-context memory disappears when the process dies. A checkpoint store does not.
Capability Manifests Define the Authority Boundary

In an early SME CRM integration, agent tool dispatch was driven entirely by prompt context. The agent received a task description, reasoned about which tools were appropriate, and called them. Authorization was implicit: if a tool appeared in the available-tools array, the agent could call it.
Permission bleed showed up within the first week of testing. An agent tasked with drafting a follow-up email reasoned — correctly, given its instructions — that it should check the customer’s recent activity. The “check customer activity” tool returned the full customer record, including fields the drafting task had no business reading. No rule existed against it. No tool-level scoping existed. The prompt had not anticipated that reasoning path, and there was no mechanism to catch it.
Tool wrappers are not authority boundaries. They are convenience wrappers with no access control semantics.
We moved to capability manifests: a structured declaration of what each agent run is permitted to access, defined at spawn time by the orchestrator and bound to the run ID. Before any tool executes, the runtime checks the manifest. If the call falls outside the declared capability set, it is rejected — without the model seeing an error in its context. The tool simply does not execute.
The manifest lives in the runtime, not in the prompt. Permissions enforced in natural language are preferences, not controls. Models do not maintain consistent preferences across a long context window, and they should not be expected to. This is not a criticism of the models; it is a recognition that access control belongs in the infrastructure layer.
The implementation complexity is real: the manifest schema must be designed, the dispatch layer must enforce it, and the orchestrator must understand each task’s scope well enough to populate it correctly. But that complexity already exists in your system, implicitly. Making it explicit is the point.
Accept the Inheritance
The pattern across all three problems is the same. We extracted capabilities from the operating system kernel, labeled them “agentic,” and were surprised when we needed the operating system back.
Process identity, parent-child supervision, checkpoints, capability manifests — these are solved problems. The solutions are in your operating system, your database, and your IAM documentation. The implementations are stable, well-documented, and not written in YAML.
If you are building agent workflows that run for more than a few minutes, touch more than one external system, or operate on behalf of users with different permission levels, you are building a distributed system. The choice is not whether to implement process management. It is whether to do so deliberately or to rediscover it through production incidents.
Push state management down to the runtime. Assign process IDs. Write checkpoints before tool execution. Enforce capabilities at dispatch time, not at prompt time. Some frameworks are beginning to expose these primitives directly; where yours does not, build them explicitly rather than papering over the gap with prompt instructions.
The YAML files will still be there. They will just be doing less of the wrong work.