agents-cli · teams · graph engineering
agents teams turns a multi-step coding goal into a directed acyclic graph
of agent processes: nodes are named teammates, edges are --after dependencies,
and a supervisor drains the DAG wave by wave — locally or across a device pool.
That is graph engineering applied to real CLIs (Claude, Codex, Grok, …), not a slide deck.
In 2026 the industry name for designing multi-agent topology — not just one agent’s tool loop — is graph engineering.
Linear chains (A then B then C) break under real product work: independent surfaces want parallelism; QA should wait on both backend and frontend; a planner can add nodes mid-flight. A DAG encodes that structure once — true parallelism for independent nodes, joins for multi-parent deps, no circular waits.
See also: DAG-First Agent Orchestration (Apr 2026); Microsoft Conductor (YAML deterministic multi-agent graphs, May 2026); LangGraph multi-agent workflows (nodes + edges + state).
--after (and “before”)In agents-cli the edge is declared on the dependent node: “start me only after these names finish.”
# Nodes agents teams add feat claude "Implement /api/pricing" --name backend agents teams add feat codex "Build pricing UI" --name frontend # Edge: qa depends on both (multi-parent join) agents teams add feat claude "Playwright suite" --name qa --after backend,frontend
| Concept | In graph theory | In agents teams |
|---|---|---|
| Node | Vertex / task | Named teammate (--name) |
| Edge | A → B “B after A” | add … --name B --after A |
| Join | Multi-inbound edges | --after A,B,C (all must complete) |
| “Before” | Inverse edge language | Not a flag — declare on the child with --after |
| Cycle | Forbidden in a DAG | Rejected at add time (validateAddPreconditions) |
| Ready set | Zero indegree remaining | startReady(team) each wave |
meta.json as after: string[].
Writing “B before A” from A’s side would be the same edge; one direction keeps
the graph unambiguous and cycle checks simple. Name is required when using
--after because deps are by name, not UUID.
The supervisor is a classic DAG dispatcher: poll disk, launch the ready set, wait, repeat until drained.
teams add is picked up on the next rescan — the graph can grow while it runs (Factory planner pattern).agents teams start pricing-page --watch # --interval 8 seconds between waves (default) # --max-waves 1000 # --json one JSON object per wave
after[] are all terminal → launchpending + running == 0 ends the loopfailed count — failures still drainOne orchestrator owns the DAG. Teammates can run on different fleet devices; placement is a separate axis from dependency.
--after is time/order. --device / --devices is where. The supervisor still sees one team graph.| Placement rule | Behavior |
|---|---|
--device X on add | Pin — never second-guessed |
| Pool of one | Whole team on that device |
| Pool of many (unpinned) | Best-viable: reachable, not overloaded, agent installed, under cap, least loaded |
| No pool / no pin | Local |
| No viable device | Fail loud — never silent fallback to local |
agents teams create feat \ --devices yosemite-s0,yosemite-s1 \ --repo git@github.com:org/app.git \ --enable-worktrees agents teams add feat claude "API" --name backend --device yosemite-s0 --worktree api agents teams add feat claude "UI" --name frontend --device yosemite-s1 --worktree ui agents teams add feat claude "QA" --name qa --after backend,frontend --worktree qa agents teams start feat --watch
Topology without ownership is a race. Parallel teammates need file boundaries; --after only orders time.
--after only for real data dependencies (API ready → QA).
| Anti-pattern | Fix |
|---|---|
| Two edit-mode agents, shared checkout, no worktrees | --enable-worktrees + unique --worktree names |
Serializing independent work with --after | Drop the edge; run same wave |
Cross-repo team with one --repo | One team per repo |
| Assuming shared memory between teammates | Pass outcomes via PRs, files, or explicit messages (teams message) |
Modes: plan (read-only) · edit · auto · skip. Pair plan-mode reviewers with edit-mode implementors on separate branches.
# 1. Create + DAG + watch agents teams create pricing -d "Ship /pricing end-to-end" --enable-worktrees agents teams add pricing claude "Backend tiers API" --name backend --worktree backend agents teams add pricing codex "Frontend pricing page" --name frontend --worktree frontend agents teams add pricing claude "E2E Playwright" --name qa --after backend,frontend --worktree qa agents teams start pricing --watch # 2. Mid-flight graph growth (planner adds a node) agents teams add pricing claude "Fix flake from QA log" --name bugfix --after qa --worktree bugfix # supervisor rescans disk next wave and stages it # 3. Steer / resume agents teams message pricing qa "Skip visual snapshot for now" agents teams resume pricing backend "Review green — rebase-merge then release" # 4. Observe agents teams status pricing agents sessions --teams # teammate sessions tagged [team/…] agents teams disband pricing
| File | Role |
|---|---|
| commands/teams.ts | CLI: create / add / start / status / message / … |
| lib/teams/agents.ts | Teammate process model · after[] · validateAddPreconditions · startReady |
| lib/teams/supervisor.ts | runSupervisor wave loop (shared with factory run) |
| lib/teams/scheduler.ts | Device placement cascade (pin / pool / least-loaded / fail-loud) |
| lib/teams/worktree.ts · remoteWorktree.ts | Isolated branches for parallel edit |
| lib/teams/registry.ts | Team registry on disk |
| docs/teams.md | Full reference |
--after edges, isolate edit surfaces with worktrees, place nodes
across devices with --device/--devices, and let start --watch drain ready
waves until the graph is done. Not shared memory — explicit topology + disk state.