Fast, local-first Rust CLI for the Slack Web API.
Default output is pretty JSON. Use --output json or --output yaml when you
want stable machine-readable output.
Pick one:
| Method | Command / steps |
|---|---|
| Homebrew (macOS / Linux) | brew install donutdaniel/homebrew-tap/slackcli |
| Binary (GitHub Releases) | Download the archive for your platform, extract it, and move slackcli onto your PATH |
| Cargo (from a local checkout) | Clone this repo, then run cargo install --path . from the repo root |
For local development:
cargo build --release
./target/release/slackcli --help
# or run directly from the repo
cargo run -- --help- Create a Slack app from the included manifest.
- Go to https://api.slack.com/apps and choose
From a manifest. - Paste slack-app-manifest.json.
- Install the app to your workspace.
- Copy the
User OAuth Token(xoxp-...) from theOAuth Tokenssection. - The manifest is intentionally scoped to the current first-class commands.
- Corporate workspaces may require admin approval to create or install the app.
- Go to https://api.slack.com/apps and choose
- Choose an auth mode.
Persist a profile with the hidden token prompt:
slackcli auth loginPersist a profile non-interactively:
slackcli auth login --token "$SLACK_TOKEN"Use an existing SLACK_TOKEN without saving credentials:
env SLACK_TOKEN="$SLACK_TOKEN" slackcli team info- Verify the token and active profile:
slackcli auth doctor
slackcli auth whoami- Try a few commands:
slackcli conversation list --types im,mpim
slackcli conversation history '#general' --limit 50
slackcli conversation open @alice
slackcli resolve conversation @alice
slackcli search messages "from:alice deploy failed"For a personal CLI, a user token is usually the most useful option because it can read the conversations your Slack user can access. A bot token works too, but it only sees what the bot itself can access.
Shell note: quote references that start with #, for example '#general', so
your shell does not treat them as comments.
Most commands accept more than raw Slack IDs:
- conversation refs:
C123,D123,'#general',general,@alice - user refs:
U123,@alice,alice@example.com, display names
Resolution note:
- read commands do not create or open DMs implicitly
conversation open,message send @user, andfile upload --channel @usermay create or resume a DM explicitlyresolve conversation @useronly returns an existing DM; it never opens onesearch messagespasses the query string to Slack unchanged, so Slack's own search syntax and quirks apply
| Flag | Description |
|---|---|
--output <format> |
human (default), json, or yaml |
--profile <name> |
Use a specific saved profile instead of the active one |
--verbose |
Increase log verbosity. Repeat for more detail |
Run slackcli <group> --help for the full flag surface and more examples.
slackcli auth login
slackcli auth login --token "$SLACK_TOKEN"
slackcli auth login --profile-name work
slackcli auth list
slackcli auth use work
slackcli auth logout workslackcli conversation list --types public_channel,private_channel
slackcli conversation open @alice
slackcli conversation open @alice,@bob
slackcli conversation create slackcli-smoke --private
slackcli conversation info '#general'
slackcli conversation history '#general' --limit 100
slackcli conversation replies '#general' 1710000000.000100 --limit 100
slackcli conversation members '#general'slackcli resolve user @alice
slackcli resolve conversation '#general'
slackcli resolve conversation @aliceslackcli message send '#general' --text "hello"
slackcli message send @alice --text "reply" --thread-ts 1710000000.000100
slackcli message send '#general' --text "plain link" --no-unfurl-links --no-unfurl-media
slackcli message update '#general' 1710000000.000100 --text "updated"
slackcli message delete '#general' 1710000000.000100
slackcli message permalink '#general' 1710000000.000100
slackcli reaction add '#general' 1710000000.000100 thumbsup
slackcli reaction remove '#general' 1710000000.000100 thumbsup
slackcli reaction list --user @alice --fullmessage send preserves Slack's default unfurl behavior. Pass
--no-unfurl-links and/or --no-unfurl-media when you want a clean
no-preview send.
slackcli file list --channel '#general' --count 50
slackcli file upload ./report.pdf --channel '#general'
slackcli file upload ./image.png --channel @alice --initial-comment "latest"
slackcli user me
slackcli user get @alice
slackcli team info
slackcli search messages "from:alice in:#eng" --count 50 --sort timestamp --sort-dir descUse this when a Slack method is not covered by a dedicated command yet. The
bundled manifest stays intentionally minimal for the first-class commands
above, so direct api call usage may require adding extra Slack scopes first.
slackcli api call conversations.list --http get --param types=public_channel
slackcli api call chat.postMessage --param channel=C12345 --param text=hello
slackcli api call views.publish --body-json '{"user_id":"U123","view":{"type":"home","blocks":[]}}'For GET requests, repeated --param key=value entries become query
parameters. For POST requests, they merge into the JSON object body. Use
--body-json, --from-file, or --stdin when you need a richer payload.
slackcli conversation list
slackcli --output json conversation history '#general'
slackcli --output yaml team infohuman is the default. Most commands emit the raw Slack API response whenever
possible. CLI-native commands such as auth list and auth doctor emit
structured wrapper objects instead.
Current first-class coverage, raw API fallback coverage, and notable gaps live in COVERAGE.md.
Three local scripts exercise a real Slack workspace:
scripts/live_smoke.sh: safe default; keeps writes inside your private test channelscripts/live_matrix.sh: broader pass with workspace reads plus isolated writesscripts/live_write_smoke.sh: compatibility alias forscripts/live_smoke.sh
Requirements:
- a logged-in profile
jq
Examples:
cargo build
scripts/live_smoke.sh
scripts/live_matrix.shIf you want the safest smoke path, use scripts/live_smoke.sh.
This repo includes a CLI-vs-MCP benchmark harness. It compares slackcli
against Slack's hosted MCP server using the same saved user token and isolated
private benchmark channels.
See BENCHMARKS.md for methodology and current numbers.
Quick example:
cargo build --release
scripts/hyperfine_bench.sh
python3 scripts/bench_strengthen.py --suite readIf you want CLI-vs-MCP comparison, Slack MCP must be enabled for your app first.
Primary references for this CLI:
- Token guidance: https://docs.slack.dev/authentication/tokens/
- OAuth install: https://docs.slack.dev/authentication/installing-with-oauth/
- Web API reference: https://docs.slack.dev/reference/methods
- Slack MCP overview: https://docs.slack.dev/ai/slack-mcp-server/