slackctl

module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT

README

slackctl

CI Release Coverage Go Reference Go version Ask DeepWiki Built with cliwright

A CLI for the Slack Web API — with a Socket Mode event listener and local full-text message history.

Documentation · Commands


A fast, scriptable command-line tool for the Slack Web APIgh-style ergonomics, table/json/yaml/csv output, named profiles for multiple workspaces, OS-keyring token storage, a Socket Mode event stream (slackctl listen), an MCP server so AI agents can drive Slack safely, and an agent guard that hard-blocks the irreversible stuff.

$ slackctl conversations list
ID           NAME        IS_PRIVATE  IS_ARCHIVED  NUM_MEMBERS
C0123ABCD    general     false       false        42
C0456EFGH    eng-alerts  false       false        17

$ slackctl msg post --channel C0456EFGH --text "deploy finished ✅"
$ slackctl listen --dms --json | jq -r .text

Install

# Install script (macOS / Linux) — downloads the release binary, verifies its checksum
curl -fsSL https://raw.githubusercontent.com/jjuanrivvera/slackctl/main/install.sh | sh

# From source (Go 1.24+)
go install github.com/jjuanrivvera/slackctl/cmd/slackctl@latest

# Or build locally
git clone https://github.com/jjuanrivvera/slackctl && cd slackctl && make build

Homebrew/Scoop/deb/rpm/apk packaging ships with tagged releases (GoReleaser config is in the repo; releases are cut from main).

Setup

slackctl talks to Slack as a Slack app. Create one at https://api.slack.com/apps (from scratch), install it to your workspace, and grab tokens:

Token Where Unlocks
Bot xoxb-… OAuth & Permissions → Bot User OAuth Token almost everything (default)
User xoxp-… OAuth & Permissions → User OAuth Token search, saved (user-only methods), --as-user, listen via RTM
App-level xapp-… Basic Information → App-Level Tokens (scope connections:write) slackctl listen via Socket Mode
Session xoxc-… + xoxd-… your Slack web-client session (browser token + d cookie) everything except Socket Mode — no Slack app needed; listen runs over RTM
No Slack app? Use your browser session

If you have a Slack web-client session — an xoxc token plus the paired xoxd cookie (the credentials your browser uses) — slackctl can authenticate with it directly, no app to create:

slackctl auth login --kind session      # paste the xoxc token, then the xoxd cookie
# or, env-only:
export SLACK_XOXC_TOKEN=xoxc-…
export SLACK_XOXD_TOKEN=xoxd-…
slackctl auth status                     # verifies as your user
slackctl conversations list              # reads/writes as you
slackctl listen --dms --json             # streams over RTM (no app needed)

Session creds carry your own identity, so they back bot- and user-kind commands (search and saved items included). The one thing they can't do is Socket Mode; listen uses RTM instead (see the caveat below).

Bot-token scopes to request, matched to what you'll use: channels:read, groups:read, im:read, mpim:read (listing), channels:history + groups:history + im:history + mpim:history (history/replies and message events), chat:write (posting), channels:manage, groups:write, im:write, mpim:write (create/invite/topic/mark), channels:join, reactions:read, reactions:write, users:read, users:read.email, usergroups:read, usergroups:write, pins:read, pins:write, emoji:read, team:read. For the user token: search:read, stars:read, stars:write.

Then:

slackctl init                      # wizard: bot token + optional user/app tokens
# or piecemeal:
slackctl auth login                # bot token → OS keyring
slackctl auth login --kind user    # user token (search, saved items)
slackctl auth login --kind app     # app-level token (listen)
slackctl auth status               # who am I?
slackctl doctor                    # full diagnostics

Tokens live in the OS keyring (macOS Keychain / Linux Secret Service / Windows Credential Manager), never in config files. Env overrides: SLACK_BOT_TOKEN, SLACK_USER_TOKEN, SLACK_APP_TOKEN, or SLACKCTL_TOKEN (explicit, any kind).

Multiple workspaces

A profile is a workspace. --workspace acme (env SLACKCTL_WORKSPACE) selects one; slackctl config use acme switches the default. --profile works as a hidden alias.

Commands

conversations  list · info · history · replies · members · create · rename · archive ·
               unarchive · invite · join · leave · kick · set-topic · set-purpose ·
               mark · open · close · unreads · export   (aliases: conv, channels)
msg            post · update · delete · ephemeral · me · permalink · schedule ·
               scheduled · delete-scheduled · template  (aliases: chat, message)
search         messages · files · all                   (user token)
assistant      search-context                           (bot-token search)
files          list · info · delete · upload · download (aliases: file)
canvases       create · edit · delete · access-set · access-delete · sections-lookup
users          list · info · lookup-email · conversations · presence · profile · search ·
               set-presence · set-status                (aliases: user)
usergroups     list · create · update · enable · disable · members · members-update
dnd            info · set-snooze · end-snooze · end-dnd · team-info
reactions      add · remove · get · list
pins           list · add · remove       bookmarks   list · add · edit · remove
saved          list · add · remove                      (stars API; user token)
emoji          list          team    info · profile
listen         live event stream: Socket Mode (app token) OR RTM (session/user)
log            search your local message history (list · search · stats · prune · path)
auth · config · init · doctor · completion · alias · api · version · mcp · agent

Every command supports -o table|json|yaml|csv|id, --jq <expr>, --columns, --dry-run (prints the equivalent curl, token redacted), --all/--limit on paginated lists, and --as-user to run with the stored user token.

slackctl conversations history --channel C0123 --limit 50 -o json
slackctl conversations export --channel C0123 --threads > history.jsonl   # archive a channel
slackctl files upload --file report.pdf --channels C0123 --comment "Q3"
slackctl users set-status --text "In a meeting" --emoji :calendar:
slackctl dnd set-snooze --minutes 60
slackctl msg template --channel C0123 --file alert.tmpl --set service=api --set status=down
slackctl assistant search-context --query "deploy failed"       # search with a bot token
slackctl api conversations.info -q channel=C0123 --idempotent   # raw escape hatch

slackctl listen — live event stream

Streams events (messages, reactions, …) as they happen, one line each — built for pipes. It has two transports and auto-selects by the credential you have, so it works whether or not you created a Slack app:

Transport Needs Notes
RTM (--transport rtm) user token (xoxp-) or the session pair (xoxc-+xoxd-) No Slack app required — streams with a browser web-client session. Legacy/unofficial for xoxc; a workspace may block it.
Socket Mode (--transport socket) app-level token (xapp-, connections:write) + Socket Mode enabled + event subscriptions Official and robust. Only delivers subscribed events for conversations the bot is in.

--transport auto (default) picks Socket Mode when an app token is present, else RTM.

slackctl listen --dms --json                          # auto transport, DM events as NDJSON
slackctl listen --transport rtm --json                # force RTM (session/user token)
slackctl listen --dms --channels C0123,C0456 --json   # DMs OR those channels
slackctl listen --channels C0123 --since 1h --json    # replay the last hour, then go live
slackctl listen --events message,reaction_added       # filter by event type
slackctl listen --raw | jq .                           # full wire frames

Both transports feed one filter/render path, reconnect with a fresh URL on drop (RTM keeps the socket alive with a periodic ping; Socket Mode acks each envelope before filtering), and shut down cleanly on Ctrl-C.

RTM caveat: Slack marks RTM as legacy and doesn't officially support it for xoxc session tokens — it works today but could be disabled, and some Enterprise Grid workspaces block it. For a durable listener, create a Slack app (no need to publish it), grab an app-level token, and use --transport socket.

slackctl records the messages it sees — posts, fetched history/replies, and streamed listen events — into a per-workspace SQLite database, so you can full-text search your Slack history offline and without Slack's user-token-only, rate-limited search API.

slackctl listen --channels C0123 &          # mirror a channel in real time
slackctl log search "deploy failed"          # search it offline, instantly
slackctl log --channel C0123 --since 24h     # filter by channel + time
slackctl log stats                           # size + FTS mode        log path
slackctl log prune --older-than 2160h        # drop anything older than 90 days

Recording is on by default; disable it with --no-store (per call). The database holds message text — it lives at slackctl log path with 0600 perms, is never uploaded, and log is excluded from the MCP tool surface. See the history guide.

AI agents

slackctl mcp start                            # run as an MCP server (annotated tools)
slackctl agent guard --host claude-code       # generate safety rails
slackctl agent guard --host codex             # read-only sandbox config
slackctl agent guard --host opencode          # permission map

The MCP server exposes each command as a tool with read-only/write/destructive annotations and hides secret/instance flags (--show-token, --workspace, --as-user, --base-url). The agent guard hard-blocks irreversible operations (message deletes, archive/kick/leave, usergroup disable) across canonical and alias command paths, gates the raw api escape hatch to read-shaped methods, and emits a PreToolUse hook that resists quoting/path obfuscation. MCP-only operation is the hard guarantee; the Bash hook is best-effort (documented limits: variable indirection, shell aliases).

Honest limits & alternatives

  • Slack's official CLI targets building/deploying Slack apps (manifests, functions, triggers) — it is not a Web-API data tool. If you're developing a Slack platform app, use it; slackctl is for driving the API from scripts.
  • search and saved need a user token — Slack rejects bot tokens on those methods (not_allowed_token_type), and the stars API (the only public saved-items surface) is deprecated: items you star may not show in the Later tab.
  • Unreads are cursor-relative. conversations unreads reports unreads for whoever owns the token; use --as-user for your own read state.
  • New commercially-distributed non-Marketplace apps (created after May 2025) get conversations.history/replies limited to 1 req/min · 15 items. Internal apps — the normal slackctl case — keep standard Tier 3 limits.
  • No file upload yet: Slack sunset files.upload (Nov 2025); the external-upload flow is on the roadmap.

Development

make verify is the gate: fmt, vet, golangci-lint, tests (race on CI), coverage ≥80%, spec-check (CLI surface ⊆ api-manifest.json), spec-completeness (manifest vs the enumerated 308-method API), and the Definition-of-Done checks. See AGENTS.md and DECISIONS.md for architecture and pinned assumptions.

License

MIT

Directories

Path Synopsis
cmd
slackctl command
Command slackctl is a command-line tool for the Telegram Bot API.
Command slackctl is a command-line tool for the Telegram Bot API.
Package commands wires the Slack Web API client (internal/api) into a Cobra command tree.
Package commands wires the Slack Web API client (internal/api) into a Cobra command tree.
internal
api
auth
Package auth stores bot tokens out of plaintext.
Package auth stores bot tokens out of plaintext.
config
Package config resolves slackctl configuration with a manual flag > env > file > default precedence (no Viper, per the cliwright house pattern).
Package config resolves slackctl configuration with a manual flag > env > file > default precedence (no Viper, per the cliwright house pattern).
output
Package output renders Bot API JSON results in table/json/yaml/csv.
Package output renders Bot API JSON results in table/json/yaml/csv.
rtm
Package rtm is a hand-written client for Slack's legacy Real Time Messaging API — the WebSocket stream that works with a user/session token (xoxc+xoxd), the credential a browser web-client session already has.
Package rtm is a hand-written client for Slack's legacy Real Time Messaging API — the WebSocket stream that works with a user/session token (xoxc+xoxd), the credential a browser web-client session already has.
slackevent
Package slackevent holds the event shape shared by both streaming transports — Socket Mode (app token) and RTM (session/user token).
Package slackevent holds the event shape shared by both streaming transports — Socket Mode (app token) and RTM (session/user token).
socketmode
Package socketmode is a hand-written Slack Socket Mode client (no Slack SDK): it fetches a fresh wss URL from apps.connections.open (app-level xapp token), reads envelopes, acknowledges each within Slack's 3-second window BEFORE handing it to the caller, and reconnects on disconnect frames and socket errors.
Package socketmode is a hand-written Slack Socket Mode client (no Slack SDK): it fetches a fresh wss URL from apps.connections.open (app-level xapp token), reads envelopes, acknowledges each within Slack's 3-second window BEFORE handing it to the caller, and reconnects on disconnect frames and socket errors.
store
Package store is slackctl's local message history: messages you post, read (history/ replies/export), or stream (listen) are recorded to a per-workspace SQLite database, so you can full-text search your Slack history locally — instantly, offline, and without hitting Slack's user-token-only, rate-limited search API.
Package store is slackctl's local message history: messages you post, read (history/ replies/export), or stream (listen) are recorded to a per-workspace SQLite database, so you can full-text search your Slack history locally — instantly, offline, and without hitting Slack's user-token-only, rate-limited search API.
update
Package update self-updates the CLI binary from its GitHub releases.
Package update self-updates the CLI binary from its GitHub releases.
version
Package version holds build metadata, injected at link time via -ldflags.
Package version holds build metadata, injected at link time via -ldflags.
tools
gendocs command
Command gendocs generates the Markdown command reference under docs/commands from the live cobra tree, so the published docs never drift from the actual CLI surface.
Command gendocs generates the Markdown command reference under docs/commands from the live cobra tree, so the published docs never drift from the actual CLI surface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL