An agent that can call tools, retain information, recover from failures, and continue over multiple steps needs more than a sequence of prompts. It needs a representation of where it is now.
That sounds obvious until you inspect a real workflow.
Imagine an agent handling a payment:
User request
↓
Prepare payment
↓
Submit
↓
???
What does ??? mean after a network timeout?
The payment might have failed. It might have succeeded. It might still be processing. The agent might not know.
A robust system does not force this uncertainty into a binary success / failure value. It can represent an explicit state such as:
PAYMENT_OUTCOME_UNKNOWN
That state can determine what the agent is allowed to do next.
This is the core idea behind a state machine.
What is a state machine?
A state machine represents a system as a set of possible states and defined transitions between them.
Conceptually:
STATE A
│
│ event / condition
↓
STATE B
│
│ event / condition
↓
STATE C
A state is not simply a description of what the model happens to be thinking. It is a representation of the system's operational condition.
For an agent processing a support request, you might have:
RECEIVED
↓
CLASSIFYING
↓
NEEDS_INFORMATION ──→ WAITING_FOR_USER
↓
READY_TO_ACT
↓
ACTING
↓
VERIFYING
├── SUCCESS → COMPLETED
├── RETRYABLE_FAILURE → RETRYING
└── UNRESOLVED → ESCALATED
The exact states depend on the application. What matters is that the transitions are explicit enough to reason about and test.
Why not just let the LLM decide the next step?
Sometimes that is perfectly reasonable for a low-risk task.
But an unconstrained loop like:
LLM → decide → tool → LLM → decide → tool → ...
has an important weakness: the model can implicitly invent the state of the system.
It may believe:
“The email was sent.”
when the tool actually reported:
“Request accepted for asynchronous processing.”
Or it may believe:
“Payment failed.”
when the actual state is unknown.
An explicit state machine creates a place where the application can say:
No. The system is in OUTCOME_UNKNOWN. You cannot execute another payment until reconciliation occurs.
This is a powerful division of responsibility.
The model can help interpret observations and propose actions. The surrounding system can constrain which transitions are legal.
State is not the same as memory
The previous article discussed memory. State is related but different.
Consider:
“The user prefers concise answers.”
That can be durable preference memory.
Now consider:
“The agent is waiting for the user to confirm the email recipient.”
That is current execution state.
And:
“The user confirmed the recipient at 14:32.”
That is an event or historical record that may help explain the state transition.
A useful mental model is:
MEMORY = information worth retaining
EVENT = something that happened
STATE = current condition derived from relevant information
ACTION = an attempted transition-producing operation
These can be stored together in a database, but they should not be conceptually collapsed.
States should have invariants
A state becomes much more useful when you can describe what must be true while the system is in that state.
For example:
STATE: READY_TO_SEND
INVARIANTS:
- recipient is known
- message content is finalized
- sender is authorized
- required confirmation has been obtained
If one invariant is false, the system should not enter that state.
This is stronger than putting all four requirements into a prompt and hoping the model remembers them.
The application can validate them deterministically.
Preconditions and postconditions
The same idea applies to transitions.
Suppose an agent transitions from READY_TO_SEND to SENT.
A weak definition is:
CALL send_email
→ state = SENT
A stronger definition is:
PRECONDITIONS
- recipient validated
- message approved
- sender authorized
ACTION
- submit email
POSTCONDITION
- evidence exists that the external service accepted the message
If the API returns an ambiguous result, the transition to SENT may not be legal.
Instead:
READY_TO_SEND
↓
SENDING
↓
OUTCOME_UNKNOWN
↓
RECONCILING
↙ ↘
SENT FAILED
The state machine therefore turns the tool-reliability principles from Article #06 into executable structure.
Copy-paste prompt: build your first state machine
I want to learn how to model an AI workflow as a state machine.
Act as a systems-engineering tutor.
Give me a realistic workflow involving an AI agent and at least one external tool.
Do not solve it for me immediately.
Ask me to identify:
1. The initial state.
2. Every meaningful intermediate state.
3. Events or observations that cause transitions.
4. Actions allowed in each state.
5. Preconditions for important transitions.
6. Postconditions that establish successful transitions.
7. Failure states.
8. Unknown or ambiguous states.
9. Human-intervention states.
10. Terminal states.
Do not allow me to use vague states such as “processing” unless I define exactly what is true while the system is in that state.
After I propose the state machine, challenge it with five unexpected events and ask me how the system should transition.
Do the exercise before reading further. The difficult part is usually discovering states that the happy path hides.
Example: an AI coding agent
Consider an agent asked to modify a software repository.
A naive design might be:
READ TASK
→ WRITE CODE
→ RUN TESTS
→ REPORT DONE
A more explicit state machine could be:
TASK_RECEIVED
↓
REPOSITORY_INSPECTED
↓
PLAN_READY
↓
IMPLEMENTING
↓
TESTING
↙ ↘
PASS FAIL
↓ ↓
REVIEW DIAGNOSE
↓ ↓
MERGE? IMPLEMENTING
↓
COMPLETED
Now add reality.
What if the tests fail because the test environment is broken?
What if the agent changed files outside the intended scope?
What if tests pass but a required configuration file was not updated?
What if the agent cannot determine whether the change is safe to merge?
Those conditions may justify additional states such as:
ENVIRONMENT_FAILURE
SCOPE_VIOLATION
REVIEW_REQUIRED
UNRESOLVED
The point is not to create a diagram with 50 states. Excessive state modelling can itself become difficult to maintain. The point is to make important distinctions explicit.
Finite-state machines versus richer workflows
A classic finite-state machine has a finite set of states and transitions. Real agent systems can be more complicated.
They may involve:
- nested workflows;
- parallel tasks;
- event streams;
- long-lived processes;
- external queues;
- human approvals;
- retries;
- timers;
- dynamic plans.
You may therefore encounter statecharts, workflow engines, Petri-net-like models, process models, actor systems, or other formalisms.
You do not need to adopt a particular formalism to benefit from explicit state.
The engineering principle is:
If a distinction changes what the system is allowed to do next, represent that distinction somewhere the system can enforce.
Illegal transitions are useful
A mature state model defines not only what can happen, but what must not happen.
Suppose:
PAYMENT_OUTCOME_UNKNOWN
Then this transition should normally be illegal:
PAYMENT_OUTCOME_UNKNOWN
↓
SUBMIT_SECOND_PAYMENT
unless the application has a mechanism proving that the second operation is safe.
Similarly:
WAITING_FOR_APPROVAL
↓
PUBLISH
should be impossible if approval is a required precondition.
This is where state machines become more than documentation. They can become guardrails.
Copy-paste prompt: find the missing states
Review the following agent workflow as a state-machine designer.
WORKFLOW:
[PASTE WORKFLOW]
Find every place where two situations that look similar could require different next actions.
For each one:
1. Name the hidden distinction.
2. Propose separate states if appropriate.
3. Define the invariant for each state.
4. Define legal transitions.
5. Define illegal transitions.
6. Define what evidence allows the transition.
7. Identify whether a human must intervene.
Pay particular attention to:
- partial completion;
- ambiguous tool outcomes;
- stale information;
- authorization changes;
- waiting states;
- external systems changing unexpectedly;
- retries;
- cancellation;
- timeouts.
Do not add states merely for complexity. Explain the operational consequence of every proposed state.
This prompt is especially useful when reviewing an existing agent. Ask the model to challenge the workflow rather than beautify it.
State machines and planning are different
A state machine answers:
Where are we, and what transitions are legal from here?
Planning answers:
Given the goal and current state, what sequence of actions might achieve it?
An agent can have both.
For example:
CURRENT STATE
↓
PLANNER proposes steps
↓
STATE MACHINE constrains legal actions
↓
ACTION
↓
OBSERVATION
↓
NEW STATE
↓
PLANNER revises plan
This distinction becomes important as agents become more autonomous. A plan can be wrong, stale, or invalidated by the environment. The state machine gives the system a stable representation of what is actually true and what actions remain permissible.
That leads directly to our next topic: planning is not thinking.
State as an audit trail
Explicit state also improves observability.
Instead of an opaque transcript saying:
“I tried again because the previous attempt didn't work,”
a system can record:
14:03:12
STATE: PAYMENT_SUBMITTED
14:03:27
EVENT: REQUEST_TIMEOUT
14:03:27
STATE: PAYMENT_OUTCOME_UNKNOWN
14:03:31
ACTION: QUERY_PAYMENT_STATUS
14:03:32
EVENT: PAYMENT_CONFIRMED
14:03:32
STATE: PAYMENT_COMPLETED
This is valuable for debugging, evaluation, incident investigation, and reproducibility.
It also changes what you can measure.
You can ask:
- How often do agents enter unknown states?
- How often do they recover correctly?
- How long do they remain stuck?
- Which transitions fail most often?
- Which states produce the most human escalations?
- How often does the model propose an action that is illegal for the current state?
Those are much more informative questions than simply asking whether the final answer was correct.
A small experiment: remove the state machine
Take a workflow you can run repeatedly and compare two implementations:
Condition A: the LLM receives the workflow and decides what to do next.
Condition B: the LLM receives the same information, but a deterministic state machine restricts legal transitions.
Introduce failures deliberately:
- timeout;
- partial success;
- stale data;
- invalid authorization;
- unexpected tool response;
- duplicate request.
Measure:
final task success
invalid actions
unsafe retries
recovery success
human interventions
number of tool calls
latency
If Condition B performs better, investigate why. Perhaps explicit state prevented an unsafe transition. Perhaps it also added overhead. A useful experiment should expose both benefits and costs.
Copy-paste prompt: design the experiment
Design a controlled experiment comparing these two versions of an AI agent:
A. The LLM decides the next action directly.
B. The LLM proposes the next action, but a deterministic state machine allows or rejects the transition.
TASK:
[DESCRIBE TASK]
Design:
- the state representation;
- the allowed transitions;
- the failure scenarios;
- the evaluation metrics;
- the controls needed to keep the comparison fair;
- the number and type of test cases;
- what result would support the state-machine approach;
- what result would show that its complexity is not justified.
Pay particular attention to confounders such as different prompts, different tool access, different numbers of model calls, and different amounts of available context.
This turns state machines from a software-design slogan into a testable engineering hypothesis.
The practical rule
Do not model every thought the LLM has.
Model the external and operational distinctions that matter.
If the difference between FAILED and OUTCOME_UNKNOWN changes whether another payment may be submitted, those states matter.
If the difference between two internal reasoning descriptions changes nothing about what the system can do, it probably does not belong in the operational state machine.
Good state modelling is therefore an exercise in choosing the right abstraction.
The objective is not a beautiful diagram.
It is a system where, at any important moment, you can answer:
What is true right now? What is the agent allowed to do next? What evidence permits the transition? And what happens if the world does something we did not expect?
Once those questions have explicit answers, an agent becomes substantially easier to build, test, debug, and trust.
"An agent becomes easier to reason about when you can answer one question at any moment: what state is the system actually in?"