← All courses ← Course home

Lesson 01 of 05

Why agents need a state machine

Support cannot debug "the model felt like calling a tool." Named states and legal moves make the next step visible.

Agent brief (llms.md)

A demo agent that can call anything looks clever. A shipped EDGE FDE agent has a finite set of states: gather, decide, act, review, done. Each state has a Profile, a tool allow-list, and a list of exits. If the model asks for an illegal exit, the app says no.

GatherRead notes
DecidePick an action
ActOne tool
ReviewShow the user

Do not import LangChain, LangGraph, or a Python graph runner. Those stacks hide the loop. On iOS 27 and macOS 27 you already have Dynamic Profiles and tools. The missing piece is your enum and your transition table.

enum Mode: String, Sendable { case gather, decide, act, review, done }

let legal: [Mode: Set<Mode>] = [
    .gather: [.decide],
    .decide: [.act, .gather],
    .act: [.review],
    .review: [.done, .gather],
    .done: []
]

WWDC26 session 242 describes orchestration patterns on top of Profiles. It still expects you to own mode. The Crafts sample switches analysis and brainstorm from app state. That is a state machine, even when the file is named Profile.

Product test. A teammate should point at the current state and say what can happen next without reading the prompt.

Next, bind each state to one active Profile.

Key concepts

  • Shipped agents have finite states: gather, decide, act, review, done.
  • Each state has a Profile, a tool allow-list, and legal exits.
  • Write a Mode enum and a legal transition table.
  • WWDC26 orchestration patterns still expect you to own mode.

Takeaways

  • Named states make the next step visible.
  • Do not import LangChain or LangGraph.
  • A teammate should point at current state and say what can happen next.