Skip to content

open-cli-collective/slack-chat-api

Repository files navigation

slack-chat-cli

A lightweight command-line interface for interacting with the Slack Web API.

Not the Official Slack CLI

This project is not affiliated with Slack or Salesforce. If you're looking to build Slack apps with workflows, triggers, and datastores, check out the official Slack CLI.

What's the difference?

Feature slck (this project) Official Slack CLI
Purpose Direct API access for automation & scripting Build and deploy Slack apps
Use cases Send messages, manage channels, search, CI/CD integration Workflows, triggers, datastores, app development
Authentication Bot/User OAuth tokens Slack app credentials
Complexity Simple, single binary Full development framework

When to use slck:

  • Sending notifications from CI/CD pipelines
  • Automating channel management
  • Scripting message operations
  • Quick API interactions from the terminal
  • Integrating Slack into shell scripts or automation tools

Installation

macOS

Homebrew (recommended)

brew install open-cli-collective/tap/slack-chat-cli

Note: This installs from our third-party tap.


Windows

Chocolatey

choco install slack-chat-cli

Winget

winget install OpenCLICollective.slack-chat-cli

Linux

Snap

sudo snap install ocli-slack

Note: After installation, the command is available as slck.

APT (Debian/Ubuntu)

# Add the GPG key
curl -fsSL https://open-cli-collective.github.io/linux-packages/keys/gpg.asc | sudo gpg --dearmor -o /usr/share/keyrings/open-cli-collective.gpg

# Add the repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/open-cli-collective.gpg] https://open-cli-collective.github.io/linux-packages/apt stable main" | sudo tee /etc/apt/sources.list.d/open-cli-collective.list

# Install
sudo apt update
sudo apt install slck

Note: This is our third-party APT repository, not official Debian/Ubuntu repos.

DNF/YUM (Fedora/RHEL/CentOS)

# Add the repository
sudo tee /etc/yum.repos.d/open-cli-collective.repo << 'EOF'
[open-cli-collective]
name=Open CLI Collective
baseurl=https://open-cli-collective.github.io/linux-packages/rpm
enabled=1
gpgcheck=1
gpgkey=https://open-cli-collective.github.io/linux-packages/keys/gpg.asc
EOF

# Install
sudo dnf install slck

Note: This is our third-party RPM repository, not official Fedora/RHEL repos.

Binary download

Download .deb, .rpm, or .tar.gz from the Releases page - available for x64 and ARM64.

# Direct .deb install
curl -LO https://github.com/open-cli-collective/slack-chat-api/releases/latest/download/slck_VERSION_linux_amd64.deb
sudo dpkg -i slck_VERSION_linux_amd64.deb

# Direct .rpm install
curl -LO https://github.com/open-cli-collective/slack-chat-api/releases/latest/download/slck-VERSION.x86_64.rpm
sudo rpm -i slck-VERSION.x86_64.rpm

From Source

go install github.com/open-cli-collective/slack-chat-api/cmd/slck@latest

Manual Build

git clone https://github.com/open-cli-collective/slack-chat-api.git
cd slack-chat-api
make build

Platform Support

Credentials are stored in the OS keyring via the shared cli-common/credstore library:

Platform Credential Storage
macOS Keychain
Windows Credential Manager
Linux Secret Service (D-Bus); fails closed if a working keyring is locked. Encrypted-file backend only when there is no keyring at all, or by explicit opt-in (keyring.backend: file in config.yml).

Tokens are never written to a plaintext file. Non-secret config (credential_ref, workspace) lives in ~/.config/slack-chat-api/config.yml.

Credential Resolution

At runtime the only source of a token is the OS keyring. Environment variables are not read as credentials at runtime (per the Open CLI Collective Secret-Handling Standard §1.11) — they are accepted only as ingress during setup, e.g. slck init --bot-token-from-env SLACK_BOT_TOKEN or op read ... | slck set-credential --key bot_token --stdin.

Migrating from an older slck? On first run, any tokens from a previous version (old macOS Keychain items under service slck/slack-chat-api, or the legacy ~/.config/slack-chat-api/credentials file) are moved into the keyring automatically, once, then the originals are removed. A one-line notice is printed to stderr (and a _migration block to JSON output).

Authentication

Quick Setup (2 minutes)

  1. Go to api.slack.com/appsCreate New AppFrom an app manifest

  2. Select your workspace

  3. Paste this manifest (JSON tab recommended):

    {
      "display_information": {
        "name": "Slack Chat API"
      },
      "features": {
        "bot_user": {
          "display_name": "Slack Chat API",
          "always_online": false
        }
      },
      "oauth_config": {
        "scopes": {
          "bot": [
            "channels:history",
            "channels:manage",
            "channels:read",
            "chat:write",
            "emoji:read",
            "files:read",
            "groups:history",
            "groups:read",
            "reactions:write",
            "team:read",
            "users:read"
          ],
          "user": [
            "search:read"
          ]
        }
      },
      "settings": {
        "org_deploy_enabled": false,
        "socket_mode_enabled": false
      }
    }
    YAML alternative (if you prefer)
    display_information:
      name: Slack Chat API
    features:
      bot_user:
        display_name: Slack Chat API
        always_online: false
    oauth_config:
      scopes:
        bot:
          - "channels:history"
          - "channels:manage"
          - "channels:read"
          - "chat:write"
          - "emoji:read"
          - "files:read"
          - "groups:history"
          - "groups:read"
          - "reactions:write"
          - "team:read"
          - "users:read"
        user:
          - "search:read"
    settings:
      org_deploy_enabled: false
      socket_mode_enabled: false
    Extended manifest — every read scope slck can use, plus all writes (DMs, group DMs, file uploads, canvas CRUD, etc.)

    Use this if you want maximum capability out of the box — reading DMs and group DMs, uploading file attachments to any channel/DM/group-DM, creating/editing/deleting canvases, resolving @subteam mentions, extended user profile data, etc. Every scope here is either needed by an existing slck command or unlocks a capability that commonly extends one (e.g. im:history so slck messages thread works on DMs, files:write for slck messages send --file, canvases:write for slck canvas create).

    {
      "display_information": {
        "name": "Slack Chat API"
      },
      "features": {
        "bot_user": {
          "display_name": "Slack Chat API",
          "always_online": false
        }
      },
      "oauth_config": {
        "scopes": {
          "bot": [
            "app_mentions:read",
            "bookmarks:read",
            "calls:read",
            "canvases:read",
            "canvases:write",
            "channels:history",
            "channels:manage",
            "channels:read",
            "chat:write",
            "chat:write.public",
            "dnd:read",
            "emoji:read",
            "files:read",
            "files:write",
            "groups:history",
            "groups:read",
            "groups:write",
            "im:history",
            "im:read",
            "im:write",
            "links:read",
            "lists:read",
            "metadata.message:read",
            "mpim:history",
            "mpim:read",
            "mpim:write",
            "pins:read",
            "reactions:read",
            "reactions:write",
            "reminders:read",
            "remote_files:read",
            "search:read.files",
            "search:read.mpim",
            "search:read.public",
            "search:read.users",
            "team:read",
            "usergroups:read",
            "users.profile:read",
            "users:read"
          ],
          "user": [
            "search:read",
            "search:read.files",
            "search:read.im",
            "search:read.mpim",
            "search:read.private",
            "search:read.public",
            "search:read.users"
          ]
        },
        "pkce_enabled": false
      },
      "settings": {
        "org_deploy_enabled": false,
        "socket_mode_enabled": false,
        "token_rotation_enabled": false,
        "is_mcp_enabled": false
      }
    }

    Upgrading an existing install? Paste the full manifest above into your app's Features → App Manifest tab (replacing the previous manifest), click Save Changes, then click Install App → Reinstall to Workspace to grant the new scopes. Copy the fresh xoxb-… token and run slck init (or slck set-credential).

  4. Click CreateInstall to WorkspaceAllow

  5. Copy the Bot User OAuth Token (starts with xoxb-)

  6. Run the interactive setup:

    slck init
    # Paste your token when prompted (input is not echoed back)

Your token is stored in the OS keyring (Keychain / Credential Manager / Secret Service). It is never written to a plaintext file.

NOTE: If you plan on sending messages or taking actions using your user token (See: Choosing Between Bot and User Tokens), you'll need to adjust the manifest above to have all the same scopes configured for your user as your bot (with the exception of the "channels:manage" scope, which only applies to bots).

Scripted / non-interactive setup

The token is read only from stdin or a named env var — never a flag or positional value (so it can't leak via shell history or ps):

# From a pipe (preferred for automation):
op read 'op://Personal/slck/bot_token' | slck set-credential --key bot_token --stdin

# Or, during full init, from a named env var (the env var is consumed at
# setup time only; it is NOT read on subsequent runs):
slck init --bot-token-from-env SLACK_BOT_TOKEN --user-token-from-env SLACK_USER_TOKEN

1Password integration

Because the token lives in the keyring after setup, you do not wrap every invocation in op. Stage it once:

op read 'op://Personal/slck/bot_token'  | slck set-credential --key bot_token  --stdin
op read 'op://Personal/slck/user_token' | slck set-credential --key user_token --stdin

Replace the op://… references with your own 1Password secret references. Re-run only when the token rotates.

Required Scopes

The manifest above includes these scopes:

Scope Purpose
channels:read List public channels, get channel info
channels:history Read message history from public channels
channels:manage Create, archive, set topic/purpose, invite users
chat:write Send, update, delete messages
emoji:read List custom workspace emoji
files:read Download files, get file info
groups:read List private channels
groups:history Read message history from private channels
reactions:write Add/remove reactions
team:read Get workspace info
users:read List users, get user info
search:read Search messages and files (user token only)

The extended manifest (see the collapsible section above) adds these capabilities on top of the default:

Scope Unlocks
im:history / im:read / im:write Read messages in DMs, list DMs, open new DMs to post to
mpim:history / mpim:read / mpim:write Same for multi-person DMs (group DMs)
files:write Upload files — slck messages send --file in any channel/DM/group-DM
canvases:write Create, edit, delete canvases — slck canvas create/edit/delete
groups:write Create/archive private channels
chat:write.public Post to public channels the bot isn't a member of
users.profile:read Extended user profile (status, timezone, custom fields)
usergroups:read Resolve @subteam / user-group mentions
app_mentions:read Receive @-mention events (needed for event subscriptions)
reactions:read List reactions on a message
Other *:read scopes (bookmarks, pins, reminders, links, lists, calls, dnd, metadata.message, remote_files) Read-only access to those domains; mostly forward-compat for commands that may use them

Token Types

This CLI supports two types of Slack tokens:

Token Type Prefix Commands How to Get
Bot token xoxb- channels, users, messages, workspace OAuth & Permissions → Bot User OAuth Token
User token xoxp- search OAuth & Permissions → User OAuth Token

Most commands use the bot token. Search commands require a user token.

Setting up both tokens:

# Bot token (for channels, users, messages, workspace)
op read 'op://Personal/slck/bot_token'  | slck set-credential --key bot_token  --stdin

# User token (for search)
op read 'op://Personal/slck/user_token' | slck set-credential --key user_token --stdin

Or run slck init for a guided, interactive setup of both.

Getting a user token:

  1. Go to api.slack.com/apps → Your app
  2. OAuth & Permissions → User Token Scopes → Add search:read
  3. Reinstall app to workspace (if already installed)
  4. Copy the User OAuth Token (starts with xoxp-)

Setup-time env-var ingress (read once during slck init, never at runtime):

Flag Description
slck init --bot-token-from-env NAME Read the bot token from env var NAME at setup
slck init --user-token-from-env NAME Read the user token from env var NAME at setup

Global Flags

These flags are available on all commands:

Flag Short Default Description
--output -o text Output format: text, json, or table
--no-color false Disable colored output
--as-user false Use user token
--as-bot false Use bot token
--version -v Show version information
--help -h Show help for any command

Choosing Between Bot and User Tokens

By default, all commands other than search use your bot token. You can set the SLCK_AS_USER env var to true to make your user token the default. You can also use flags to specify which token to use for any specific command (and this will override the default behavior set by your env var).

# Send a message as yourself (using user token)
slck messages send --as-user C1234567890 "Hey team!"

# Set default to user token via environment variable
export SLCK_AS_USER=true
slck messages send C1234567890 "Uses user token by default"

# If the default is user token, you can override back to bot token for a specific command
export SLCK_AS_USER=true
slck messages send --as-bot C1234567890 "Uses bot token"

Usage

Channels

# List all channels
slck channels list

# List with options
slck channels list --types public_channel,private_channel  # Include private channels
slck channels list --limit 50                              # Limit results
slck channels list --exclude-archived=false                # Include archived channels

# Get channel info
slck channels get C1234567890

# Create a channel
slck channels create my-new-channel
slck channels create private-channel --private

# Archive/unarchive
slck channels archive C1234567890
slck channels unarchive C1234567890

# Set topic/purpose
slck channels set-topic C1234567890 "New topic"
slck channels set-purpose C1234567890 "Channel purpose"

# Invite users
slck channels invite C1234567890 U1111111111 U2222222222

Channels Command Reference

Command Flags Description
list --types, --limit, --exclude-archived List channels
get <id> Get channel details
create <name> --private Create a channel
archive <id> --force Archive a channel (prompts for confirmation)
unarchive <id> Unarchive a channel
set-topic <id> <topic> Set channel topic
set-purpose <id> <purpose> Set channel purpose
invite <id> <user>... Invite users to channel

Users

# List all users
slck users list
slck users list --limit 50

# Get user info
slck users get U1234567890

# Search users
slck users search "john"
slck users search "john@company.com" --field email
slck users search "John Smith" --field display_name
slck users search "bot" --include-bots

Users Command Reference

Command Flags Description
list --limit List all users
get <id> Get user details
search <query> --limit, --field, --include-bots Search users by name, email, or display name

Users Search Flags

Flag Default Description
--limit 1000 Maximum users to search through
--field all Search field: all, name, email, display_name
--include-bots false Include bot users in results

Messages

# Send a message (uses Block Kit formatting by default)
slck messages send C1234567890 "Hello, *world*!"

# Send using --channel flag (alternative to positional arg)
slck messages send --channel general "Hello team"

# Send from stdin (use "-" as text argument)
echo "Hello from stdin" | slck messages send C1234567890 -
cat message.txt | slck messages send C1234567890 -

# Send plain text (no formatting)
slck messages send C1234567890 "Plain text" --simple

# Send with custom Block Kit blocks
slck messages send C1234567890 "Fallback" --blocks '[{"type":"section","text":{"type":"mrkdwn","text":"*Bold*"}}]'

# Reply in a thread
slck messages send C1234567890 "Thread reply" --thread 1234567890.123456

# Upload files with a message
slck messages send C1234567890 "Here's the report" --file ./report.csv
slck messages send C1234567890 --file ./a.csv --file ./b.csv

# Update a message
slck messages update C1234567890 1234567890.123456 "Updated text"
slck messages update C1234567890 1234567890.123456 "Plain update" --simple

# Delete a message
slck messages delete C1234567890 1234567890.123456

# Get channel history
slck messages history C1234567890
slck messages history C1234567890 --limit 50
slck messages history C1234567890 --oldest 1234567890.000000  # After this time
slck messages history C1234567890 --latest 1234567890.000000  # Before this time

# Get thread replies
slck messages thread C1234567890 1234567890.123456
slck messages thread C1234567890 1234567890.123456 --limit 50
slck messages thread C1234567890 1234567890.123456 --since 1234567890.000000  # Only newer replies

# Add/remove reactions
slck messages react C1234567890 1234567890.123456 thumbsup
slck messages unreact C1234567890 1234567890.123456 thumbsup

Messages Command Reference

Command Flags Description
send <channel> <text> --thread, --blocks, --simple, --channel, --file Send a message (use - for stdin)
update <channel> <ts> <text> --blocks, --simple Update a message
delete <channel> <ts> --force Delete a message (prompts for confirmation)
history <channel> --limit, --oldest, --latest Get channel history
thread <channel> <ts> --limit, --since Get thread replies
react <channel> <ts> <emoji> Add reaction
unreact <channel> <ts> <emoji> Remove reaction

Search

Note: Search requires a user token (xoxp-*). See Token Types.

# Search messages
slck search messages "quarterly report"
slck search messages "in:#general bug fix"
slck search messages "from:@alice project update"

# Search files
slck search files "budget spreadsheet"
slck search files "type:pdf report"

# Search all (messages + files)
slck search all "project proposal"
slck search all "quarterly" --sort timestamp

# With pagination
slck search messages "error" --count 50 --page 2

# Using query builder flags (alternative to modifiers in query string)
slck search messages "meeting" --in "#general"
slck search messages "update" --from "@alice"
slck search messages "report" --scope public
slck search messages "project" --after 2025-01-01 --before 2025-12-31
slck search messages "link" --has-link
slck search files "document" --type pdf

Search Modifiers

Modifier Example Description
in: in:#channel or in:@user Search in specific channel or DM
from: from:@username Content from specific user
before: before:2025-01-01 Before date
after: after:2025-01-01 After date
has:link Messages containing links
has:reaction Messages with reactions
type: type:pdf Files of specific type

Search Command Reference

Command Flags Description
messages <query> --count, --page, --sort, --sort-dir, --highlight, --scope, --in, --from, --after, --before, --has-link, --has-reaction Search messages
files <query> --count, --page, --sort, --sort-dir, --highlight, --scope, --in, --from, --after, --before, --type, --has-pin Search files
all <query> --count, --page, --sort, --sort-dir, --highlight, --scope, --in, --from, --after, --before, --has-link, --has-reaction Search messages and files

Search Flags

Flag Short Default Description
--count -c 20 Results per page (max 100)
--page -p 1 Page number (max 100)
--sort -s score Sort by: score or timestamp
--sort-dir desc Sort direction: asc or desc
--highlight false Highlight matching terms

Query Builder Flags

These flags provide an alternative to using modifiers in the query string:

Flag Description
--scope Search scope: all, public, private, dm, mpim
--in Filter by channel (e.g., #general or general)
--from Filter by user (e.g., @alice or alice)
--after Content after date (YYYY-MM-DD)
--before Content before date (YYYY-MM-DD)
--has-link Messages containing links
--has-reaction Messages with reactions
--type File type filter (files only, e.g., pdf, image)
--has-pin Files that are pinned (files only)

Workspace

# Get workspace info
slck workspace info

Emoji

# List custom workspace emoji
slck emoji list

# Include aliases
slck emoji list --include-aliases

Emoji Command Reference

Command Flags Description
list --include-aliases List custom workspace emoji

Files

# Download a file by ID
slck files download F0AHF3NUSQK

# Download to a specific path
slck files download F0AHF3NUSQK --output report.pdf

# Download using a Slack file URL
slck files download "https://files.slack.com/files-pri/T.../F0AHF3NUSQK/file.csv"

Files Command Reference

Command Flags Description
download <file-id-or-url> --output, -O Download a Slack file

Canvas

# Create a standalone canvas
slck canvas create --title "Sprint Review" --text "# Sprint Review\n\nContent here"
slck canvas create --title "Report" --file report.md
echo "# Report" | slck canvas create --title "Report" --file -

# Create a channel canvas (pinned to channel tab)
slck canvas create --channel C1234567890 --file runbook.md

# Edit a canvas
slck canvas edit F12345ABC --text "# Updated content"
slck canvas edit F12345ABC --file updated.md

# Delete a canvas
slck canvas delete F12345ABC

Canvas Command Reference

Command Flags Description
create --title, --text, --file, --channel Create a standalone or channel canvas
edit <canvas-id> --text, --file Replace canvas content
delete <canvas-id> Delete a canvas

Note: Canvas commands require additional Slack app scopes not included in the default manifest. See Slack Canvas API docs for required scopes.

Identity

# Show authenticated identity (bot, user, workspace)
slck me

Config

# Guided interactive setup (bot + optional user token)
slck init

# Set one credential from stdin (scriptable; no value on the command line)
op read 'op://Personal/slck/bot_token' | slck set-credential --key bot_token --stdin

# Show current config status (backend, ref, which keys present — never values)
slck config show

# Delete stored token(s)
slck config delete-token

Config Command Reference

Ingress is at the top level, not under config:

Command Flags Description
slck init --bot-token-from-env, --user-token-from-env, --bot-token-stdin, --overwrite, --no-verify Guided setup; stores into the keyring
slck set-credential --key, --stdin, --from-env, --ref Set one credential (stdin/env only)

config subcommands (none accept a secret value):

Command Flags Description
set-token Removed — errors out, points to set-credential
show Show backend, ref, which keys are present (never values)
delete-token --force, --type Delete stored token(s)
test Test authentication for configured tokens

The delete-token command accepts a --type flag:

  • --type bot - Delete only the bot token
  • --type user - Delete only the user token
  • --type all - Delete both tokens (default)

Output Formats

All commands support multiple output formats via the --output (or -o) flag:

# Default text output
slck channels list

# JSON output (for scripting)
slck channels list --output json
slck users get U1234567890 -o json

# Table output (aligned columns)
slck channels list --output table

Shell Completion

# Bash
slck completion bash > /etc/bash_completion.d/slck

# Zsh
slck completion zsh > "${fpath[1]}/_slck"

# Fish
slck completion fish > ~/.config/fish/completions/slck.fish

# PowerShell
slck completion powershell > slck.ps1

Aliases

Commands have convenient aliases:

Command Aliases
canvas cv
channels ch
users u
messages msg, m
search s
emoji e
workspace ws, team

Environment Variables

Variable Description
SLCK_AS_USER Set to true or 1 to default to user token instead of bot token
SLACK_CHAT_API_KEYRING_BACKEND Force the keyring backend (e.g. file) — non-secret selector (§1.4)
SLACK_CHAT_API_KEYRING_PASSPHRASE Passphrase for the encrypted-file backend (the one runtime secret-env exception, §1.4)
NO_COLOR Disable colored output when set
XDG_CONFIG_HOME Custom config directory (default: ~/.config)

SLACK_API_TOKEN / SLACK_USER_TOKEN are no longer read at runtime (§1.11). Use slck init --bot-token-from-env / slck set-credential to stage a token into the keyring instead.

Known Limitations

Message Length Limits

Slack silently truncates messages exceeding 40,000 characters. slck validates message length before sending and returns an error with suggestions:

  • Upload as a file: slck messages send C123 --file ./content.txt
  • Create a canvas: slck canvas create --title "Title" --file ./content.md

Unarchiving Channels

Bot tokens (xoxb-) cannot unarchive channels due to a Slack API limitation. When a channel is archived, the bot is automatically removed from it, and bot tokens require membership to unarchive.

Workarounds:

  • Unarchive channels via the Slack UI
  • Use a user token (xoxp-) instead of a bot token

License

MIT

About

Command-line interface for Slack

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages