When to use it
The embedded
task-graph skill teaches the model this ruler, the plan schema and the discipline (“you never declare done”).
The plan schema
One JSON object describes the whole delivery:depsmay only reference tasks declared earlier (which also rules out cycles).promptmust be self-contained — workers do not see the conversation.#<depID>is replaced with that dependency’s output.validation[].runcommands are executed by the engine (inheriting the coder sandbox and the unsafe-command denylist) — never by the executor.expectis prose for the reviewer. A bare string is a prose-only contract (reviewer verifies by inspection).agentdefaults tocoder(any squad worker type works);max_attemptsdefaults to 3;require_reviewdefaults to true, per graph or per task.
Execution: ready-set scheduling
Tasks fire the moment their dependencies complete — no level barriers, no wasted wall-clock. Concurrency is capped by the squad’s existingCHATCLI_AGENT_MAX_WORKERS knob (the graph’s own max_parallel can lower it); no new environment variables were added for this feature.
Each task runs through an attempt loop:
- Checkpoint — a shadow-git snapshot of the workspace, best-effort, before the executor starts.
- Executor — a fresh worker receives the prompt (plus reviewer feedback on retries).
- Gate — the engine runs every
validation[].runcommand itself and records output; a non-zero exit fails the attempt without spending a reviewer. - Review — a fresh
reviewerworker (read-only tools) receives the contract, the gate outputs and the executor’s report, and must end withVERDICT: PASS — evidenceorVERDICT: FAIL — what is missing. - Promote or retry — gate green + PASS promotes to
donewith the evidence recorded; FAIL retries with the feedback injected, up tomax_attempts, then the task fails and its successors becomeblocked.
pending → running → reviewing → done | failed | blocked.
Every attempt also carries its real cost: each worker LLM call is attributed to the graph node that spawned it, using the same per-call accounting as cost tracking.
Surfaces
@taskgraph (for the AI)
run executes the whole graph in a single tool call, streaming events as they happen. Resume is inherent: completed tasks stay done, so re-running a failed graph continues where it stopped.
/taskgraph (for humans)
/taskgraph is allowlisted as a mid-run side command — type it while the graph executes to inspect progress without touching the orchestrator loop.
The live dashboard
/taskgraph dash (or {"cmd":"dash"}) serves a browser dashboard from an ephemeral 127.0.0.1 port — a single embedded file, zero CDN, zero configuration:
- Animated DAG canvas — phase swimlanes, dependency béziers with animated dashes into running tasks, status-colored cards with attempt count and per-task cost; drag to pan, ctrl/⌘+wheel to zoom,
0to fit, lineage highlight on hover. - Evidence popovers — click a task for its prompt, validation contract, gate outputs, reviewer verdict + evidence and the executor/reviewer run IDs.
- Results tab — critical path, wall-clock vs agent time, parallelism factor and the real cost per task.
- Live — the page polls the persisted state every second and tails the event feed.
state.json and events.ndjson from disk on every request. Closing the dashboard never affects a run, and finished runs render just as well.
Persistence
Each run owns~/.chatcli/taskgraph/<runID>/:
Runs appear in
/agents (and the Conversation Hub) as a parent run with each executor and reviewer registered as children — cancellation propagates down the tree.