JJoeven

Curriculum/Multi-Agent Systems

Supervisor Plus a Sequential Subgraph

A mature shape: the supervisor picks a pipeline. Billing always runs extract → policy → HITL → apply. That is not a purity failure. Irreversible steps stay off a chatty handoff graph.

intermediate21 min15 / 24

A common mature shape: supervisor chooses a sequential subgraph.

Billing tickets always run extract → policy → HITL → apply. Tech tickets run logs → brief → patch → tests. The supervisor is a router. The subgraph is a workflow. Workers inside a subgraph still do not pick the next node, and they still do not DM other workers.

Hub picks a pipeline
SupervisorBilling listTech list

Irreversible steps stay in a list you can grep. Not on a chatty graph.

Hub picks a pipeline

This is not a purity failure. Purity would be “one pattern forever.” Products mix a stingy hub with boring lists so irreversible steps never sit on a chatty handoff graph. Money apply, email send, production deploy — those stay in a list you can grep.

The last four lessons gave you modes, sequential default, hop brakes, and a star. This lesson is how they compose without inventing a mesh “because billing is special.”

Two catalogs

Graph catalog. GRAPHS["billing"] and GRAPHS["tech"] are lists. Adding a node is a config change. Billing always contains HITL. Tech does not contain money apply. That difference is the product. If tech grows a “we refund because the job failed” node, you have mixed money into the wrong graph. Do not.

Picker. pick(ticket) is rules: refund or invoice → billing, else tech. A model picker is allowed only if rules fail on goldens. The picker returns a key, not a custom list. The supervisor must not edit the list per vibe (skip hitl for this VIP). That was sequential’s skip flag, now at hub layer. Still forbidden.

TicketKeyPath includes HITL?Path includes money apply?
invoice refundbillingyesyes, after HITL
job 17 timeouttechnono
mixed “timeout plus refund me”pick must not guess bothsplit to two jobs or a humannever a homegrown mesh

Mixed tickets are how teams invent a mesh. Honest design: two jobs, or HITL that chooses a graph, or a human. Not coder DMing billing.

If intake cannot classify, do not invent a “generalist graph” that contains every node including apply. Generalist graphs are meshes with extra YAML. Send unknowns to a human queue. Measure how often that happens. If it is rare, you are done. If it is common, you are missing a third named graph, not a free-form hop.

Walkthrough: invoice versus timeout

“Where is my invoice refund?” → billing → ["extract", "policy", "hitl", "apply"]hitl: True.

“job 17 timeout” → tech → ["logs", "brief", "patch", "tests"] → HITL false, and apply not in the path. Tech never hits the money node.

Prints in the box also assert the invariants in English: billing always HITL; tech has no apply money.

If the billing worker (a node inside extract or policy) emits skip-HITL, the subgraph runner ignores it the same way run_pipeline refused the flag. The supervisor only picked billing. It does not pass extra permissions.

Job 17 from the why-part can live on tech: logs worker (researcher contract), brief on the board, coder patch, tests as critic-or-tests node. That is sequential roles inside the tech graph. You did not need peer handoff.

Live PythonOpen full playgroundpython
Output
Run to execute this in your browser. Nothing is sent to a server.

What printed: invoice picks billing, path with HITL and apply. Timeout picks tech, path with logs through tests. The two invariant prints are True. Billing always HITL. A timeout picks tech and never hits the money apply node.

The picker is a substring rule. Production pickers use ticket category fields from intake, not a hope that the user said “invoice.” If intake is a model, eval intake separately from the graph runner. A wrong pick is a hub fail. A skipped HITL on a correct pick is a graph-config fail.

Irreversible steps stay in lists

Handoff graphs are the wrong home for apply. A model that can name to: apply will do it when the user is loud. Sequential subgraphs make apply a position, not a destination a peer can vote.

Swarms, later, fan out inside a node (score 200 tickets as map) and reduce before the parent continues the list. They do not let 200 children call apply. Write barrier plus this graph: children never see the money node.

Debate, later, can be a node on a high-stakes subgraph (... → debate → judge → hitl → apply) with a round cap. It is not a reason to mesh the whole product.

How agents use this

Do not let the billing worker decide to skip HITL. The subgraph is config. The supervisor only picks the key.

Log kind, path, mode=supervisor+sequential. On-call should see “billing graph” in one field, not infer it from five peer names.

When you add a third graph (legal holds, security incidents), add a list and a pick rule. Do not add a “generalist mesh” for leftovers. Leftovers go to a human or to the one-agent baseline.

Irreversible nodes should be greppable. apply, wire, deploy, delete_customer belong in lists, never as destinations a peer can name. If a framework wants every node callable from every node, you wrap it: the only legal calls are “run this key’s list in order.” The wrapper is the product. The framework is a costume.

Review GRAPHS in the same PR ritual as ALLOW and EDGES. If a PR removes hitl from billing, that is a stop-ship, not a style comment. The quiz is that idea in one sentence.

You now have roles, typed events, and a control plane that can stay boring. The next part is work patterns on top: debate, swarms, reduce, write barriers — still in lane, still not a single-agent ReAct rerun. If a ticket needs none of those, it still belongs on this ladder’s sequential subgraph or on the one-agent baseline. Extra patterns are optional. The list is not.

Check your understanding

Who may skip HITL on a billing subgraph?