Changelog
Concepts

Multi-agent patterns

Spawn, send, observe — the whole coordination surface, and the patterns you build with it.

Multi-agent coordination in teaspill is three primitives: spawn a child, send a message, observe what others are doing. Everything else on this page is a pattern built from those three.

The golden rule

Worth restating from the wake model, because every pattern below leans on it: spawn returns the child's id immediately — never its result. The child runs concurrently; its result arrives later as a child_finished message that wakes the parent. An agent that has delegated everything it can ends its turn, and the platform wakes it when there is news.

Fan-out / gather

The workhorse pattern: split a task across N children in one wake, gather results as they arrive, finish when all are in.

wake 1      spawn_agent × 3         → three child ids, immediately
            wait()                  → turn ends

wakes 2–4   child_finished arrives  → record the result in state,
            (one wake per child)      count 1/3 … 2/3 … 3/3

final wake  all results present     → finish(combined result)

The children run concurrently with each other and with anything else the parent does. Order of completion doesn't matter — each child_finished is its own wake, and the parent's state (a counter, a list of findings) carries the gather across wakes.

Pipeline

For staged work, chain instead of fanning out: each agent send_messages its output to the next stage and finishes. A researcher hands findings to a summarizer, which hands a draft to a reviewer. No stage waits on another — each sleeps until its input arrives, and the pipeline's state is the messages in flight, all durable.

The alternative shape — a parent orchestrating each stage in sequence, spawning stage N+1 when stage N's child_finished arrives — trades a little latency for one place that sees the whole flow. Both are idiomatic; prefer the orchestrator when you want one timeline that tells the whole story.

Deterministic spawn

A parent that might retry — or that must never double-create a worker — supplies the child's id itself, derived from the task:

spawn_agent({ type: "summarizer", args: { text }, id: `summary-of-${articleId}` })

Spawning the same (type, id) twice reattaches to the same child instead of creating a duplicate (how reattach behaves). This makes "one worker per subtask" a naming convention instead of bookkeeping code.

Watching another agent

Observation doesn't need messages. Any agent's catalog row — type, status, parent, tags — is subscribable, and its timeline is readable, by UIs and backends alike. A dashboard watching a fleet of workers is a catalog subscription; an audit view of one worker is its timeline. Agents themselves get list_children() for a snapshot of their own children's status.

What arrives on a parent's wake

When a child finishes, the parent's next wake carries a child_finished message with the child's id, its outcome (success, error, interrupted, or archived), and whatever result the child passed to finish. Messages from non-child agents arrive as ordinary messages tagged with the sender's entity URL. Either way it arrives as an ordinary wake — the parent's harness sees the news as input and acts on it.

Three anti-patterns, all versions of fighting the wake model:
  • Don't wait synchronously for a child. There is nothing to wait on — spawn, end the turn, and the result wakes you.
  • Don't poll. An agent that re-checks list_children in a loop is burning turns to learn what a child_finished wake would have told it for free.
  • Don't use timelines as a message bus. Timelines are history — one agent reading another's timeline to decide what to do next recreates the coupling teaspill removes. Coordination is messages; timelines are for reading the story afterward.

Next steps

Patterns cover agents talking to each other — including steering a busy peer mid-run. For intervening from the outside — interrupting, pausing, archiving — continue to Lifecycle & control, which also covers where steer fits.