Most agent workflows start life as control flow. A function calls the model, checks the result, maybe loops, maybe branches, calls another tool, and returns. It works in the demo. Then production adds retries, interruptions, human approvals, and partial failures, and that tidy function turns into a thicket of if-statements nobody can hold in their head. When a task gets stuck, the honest answer to "what is it doing right now" becomes "let me read the logs and guess."
There is an old, boring fix for this, and it works better for agents than almost anything newer: model the workflow as an explicit state machine. Name the states a task can be in, name the transitions allowed between them, and make every move from one state to the next a deliberate, recorded event. The chaos does not go away, but it becomes legible.
What an agent state machine actually is
An agent state machine is a small, explicit description of two things: the states a unit of work can occupy, and the transitions that are allowed between them.
For a coding agent, the states might be something like queued, planning, implementing, in review, deploying, done, plus the ones people forget until they get burned: blocked and failed. The transitions are the edges: planning can move to implementing, implementing can move to in review, in review can move back to implementing or forward to deploying. Each edge can carry a guard, a condition that must hold before the move is legal.
The important shift is that the state is data, not an implicit position in a call stack. At any moment you can ask a task what state it is in and get a real answer, because the state is written down, not inferred from where the code happens to be paused.
Why implicit control flow fails for agents
Ordinary functions get away with implicit state because they are deterministic and fast. Agent workflows are neither. Three things break the tidy version.
The model is nondeterministic. The same input can take a different path on different runs, so the branch structure is not fixed and you cannot reason about it the way you would a normal function.
Steps fail and retry. Public reports put tool-call retry rates in the range of 15 to 30 percent, and a retried step re-enters the flow partway through. If your position in the workflow lives in the call stack, a retry either restarts everything or resumes in a place your code did not expect.
Work gets interrupted. A process restarts, a machine dies, a task waits hours for a human. Implicit control flow does not survive a restart, because the stack is gone. Explicit state does, because it was written down.
Put those together and the reason for the state machine becomes obvious. It is the thing that lets a workflow pause, fail, retry, and resume without losing track of where it was.
Gates become transitions, not comments
Here is where the pattern earns its keep for anything that ships to production. A human approval, the moment someone signs off before code merges or deploys, is not a step you politely wait for. It is a transition that only a specific actor is allowed to make.
Model it that way and the guarantee becomes structural. The edge from in review to deploying exists only when a human approval has been recorded. Nothing else can cross it: not the agent, not a retry, not a race between two workers. An unapproved attempt to move to deploying is treated exactly like any other illegal transition, which is to say it is refused. The gate stops being a convention you hope everyone respects and becomes a property of the graph. How you enforce that at the storage layer is its own engineering problem, but the modeling decision, making the gate an edge rather than a checkpoint in code, is what makes the guarantee possible at all.
What you get for the trouble
Four things, and they compound.
Observability. Because state is explicit and every transition is an event, you always know what any task is doing and how it got there. "What is it doing right now" has an answer you can query, and "how did it get into this state" has an audit trail.
Resumability. A workflow modeled as states can be picked up from its last recorded state after any interruption, rather than restarted from the top. That is the whole subject of resumability, surviving an interruption mid-task, and it is nearly free once state is explicit.
Testability. You can test transitions in isolation. Does implementing move to in review only when tests pass? Does an illegal transition get refused? These are unit tests against a graph, not end-to-end runs against a nondeterministic model.
Safety against duplicates and races. When a transition is a guarded, recorded move, two workers cannot both advance the same task, because the second attempt sees the state has already changed. This pairs directly with idempotency and retries and with preventing duplicate work when a task fires twice; the state machine is where those guarantees live.
How to introduce one without over-engineering
You do not need a heavyweight framework to start. List the states your work actually passes through, on paper, honestly, including the failure and blocked states. Draw the legal transitions between them and cross out the ones that should never happen. Then make the state a persisted field on the task and force every change to go through one function that checks the transition is legal before applying it. That single choke point, every state change goes through here and illegal moves are refused, is most of the value. The formal library can come later if you need it.
Resist the urge to model the reasoning inside a state. The state machine governs the workflow, the coarse-grained shape of the work, not the fine-grained thinking the model does within a step. Implementing is one state; the dozen model calls and edits that happen inside it are not more states. Keep the machine small or it becomes its own thicket.
The honest limitation
A state machine is structure, and structure has a cost. It adds upfront modeling, and a workflow whose shape genuinely changes every run is a poor fit, you will spend more time editing the graph than it saves. It also does nothing for correctness inside a state: the model can still do the wrong thing while perfectly legally in the implementing state, and catching that is the job of tests and review, not the graph. And a state machine is only as honest as its failure states; if you model the happy path and treat everything else as an exception, you have rebuilt the thicket with extra steps.
Used with judgment, though, it is one of the highest-leverage architectural choices available for anything agentic that has to survive production. It turns "what is this thing doing" from an investigation into a query.
That is the stance we take in Loopsfinity: delivery is modeled as explicit states, and the human decisions that carry real consequences are transitions that only a person can make, so an agent can never quietly cross a gate. The details of how we store and enforce that are ours, but the principle, model the workflow as states and make the gates edges, is one worth applying to any agent system you build. It sits inside the broader picture of AI agent architecture.