# 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):
```bash
curl -fsSL https://raw.githubusercontent.com/stablyai/agent-slack/main/install.sh | sh
```
OR npm global install (requires Node >= 22.5):
```bash
npm i -g agent-slack
```
OR run via Nix flake:
```bash
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**: send now or schedule delivery, 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](https://skills.sh)** (recommended):
```bash
npx skills add stablyai/agent-slack
```
Manual installation
```bash
bash ./scripts/install-skill.sh
```
## Command map (high level)
```text
agent-slack
├── update # self-update (detects npm/bun/binary)
├── auth
│ ├── whoami
│ ├── test
│ ├── import-desktop
│ ├── import-brave
│ ├── import-chrome
│ ├── import-firefox
│ └── parse-curl
├── message
│ ├── get # fetch 1 message (+ thread meta )
│ ├── list # fetch thread or recent channel messages
│ ├── send [text] # send / reply / schedule (supports --attach, --blocks)
│ ├── scheduled
│ │ ├── list # list pending scheduled messages
│ │ └── cancel # cancel a pending scheduled message
│ ├── draft [text] # open Slack-like editor in browser
│ ├── edit # edit a message
│ ├── delete # delete a message
│ └── react
│ ├── add
│ └── remove
├── channel
│ ├── list # list conversations (user-scoped or all)
│ ├── new # create channel
│ └── invite # invite users to channel
├── user
│ ├── list
│ └── get
├── search
│ ├── all # messages + files
│ ├── messages
│ └── files
├── workflow
│ ├── list # workflows bookmarked in a channel
│ ├── preview # trigger metadata (no side effects)
│ ├── get # workflow definition + form fields
│ └── run # trip a workflow trigger
└── canvas
└── get # 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/Brave/Firefox extraction (macOS)
You can also run manual imports:
```bash
agent-slack auth whoami
agent-slack auth import-desktop
agent-slack auth import-brave
agent-slack auth import-chrome
agent-slack auth import-firefox
agent-slack auth test
```
> [!NOTE]
> `import-brave` / `import-chrome` read tokens from a logged-in Slack tab via AppleScript. Both browsers ship with **Allow JavaScript from Apple Events** disabled by default — enable it in **View → Developer** before running these commands. macOS will prompt for your password the first time.
Alternatively, set env vars:
```bash
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):
```bash
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//p[?thread_ts=...]`
- Channel: `#general` (or bare `general`) or a channel ID like `C0123...`
In practice:
```bash
# 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:
```bash
agent-slack message get "#general" --workspace "https://stablygroup.slack.com" --ts "1770165109.628379"
agent-slack message get "#general" --workspace "stablygroup" --ts "1770165109.628379"
```
## Examples
> [!TIP]
> You should probably just use the skill for your agent instead of reading below.
### Read messages / threads
```bash
# Single message (+ thread summary if threaded)
agent-slack message get "https://workspace.slack.com/archives/C123/p1700000000000000"
# Full thread for a message
agent-slack message list "https://workspace.slack.com/archives/C123/p1700000000000000"
# Recent channel messages (browse channel history)
agent-slack message list "#general" --limit 20
# Recent channel messages that are marked with :eyes:
agent-slack message list "#general" --with-reaction eyes --oldest "1770165109.000000" --limit 20
# Recent channel messages that do not have :dart:
agent-slack message list "#general" --without-reaction dart --oldest "1770165109.000000" --limit 20
```
Optional:
```bash
# Include reactions + which users reacted
agent-slack message get "https://workspace.slack.com/archives/C123/p1700000000000000" --include-reactions
```
### Draft a message (browser editor)
Opens a Slack-like WYSIWYG editor in your browser for composing messages with full formatting support (bold, italic, strikethrough, links, lists, quotes, code, code blocks).
```bash
# Open editor for a channel
agent-slack message draft "#general"
# Open editor with initial text
agent-slack message draft "#general" "Here's my update"
# Reply in a thread
agent-slack message draft "https://workspace.slack.com/archives/C123/p1700000000000000"
```
After sending, the editor shows a "View in Slack" link to the posted message.
### Reply, edit, delete, and react
```bash
agent-slack message send "https://workspace.slack.com/archives/C123/p1700000000000000" "I can take this."
agent-slack message send "#alerts-staging" "here's the report" --attach ./report.md
agent-slack message send "#announcements" "Deploy starts at 6pm." --schedule ""
agent-slack message send "U05BRPTKL6A" "Heads up before standup" --schedule-in "monday 9am"
agent-slack message edit "https://workspace.slack.com/archives/C123/p1700000000000000" "I can take this today."
agent-slack message delete "https://workspace.slack.com/archives/C123/p1700000000000000"
agent-slack message react add "https://workspace.slack.com/archives/C123/p1700000000000000" "eyes"
agent-slack message react remove "https://workspace.slack.com/archives/C123/p1700000000000000" "eyes"
```
Channel mode requires `--ts`:
```bash
agent-slack message edit "#general" "Updated text" --workspace "myteam" --ts "1770165109.628379"
agent-slack message delete "#general" --workspace "myteam" --ts "1770165109.628379"
```
`message send` and `message edit` convert bullet/numbered lists to Slack native rich text. Inline mentions, broadcasts, emoji shortcodes, and `<#C...>` channel references inside those lists are preserved as Slack elements.
Send options for `message send`:
- `--attach ` upload a local file (repeatable; `` is optional when attaching files)
- `--blocks ` send raw [Block Kit](https://docs.slack.dev/block-kit/) blocks from a JSON file (or `-` for stdin). Bypasses the automatic markdown-to-rich-text conversion, unlocking header/divider/section/table blocks and other structured layouts. Cannot be combined with `--attach`.
- `--reply-broadcast` when replying in a thread, also post the reply to the parent channel (Slack's "Also send to #channel" checkbox). For channel targets, pair with `--thread-ts`; for URL targets, the thread context is derived from the message. Not supported for DM targets; cannot be combined with `--attach`.
- `--schedule