Skip to content

[Bug]: mode="session" requires thread=true — blocks orchestrator pattern on non-Discord channels #23414

@eminos

Description

@eminos

Summary

sessions_spawn with mode: "session" is hardcoded to require thread: true. Since thread binding currently only works on Discord (via subagent_spawning hooks), persistent sub-agent sessions are completely unavailable on Telegram, Slack, WhatsApp, and all other channels.

This blocks the orchestrator pattern documented in the official docs (docs.openclaw.ai/tools/subagents#nested-sub-agents) from working on any non-Discord channel.

Steps to reproduce

  1. Configure OpenClaw with Telegram (or any non-Discord channel)
  2. Set maxSpawnDepth: 2 in config
  3. Attempt to spawn an orchestrator sub-agent:
sessions_spawn({
  task: "...",
  mode: "session"
})

Error: mode="session" requires thread=true so the subagent can stay bound to a thread.

  1. Add thread: true:
sessions_spawn({
  task: "...",
  mode: "session",
  thread: true
})

Error: Unable to create or bind a thread for this subagent session. Session mode is unavailable for this target.

Root cause

In reply-B2UJINPw.js (spawnSubagentDirect):

if (spawnMode === "session" && !requestThreadBinding) return {
    status: "error",
    error: "mode=\"session\" requires thread=true..."
};

And ensureThreadBindingForSubagentSpawn requires:

if (!hookRunner?.hasHooks("subagent_spawning")) return {
    status: "error",
    error: "thread=true is unavailable because no channel plugin registered subagent_spawning hooks."
};

Only Discord registers subagent_spawning hooks, so mode: "session" is Discord-only in practice.

Why this matters

The orchestrator pattern (main → orchestrator sub-agent → worker sub-sub-agents) requires the orchestrator to stay alive between child announces. Sequential workflows like:

  1. Orchestrator spawns Agent A
  2. Agent A finishes → announces back to orchestrator
  3. Orchestrator processes result → spawns Agent B
  4. Repeat

...require mode: "session" because mode: "run" ends the session after the first turn completes. Without session persistence, the orchestrator exits before child announces arrive.

This is documented as a supported pattern in the docs (maxSpawnDepth: 2, nested sub-agents, announce chain), but it cannot actually work on non-Discord channels.

Proposed fix

Decouple session persistence from thread binding. These are independent concepts:

  1. Session persistence (mode: "session") — session stays alive to receive messages (sub-agent announces, sessions_send, etc.)
  2. Thread binding (thread: true) — routes platform thread I/O to the session (Discord/Slack feature)

The guard clause should be relaxed: allow mode: "session" without thread: true. The session stays alive headlessly (no platform thread presence) but can still receive child announces as new turns.

// Current (blocks non-Discord):
if (spawnMode === "session" && !requestThreadBinding) return error;

// Proposed (allow headless persistent sessions):
// Remove this guard. Thread binding becomes optional for session mode.

Related issues

Environment

  • OpenClaw: latest (2026-02-22)
  • Channel: Telegram
  • Config: maxSpawnDepth: 2, maxChildrenPerAgent: 5
  • OS: Linux (WSL2)

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions