Skip to content

name: chad-orchestrator description: "Spawn, route, and collect from typed sub-agents inside Chad's sandbox. Use when Chad needs to delegate a task to a coding, research, writing, or review sub-agent, track the result in the task queue, and merge structured output back into daily memory. Trigger keywords - delegate, spawn sub-agent, fan out, sub-task, dispatch, chad delegate, chad spawn, route this task." argument-hint: "Task description or kind + task-file path"


Chad Orchestrator

This is the skill Chad uses to act as an agent orchestrator rather than a single agent. It wraps five baked-in helpers that implement a canonical sub-agent contract, a task queue, a token budget, and a memory merge path.

The Sub-Agent Contract

Every sub-agent, regardless of kind, is invoked with the same shape:

chad-spawn \
  --kind coder \
  --task-file /tmp/task-<id>.json \
  [--workdir /sandbox/.openclaw-data/subagents/<id>] \
  [--result-file /sandbox/.openclaw-data/subagents/<id>/result.json] \
  [--timeout 600] \
  [--budget-tokens 50000] \
  [--dry-run]

The helper resolves the kind manifest under kinds/<kind>.yaml, validates the budget against /sandbox/.openclaw-data/budget.json, writes a queued entry to queue/tasks.jsonl, runs the sub-agent binary with the task as its prompt, collects stdout + stderr into the workdir, and on exit writes a structured result.json.

Kinds currently supported:

Kind Binary Policy preset Brain? GStack? Use case
brain gbrain (none — local PGLite) native — Query/store knowledge brain; free (no inference unless needed)
coder /usr/local/bin/pi pi-agent brain-first /gstack-qa, /gstack-ship Write/refactor code, run build + tests
researcher /usr/local/bin/claude subagent-researcher brain-first — Web/gh search, collect facts, produce a report
writer /usr/local/bin/claude subagent-writer brain context /gstack-ceo, /gstack-ship Draft email replies, docs, comments
reviewer /usr/local/bin/claude subagent-reviewer brain context /gstack-review Audit a diff, run checklist against code
fitness /usr/local/bin/claude subagent-researcher brain-first — Strength/mobility questions from Starting Strength + Supple Leopard

Adding a new kind is one YAML file under kinds/ plus (optionally) one network policy preset under nemoclaw-blueprint/policies/presets/.

GBrain Integration

All openclaw-agent kinds (researcher, writer, reviewer) inherit the gbrain MCP server because it is registered persistently in the sandbox's openclaw.json by chad-setup.sh:

openclaw mcp set gbrain '{"command":"gbrain","args":["serve"]}'

Every openclaw agent invocation thereafter has the gbrain MCP tools (mcp_gbrain_search, mcp_gbrain_put_page, …) available with no spawn-time flags required. chad-spawn now invokes:

env HOME=/sandbox \
  openclaw agent --agent main --timeout "${timeout_secs}" \
    --session-id "sub-<id>" \
    -m "<prompt>"

The --mcp-server flag is not supported in openclaw 2026.4.x — gbrain lives in openclaw.json instead, and --local was dropped at the same time. The brain kind uses the gbrain CLI directly (no inference required for pure recall tasks).

Brain-first rule: researcher, coder, and reviewer prompts all instruct the sub-agent to run gbrain query before any external API call. Findings are stored back with gbrain put-page so the next spawn doesn't pay the same research cost twice.

GStack Workflow Skills

The full canonical 40-skill gstack OpenClaw-adapter bundle is synced by chad-setup.sh into /sandbox/.openclaw-data/skills/ (chosen because that path is sandbox-writable and survives openclaw upgrades). The same script registers that directory as skills.load.extraDirs in openclaw.json so the dashboard, CLI listing, and agent's <available_skills> prompt block all see them. Skill names use the canonical gstack-<verb> shape (e.g. gstack-investigate, gstack-qa, gstack-ship, gstack-review, gstack-ceo-review, gstack-retro, gstack-cso, gstack-canary, …) — the legacy gstack-openclaw-* 4-skill subset is pruned on every sync.

Sub-agent prompts mention the most relevant skill but leave the choice to the agent:

Kind Relevant skills
reviewer /gstack-review — structured role-based review (CEO/QA/security)
writer /gstack-ceo-review, /gstack-ship — for long-form docs or release notes
coder /gstack-qa, /gstack-ship — QA checklist + ship readiness

When to skip gstack: Quick patches, one-line email replies, and PR descriptions under 50 lines don't need gstack overhead. The prompt templates say "optional" and leave the call to the agent's judgment.

For the full 40-skill catalog see docs/operations/chad-skills.md.

Fan-Out Pattern (Multiple Similar Items)

When the user asks for N similar outputs (N articles, N reports, N drafts), spawn one agent per item — never cram all N into a single task.

# Correct: 4 writer spawns, one per article
for topic in "community" "barbell" "micros-macros" "habits"; do
  chad-spawn --kind writer --task-file /tmp/task-${topic}.json
done

# Wrong: one writer with "write 4 articles" — times out after #1

Run chad-collect --today after each spawn so the result is checkpointed in daily memory before the next spawn starts.

Partial-Completion Recovery

If a spawn batch is interrupted (timeout, crash, budget):

  1. Run chad-collect --today to flush completed results into memory.
  2. Write remaining tasks to HEARTBEAT.md so the next heartbeat picks up:
## Pending spawns (resume next heartbeat)
- [ ] writer: "Barbell Strength Training article" → /tmp/article-barbell.md
- [ ] writer: "Micros vs Macros article"          → /tmp/article-micros.md
- [ ] writer: "Habits article"                     → /tmp/article-habits.md
- [ ] After all done: reply-mail --id=<MSGID> with all articles
  1. Do not ask the user what to do. The instruction is still valid — save the checkpoint and continue on the next heartbeat.

When To Use This Skill

  • A bug intake task breaks down into >1 concrete sub-tasks and Chad wants to run the coding one in parallel with the research one.
  • A long email response needs research from the web and a draft reply — route research to researcher, drafting to writer, and have Chad integrate both results.
  • A PR review needs both a security checklist and a build check — spawn a reviewer + a coder against the same PR and merge results.

Directory Layout

/sandbox/.openclaw-data/
├── subagents/
│   ├── <task-id-1>/
│   │   ├── task.json         # input
│   │   ├── prompt.txt        # rendered prompt for the sub-agent binary
│   │   ├── stdout.log        # sub-agent stdout (streamed)
│   │   ├── stderr.log        # sub-agent stderr (streamed)
│   │   └── result.json       # structured output (written on exit)
│   └── <task-id-2>/…
├── queue/
│   └── tasks.jsonl           # append-only ledger (queued → running → done|failed)
└── budget.json               # daily token budget with UTC reset

All of subagents/, queue/, and budget.json are included in the chad-backup-to-github backup set — so the sub-agent ledger survives sandbox resets alongside memory.

Entries stuck in queued/running for more than 24h (parent cron killed mid-spawn) are terminal-ized by the weekly chad-spawn-gc cron's orphan-reconcile phase: failed with a reconcile note, or done if a result.json exists but the parent never recorded it.

Canonical Workflow

# 1. Classify a task (optional — Chad can pick the kind directly).
kind="$(chad-route --task-file /tmp/task.json)"     # echoes: coder|researcher|writer|reviewer|fitness|codex|opencode

# 2. Spawn.
task_id="$(chad-spawn --kind "$kind" --task-file /tmp/task.json)"

# 3. Wait or poll.
chad-spawn-status --id "$task_id"     # prints queued|running|done|failed

# 4. Collect results into today's memory.
chad-collect --today                   # scans recent subagents/, appends "## Dispatched Tasks"

Chad can also run the intake helper which does all four steps in sequence:

chad-intake --from chat --task-file /tmp/task.json
# or:
chad-intake --from proton --message-id MSGID

Substrate selection (where the sub-agent runs)

Each kind has a default substrate set in its manifest. Override per spawn when you need to:

# Force in-container execution (default for coder/researcher/writer/reviewer/fitness):
chad-spawn --kind coder --substrate local --task-file /tmp/task.json

# Force GHA runner (default for codex/opencode):
chad-spawn --kind writer --substrate gha --task-file /tmp/task.json

# Async dispatch (gha-only) — returns task_id immediately. The
# chad-spawn-poll cron (every 5min) transitions the ledger entry
# from running → done|failed when the runner commits result.json back.
chad-spawn --kind codex --async --task-file /tmp/task.json

# Per-spawn binary swap — use codex for one writer spawn. The kind's
# L7 policy preset still applies; the override binary must be on its
# allowlist or the proxy 403s.
chad-spawn --kind writer --binary-override /usr/local/bin/codex --task-file /tmp/task.json

Substrates:

  • local — runs in Chad's container under the kind's L7 policy preset. Synchronous. Default for kinds whose work needs gbrain, embedded Nemotron, or /sandbox/source access.
  • gha — runs on a GitHub Actions runner via tantodefi/chad-state (popebot-style branch-as-job-record). Runner installs the binary on demand, picks provider by available secret (NVIDIA fallback when OPENAI_API_KEY absent), commits result back. Loses L7 enforcement; gains real per-spawn isolation. Default for codex / opencode.

See docs/design/spawn-as-github-run.md for the full architecture.

Dry-Run Mode

Before trusting a spawn to burn real tokens, --dry-run writes a fake result.json with {"dry_run": true, "would_invoke": "<binary> <args>"}. Safe for validating the queue shape, memory merge, and budget math without hitting any inference endpoint.

chad-spawn --kind coder --task-file /tmp/task.json --dry-run

Budget Protection

Every spawn decrements /sandbox/.openclaw-data/budget.json:

{
  "date_utc": "2026-04-08",
  "remaining_tokens": 450000,
  "daily_limit": 500000,
  "spent_by_kind": { "coder": 30000, "researcher": 20000 }
}
  • On the first spawn of a UTC day the file is rewritten with remaining_tokens = daily_limit.
  • chad-spawn refuses (exit 77) when --budget-tokens > remaining_tokens.
  • Dry-runs don't touch the budget.
  • Override with CHAD_DAILY_TOKEN_LIMIT env var or edit the JSON directly for one-off tests.

This is the single most important safety net in the orchestrator: prevents a runaway loop where Chad spawns a sub-agent that spawns a sub-agent that spawns a sub-agent.

Safety Rules

  • Never let a sub-agent spawn another sub-agent without explicit parent approval. The budget file is advisory, not enforced at the kernel level — the contract is honor-based inside the sandbox.
  • Never commit secrets into result.json or stdout.log. The backup pipeline pushes these files to tantodefi/chad-state (a private repo) but the same caution applies as with memory/.
  • Never route a task to coder without reading the task file first. A malicious task title "fix bug" could hide a prompt-injection payload.
  • Always run with --dry-run the first time a new kind is exercised, or after editing a kinds/*.yaml manifest.
  • Always let chad-collect run after a spawn batch so the ledger converges with memory/YYYY-MM-DD.md before the next cron fire.
  • chad-bug-intake — upstream source of tasks for the orchestrator.
  • proton-calendar — the email cron can route non-trivial replies to a writer sub-agent via chad-intake --from proton.
  • nemoclaw-manage-policy — use when a new kind needs a network policy that doesn't exist yet.

See Also

chad-readme.md at the repo root documents the whole orchestrator system including the Dockerfile wiring, host-side setup, and phase-2 items (nested sandbox spawn, cron DSL, policy composability).