Skip to content

Commit fb257b7

Browse files
committed
feat(slack): add full Slack-NATS integration with Claude streaming
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
1 parent 19aea84 commit fb257b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+20431
-57
lines changed

devops/docker/compose/compose.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,109 @@ services:
9898
profiles:
9999
- dev
100100

101+
slack-bot:
102+
build:
103+
context: ../../../rsworkspace
104+
dockerfile: crates/slack-bot/Dockerfile
105+
environment:
106+
SLACK_BOT_TOKEN: ${SLACK_BOT_TOKEN}
107+
SLACK_APP_TOKEN: ${SLACK_APP_TOKEN}
108+
SLACK_BOT_USER_ID: ${SLACK_BOT_USER_ID:-}
109+
SLACK_MENTION_GATING: ${SLACK_MENTION_GATING:-true}
110+
SLACK_MENTION_GATING_CHANNELS: ${SLACK_MENTION_GATING_CHANNELS:-}
111+
SLACK_NO_MENTION_CHANNELS: ${SLACK_NO_MENTION_CHANNELS:-}
112+
SLACK_ALLOW_BOTS: ${SLACK_ALLOW_BOTS:-false}
113+
SLACK_SIGNING_SECRET: ${SLACK_SIGNING_SECRET:-}
114+
SLACK_EVENTS_PORT: ${SLACK_EVENTS_PORT:-3001}
115+
SLACK_API_RPS: ${SLACK_API_RPS:-1.0}
116+
SLACK_MEDIA_MAX_MB: ${SLACK_MEDIA_MAX_MB:-20}
117+
SLACK_MENTION_PATTERNS: ${SLACK_MENTION_PATTERNS:-}
118+
SLACK_TEXT_CHUNK_LIMIT: ${SLACK_TEXT_CHUNK_LIMIT:-4000}
119+
SLACK_CHUNK_MODE: ${SLACK_CHUNK_MODE:-chars}
120+
SLACK_USER_TOKEN: ${SLACK_USER_TOKEN:-}
121+
HEALTH_PORT: 8080
122+
NATS_URL: nats://nats:4222
123+
NATS_TOKEN: ${NATS_TOKEN:-}
124+
NATS_CREDS: ${NATS_CREDS:-}
125+
RUST_LOG: ${RUST_LOG:-info}
126+
depends_on:
127+
nats:
128+
condition: service_healthy
129+
restart: unless-stopped
130+
131+
slack-agent:
132+
build:
133+
context: ../../../rsworkspace
134+
dockerfile: crates/slack-agent/Dockerfile
135+
environment:
136+
NATS_URL: nats://nats:4222
137+
NATS_TOKEN: ${NATS_TOKEN:-}
138+
NATS_CREDS: ${NATS_CREDS:-}
139+
LLM_PROVIDER: ${LLM_PROVIDER:-anthropic}
140+
SLACK_REPLY_TO_MODE: ${SLACK_REPLY_TO_MODE:-off}
141+
SLACK_REPLY_TO_MODE_DM: ${SLACK_REPLY_TO_MODE_DM:-}
142+
SLACK_REPLY_TO_MODE_GROUP: ${SLACK_REPLY_TO_MODE_GROUP:-}
143+
SLACK_REPLY_TO_MODE_CHANNEL: ${SLACK_REPLY_TO_MODE_CHANNEL:-}
144+
SLACK_ACK_REACTION: ${SLACK_ACK_REACTION:-}
145+
SLACK_DM_POLICY: ${SLACK_DM_POLICY:-open}
146+
SLACK_CHANNEL_ALLOWLIST: ${SLACK_CHANNEL_ALLOWLIST:-}
147+
SLACK_USER_ALLOWLIST: ${SLACK_USER_ALLOWLIST:-}
148+
SLACK_USER_BLOCKLIST: ${SLACK_USER_BLOCKLIST:-}
149+
SLACK_WELCOME_MESSAGE: ${SLACK_WELCOME_MESSAGE:-}
150+
SLACK_ALLOW_BOTS: ${SLACK_ALLOW_BOTS:-false}
151+
SLACK_USER_RATE_LIMIT: ${SLACK_USER_RATE_LIMIT:-0}
152+
SLACK_DEBOUNCE_MS: ${SLACK_DEBOUNCE_MS:-0}
153+
SLACK_REACTION_NOTIFICATIONS: ${SLACK_REACTION_NOTIFICATIONS:-false}
154+
SLACK_MAX_CONCURRENT_SESSIONS: ${SLACK_MAX_CONCURRENT_SESSIONS:-0}
155+
SLACK_UPLOAD_THRESHOLD_CHARS: ${SLACK_UPLOAD_THRESHOLD_CHARS:-0}
156+
SLACK_SEED_HISTORY_ON_START: ${SLACK_SEED_HISTORY_ON_START:-0}
157+
SLACK_NO_TYPING_CHANNELS: ${SLACK_NO_TYPING_CHANNELS:-}
158+
SLACK_DM_PAIR_CHANNEL: ${SLACK_DM_PAIR_CHANNEL:-}
159+
SLACK_SUGGESTED_PROMPTS: ${SLACK_SUGGESTED_PROMPTS:-}
160+
SLACK_STREAM_MODE: ${SLACK_STREAM_MODE:-partial}
161+
SLACK_REQUIRE_MENTION: ${SLACK_REQUIRE_MENTION:-false}
162+
SLACK_DM_SCOPE: ${SLACK_DM_SCOPE:-}
163+
SLACK_HISTORY_SCOPE: ${SLACK_HISTORY_SCOPE:-}
164+
SLACK_INHERIT_PARENT: ${SLACK_INHERIT_PARENT:-false}
165+
SLACK_SLASH_COMMAND_NAME: ${SLACK_SLASH_COMMAND_NAME:-}
166+
SLACK_SLASH_COMMAND_EPHEMERAL: ${SLACK_SLASH_COMMAND_EPHEMERAL:-true}
167+
SLACK_SLASH_COMMAND_OPTIONS: ${SLACK_SLASH_COMMAND_OPTIONS:-}
168+
CHANNEL_SYSTEM_PROMPTS: ${CHANNEL_SYSTEM_PROMPTS:-}
169+
CHANNEL_USER_ALLOWLISTS: ${CHANNEL_USER_ALLOWLISTS:-}
170+
CHANNEL_ACK_REACTIONS: ${CHANNEL_ACK_REACTIONS:-}
171+
THREAD_INITIAL_HISTORY_LIMIT: ${THREAD_INITIAL_HISTORY_LIMIT:-0}
172+
CLAUDE_MODEL: ${CLAUDE_MODEL:-claude-sonnet-4-6}
173+
CLAUDE_MAX_TOKENS: ${CLAUDE_MAX_TOKENS:-8192}
174+
CLAUDE_SYSTEM_PROMPT: ${CLAUDE_SYSTEM_PROMPT:-}
175+
CLAUDE_SYSTEM_PROMPT_FILE: ${CLAUDE_SYSTEM_PROMPT_FILE:-}
176+
CLAUDE_RETRY_ATTEMPTS: ${CLAUDE_RETRY_ATTEMPTS:-3}
177+
CLAUDE_MAX_HISTORY: ${CLAUDE_MAX_HISTORY:-40}
178+
CLAUDE_MAX_HISTORY_CHARS: ${CLAUDE_MAX_HISTORY_CHARS:-0}
179+
HEALTH_PORT: 8081
180+
RUST_LOG: ${RUST_LOG:-info}
181+
depends_on:
182+
nats:
183+
condition: service_healthy
184+
restart: unless-stopped
185+
186+
llm-anthropic:
187+
build:
188+
context: ../../../rsworkspace
189+
dockerfile: crates/llm-anthropic/Dockerfile
190+
environment:
191+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
192+
ANTHROPIC_DEFAULT_MODEL: ${ANTHROPIC_DEFAULT_MODEL:-claude-sonnet-4-6}
193+
ANTHROPIC_DEFAULT_MAX_TOKENS: ${ANTHROPIC_DEFAULT_MAX_TOKENS:-8192}
194+
ANTHROPIC_RETRY_ATTEMPTS: ${ANTHROPIC_RETRY_ATTEMPTS:-3}
195+
ACCOUNT_ID: ${SLACK_ACCOUNT_ID:-}
196+
NATS_URL: nats://nats:4222
197+
NATS_TOKEN: ${NATS_TOKEN:-}
198+
NATS_CREDS: ${NATS_CREDS:-}
199+
RUST_LOG: ${RUST_LOG:-info}
200+
depends_on:
201+
nats:
202+
condition: service_healthy
203+
restart: unless-stopped
204+
101205
volumes:
102206
nats_data:

rsworkspace/.env.example

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# ── Slack (slack-bot) ────────────────────────────────────────────────────────
2+
3+
# Required: Slack bot token (xoxb-...)
4+
SLACK_BOT_TOKEN=xoxb-
5+
6+
# Required: Slack app-level token for Socket Mode (xapp-...)
7+
SLACK_APP_TOKEN=xapp-
8+
9+
# Optional: Bot user ID (e.g. U01234ABCDE) — auto-detected via auth.test at startup.
10+
# Only needed if auto-detection fails.
11+
# SLACK_BOT_USER_ID=
12+
13+
# Optional: When "false" or "0", the bot responds to all channel messages
14+
# without requiring an @mention. DMs always pass through regardless.
15+
# Default: true (mirrors OpenClaw requireMention)
16+
SLACK_MENTION_GATING=true
17+
18+
# Optional: Per-channel overrides (comma-separated channel IDs).
19+
# SLACK_MENTION_GATING_CHANNELS: gating ON even when SLACK_MENTION_GATING=false
20+
# SLACK_NO_MENTION_CHANNELS: gating OFF even when SLACK_MENTION_GATING=true
21+
# SLACK_MENTION_GATING_CHANNELS=C01234ABCDE,C56789FGHIJ
22+
# SLACK_NO_MENTION_CHANNELS=C01234ABCDE
23+
24+
# Optional: When "true" or "1", messages from other bots are forwarded to NATS.
25+
# Default: false
26+
SLACK_ALLOW_BOTS=false
27+
28+
# Optional: Slack signing secret for verifying Events API webhook requests.
29+
# When set, all requests to /slack/events are HMAC-SHA256 verified.
30+
# SLACK_SIGNING_SECRET=
31+
32+
# Optional: Port for the raw Events API HTTP webhook server (pin events).
33+
# Default: 3001
34+
SLACK_EVENTS_PORT=3001
35+
36+
# Optional: Health check HTTP port for slack-bot.
37+
# Default: 8080
38+
HEALTH_PORT=8080
39+
40+
# Optional: Custom text patterns (comma-separated) that activate the bot even
41+
# when mention gating is enabled. Case-insensitive substring match.
42+
# Example: hey bot,assistant,help me
43+
# SLACK_MENTION_PATTERNS=
44+
45+
# Optional: Slack API requests-per-second limit.
46+
# Default: 1.0
47+
# SLACK_API_RPS=1.0
48+
49+
# Optional: Maximum file size in MB for inbound media downloads. Default: 20.
50+
# SLACK_MEDIA_MAX_MB=20
51+
52+
# Optional: Maximum characters per Slack message before chunking. Default: 4000.
53+
# SLACK_TEXT_CHUNK_LIMIT=4000
54+
55+
# Optional: Text chunking mode. "chars" splits at limit, "newline" prefers paragraph breaks.
56+
# SLACK_CHUNK_MODE=chars
57+
58+
# Optional: Slack user token (xoxp-...) for read operations requiring user permissions.
59+
# SLACK_USER_TOKEN=
60+
61+
# ── Slack (slack-agent) ───────────────────────────────────────────────────────
62+
63+
# Optional: Emoji shortcode (no colons) to add while processing a message,
64+
# removed once the response is delivered. Leave empty to disable.
65+
# Example: eyes
66+
SLACK_ACK_REACTION=eyes
67+
68+
# Optional: Threading mode.
69+
# Values: "off" (default) | "first" | "all"
70+
SLACK_REPLY_TO_MODE=first
71+
72+
# Optional: Per-chat-type threading overrides.
73+
# SLACK_REPLY_TO_MODE_DM=off # override for direct messages
74+
# SLACK_REPLY_TO_MODE_GROUP=off # override for group DMs
75+
76+
# Optional: Message posted to a channel when a new member joins.
77+
# Leave empty to disable.
78+
# SLACK_WELCOME_MESSAGE=Welcome to the channel! I'm here to help.
79+
80+
# Optional: Controls who can send the bot direct messages.
81+
# Values: "open" (default, anyone may DM) | "disabled" (all DMs are silently ignored).
82+
# SLACK_DM_POLICY=open
83+
84+
# Optional: Comma-separated list of Slack channel IDs the bot will process.
85+
# When set, only messages from listed channels are handled. DMs always pass through.
86+
# Leave empty (default) to handle messages from all channels.
87+
# SLACK_CHANNEL_ALLOWLIST=C01234ABCDE,C56789FGHIJ
88+
89+
# Optional: Health check HTTP port for slack-agent.
90+
# Default: 8081
91+
# HEALTH_PORT=8081
92+
93+
# Optional: Comma-separated Slack user IDs allowed to interact with the bot.
94+
# When set, only messages from listed users are processed. Leave empty (default)
95+
# to allow all users.
96+
# SLACK_USER_ALLOWLIST=U01234ABCDE,U56789FGHIJ
97+
98+
# Optional: Comma-separated Slack user IDs blocked from interacting with the bot.
99+
# Messages from listed users are silently ignored. Leave empty (default).
100+
# SLACK_USER_BLOCKLIST=
101+
102+
# Optional: Per-channel system prompt overrides. Format: C123=prompt,C456=other prompt
103+
# The first = in each pair is the delimiter; prompt text may contain =.
104+
# CHANNEL_SYSTEM_PROMPTS=
105+
106+
# Optional: Milliseconds to wait before processing a message. When a second message
107+
# arrives from the same session within the window, the first is discarded.
108+
# 0 = disabled (default).
109+
SLACK_DEBOUNCE_MS=0
110+
111+
# Optional: When "true" or "1", thumbs-up/thumbs-down reactions on messages
112+
# trigger an acknowledgment response in the channel.
113+
# Default: false
114+
SLACK_REACTION_NOTIFICATIONS=false
115+
116+
# Optional: Maximum number of concurrent Claude API calls. 0 = unlimited (default).
117+
SLACK_MAX_CONCURRENT_SESSIONS=0
118+
119+
# Optional: Upload responses longer than this many characters as a Markdown file
120+
# instead of sending them as inline text. 0 / unset = disabled (default).
121+
# SLACK_UPLOAD_THRESHOLD_CHARS=3000
122+
123+
# Optional: Maximum messages per user per minute. 0 = unlimited (default).
124+
# SLACK_USER_RATE_LIMIT=0
125+
126+
# Optional: Number of recent channel messages to fetch from Slack when a session
127+
# starts with no history. 0 = disabled (default).
128+
# SLACK_SEED_HISTORY_ON_START=0
129+
130+
# Optional: Channels where the typing indicator is suppressed (comma-separated).
131+
# Example: C01234ABCDE,C56789FGHIJ
132+
# SLACK_NO_TYPING_CHANNELS=
133+
134+
# Optional: When set, DM sessions share conversation history with this channel.
135+
# Specify a single channel ID (e.g. "C01234ABCDE").
136+
# SLACK_DM_PAIR_CHANNEL=
137+
138+
# Optional: Suggested prompts to show in the Slack assistant thread UI.
139+
# Format: "Title1:Message1,Title2:Message2"
140+
# SLACK_SUGGESTED_PROMPTS=Get started:Summarize the conversation,Help me code:Write a function
141+
142+
# ── Claude / Anthropic (slack-agent) ─────────────────────────────────────────
143+
144+
# Required for AI responses: Anthropic API key
145+
ANTHROPIC_API_KEY=sk-ant-
146+
147+
# Optional: Claude model to use.
148+
# Default: claude-sonnet-4-6
149+
CLAUDE_MODEL=claude-sonnet-4-6
150+
151+
# Optional: Maximum output tokens per response.
152+
# Default: 8192
153+
CLAUDE_MAX_TOKENS=8192
154+
155+
# Optional: System prompt — choose one of the two options below.
156+
# Inline text (good for short prompts):
157+
CLAUDE_SYSTEM_PROMPT=You are a helpful assistant.
158+
# Path to a file containing the prompt (takes precedence when both are set):
159+
# CLAUDE_SYSTEM_PROMPT_FILE=/run/secrets/prompt.txt
160+
161+
# Optional: Number of retry attempts when the Claude API returns a transient error.
162+
# Default: 3 (0 = no retries, max 5).
163+
CLAUDE_RETRY_ATTEMPTS=3
164+
165+
# Optional: Maximum number of messages to retain in conversation history
166+
# per session (user + assistant messages count together).
167+
# Default: 40
168+
CLAUDE_MAX_HISTORY=40
169+
170+
# Optional: Maximum total characters in history before truncating old messages.
171+
# Uses chars/4 as a token proxy. 0 = disabled (default). ~200000 ≈ 50K tokens.
172+
CLAUDE_MAX_HISTORY_CHARS=0
173+
174+
# Optional: Thread history seeding — number of messages to load from the
175+
# parent channel session when a new thread starts.
176+
# Default: 0 (disabled)
177+
THREAD_INITIAL_HISTORY_LIMIT=0
178+
179+
# Optional: When "true" or "1", messages from other bots are forwarded.
180+
# Default: false
181+
# SLACK_ALLOW_BOTS=false
182+
183+
# ── NATS ──────────────────────────────────────────────────────────────────────
184+
185+
# Required: NATS server URL
186+
NATS_URL=nats://localhost:4222
187+
188+
# Optional: NATS authentication token (mutually exclusive with NATS_CREDS)
189+
NATS_TOKEN=
190+
191+
# Optional: Path to a NATS credentials file (.creds)
192+
NATS_CREDS=

0 commit comments

Comments
 (0)