State Machines for Agents in Regulated Flows

When doing steps out of order is a compliance failure regardless of outcome, a model-decided control flow is the wrong shape. Put the ordering in code, the conversation in the agent, and scope the tools per state.

Some processes have a legally or contractually required shape. Identity must be verified before an account is opened. Consent must be recorded before data is processed. A disclosure must be presented before an agreement is executed. Not guidelines — obligations, where doing the steps out of order is a compliance failure regardless of how the conversation went.

An agent whose control flow is decided by a model is a poor fit for this by construction. The answer isn't to abandon the agent; it's to put the required ordering somewhere the model can't reach.

The shape that works

An explicit state machine owns the sequence. The agent operates within a state, handling the language and judgment work, while transitions are enforced in code.

states:
  collecting_identity  -> verifying    [requires: id_document, selfie]
  verifying            -> disclosures  [requires: verification_passed]
  disclosures          -> agreement    [requires: all_disclosures_acknowledged]
  agreement            -> complete     [requires: signature]

any_state -> abandoned  [timeout, user request]

The machine decides which state the flow is in and which transitions are legal. The agent, given the current state, does what that state needs: ask for the document, explain the disclosure, answer questions, handle the confused user. It cannot advance the flow by concluding that it should.

What each layer owns

The state machine owns: the current state, which transitions are legal, what evidence each transition requires, and the audit record of every transition with its timestamp and evidence.

The agent owns: conversation within the state, explaining requirements, handling objections and questions, deciding when the state's requirements appear satisfied — and requesting a transition.

The transition guard owns: verifying the evidence is genuinely present. Not asking the model whether the disclosure was acknowledged; checking that an acknowledgement record exists.

request_transition(to: "agreement") ->
  guard checks: all required disclosures have acknowledgement records
  if not: {denied: true, missing: ["risk_disclosure"],
           instruction: "present the risk disclosure and record acknowledgement"}

⚠️ The denial message matters as much as the check. A bare refusal produces an agent that retries; a specific missing-requirement list produces one that does the right thing next.

Tools scoped per state

The second enforcement layer: the agent's tool list depends on the state. In collecting_identity it has document-upload tools and no signing tools. The signing tool doesn't exist until the machine says the flow is in agreement.

This removes an entire class of failure without relying on instructions. A tool that isn't offered cannot be called, no matter what the conversation contains — including content designed to make it want to.

What you get beyond compliance

The structure pays for itself in ways unrelated to regulation:

A real audit trail. Every transition, with timestamp, evidence, and the agent's stated reason. When someone asks whether the disclosure was presented before the agreement, the answer is a record, not a transcript to be interpreted.

Resumability comes free. The state is durable, so a flow interrupted on Tuesday continues on Thursday from exactly where it stopped.

Testability. Each state is testable in isolation with stubbed transitions, and the machine itself is testable without a model at all — including the negative cases, which is where compliance failures live.

Legible progress. "Step 3 of 5: disclosures" is real, not an estimate, because the states are known in advance.

✅ When this is worth it

  • Ordering is externally mandated.
  • Out-of-order execution is a failure even if the outcome looks fine.
  • You must prove afterwards that the sequence was followed.
  • The flow spans sessions and must resume mid-way.

❌ When it isn't

  • Ordering is a preference, not a requirement. A state machine over a flexible process makes it rigid and frustrating, and users find the seams.
  • Steps genuinely vary by case. If half your flows need a custom path, you'll encode the exceptions as states until the machine is unreadable.
  • Investigation and exploration, where the whole value is the agent deciding what to look at next.

The middle ground for partially-structured work: enforce only the few genuinely mandatory orderings as guards, and leave the rest to the agent. You don't need a state per step — you need a guard per obligation.

The takeaway

When ordering is an obligation, the ordering belongs in code and the conversation belongs to the agent. A state machine holding legal transitions, guards checking real evidence rather than the model's assessment, and tools scoped per state gives you enforcement that survives any prompt change — plus an audit trail, resumability, and honest progress reporting. Encode only the obligations; leave the rest flexible.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.