agent-slack
Slack automation CLI for AI agents (TypeScript + Bun).
Guiding principle:
- Token-efficient — (compact JSON, minimal duplication, and empty/null fields pruned) so LLMs can consume results cheaply.
- Zero-config auth — Auth just works if you have Slack Desktop (with fallbacks available). No Python dependency.
- Human-in-the-loop — When appropriate (not in CI environments), loop humans in. Ex:
message draft

Getting started
Install via Bun (recommended):
curl -fsSL https://raw.githubusercontent.com/stablyai/agent-slack/main/install.sh | sh
OR npm global install (requires Node >= 22.5):
npm i -g agent-slack
OR run via Nix flake:
nix run github:stablyai/agent-slack
At a glance
- Read: fetch a message, browse channel history, list full threads
- Search: messages + files (with filters)
- Artifacts: auto-download snippets/images/files to local paths for agents
- Write: reply, edit/delete messages, add reactions (bullet lists auto-render as native Slack rich text)
- Channels: list conversations, create channels, and invite users by id/handle/email
- Canvas: fetch Slack canvases as Markdown
Agent skill
This repo ships an agent skill at skills/agent-slack/ compatible with Claude Code, Codex, Cursor, etc
Install via skills.sh (recommended):
npx skills add stablyai/agent-slack
Manual installation
bash ./scripts/install-skill.sh
Command map (high level)
agent-slack
├── update # self-update (detects npm/bun/binary)
├── auth
│ ├── whoami
│ ├── test
│ ├── import-desktop
│ ├── import-chrome
│ ├── import-firefox
│ └── parse-curl
├── message
│ ├── get <target> # fetch 1 message (+ thread meta )
│ ├── list <target> # fetch thread or recent channel messages
│ ├── send <target> <text> # send / reply (supports --attach)
│ ├── draft <target> [text] # open Slack-like editor in browser
│ ├── edit <target> <text> # edit a message
│ ├── delete <target> # delete a message
│ └── react
│ ├── add <target> <emoji>
│ └── remove <target> <emoji>
├── channel
│ ├── list # list conversations (user-scoped or all)
│ ├── new # create channel
│ └── invite # invite users to channel
├── user
│ ├── list
│ └── get <user>
├── search
│ ├── all <query> # messages + files
│ ├── messages <query>
│ └── files <query>
├── workflow
│ ├── list <channel> # workflows bookmarked in a channel
│ ├── preview <trigger-id> # trigger metadata (no side effects)
│ ├── get <id> # workflow definition + form fields
│ └── run <trigger-id> # trip a workflow trigger
└── canvas
└── get <canvas-url-or-id> # canvas → markdown
Notes:
- Output is always JSON and aggressively pruned (
null/empty fields removed).
- Attached files are auto-downloaded and returned as absolute local paths.
Authentication (no fancy setup)
On macOS and Windows, authentication happens automatically:
- Default: reads Slack Desktop local data (no need to quit Slack)
- Fallbacks: if that fails, tries Chrome/Firefox extraction (macOS)
You can also run manual imports:
agent-slack auth whoami
agent-slack auth import-desktop
agent-slack auth import-chrome
agent-slack auth import-firefox
agent-slack auth test
Alternatively, set env vars:
export SLACK_TOKEN="xoxc-..." # browser token
export SLACK_COOKIE_D="xoxd-..." # cookie d
agent-slack auth test
Or use a standard Slack token (xoxb/xoxp):
export SLACK_TOKEN="xoxb-..."
agent-slack auth test
Targets: URL or channel
message get / message list accept either a Slack message URL or a channel reference:
- URL:
https://workspace.slack.com/archives/<channel>/p<digits>[?thread_ts=...]
- Channel:
#general (or bare general) or a channel ID like C0123...
In practice:
# Get a single message by channel + ts
agent-slack message get "#general" --ts "1770165109.628379"
# List a full thread by channel + thread root ts
agent-slack message list "#general" --thread-ts "1770165109.000001"
If you have multiple workspaces configured and you use a channel name (#channel / channel), you must pass --workspace (or set SLACK_WORKSPACE_URL).
--workspace accepts a full URL or a unique substring selector:
agent-slack message get "#general" --workspace "https://stablygroup.slack.com" --ts "1770165109.628379"
agent-slack message get "#general" --workspace "stablygroup" --ts "1770165109.628379"
Examples