# Slack message behavior

> Acknowledgement reactions, live streaming previews, and slash commands

- 网址：https://funcoding.ai/agents/openclaw/channels/slack/messaging/
- 来源：OpenClaw 官方文档原文（英文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/channels/slack/messaging

---
What a Slack conversation looks like while OpenClaw works, and how commands reach it.

## Ack reactions

`ackReaction` sends an acknowledgement emoji while OpenClaw is processing an inbound message. `ackReactionScope` decides _when_ that emoji is actually sent.

The acknowledgement stays static during work. With `messages.statusReactions.enabled: true`, actual failures briefly show an error reaction before restoring the acknowledgement. Tool calls, thinking, compaction, and long-running tools do not cycle or accumulate reactions, and successful completion does not flash a separate success emoji.

### Emoji (`ackReaction`)

Resolution order:

- `channels.slack.accounts.<accountId>.ackReaction`
- `channels.slack.ackReaction`
- `messages.ackReaction`
- agent identity emoji fallback (`agents.entries.*.identity.emoji`, else `"eyes"` / 👀)

Notes:

- Slack expects shortcodes (for example `"eyes"`).
- Use `""` to disable the reaction for the Slack account or globally.

### Scope (`messages.ackReactionScope`)

The Slack provider reads scope from `messages.ackReactionScope` (default `"group-mentions"`). There is no Slack-account or Slack-channel-level override; the value is global to the gateway.

Values:

- `"all"`: react in DMs and groups, including ambient room events.
- `"direct"`: react in DMs only.
- `"group-all"`: react on every group message except ambient room events (no DMs).
- `"group-mentions"` (default): react in groups, but only when the bot is mentioned (or in group mentionables that opted in). **DMs are excluded.**
- `"off"` / `"none"`: never react.

<div class="callout callout-note">

The default scope (`"group-mentions"`) does not fire ack reactions in direct messages or ambient room events. To see the configured `ackReaction` (for example `"eyes"`) on inbound Slack DMs and quiet room events, set `messages.ackReactionScope` to `"all"`. Scope changes apply to the next message without reconnecting Slack.

</div>

```json5
{
  messages: {
    ackReaction: "eyes",
    ackReactionScope: "all", // react in DMs and groups
  },
}
```

Reply threading, history limits, text chunk limits, streaming, typing reactions, and
unfurl settings apply to the next admitted message without reconnecting Slack. An active
reply retains the settings it started with. The same behavior applies to account overrides.

## Text streaming

`channels.slack.streaming` controls live preview behavior:

- `off`: disable live preview streaming.
- `partial`: replace preview text with the latest partial output. Set this to restore the pre-2026.8.1 default, before `progress` became the default ([#122552](https://github.com/openclaw/openclaw/pull/122552)).
- `block`: append chunked preview updates.
- `progress` (default): show structured progress in a reply thread using a native task card when Slack supports it, with a Block Kit session-card fallback. Outside reply threads, leave only the final answer by default.
- `streaming.progress.toolProgress`: `progress` mode is quiet by default (`false`). Set `true` to add one task row per tool call on the native card, or tool activity, the plan checklist, and tool/file/time totals on the Block Kit card. Finished Block Kit cards retain only file diff totals. `streaming.preview.toolProgress` controls tool previews in `partial` and `block` modes (default: `true`).
- `streaming.preview.commandText` / `streaming.progress.commandText`: `status` keeps compact tool-progress lines while hiding raw command/exec text (default); set `raw` to opt into command text.

Show the tool log while hiding raw command/exec text:

```json
{
  "channels": {
    "slack": {
      "streaming": {
        "mode": "progress",
        "progress": {
          "toolProgress": true,
          "commandText": "status"
        }
      }
    }
  }
}
```

`channels.slack.streaming.nativeTransport` controls Slack native text streaming when `channels.slack.streaming.mode` is `partial` (default: `true`).

In `progress` mode, turns without a reply-thread target post no preview or progress message unless you explicitly select a presentation. This includes channel replies with effective `replyToMode: "off"` and plain top-level DMs. These turns use a temporary typing reaction and deliver the final answer once; failures still use normal error delivery. Any explicit `streaming.progress` setting opts top-level turns into a preview, including `commentary: true` or a custom `label`. The sole exception is `nativeTaskCards: true`, which only affects threads. An empty `streaming.progress` object or setting only `streaming.mode: "progress"` keeps the quiet top-level default. This rule applies to the effective settings after merging root and account overrides. Modes `off`, `partial`, and `block` retain their existing behavior.

For threaded turns, including Agent View, Assistant View, and Slack-managed threads, Slack's native agent card remains the default: the whole turn is one streamed message that interleaves narration with a live plan/task card and finishes with the assistant's answer in that same message. The card shows authored plan steps when the agent publishes a plan, otherwise one stable work-summary row; approval requests get their own row. Intermediate tool failures and nonzero command exits are hidden by default, so successful answers do not accumulate failure or `Recovered: …` rows. With `progress.toolProgress: true`, it also shows per-tool task rows, including tool failures, alongside any authored plan. Routine updates coalesce at one-second intervals; approvals, visible failures, and completion bypass that delay. The card appears only once a turn does real work — tool or plan activity still running after a short delay — so a plain question is answered without one.

Without an authored or explicit headline, native summary rows finish as **Completed** or **Failed**.

Set `channels.slack.streaming.progress.nativeTaskCards` to `false` to fall back to the Block Kit session card. By default, this separate message shows commentary and text, including italic narration and reasoning, plus actionable approval requests. Only an explicitly configured progress `label` appears as a plain title. Finished cards keep the **Open in OpenClaw** or **Open work session** link when available. The card adds no emoji, bold text, or status headings in either mode, except a plain Failed line when the turn fails. A card is posted only once it has something to show, so a turn with only tool activity and no commentary shows no card by default. A working or successful card whose last visible row goes away, such as a resolved approval, is deleted instead of keeping stale rows. Failed turns keep their card marked Failed, even without an error reply; failed turns with no reply post a plain Failed card even if none appeared while working.

Set `progress.toolProgress: true` for the detailed Block Kit card: it adds recent tool activity, a plan checklist with a completed-step count, intermediate error and recovery rows, and tool/file/time totals while working. Finished detailed cards retain only file diff totals in their footer.

Set `channels.slack.streaming.progress.style` to `"compact"` for one plain-text progress draft instead of either card surface. Explicitly setting `progress.toolProgress: false` also selects compact style when `style` is unset. Set `style: "card"` to keep a card with `toolProgress: false`, or to select a Block Kit card for top-level turns. Commentary appears as italic text, and authored reasoning and approval requests remain visible. Terminal task errors still use normal error delivery. The final response is posted as a new message, then the temporary preview is deleted after Slack confirms delivery. Older previews displaced by human replies are cleaned up with it; durable messages and videos stay in the conversation.

For streamed preambles, Slack waits for the first complete preamble before creating the message, so its notification contains the full thought rather than a single token. Once that message exists, later preambles can stream as edits without another notification.

```json5
{
  channels: {
    slack: {
      streaming: {
        mode: "progress",
        progress: {
          style: "compact",
          label: false,
          commentary: true,
          toolProgress: false,
        },
      },
    },
  },
}
```

Compact progress always uses normal final delivery, including for media and errors. Other draft modes use normal delivery when the reply cannot safely replace the draft, including oversized text, split block payloads, custom outbound identity, or an edit failure.

Both surfaces link the session with **Open in OpenClaw**, but only when that link can work: `gateway.publicOrigin` must be set (the externally reachable Gateway origin) and the Control UI must not be disabled via `gateway.controlUi.enabled: false`. Installations that leave `publicOrigin` unset — where there is no way to reach OpenClaw from Slack — get no link rather than a dead one. If the Control UI is served below a path prefix, also set `gateway.controlUi.basePath`.

When a turn spawns a visible work session, the finished card instead links to that child with **Open work session**. For multiple visible work sessions, it shows up to five links in acceptance order, using their labels or numbered **Open work session** links; hidden subagents do not replace the conversation link.

- A reply thread must be available for native text streaming and Slack session status to appear. Thread selection still follows `replyToMode`.
- Channel, group-chat, and top-level DM roots use draft previews when explicitly selected. Default `progress` turns without a reply thread use only the temporary typing reaction.
- Top-level Slack DMs stay off-thread by default; Agent View and Assistant View retain their thread-based native progress.
- Custom outbound username/icon settings keep portable previews enabled. OpenClaw keeps the preview or session card app-authored and delivers the customized final separately. Slack does not allow impersonated messages to be deleted.
- Media and non-text payloads fall back to normal delivery.
- Outside compact progress, media/error finals cancel pending preview edits; eligible text/block finals flush only when they can edit the preview in place.
- Native streamed replies wait for Slack's acknowledgement before delivery is marked successful. Each complete reply block flushes separately, including short blocks; routine progress updates still coalesce. A later progress-card finalization failure does not discard an already acknowledged reply.
- Explicit HTTP 429 rate-limit rejections are retried up to twice by default, after Slack's `Retry-After` delay. This also applies to ordinary messages and upload completion; lost responses and server errors are not replayed.
- Definite recipient or scope rejections fall back to normal delivery for buffered text. Ambiguous streaming failures (such as a lost response) report failure without replaying the unacknowledged text, because Slack may already have accepted it. Later payloads use normal delivery.

Use draft preview instead of Slack native text streaming:

```json5
{
  channels: {
    slack: {
      streaming: {
        mode: "partial",
        nativeTransport: false,
      },
    },
  },
}
```

Keep Slack native progress task cards enabled for threaded turns:

```json5
{
  channels: {
    slack: {
      streaming: {
        mode: "progress",
        progress: {
          nativeTaskCards: true,
        },
      },
    },
  },
}
```

Legacy keys:

- `channels.slack.streamMode` (`replace | status_final | append`) is a legacy alias for `channels.slack.streaming.mode`.
- boolean `channels.slack.streaming` is a legacy alias for `channels.slack.streaming.mode` and `channels.slack.streaming.nativeTransport`.
- top-level `channels.slack.chunkMode` and `channels.slack.nativeStreaming` are legacy aliases for `channels.slack.streaming.chunkMode` and `channels.slack.streaming.nativeTransport`.
- Legacy aliases are not read at runtime; run `openclaw doctor --fix` to rewrite persisted Slack streaming config to the canonical keys.

## Typing reaction fallback

`typingReaction` adds a temporary reaction to the inbound Slack message while OpenClaw is processing a reply, then removes it when the run finishes. This is most useful outside of thread replies, which use Slack's `processing` session status.

Resolution order:

- `channels.slack.accounts.<accountId>.typingReaction`
- `channels.slack.typingReaction`
- `"hourglass_flowing_sand"` for default `progress` turns without a reply thread or an explicitly selected progress presentation; otherwise no typing reaction.

Notes:

- Slack expects shortcodes (for example `"hourglass_flowing_sand"`).
- Use `""` to disable the typing reaction, including the default for quiet top-level turns.
- The reaction is best-effort and cleanup is attempted automatically after the reply or failure path completes.

## Commands and slash behavior

Slash commands appear in Slack as either a single configured command or multiple native commands. Configure `channels.slack.slashCommand` to change command defaults:

- `enabled: false`
- `name: "openclaw"`
- `sessionPrefix: "slack:slash"`
- `ephemeral: true`

```txt
/openclaw /help
```

Native commands require [additional manifest settings](https://funcoding.ai/agents/openclaw/channels/slack/manifest-and-scopes/#additional-manifest-settings) in your Slack app and are enabled with `channels.slack.commands.native: true` or `commands.native: true` in global configurations instead.

- Native command auto-mode is **off** for Slack so `commands.native: "auto"` does not enable Slack native commands.

```txt
/help
```

Native argument menus render as one of the following, in priority order:

- 3-5 short-enough options: an overflow ("...") menu
- more than 100 options, with async option filtering available: external select
- 1-2 options, or any option whose encoded value is too long for a select: button blocks
- otherwise (6-100 options, or more than 100 without async filtering): static select menu, chunked at 100 options per menu

```txt
/think
```

Slash sessions use isolated keys like `agent:<agentId>:slack:slash:<userId>` and still route command executions to the target conversation session using `CommandTargetSessionKey`.
