Spurlock Studios
Contact
State Machines for Agent Loops: Determinism Where It Matters

Models are non-deterministic. Operations cannot be. The way you reconcile those facts is a state machine: freedom to plan and act inside states, determinism about which transitions are legal, when side effects may happen, and when the run must stop.

This spoke is part of the Agentic Systems Operating Manual. If you are still shopping for whether you need an agent at all, read When Not to Build an Agent first.

What an agent loop state machine is

An agent loop state machine is an explicit set of named states and allowed transitions that wrap model calls and tool use. The model may propose content and tool calls inside a state. The machine decides whether the next state is legal given the evaluator verdict, budget, and error class.

Without that wrapper you get: unbounded retries, duplicate side effects, “done” declared by the worker, and no clean place for humans to intervene.

A default machine that ships

States:

  1. intake — validate job contract, attach budget and tool allowlist, reject out-of-scope.
  2. plan — model proposes steps; no production writes.
  3. act — allowlisted tools may run; side effects only here.
  4. evaluate — independent judge; no writes.
  5. revise — worker edits with failure evidence; increment revision counter.
  6. done — terminal success; receipts stored.
  7. escalate — terminal handoff to human with full package.
  8. abort — terminal stop on budget, policy, or unrecoverable error.

Legal transitions (simplified):

  • intakeplan | abort
  • planact | escalate | abort
  • actevaluate | escalate | abort
  • evaluatedone | revise | escalate
  • reviseact | escalate (if ceiling hit)
  • anything serious → abort

The exact graph can vary. The requirement is that it is written down and enforced in code or in the workflow rail.

Deterministic multi-agent systems (what that phrase should mean)

People say “deterministic multi-agent” when they want predictability. You will not get bit-identical model outputs. You can get:

  • Deterministic control flow (states and transitions)
  • Deterministic policy (allowlists, caps, ceilings)
  • Deterministic accounting (cost and trace always recorded)
  • Deterministic terminality (runs end in done, escalate, or abort)

That is the bar. Chasing identical tokens is a waste of budget.

Where n8n fits

n8n is a strong cage for this pattern:

  • Webhook or queue enters intake
  • Each state is a node group or sub-workflow
  • Durable execution survives restarts
  • Error workflows map to escalate / abort
  • Human-in-the-loop nodes implement approval gates
  • Idempotency keys protect act from double delivery

Keep model calls inside bounded nodes with explicit timeouts. Do not let a single “AI node” own the entire lifecycle with hidden retries. The rail should be readable by an engineer who does not speak prompt.

Spurlock Studios uses n8n heavily as that rail when the customer already lives there or when webhook/ops glue dominates. The state machine concept still applies if you use Workers, Step Functions, or a custom runner.

Side effects only in act

This rule prevents half the horror stories. Planning tokens do not email customers. Evaluation does not patch CRM. Revision drafts land in scratch until act applies them under sandbox rules.

If your architecture lets any state call any tool, you do not have a state machine. You have a directed suggestion.

Revision ceilings and escalate packages

Unbounded revise loops are how you discover a task is impossible after $400. Cap revisions (three is a good pilot default). On ceiling:

Package for humans:

  • Job contract
  • Artifacts so far
  • Evaluator failures with evidence
  • Tools called and outcomes
  • Cost and latency
  • Recommended human action (if any)

Escalation is success of a kind: the system knew it was out of its depth while someone could still help.

Idempotency at state boundaries

Webhooks and retries will re-enter states. Compute an idempotency key from job identity + state + intent. Before a hard write in act, check the store. Duplicate delivery should return success-without-redo, not a second charge or a second email.

Testing the machine (not only the model)

Unit-test transitions: given state + event, next state is correct. Fault-inject tool errors and ensure you land in escalate/abort, not a silent done. Load-test that budgets trip. These tests catch regressions prompts will never show.

Anti-patterns

Hidden loops in the prompt. “Keep going until perfect” with no machine counter.

Worker-set terminal state. Only evaluator or human marks done.

God state. One mega-state that plans, acts, and judges.

Retry storms. Provider retries + your retries + model retries without a single budget owner.

Pilot application

In a $1,500 · 5-day Spurlock Studios pilot we implement a thin machine for one job: intake, act, evaluate, revise×N, done/escalate. Fancy parallel states wait until the thin machine clears the golden set.

Parent map: operating manual. Offer: /agentic. Contact: /contact?intent=agentic-pilot.

Encoding the machine so humans can read it

Write the graph in a format engineers and operators share: a small JSON/YAML table of from, event, to, guards. Generate a diagram in docs from that file. When someone asks “can evaluate call email.send?” the answer is in the table, not in folklore.

Guards are predicates: revisions < 3, budget_remaining > 0, evaluator.verdict == pass, tool_error_class != auth. Guards failing should produce explicit reason codes on the transition to escalate or abort.

Timeouts and compensation

Every state that waits on a model or tool needs a timeout. On timeout: retry with policy, compensate if a partial write happened, or escalate. Compensation is where automation discipline meets agents — you cannot always undo an email, which is why irreversible classes should not live in optimistic loops.

For n8n specifically, prefer explicit Wait/Error paths over sprawling IF trees that bury the graph. Sub-workflows named by state keep the top-level readable when the pilot grows into a build.

Concurrency and double entry

Two webhooks can start two runs for one logical job. The machine needs a lock or a deterministic job_id lease at intake. Without it you will see duplicate act sequences that both look “correct” in isolation and wrong together.

Pair leases with idempotency keys on hard writes. Determinism at the control plane is what people mean when they ask for deterministic multi-agent systems — not identical tokens.

Evolving the graph safely

Additive changes (new optional state for human approve) are safer than rewiring terminals. Version the graph id in traces so you can compare scores across versions. Never hot-edit production transitions based on one bad run; add a golden case and ship through the same path you use for prompt changes.

Spurlock Studios installs a thin graph in the $1,500 · 5-day pilot so you feel the cage before we elaborate it. Map: operating manual. Offer: /agentic.

Event types worth standardizing

Normalize events the machine understands: start, planned, tool_ok, tool_err, eval_pass, eval_fail, budget_low, timeout, human_approve, human_reject. Models emit artifacts; adapters translate outcomes into these events. Keeping the event vocabulary small is what makes the graph testable.

Nested machines

A parent job can spawn a child machine for a subtask (e.g., retrieval-only librarian flow). Children must return a package and must not write customer-visible systems unless the parent’s sandbox allows it. Nesting without budget inheritance is a cost bug.

Mapping to n8n nodes (practical)

  • Webhook / Queue → intake
  • Set/IF → guards
  • AI nodes → plan/act model calls (bounded)
  • HTTP Request → tools through your runner, not ad hoc
  • Error Trigger → abort/escalate
  • Wait for approval → human gate
  • Static data / Redis → idempotency and leases

Readable beats clever. If only one contractor understands the workflow, you do not have an operable machine.

Next: cost controls, observability, pilot /agentic.

Recovery semantics

Define whether revise may re-enter plan or only act. Re-planning is powerful and expensive; acting on the same plan with failure evidence is usually enough for pilots. Document the choice.

Define whether human_approve returns to act or jumps to done. Approvals that skip evaluation recreate self-grading with a human rubber stamp — better than nothing, worse than approve-then-evaluate on the final artifact.

Sagas for multi-step writes

When act must touch two systems, use a saga mindset: write A with idempotency key, write B, compensate A on B failure if possible, else escalate with a repair checklist. Agents do not remove the need for distributed-systems thinking; they add a nondeterministic planner on top.

Why “while loop in the prompt” fails audits

Auditors and careful buyers ask where the stop condition lives. “The model decides” is not an answer. A state machine with counters is. That distinction is central to deterministic multi-agent systems people can operate.

Ship the thin graph in five days via /contact?intent=agentic-pilot. Deep map: operating manual.

Walkthrough narrative

A ticket arrives at intake; schema validates; budget $1.00 attached. Plan proposes two tool calls. Act runs them under sandbox. Evaluate fails citation rule. Revise 1 redrafts. Evaluate passes. Done writes internal note idempotently. Trace shows each state. Finance sees $0.27. That story is an agent loop state machine doing its job — not a chat log.

If evaluate had failed thrice, escalate would package evidence for a human. Deterministic multi-agent systems use the same terminals when more roles join later.

Common refactor

Teams start with one mega AI node. Refactor into named states when they cannot answer where side effects occur. Do the refactor before volume rises.

n8n remains a solid rail for this discipline. Pair with evaluators and /agentic.

FAQ

What is an agent loop state machine?

It is an explicit graph of states and transitions that wraps model and tool calls so side effects, retries, evaluation, and termination follow rules you enforce — not vibes from the model.

How do you get deterministic multi-agent systems?

Make control flow, policy, accounting, and terminality deterministic. Accept that tokens vary. Coordinate agents with typed handoffs entering known states, not free-form shared chats.

Why use n8n for agent state machines?

n8n gives durable execution, webhooks, error paths, and human approval nodes — the boring reliability layer around non-deterministic model steps. It is one good rail, not the only one.

How many states do we need?

Enough to separate intake, planning, acting, evaluating, revising, and terminal outcomes. Start small. Split states when a node becomes untestable or when side-effect classes collide.

What happens when the model wants an illegal transition?

The runner ignores the wish and either forces a legal path, asks for a replan inside the current state, or escalates. The model does not get to rewrite the graph at runtime.

How does Spurlock Studios implement this on a pilot?

We ship a minimal enforced graph with budgets and escalate in five days for one job, then expand. See /agentic and the operating manual.

Start a pilot