There is a moment in systems design when you realise that a data structure is not just a convenience — it is a claim about the world. Choosing a queue says: these things happen in order, each one waiting for the one before. Choosing a graph says: these things have relationships, and the relationships are what matter, not the sequence.
When we started building Stratum’s orchestration layer, the obvious choice was a queue. Most agent frameworks use queues. An agent produces a list of actions; the system executes them one at a time; you move through the list. It is simple to reason about, simple to implement, and simple to explain. It is also wrong.
The queue’s hidden assumption
A sequential queue embeds an assumption so natural it barely feels like an assumption: that every action depends on every action before it. The agent reads a config file, then writes a new one, then restarts a service, then checks the health endpoint. Put those in a queue and they execute in order, each waiting for the previous to finish. That seems right.
But consider a more realistic agent workflow. The agent is deploying a change to a distributed system. It needs to update the config on three separate servers, verify each one is healthy, then send a summary notification. The three config updates are independent — server A does not care about server B. The health checks depend on the updates, but again, each health check depends only on its corresponding update, not on the others. The notification depends on all three health checks.
In a sequential queue, this workflow takes six steps end to end, each blocking the next. Server A updates. Server A checks health. Server B updates. Server B checks health. Server C updates. Server C checks health. Notification. Seven steps, seven wait cycles, one action at a time.
The structure of the work does not require this. Server A and server B and server C can all update simultaneously. Their health checks can run simultaneously. The notification can fire the moment all three checks pass. The queue imposes order where the work has none.
This is an efficiency argument, but it is also a safety argument. A queue that pauses everything when one action escalates is a queue that freezes the agent. If server A’s config update requires human approval — because it is modifying a production config without an undo path — the sequential queue stops all work until that approval arrives. Server B and server C, which are perfectly safe to update, sit idle waiting for a human to look at server A.
A system that behaves this way will train its users to approve escalations quickly and without scrutiny. The human in the loop becomes a rubber stamp. The safety mechanism defeats itself.
The dependency graph
Stratum’s orchestrator manages a directed acyclic graph of pending actions per agent session. Each node is an intent — a pre-execution declaration of what the agent wants to do. Each edge is a dependency — a declaration that this node cannot execute until that one completes.
The graph is acyclic by construction. If you can follow the edges and return to where you started, the workflow is invalid and is rejected at submission time. This is not a technical curiosity. A cycle means deadlock — two actions each waiting for the other — and the orchestrator detects and refuses it before a single action executes.
Within a valid graph, nodes advance through states: pending, ready, executing, escalated, completed, failed, cancelled. The scheduler runs after every state transition. It finds every node whose dependencies have all completed, transitions them to ready, acquires any resource locks they need, and begins executing them. Up to a configured concurrency limit, they execute simultaneously.
The escalation case is the interesting one. When a node escalates — when the reversibility engine classifies its action as requiring human approval — the node transitions to escalated and its resource locks are released. Independent nodes continue executing. The blocked branch of the graph waits. When the human approves, the node transitions back to ready, re-acquires its locks, and executes. When the human rejects, the node cancels, and cancellation propagates forward through all dependents: every action that was waiting for this one is cancelled with it, recursively, until the cascade exhausts itself.
This is the right behavior. A human who rejects a config update on server A is implicitly rejecting everything that depended on that update. The health check that was waiting for server A to complete becomes meaningless. The notification that was waiting for all three health checks to pass becomes unreachable. The graph encodes these relationships explicitly; the cascading cancellation enforces them automatically.
What this changes about safety
The safety argument for a dependency graph is not primarily about efficiency. It is about what human oversight actually means.
In a sequential queue, escalation means: stop everything, wait for a human, resume everything. The human’s decision gates all subsequent work regardless of whether that work is related to what they approved. This is blunt. It also creates pressure: the human knows that approving quickly unblocks everything, and that pressure distorts judgment.
In a dependency graph, escalation means: stop the affected branch, continue unaffected branches, surface the question to the human without urgency pressure. The human’s decision gates only the work that actually depends on their answer. They can take time because the system is not frozen. They can focus because only the relevant context is in front of them.
There is a second safety property that is less obvious. The dependency graph makes the agent’s plan legible before it executes. When an agent submits a graph of ten intents with explicit dependency declarations, the orchestrator knows the whole plan before any of it runs. An agent submitting to a sequential queue reveals its plan one step at a time; there is no way to see what it intended to do next. A graph submission is a complete statement of intent — auditable in full before a single action is taken.
We have not yet built the workspace surface that makes this visible to humans. When we do, a submitted graph will render as exactly that: a graph. Nodes waiting to execute, dependencies as edges, escalations surfacing as interactive decision points embedded in the plan. The human will see not just “delete this file” but “delete this file so that these three subsequent actions can proceed.” The decision will be made with full context.
The implementation reality
The theory is clean. The implementation surfaces interesting questions.
Resource locking was the first one. Two independent actions that both want to write to the same file are not actually independent — they will corrupt each other if they run simultaneously. The dependency graph captures logical dependencies declared by the agent, but physical resource conflicts must be detected and resolved by the orchestrator. Each action declares the resources it will touch; the orchestrator prevents concurrent execution of actions that share a resource by acquiring locks atomically before transitioning a node to executing. If all required locks are available, the node proceeds. If any lock is unavailable, the node stays ready and is retried when a lock releases.
Cycle detection was the second question. Detecting cycles in a graph submitted all at once is a tractable graph theory problem — Kahn’s algorithm works in linear time. The tricky part is that agents can submit intents incrementally, adding new nodes to an existing graph as a session progresses. Each incremental submission must verify that the new nodes do not introduce cycles with the existing graph. We run cycle detection on every submission, not just the first.
The cancellation cascade was the third. When a node fails or is rejected, cancellation must propagate to all dependents — and their dependents — until the cascade is exhausted. A naive recursive implementation overflows the call stack on deep graphs. We implemented it iteratively using a queue-based breadth-first traversal. For a graph with hundreds of nodes and long dependency chains, this matters.
What the queue gets right
It would be dishonest not to say this: the queue is right about one thing. It is far easier to reason about. An agent that always executes one action at a time, in order, with no concurrency, produces behavior that is trivially auditable. You look at the action log and read it top to bottom. The graph introduces genuine complexity — concurrent execution, lock contention, cascading cancellation — that the queue simply does not have.
We accept this complexity because the alternative is worse. A system that freezes under escalation, trains humans to approve quickly, and cannot represent the real structure of agent work is not a safe system. It is a system that appears safe while subtly undermining the conditions that make safety meaningful.
The dependency graph makes the agent’s intent explicit, the human’s decision precise, and the system’s behavior legible. That is the trade we are making.
Running it
The orchestrator is built. The dependency graph is live. You can submit intents with explicit dependencies today and watch the DAG execute, escalate, and cascade from a terminal.
The repository is github.com/mihok-labs/stratum. The README has everything you need to run it locally. If you have a strong opinion about where the design is wrong, open an issue.
Mihok Labs is an independent research and engineering organisation working on foundational architecture for agentic computing.