Human-in-the-loop (HITL) is one of the best-known patterns in agent design. An agent works until it reaches a decision it shouldn't make alone, then pauses and asks a person: approve this refund, review this pull request, sign off on this contract. Agent frameworks now build it in as a standard feature.

Almost every example assumes the human is an employee. They're on the same Slack, answering the agent is part of their job, and if they're slow, you escalate to their manager.

This article describes a different setup: a dispatch architecture with two humans and an AI in the loop, where neither human works for the system. The AI isn't waiting on one approver. It's coordinating two people who have never met, while a third, the property owner, keeps the final say.

Three humans, one leaking sink

A tenant texts their landlord's agent: "the kitchen sink is leaking." The agent has to get a plumber and the tenant into the same place at the same time, with the landlord approving anything that costs money. Three humans, no shared channel, and no obligation on any of them to answer quickly.

A machine you already know

An AI Agent that coordinates humans is classic finite state machine with allowed transitions and defined states. The only new component is an LLM sitting at its boundaries, translating between natural language and state transitions.

That framing matters because most agent architectures get it backwards. They put the model at the center, let it hold the workflow in its context window, and hope it remembers who agreed to what. When the participants are humans, who reply hours late, change their minds, and answer the same question twice, that design fails quietly and often.

This article builds the alternative from first principles: a deterministic FSM that owns all state and actions, and an LLM that only encodes inputs and renders outputs. Here is that machine for the leaking sink.

The repair job, as a state machine

As a state machine, the job has nine states. Each arrow is a transition triggered by an input symbol; the diamonds mark transitions that also require an approval input from the landlord.

The two loops on the left are where the real work happens: a tenant declining a held slot sends the job back to proposing, and a tenant reporting the problem isn't fixed sends it back to scheduling with its history intact.

The machine

Under the hood, the dispatcher is a simple state machine. It has three parts:

  • States. Where the job is right now: reported, waiting on the tenant, scheduled, done. The current state is saved in a database, not in the AI's memory.
  • Inputs. Things that happen: a text from the tenant, a reply from the contractor, an approval from the landlord, or a timer running out.
  • Rules. Plain code that says "in this state, if this input arrives, move to that state and do these things," like sending a text or booking a slot.

Nothing in that list needs AI. The rules are ordinary if-then logic you can read and test.

Where the AI fits

The AI's job is translation, at two points.

Coming in, it turns a messy human message into one of a few clear answers. If the agent just asked the tenant to confirm Tuesday at 2pm, the possible answers are yes, no, a question, or "can't tell" (UNCLEAR). A reply like "yeah tues should be ok, after 3 tho" gets sorted into one of those. The AI never decides what happens next; it only says which answer the person gave. When it isn't sure, it picks "can't tell," and the agent simply asks again.

Going out, the code decides what needs to be said ("confirm Tuesday 2–4pm with the tenant"), and the AI writes it in friendly, natural words. It can change the tone, but not the facts.

So the flow is: the AI reads, the code decides, the AI writes. Keeping decisions out of the AI is what makes the system predictable. It can't book the wrong time because it misremembered the conversation, since the conversation's state never lived in its memory.

What changes when the inputs are people

A textbook FSM assumes well-behaved inputs: they arrive on a clock edge, exactly once, and mean what they say. Human inputs violate all three.

Assumption

Digital input

Human input

Timing

Sampled on a clock edge

Arrives minutes to days later, or never

Multiplicity

One value per cycle

Zero, one, or several replies

Stability

Holds until the next edge

Retracted ("actually, Tuesday doesn't work")

Freshness

Always current

May answer a question you stopped asking

Obligation

The circuit must drive it

A tenant or contractor owes the agent nothing

The core machine doesn't change. What changes is the input stage and a few structures around it. That's exactly why the state belongs in code: the machine keeps track even when the people don't.

Takeaways

The hard part of an AI that coordinates humans isn't the AI. It's the bookkeeping: knowing exactly who has been asked what, what they agreed to, and what is still in flight. That bookkeeping is a state machine, and we have known how to build state machines for decades.

  1. Put all state in a durable state register and all transitions in deterministic code.
  2. Use the LLM as an input encoder: map each message to a symbol from the current state's alphabet, with UNCLEAR as a first-class answer.
  3. Use the LLM as an output renderer: code decides what is said, the model decides how.

The model makes the machine speak human. The machine keeps the humans in sync.