Slack
Run your ZeroClaw agent as a Slack bot. This guide walks you through it step by step. By the end you’ll have a bot in your workspace that answers when people message it or @-mention it.
Who can talk to the agent
Inbound senders are gated against the peer set resolved for the bound
agent, drawn from the peer_groups config the agent belongs to. Matching strips
a leading @ and is case-insensitive against the channel’s native sender
identifier. An empty set denies everyone; a set containing "*" accepts
anyone; otherwise only the listed external peers (and peer agents) are accepted.
This is separate from gateway pairing (gateway.require_pairing), which
authenticates HTTP/WebSocket clients, not chat-channel senders.
A peer group for slack sets channel to slack, lists the allowed senders in
external_peers (for slack, the Slack user ID; ["*"] accepts anyone), optionally
names peer agents for cross-agent dispatch, an ignore blocklist, and an
output_modality (mirror, voice, or text). See Peer Groups
for the field reference.
Where to set this:
Gateway dashboard
Open /config/peer_groups in the web dashboard.
zerocode
In the Config pane, under Peer groups.
Quickstart
Slack needs two tokens: a bot token (what the bot speaks with) and an app token (lets the bot connect without you hosting a public URL). Both come from the same app page.
1. Create the Slack app
- Go to api.slack.com/apps and click Create New App -> From scratch.
- Name it, pick your workspace, and Create App.
2. Add the permissions the bot needs
- In the left sidebar, open OAuth & Permissions.
- Under Scopes -> Bot Token Scopes, add:
app_mentions:read,channels:history,chat:write, andchannels:read. (Addim:historyandim:writetoo if you want direct messages.)
3. Turn on Socket Mode and get the app token
- In the left sidebar, open Socket Mode and toggle it on.
- Slack prompts you to create an app-level token. Name it, give it the
connections:writescope, and Generate. - Copy the token that starts with
xapp-. This is yourapp_token.
Socket Mode lets the bot hold an outbound connection to Slack, so you don’t need a public webhook URL or any port forwarding. This is the easy path.
4. Install the app and get the bot token
- Open Install App in the sidebar and click Install to Workspace, then Allow.
- Back on OAuth & Permissions, copy the Bot User OAuth Token that
starts with
xoxb-. This is yourbot_token.
5. Tell ZeroClaw about both tokens
Both tokens are secrets, so set them through a surface that encrypts them:
Gateway dashboard
Open /config/channels/slack in the web dashboard.
zerocode
In the Config pane, under Channels.
channels.slack.<alias>.bot_tokenis a secret. Stored encrypted, never in plainconfig.toml. Set it through one of these, which encrypt on write:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.bot_token field there.
zerocode
In the Config pane, set the channels.slack.<alias>.bot_token field (input is masked).
zeroclaw config
zeroclaw config set channels.slack.<alias>.bot_token # prompts for masked input, stores encrypted
Set app_token the same way (it’s the xapp- token from step 3).
6. Invite the bot and test
In Slack, go to a channel and type /invite @YourBotName. Then send a message
or @-mention the bot. Start ZeroClaw (zeroclaw service restart or
zeroclaw daemon) and it should reply. If not, see
Troubleshooting.
Configuration
The full field list, derived from the live schema. For a basic Socket Mode bot
you only set bot_token and app_token.
app_token 🔑
Slack app-level token for Socket Mode (xapp-…).
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.app_token field.
zerocode
In the Config pane, set the channels.slack.<alias>.app_token field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.app_token # masked input, stored encrypted
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__app_token=
approval_timeout_secs
Seconds to wait for operator approval on always_ask tools before auto-denying.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.approval_timeout_secs field.
zerocode
In the Config pane, set the channels.slack.<alias>.approval_timeout_secs field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.approval_timeout_secs <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__approval_timeout_secs=
bot_token* 🔑
Slack bot OAuth token (xoxb-…).
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.bot_token field.
zerocode
In the Config pane, set the channels.slack.<alias>.bot_token field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.bot_token # masked input, stored encrypted
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__bot_token=
cancel_reaction
Emoji reaction name (without colons) that cancels an in-flight request. For example, "x" means reacting with :x: cancels the task. Leave unset to disable reaction-based cancellation.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.cancel_reaction field.
zerocode
In the Config pane, set the channels.slack.<alias>.cancel_reaction field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.cancel_reaction <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__cancel_reaction=
channel_ids
Explicit list of channel IDs to watch. Empty = listen across all accessible channels. Migrated from the legacy channel_id singular field.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.channel_ids field.
zerocode
In the Config pane, set the channels.slack.<alias>.channel_ids field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.channel_ids <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__channel_ids=
draft_update_interval_ms
Minimum interval (ms) between draft message edits to avoid Slack rate limits.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.draft_update_interval_ms field.
zerocode
In the Config pane, set the channels.slack.<alias>.draft_update_interval_ms field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.draft_update_interval_ms <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__draft_update_interval_ms=
excluded_tools
Tools excluded from this channel’s tool spec. When set, these tools are not exposed to the model when responding via this channel.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.excluded_tools field.
zerocode
In the Config pane, set the channels.slack.<alias>.excluded_tools field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.excluded_tools <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__excluded_tools=
interrupt_on_new_message
When true, a newer Slack message from the same sender in the same channel cancels the in-flight request and starts a fresh response with preserved history.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.interrupt_on_new_message field.
zerocode
In the Config pane, set the channels.slack.<alias>.interrupt_on_new_message field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.interrupt_on_new_message <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__interrupt_on_new_message=
mention_only
When true, only respond to messages that @-mention the bot in groups. Direct messages remain allowed.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.mention_only field.
zerocode
In the Config pane, set the channels.slack.<alias>.mention_only field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.mention_only <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__mention_only=
proxy_url
Per-channel proxy URL (http, https, socks5, socks5h). Overrides the global [proxy] setting for this channel only.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.proxy_url field.
zerocode
In the Config pane, set the channels.slack.<alias>.proxy_url field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.proxy_url <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__proxy_url=
reply_min_interval_secs
Per-(channel, recipient) outbound pacing floor in seconds. Range: 0..=REPLY_MIN_INTERVAL_MAX_SECS (0 disables).
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.reply_min_interval_secs field.
zerocode
In the Config pane, set the channels.slack.<alias>.reply_min_interval_secs field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.reply_min_interval_secs <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__reply_min_interval_secs=
reply_queue_depth_max
Per-(channel, recipient) outbound pacing queue depth. Range: 0..=REPLY_QUEUE_DEPTH_CEILING. When reply_min_interval_secs > 0 and this value is 0, the pacing wrapper substitutes DEFAULT_REPLY_QUEUE_DEPTH (16). When the queue is full, the newest send is dropped and a WARN is logged.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.reply_queue_depth_max field.
zerocode
In the Config pane, set the channels.slack.<alias>.reply_queue_depth_max field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.reply_queue_depth_max <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__reply_queue_depth_max=
stream_drafts
Enable progressive draft message streaming via chat.update.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.stream_drafts field.
zerocode
In the Config pane, set the channels.slack.<alias>.stream_drafts field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.stream_drafts <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__stream_drafts=
strict_mention_in_thread
When true (and mention_only is also true), messages inside a Slack thread must also @-mention the bot to trigger a response. By default, thread replies are allowed through without a mention so the bot can keep a back-and-forth going without the user repeating @-mentions. Set this to true in channels shared with human discussion where the bot should stay silent unless explicitly addressed.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.strict_mention_in_thread field.
zerocode
In the Config pane, set the channels.slack.<alias>.strict_mention_in_thread field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.strict_mention_in_thread <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__strict_mention_in_thread=
thread_replies
When true (default), replies stay in the originating Slack thread. When false, replies go to the channel root instead.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.thread_replies field.
zerocode
In the Config pane, set the channels.slack.<alias>.thread_replies field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.thread_replies <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__thread_replies=
use_markdown_blocks
Use the newer Slack markdown block type (12 000 char limit, richer formatting). Defaults to false (uses universally supported section blocks with mrkdwn). Enable this only if your Slack workspace supports the markdown block type.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.use_markdown_blocks field.
zerocode
In the Config pane, set the channels.slack.<alias>.use_markdown_blocks field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.use_markdown_blocks <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__slack__<alias>__use_markdown_blocks=
Socket Mode vs HTTP
When app_token is set, the bot uses Socket Mode: it dials out to Slack,
so no public URL is required. This is the recommended setup and what the
quickstart above uses. Without an app_token, Slack must reach your bot over
HTTP, which means hosting a public events endpoint, more setup and more to
secure.
Threads and context
When a Slack conversation happens in a thread, that thread is its own
conversation. ZeroClaw derives a distinct session key per thread, so every
thread carries an independent context window and history: messages in one
thread never bleed into another, and the agent does not see a sibling thread’s
earlier turns. For Slack this is controlled by thread_replies: when it is on, top-level messages open a thread and each thread is a separate conversation; when off, replies post at the channel root and history is keyed by sender and target instead of by thread.
- Isolation is the point. Each thread’s context is self-contained: it does not leak outside the thread, and nothing from outside the thread leaks in. Parallel threads hold separate conversational state, so unrelated tasks never contaminate each other.
- Long threads grow context. A thread accumulates history while it stays active, so a very long thread eventually fills the model’s context window like any other long conversation. Start a new thread to reset.
- In-flight work is scoped per thread. A new message in one thread does not cancel an in-flight response in another; each thread’s task stands alone.
Set the thread behavior on any surface:
Gateway dashboard
Open /config/channels/slack and toggle the channels.slack.<alias>.thread_replies field.
zerocode
In the Config pane, set the channels.slack.<alias>.thread_replies field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.thread_replies true # thread replies on
zeroclaw config set channels.slack.<alias>.thread_replies false # replies at the channel root
strict_mention_in_thread tightens this further: when true, the bot only
answers inside a thread if a message there @-mentions it, instead of replying to
every message in a thread it’s part of.
Mentions and formatting
mention_only: whentrue, the bot only answers messages that @-mention it, keeping it quiet in busy channels.use_markdown_blocks: render replies with Slack Block Kit formatting for richer layout. Turn off for plain text.
Streaming
Slack streams replies via the stream_drafts boolean:
false(default): the whole reply posts as one message once the agent finishes.true: the bot posts a placeholder immediately and edits it in place as the answer streams in.draft_update_interval_mspaces the edits; raise it if Slack rate-limits them.
Set it on any surface:
Gateway dashboard
Open /config/channels/slack and set the channels.slack.<alias>.stream_drafts field.
zerocode
In the Config pane, set the channels.slack.<alias>.stream_drafts field.
zeroclaw config
zeroclaw config set channels.slack.<alias>.stream_drafts <value>
draft_update_interval_ms controls how often the streaming draft is edited
(raise it if Slack rate-limits the edits), and cancel_reaction sets an emoji
users can react with to cancel an in-flight reply.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Bot connects but never replies | Bot not invited to the channel | /invite @YourBot in the channel |
| “not_authed” / “invalid_auth” at startup | Wrong or missing bot_token | Recopy the xoxb- token (step 4) |
| Bot never connects | Missing app_token or Socket Mode off | Turn on Socket Mode and set the xapp- token (step 3) |
| Bot ignores most messages | mention_only = true | @-mention the bot, or set it to false |
| Replies have no formatting | use_markdown_blocks = false | Set it to true |
See also
- Who can talk to the agent (peer groups)
- Discord
- Channels overview