Skip to content

Overview

A headless Slack CLI for agents, scripts, and CI jobs. The binary is slick; the repo and Go module are slack-cli.

Runtime commands take flags, stdin, or environment variables. They never prompt. Command data goes to stdout; diagnostics and errors go to stderr. Successful events render as human-friendly clog output by default and auto-switch to JSON when stdout is not a TTY or an agent is detected.

Install

brew install matcra587/tap/slick

Also available via go install and pre-built binaries. See Installation for go install, GitHub Releases, source builds, and upgrade paths.

The examples below assume slick is on PATH. Every visible flag has a short form; run slick <command> --help for the current mapping.

First-time setup

slick manifest template --preset messaging --type user --name slack-cli > manifest.json
# Import manifest.json in Slack, then:
slick auth login
slick auth status

See auth and manifest for full setup, including OAuth redirect URL handling and the token-based auth path.

Commands

Command Summary
auth Manage Slack authentication: OAuth or token login, status, switch, logout.
message Send, edit, and delete Slack messages (channels and DMs).
reply Reply to a Slack thread by parent timestamp.
react Add, remove, or list emoji reactions.
history Read channel or thread history.
lookup Look up channels, users, or search messages.
cache Prime and inspect local Slack metadata caches.
status Set or clear the authenticated user's Slack status.
health Check Slack service health and Web API reachability.
file Upload a file to Slack (probationary; hidden in help).
config Manage local preferences (not auth).
workspace List configured workspace profiles.
manifest Generate Slack app manifests for import.
agent Emit command schema and workflow runbooks for agents.
version Print version information.

Output modes

slick has a single output flag, --output (short -o), with four values:

  • auto — the default. TTY without an agent renders human-readable clog output; everything else renders the JSON envelope.
  • human — human-readable clog output.
  • json — full envelope with meta, data, and errors[].
  • compact — JSON data only; no envelope.

Under auto, JSON is selected when stdout is not a TTY or when slick detects an agent environment (e.g. CLAUDE_CODE, CURSOR_TERMINAL, CODEX, GITHUB_ACTIONS, CI).

Use command-local --blocks when the message body is already a Slack Block Kit JSON array.

Exit codes

Code Meaning
0 Success
1 auth_failure (invalid_auth, missing_scope, no_permission, expired)
2 not_found (channel_not_found, user_not_found, not_in_channel, …)
3 rate_limit (with retry_after_seconds in the error envelope)
4 validation_error (bad flags, malformed input, Slack rejects the value)
5 server_error (Slack 5xx or filesystem/runtime failure)
6 canceled (SIGINT/SIGTERM during a Slack call)
7 timeout (--timeout exceeded)

JSON-mode failures put errors[0].type, errors[0].message, and errors[0].exit_code on stderr. The action label (e.g. Message sent) goes to stdout only on success.

Output styling

slick uses gechr/clog for human-mode output and gechr/primer/table for tables. The visual conventions:

  • Identity fields (channel, user, team_id, workspace, file_id, …) are hash-coloured from the theme's entity palette so the same ID renders the same colour across commands.
  • Human labels (channel name, user name, file name, descriptions) render default-styled.
  • Slack entity and permalink fields may render as OSC 8 terminal hyperlinks in human mode when slick has enough workspace metadata. Parse JSON for raw channel IDs, channel_name, channel_hr, channel_url, timestamps, and full permalink URLs. channel_url uses Slack's native slack:// scheme on macOS and https://app.slack.com/client/<team>/<conversation> elsewhere; it is omitted when slick lacks a team ID or real conversation ID.
  • Time fields (ts, fetched_at, expiration) render in clog's FieldTime magenta.
  • Bool fields follow a three-tier polarity:
    • Alarming on true (e.g. is_archived, deleted, truncated) — red on true, dim on false.
    • Both states matter (e.g. authenticated, exists) — green on true, red on false.
    • Routine on true (e.g. is_member) — dim on true, default on false.
  • Action-result bools (dry_run) are kept where they convey whether a real Slack call happened. cache clear retains cleared because the operation has no other status field; the other action-result bools (deleted, removed, written) were dropped in v0.4.0 in favour of the action label plus errors[].

Field order across commands follows a canonical taxonomy: where → what → when → state → detail → numbers → diagnostics → pagination. An AST-walking test enforces this on every CI run; see internal/cli/output/field_order_test.go if you want the full rule.

Attribution

When slick detects an agent or CI environment, the four mutating commands (message send, message edit, reply, file upload) attach a Block Kit context block to the Slack message. The trigger set covers most popular AI assistants (Claude Code, Cursor, Codex, Aider, Cline, Windsurf, GitHub Copilot, Codeium, Amazon Q, Gemini Code Assist, Cody) and CI systems (GitHub Actions, Buildkite, Jenkins, GitLab CI, CircleCI, Travis, Bitbucket Pipelines, TeamCity, Azure Pipelines, and the generic CI variable). The authoritative list lives in internal/agent/detect.go. Override per-call with --attribution-label, --attribution-emoji, --attribution-message. Toggle the block itself with --attribution (force on) or --no-attribution (force off); both override config defaults and env detection, so you can attribute a single command on a workspace with attribution.enabled = false or suppress a single one when running inside a detected agent.

The attribution context block reflects the detection state in the rendered Slack message:

  • :robot_face: _Sent via slick (agent mode)_ — slick auto-detected an agent or CI environment.
  • :robot_face: _Sent via slick_ — slick is running interactively (no agent triggers) but attribution.enabled = true is set in config.

Override either piece with --attribution-message (text body) or --attribution-emoji (leading emoji).

Config can pin attribution defaults per workspace:

slick config set workspaces.default.attribution.enabled true
slick config set workspaces.default.attribution.emoji :robot_face:
slick config set workspaces.default.attribution.message "Sent via build agent"

Configuration paths

  • Config: ${SLICK_CONFIG:-${XDG_CONFIG_HOME:-~/.config}/slick/config.toml}. SLACK_CLI_CONFIG remains as a legacy override.
  • Cache: ${XDG_CACHE_HOME:-~/.cache}/slick/<profile>/.
  • Path inputs (SLICK_CONFIG, --token-file, --file, …) expand ~ and environment variables.

Tokens never appear in argv, TOML, stdout, stderr, or any of these docs. Auth-owned fields store keychain or secret-manager references; config commands do not edit them.

Further reading

  • Per-command pages above for flags, examples, and JSON shapes.
  • slick agent guide for machine-readable runbooks designed for agent consumption.
  • slick agent schema for the full command tree and exit-code contract in JSON.
  • Repo source