Discord Threads, Forums, and Session Mapping

Explains how OpenClaw maps Discord forum threads, history limits, subagent sessions, and ACP channel bindings onto sessions. Useful for integrators configuring Discord channels and thread-based workflows.

Read this when

  • Posting to a Discord forum or media channel
  • Working out which session a Discord thread maps to
  • Binding a Discord channel to a subagent or ACP agent

How OpenClaw maps Discord channels, forums, and threads onto sessions.

Forum channels

Thread posts are the only thing Discord forum and media channels accept. OpenClaw offers two ways to create them:

  • Auto-create a thread by sending a message to the forum parent (channel:<forumId>). Discord limits thread names to 100 characters, and the title is taken from the first non-empty line of the message (truncated to fit).
  • Create a thread directly with openclaw message thread create. For forum channels, omit --message-id.

Creating a thread by sending to the forum parent:

openclaw message send --channel discord --target channel:<forumId> \
  --message "Topic title\nBody of the post"

Creating a forum thread explicitly:

openclaw message thread create --channel discord --target channel:<forumId> \
  --thread-name "Topic title" --message "Body of the post"

Discord components are not accepted by forum parents. When you need components, target the thread itself (channel:<threadId>).

If thread-create sends all initial content successfully, its result reports confirmed message IDs and chunk counts in initialMessageDelivery alongside status: "delivered". A value of threadSnapshot: "creation" means the returned thread fields describe creation time; do not retry content because of message_count or last_message_id. Standalone threads that are empty have no initial-delivery receipt. Accepted chunks are reported separately when failures are partial; failedChunkDelivery: "unknown" means the failed chunk may still have been delivered, so check the thread before retrying.

Session and thread behavior

History, context, and thread behavior

Guild history context:

  • channels.discord.historyLimit, default 20
  • fallback: messages.groupChat.historyLimit
  • 0 turns off automatic guild/thread history reads. Explicit message reads and reply context are unaffected.

Admitted guild turns pull their recent window from Discord, including after a Gateway restart. For thread turns, the exact thread channel is used rather than its parent. In mention-gated rooms, messages that do not mention the bot stay quiet. Excluded from history are the current and batched source messages, later messages, and rows preceding the active session boundary. Sender visibility still applies, so filtering may return fewer messages than the configured limit. Messages from other bots stay available as context even when allowBots: false stops those bots from triggering turns. The receiving bot's own output is left out of automatic history.

The selected parent message travels with human replies regardless of allowBots. When nested reply payloads are missing or empty, they are fetched from Discord. Should the parent be deleted or unavailable, its reply ID stays in context instead of the message quietly becoming an unrelated top-level question. Which supplemental reply content gets included is still governed by contextVisibility.

Discord is the owner of history: fresh reads reflect its current message content, deletions, permissions, and availability. No separate durable message archive is kept. When automatic recovery fails, OpenClaw logs the omission and carries on with the addressed turn. Historical attachments that lack reusable local media are marked unavailable rather than restoring stale media. Prior agent transcripts are not rewritten by recovery.

Native pagination and exact message lookup remain in the existing message(action="read") tool. After a restart or /new, older reads stay available, subject to Discord's Read Message History permission and current access rules.

DM history controls:

  • channels.discord.dmHistoryLimit
  • channels.discord.dms["<user_id>"].historyLimit

Thread behavior:

  • Discord threads route as channel sessions and inherit parent channel config unless overridden.
  • As a model-only fallback, thread sessions inherit the parent channel's session-level /model selection; thread-local /model selections take precedence, and parent transcript history is not copied unless transcript inheritance is enabled.
  • channels.discord.thread.inheritParent (default false) opts new auto-threads into seeding from the parent transcript. Per-account override: channels.discord.accounts.<id>.thread.inheritParent.
  • Message-tool reactions can resolve user:<id> DM targets.
  • guilds.<guild>.channels.<channel>.requireMention: false is preserved during reply-stage activation fallback.

Channel topics are injected as untrusted context. Allowlists decide who may trigger the agent; they are not a full redaction boundary for supplemental context.

Thread-bound sessions for subagents

A thread can be bound by Discord to a session target, so later messages in that thread continue routing to the same session (subagent sessions included).

Commands:

  • /session unbind removes the current thread binding without closing its agent session

  • /agents shows active runs and binding state

  • /session idle <duration|off> inspects or updates inactivity expiry for the current binding

  • /session max-age <duration|off> inspects or updates hard max age for the current binding

    Config:

{
  session: {
    threadBindings: {
      enabled: true,
      idleHours: 24,
      maxAgeHours: 0,
      spawnSessions: true,
      defaultSpawnContext: "fork",
    },
  },
}

Notes:

  • session.threadBindings.* is the shared policy for Discord and Telegram.

  • spawnSessions controls auto-create/bind threads for sessions_spawn({ thread: true }) and ACP thread spawns. Default: true.

  • defaultSpawnContext controls native subagent context for thread-bound spawns. Default: "fork".

  • Deprecated spawnSubagentSessions/spawnAcpSessions keys are migrated by openclaw doctor --fix.

  • Thread-bound spawns are unavailable when thread bindings are disabled.

    See Sub-agents, ACP Agents, and Configuration Reference.

Persistent ACP channel bindings

To get stable "always-on" ACP workspaces, set up top-level typed ACP bindings that target Discord conversations.

Config path: bindings[] with type: "acp" and match.channel: "discord".

{
  agents: {
    entries: {
      codex: {
        runtime: {
          type: "acp",
          acp: {
            agent: "codex",
            backend: "acpx",
            mode: "persistent",
            cwd: "/workspace/openclaw",
          },
        },
      },
    },
  },
  bindings: [
    {
      type: "acp",
      agentId: "codex",
      match: {
        channel: "discord",
        accountId: "default",
        peer: { kind: "channel", id: "222222222222222222" },
      },
      acp: { label: "codex-main" },
    },
  ],
  channels: {
    discord: {
      guilds: {
        "111111111111111111": {
          channels: {
            "222222222222222222": {
              requireMention: false,
            },
          },
        },
      },
    },
  },
}

Notes:

  • /acp spawn codex --bind here locks the channel or thread you are in and routes later messages to that same ACP session. Messages posted in a thread take on the binding of the parent channel.

  • Inside a channel or thread that is bound, both /new and /reset perform an in-place reset of the same ACP session. While a temporary thread binding is active, it can take precedence over target resolution.

  • Child thread creation and binding are gated by spawnSessions through --thread auto|here.

    Binding behavior is described in detail under ACP Agents.

996 words · updated Oct 26, 2026