Skip to content

Spawn SOP

Full SOP for sessions_spawn, sessions_send, and Claude Code CLI.

  • Non-blocking: “accepted” means queued, not finished.
  • Always include: label, runTimeoutSeconds, and cleanup="keep".
  • Write chunked task briefs with exact paths + success criteria. Avoid giant one-shot requests.
  • Do not busy-poll. If no completion by timeout + 2m, check once: subagents list or sessions_history(sessionKey=childKey, includeTools=true, limit=5).
  • If stalled: steer once (subagents steer), then kill + respawn with a tighter brief.
  • Treat child transcript + artifacts as source of truth; completion announce is best-effort.

Sentinel Pattern — Auto-Wake on Completion

Section titled “Sentinel Pattern — Auto-Wake on Completion”

Problem: Final sub-agent completion uses passive delivery (method: "send") — doesn’t wake the parent. Parent goes silent until a human intervenes.

Fix: Spawn a dummy “sentinel” alongside real workers. The sentinel keeps activeDescendantRuns > 0, forcing worker completions to wake the parent via method: "agent".

# 1. Spawn sentinel (Gemini Flash, free — zero intelligence needed)
sessions_spawn(
task="Run: exec sleep 3600. Do nothing else.",
label="sentinel",
model="google-antigravity/gemini-3-flash",
runTimeoutSeconds=3600,
cleanup="keep"
)
# 2. Spawn real worker(s)
sessions_spawn(task="Actual work...", label="worker-1", ...)
# 3. Worker completes → parent auto-wakes (sentinel still active)
# 4. Parent processes result, then kills sentinel:
subagents(action="kill", target="sentinel")

sessions_send — Fire-and-Forget (CRITICAL)

Section titled “sessions_send — Fire-and-Forget (CRITICAL)”

Always pass timeoutSeconds=0:

sessions_send(sessionKey="agent:main:main", message="...", timeoutSeconds=0)

Returns { status: "accepted" } immediately. The message IS delivered and queued.

Why: Cross-agent runs share a single-concurrency nested lane. Default 30s timeout fails whenever another agent-to-agent run is in progress.

To check results later: sessions_history(sessionKey="agent:<id>:main", limit=5)

sessions_send vs sessions_spawn — Routing

Section titled “sessions_send vs sessions_spawn — Routing”
Use CaseTool
Named persistent agents: Tila, PMs, Claw, Coachsessions_send (retains memory + context)
Spawn-only templates: dev, researchsessions_spawn (disposable, auto-announce)

Spawn-only templates always use sessions_spawn. Never sessions_send for them.

# Target agent's main session
sessions_send(sessionKey="agent:main:main", message="...", timeoutSeconds=0)
sessions_send(sessionKey="agent:frankel:main", message="...", timeoutSeconds=0)
# Target specific HQ topic
sessions_send(sessionKey="agent:frankel:telegram:group:-1003780594815:topic:4", message="...", timeoutSeconds=0)
sessions_send(sessionKey="agent:main:telegram:group:-1003780594815:topic:2", message="...", timeoutSeconds=0)
  • sessionKey="agent:main:main" — correct
  • sessionKey="agent:frankel:telegram:group:-1003780594815:topic:4" — correct

Before every sessions_spawn or Codex/Claude Code invocation:

  1. Read HANDOVER.md — check “Dev Model” or tool preference field
  2. Use whatever it specifies (Codex, Claude Code, etc.)

Standard pattern:

Terminal window
cd /project && git init 2>/dev/null
claude -p --dangerously-skip-permissions --model sonnet --max-budget-usd 3 \
"Your task. Run tests. Fix errors. Commit. Do NOT ask questions."

Pattern: Plan → Execute in batches of 5–7 items

Binary: /home/chrisr6/.mcp-venv/bin/jcodemunch-mcp

For headless spawns (any project):

Terminal window
cd /path/to/project && claude -p \
--mcp-config '{"jcodemunch":{"type":"stdio","command":"/home/chrisr6/.mcp-venv/bin/jcodemunch-mcp"}}' \
"Task brief. Use jCodeMunch for code navigation (search_symbols, get_symbol). Do not read entire files."
Task: <what to build/do>
Paths: <exact file paths>
Success criteria: <how to verify it worked>
Output: Write summary to /home/chrisr6/.openclaw/workspace/checkpoints/subagent-<label>.md
Include: status (done|error), files_changed, summary, next_action (if any)
Do NOT ask questions. Execute and commit.