Skip to content

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

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

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions