Install
openclaw skills install session-coordinatorEnsures the main process never blocks by spawning async subagents for long, uncertain, or remote tasks, keeping dialog always responsive.
openclaw skills install session-coordinatorMain process = dialog + dispatch. Never block.
The main goal is responsiveness — the main process must never be blocked, stalled, or made unresponsive. This is not "never execute." It is "never block."
A blocked main process shows as: typing indicator disappears, user cannot get a response, session appears frozen.
label parameter (see Spawn Label Convention below)"If my typing indicator disappeared, am I being blocked right now?"
If a question or request is on a DIFFERENT topic, spawn it — do not handle it directly even if it seems fast. Different topic = different subagent.
Default spawn mode is mode="session" with thread=true.
mode="session", thread=true for most tasks (interactive, multi-step, or uncertain duration)mode="one-shot" only when explicitly instructed or when the task is trivial and guaranteed single-turnmode="run" (run = detached, no result push = unreliable)# ✅ Default: session thread (most tasks)
spawn(task="task-description", mode="session", thread=true, label="task-label")
# ✅ Explicit one-shot: only when scope is trivially bounded
spawn(task="task-description", mode="one-shot", label="task-label")
# ❌ Don't use run unless you explicitly need detached/no-result
spawn(task="task-description", mode="run")
Use these as a guide to set runtime when spawning:
| Tier | Duration | Examples |
|---|---|---|
| fast | ~5 min | file ops, single API call, config check, quick test |
| medium | ~15 min | git operations, moderate build, moderate data processing |
| long | 60 min+ | large clones, heavy builds, multi-step deployments, data migration |
# Fast task — 5 min timeout
spawn(task="check service status", runtime="fast", label="service-status-check")
# Medium task — 15 min timeout
spawn(task="clone repository and run tests", runtime="medium", label="repo-test")
# Long task — 60 min timeout
spawn(task="full deployment pipeline", runtime="long", label="deploy-pipeline")
When spawning a subagent, always include a descriptive label parameter:
project-config-sync not project config sync)Generic placeholder examples:
project-name → repo-name or project-alfa192.168.x.x → remote-host or node-alphauser@host → admin-user or service-account# ✅ Good: generic, dashes, descriptive
spawn(task="sync config to remote node", label="config-sync")
spawn(task="run test suite for module", label="test-suite")
spawn(task="deploy service to environment", label="service-deploy")
# ❌ Bad: spaces, specific names, cryptic
spawn(task="...", label="proj1") # too short, no dashes
spawn(task="...", label="192-168-1-1") # specific IP — not allowed
spawn(task="...", label="johns-task") # specific user name — not allowed
spawn(task="...", label="foo-bar-v2") # specific project codename — not allowed
When the user says "stop that thing", look at subagents list and match the label to find the right subagent to stop.
runtime timeout (fast/medium/long)A subagent can be safely let timeout (or can terminate early) when:
After a subagent completes, if the result is significant (decision made, lesson learned, important output, state change), write it to MEMORY.md in the main session.
## [Date] Task Result
- Task: task-description
- Outcome: what happened
- Key decision/learning: ...
Routine subagent work should be logged in the daily memory file:
# Create/update daily log
memory/2026-04-06.md
Include: task label, what was done, key result. Keep it concise.
Do not announce to user when you are spawning a subagent.
user does not need to know the execution architecture. The subagent handles the work; you handle the conversation.
| Responsibility | Main Process | Subagent |
|---|---|---|
| User dialog | ✅ | ❌ |
| Task dispatch | ✅ | ❌ |
| Result production | ❌ | ✅ |
| Result delivery to user | ✅ | ❌ |
| Decision making | ✅ | ❌ |
| Status coordination | ✅ | ❌ |
| Fast local operations | ✅ | ❌ |
| Blocking operations | ❌ | ✅ |
If the main process blocks, the pattern has failed — regardless of whether the task eventually completes.
# ❌ Wrong — blocks main process, typing disappears
exec("ssh remote-host ...")
subprocess.run(...)
# ✅ Correct — non-blocking, typing stays active
spawn(task="remote operation description", runtime="medium", mode="session", thread=true, label="remote-task")
After spawning: continue dialog with user. Do NOT wait. Results arrive via push event.
Each node runs its own subagents. Nodes do not delegate to each other's subagents. Coordination between nodes goes through whatever inter-node protocol is configured for that setup.
| Anti-Pattern | Why Wrong | Correct |
|---|---|---|
| "Let me check..." + exec in main | Blocks typing | Spawn subagent |
| Waiting for subagent result before responding | Blocks dialog | Continue, report later |
| Direct remote operations in main process | Blocks | Spawn |
| Spawning to avoid doing work (not to avoid blocking) | Misuse of pattern | Execute directly if fast |
| All work spawn, nothing direct | Over-interpretation | Fast ops = direct |
| Announcing the spawn to user | Noise, breaks flow | Spawn silently, continue |
| Using specific IPs/hostnames in labels | Privacy leak | Use generic names |
"Never block" is the rule. "Never execute" is a misreading of the rule — fast operations should be direct because they do not block. The typing indicator is the visible signal: if it disappears, something is blocking.
All examples in this skill use generic placeholders only. No specific project names, IPs, hostnames, user names, service names, or AI names appear in any example. This protects both operational security and privacy.