Slack message behavior
Acknowledgement reactions, live streaming previews, and slash commands
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>.ackReactionchannels.slack.ackReactionmessages.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.
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.
{
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, beforeprogressbecame the default (#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:progressmode is quiet by default (false). Settrueto 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.toolProgresscontrols tool previews inpartialandblockmodes (default:true).streaming.preview.commandText/streaming.progress.commandText:statuskeeps compact tool-progress lines while hiding raw command/exec text (default); setrawto opt into command text.
Show the tool log while hiding raw command/exec text:
{
"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.
{
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
progressturns 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-Afterdelay. 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:
{
channels: {
slack: {
streaming: {
mode: "partial",
nativeTransport: false,
},
},
},
}Keep Slack native progress task cards enabled for threaded turns:
{
channels: {
slack: {
streaming: {
mode: "progress",
progress: {
nativeTaskCards: true,
},
},
},
},
}Legacy keys:
channels.slack.streamMode(replace | status_final | append) is a legacy alias forchannels.slack.streaming.mode.- boolean
channels.slack.streamingis a legacy alias forchannels.slack.streaming.modeandchannels.slack.streaming.nativeTransport. - top-level
channels.slack.chunkModeandchannels.slack.nativeStreamingare legacy aliases forchannels.slack.streaming.chunkModeandchannels.slack.streaming.nativeTransport. - Legacy aliases are not read at runtime; run
openclaw doctor --fixto 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>.typingReactionchannels.slack.typingReaction"hourglass_flowing_sand"for defaultprogressturns 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: falsename: "openclaw"sessionPrefix: "slack:slash"ephemeral: true
/openclaw /helpNative commands require 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.
/helpNative 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
/thinkSlash sessions use isolated keys like agent:<agentId>:slack:slash:<userId> and still route command executions to the target conversation session using CommandTargetSessionKey.