@urugus/slack-cli
v0.27.0
Published
A command-line tool for sending messages to Slack
Downloads
1,877
Maintainers
Readme
Slack CLI
A command-line tool for sending messages to Slack using the Slack API.
Installation
npm install -g @urugus/slack-cliBy default, when you run commands, the CLI will show an update notification if a new npm release is available. To disable this, set SLACK_CLI_DISABLE_UPDATE_NOTIFIER=1.
Configuration
You need to configure your Slack API token on first use:
# Interactive secure prompt (recommended)
slack-cli config set
# Non-interactive (CI/scripts)
printf '%s\n' "$SLACK_API_TOKEN" | slack-cli config set --token-stdinToken storage security:
- Tokens are encrypted with AES-256-GCM before being written to disk.
- A local master key is created at
~/.slack-cli-secrets/master.keywith owner-only permissions. - Existing
~/.slack-cli/master.keyfiles are migrated automatically on first use. - For ephemeral environments, you can supply
SLACK_CLI_MASTER_KEYto override the local key. - Local encryption is defense in depth for token-at-rest storage. It does not protect tokens from compromise of the same local user account, because that user can read the config and key material needed to decrypt them.
- If a legacy encrypted token is migrated, the CLI will warn you to rotate the Slack token because the old stored value may have been copied, backed up, or exposed before migration.
Usage
Managing Multiple Workspaces (Profiles)
# Set tokens for different workspaces
printf '%s\n' "$WORK_SLACK_TOKEN" | slack-cli config set --profile work --token-stdin
printf '%s\n' "$PERSONAL_SLACK_TOKEN" | slack-cli config set --profile personal --token-stdin
# Show all profiles
slack-cli config profiles
# Switch default profile
slack-cli config use work
# Show current active profile
slack-cli config current
# Show configuration for specific profile
slack-cli config get --profile personal
# Clear specific profile
slack-cli config clear --profile workSending Messages
# Basic usage (uses default profile)
slack-cli send -c channel-name -m "Your message here"
# Using specific profile
slack-cli send -c channel-name -m "Your message here" --profile personal
# Using channel ID
slack-cli send -c C1234567890 -m "Your message here"
# Multi-line message
slack-cli send -c general -m "Line 1\nLine 2\nLine 3"
# Send message from file
slack-cli send -c random -f message.txt
# Reply to a thread
slack-cli send -c channel-name -m "Reply message" --thread 1719207629.000100
# Reply to a thread (short option)
slack-cli send -c channel-name -m "Reply message" -t 1719207629.000100
# Schedule by absolute time (Unix seconds or ISO 8601)
slack-cli send -c channel-name -m "Scheduled message" --at "2026-03-01T09:00:00Z"
# Schedule after N minutes
slack-cli send -c channel-name -m "Scheduled message" --after 30
# Send DM by username
slack-cli send --user @john -m "Hello via DM!"
# Send DM by email
slack-cli send --email [email protected] -m "Hello via DM!"
# Send Block Kit blocks
slack-cli send -c general --blocks '[{"type":"divider"}]'
# Send Block Kit blocks from a file
slack-cli send -c general --blocks-file ./blocks.json -m "fallback"Assistant Thread Status
Slack's assistant.threads.setStatus API can show a temporary loading status such as
<App name> is thinking... on a normal channel thread. Since Slack's 2026-03-05
change, this works with the chat:write scope.
# Set status on a thread
slack-cli status set -c channel-name -t 1719207629.000100 --text "Working on it"
# Set status with rotating loading messages
slack-cli status set -c channel-name -t 1719207629.000100 --text "Working on it" \
--loading-message "Reading context" \
--loading-message "Calling tools"
# Clear status
slack-cli status clear -c channel-name -t 1719207629.000100
# Keep status alive until max duration, stop file, or SIGINT/SIGTERM
slack-cli status keep-alive -c channel-name -t 1719207629.000100 --text "Working on it" \
--interval 80 \
--max-duration 600 \
--stop-file /tmp/slack-cli-status.stop
# Keep status alive with dynamic status text from a file
slack-cli status keep-alive -c channel-name -t 1719207629.000100 --text "Working on it" \
--text-file /tmp/slack-cli-status.txt \
--loading-message-file /tmp/slack-cli-loading-message.txt \
--interval 80 \
--max-duration 600 \
--stop-file /tmp/slack-cli-status.stop
# Run keep-alive in the background, record its PID, and log activity to a file
slack-cli status keep-alive -c channel-name -t 1719207629.000100 --text "Working on it" \
--interval 80 \
--max-duration 600 \
--stop-file /tmp/slack-cli-status.stop \
--detach \
--pid-file /tmp/slack-cli-status.pid \
--log-file /tmp/slack-cli-status.log
# Stop a background keep-alive process and clear status as a backstop
slack-cli status stop -c channel-name -t 1719207629.000100 \
--stop-file /tmp/slack-cli-status.stop \
--pid-file /tmp/slack-cli-status.pidList Channels
# List all channels (uses default profile)
slack-cli channels
# List channels from specific profile
slack-cli channels --profile work
# List public channels only
slack-cli channels --type public
# List private channels only
slack-cli channels --type private
# List all channel types including IMs and MPIMs
slack-cli channels --type all
# Include archived channels
slack-cli channels --include-archived
# Limit number of channels displayed
slack-cli channels --limit 20
# Output in different formats
slack-cli channels --format json
slack-cli channels --format simpleChannel Info & Management
# Display channel details (topic, purpose, members, etc.)
slack-cli channel info -c general
# Output channel info in different formats
slack-cli channel info -c general --format json
slack-cli channel info -c general --format simple
# Set channel topic
slack-cli channel set-topic -c general --topic "Current sprint: v2.0"
# Set channel purpose
slack-cli channel set-purpose -c general --purpose "Project X development channel"View Message History
# Get latest 10 messages (default)
slack-cli history -c general
# Specify number of messages
slack-cli history -c general -n 20
# Get messages since specific date
slack-cli history -c general --since "2024-01-01 00:00:00"
# Get complete conversation of a thread
slack-cli history -c general --thread 1719207629.000100
# Get a single message from a Slack permalink
slack-cli history --url "https://example.slack.com/archives/C123/p1780638511660849"
# Extract table blocks from a Slack permalink
slack-cli history --url "https://example.slack.com/archives/C123/p1780638511660849" --tables
# Extract table blocks as JSON
slack-cli history --url "https://example.slack.com/archives/C123/p1780638511660849" --tables --table-format json
# Output in different formats
slack-cli history -c general --format json
slack-cli history -c general --format simple
# Include permalink for each message
slack-cli history -c general --with-link
# Use specific profile
slack-cli history -c general --profile workGet Unread Messages
# Get all unread messages across all channels
slack-cli unread
# Get unread messages from specific channel
slack-cli unread -c general
# Show only unread counts (no message content)
slack-cli unread --count-only
# Mark messages as read after fetching
slack-cli unread --mark-read
# Mark messages as read for specific channel
slack-cli unread -c general --mark-read
# Limit number of channels displayed
slack-cli unread --limit 10
# Output in different formats
slack-cli unread --format json
slack-cli unread --format simpleSearch Messages
# Basic search
slack-cli search -q "deploy error"
# Sort by timestamp (newest first)
slack-cli search -q "meeting" --sort timestamp
# Sort oldest first
slack-cli search -q "release" --sort timestamp --sort-dir asc
# Limit results per page
slack-cli search -q "bug fix" -n 50
# Paginate through results
slack-cli search -q "deploy" --page 2
# Use Slack search modifiers in query
slack-cli search -q "in:general from:@alice deploy"
# Output in different formats
slack-cli search -q "error" --format json
slack-cli search -q "error" --format simple
# Use specific profile
slack-cli search -q "release" --profile workEdit Messages
# Edit a sent message
slack-cli edit -c general --ts 1234567890.123456 -m "Updated message text"
# Use specific profile
slack-cli edit -c general --ts 1234567890.123456 -m "Fixed typo" --profile workDelete Messages
# Delete a message
slack-cli delete -c general --ts 1234567890.123456
# Use specific profile
slack-cli delete -c general --ts 1234567890.123456 --profile workUpload Files
# Upload a file
slack-cli upload -c general -f ./report.csv
# Upload with title and initial comment
slack-cli upload -c general -f ./report.csv --title "Daily Report" -m "Here is the report"
# Upload a text snippet
slack-cli upload -c general --content 'console.log("hello")' --filename snippet.js --filetype javascript
# Upload as a thread reply
slack-cli upload -c general -f ./logs.txt -t 1234567890.123456Download Files
# Download the first file attached to a Slack message URL
slack-cli file download --url "https://example.slack.com/archives/C123/p1780530261218279?thread_ts=1780527015.228619" --dir ./downloads
# Download by Slack file ID
slack-cli file download --id F012ABCDEF --output ./image.png
# Download a file from a message timestamp
slack-cli file download -c C123 -t 1780530261.218279 --thread 1780527015.228619 --index 1Reactions
# Add a reaction to a message
slack-cli reaction add -c general -t 1234567890.123456 -e thumbsup
# Remove a reaction from a message
slack-cli reaction remove -c general -t 1234567890.123456 -e thumbsupPins
# Pin a message
slack-cli pin add -c general -t 1234567890.123456
# Unpin a message
slack-cli pin remove -c general -t 1234567890.123456
# List pinned items in a channel
slack-cli pin list -c general
# Output in different formats
slack-cli pin list -c general --format json
slack-cli pin list -c general --format simpleUsers
# List workspace users
slack-cli users list
# Limit number of users
slack-cli users list --limit 50
# Output in different formats
slack-cli users list --format json
slack-cli users list --format simple
# Get detailed info for a specific user
slack-cli users info --id U01ABCDEF
# Look up user by email address
slack-cli users lookup --email [email protected]
# Use specific profile
slack-cli users list --profile workScheduled Messages
# List scheduled messages
slack-cli scheduled list
# Filter by channel
slack-cli scheduled list -c general
# Limit results
slack-cli scheduled list --limit 20
# Output in different formats
slack-cli scheduled list --format json
slack-cli scheduled list --format simple
# Cancel a scheduled message
slack-cli scheduled cancel -c general --id Q1298393284Canvases
# Get sections of a Canvas
slack-cli canvas read -i F01234567890
# Output in different formats
slack-cli canvas read -i F01234567890 --format json
slack-cli canvas read -i F01234567890 --format simple
# List canvases linked to a channel
slack-cli canvas list -c general
# Output in different formats
slack-cli canvas list -c general --format json
slack-cli canvas list -c general --format simple
# Append markdown to an existing Canvas
slack-cli canvas write -i F01234567890 -m "追記する内容"
# Insert markdown at the start of an existing Canvas
slack-cli canvas write -i F01234567890 -m "先頭に追加" --position start
# Replace the entire Canvas content
# This discards the current Canvas content and requires --yes.
slack-cli canvas write -i F01234567890 -m "全体を置換" --position replace --yes
# Use specific profile
slack-cli canvas read -i F01234567890 --profile work
slack-cli canvas list -c general --profile work
slack-cli canvas write -i F01234567890 -m "追記する内容" --profile workOther Commands
# Show help
slack-cli --help
# Show version
slack-cli --version
# Show current configuration
slack-cli config get
# Update token for default profile
printf '%s\n' "$NEW_TOKEN" | slack-cli config set --token-stdinOptions
Global Options
| Option | Short | Description | | --------- | ----- | ------------------------------ | | --profile | -p | Use specific workspace profile |
send command
| Option | Short | Description | | --------- | ----- | ---------------------------------------- | | --channel | -c | Target channel name or ID (required) | | --message | -m | Message to send | | --file | -f | File containing message content | | --thread | -t | Thread timestamp to reply to | | --blocks | | Block Kit blocks as a JSON array | | --blocks-file | | File containing Block Kit blocks JSON | | --at | | Schedule time (Unix seconds or ISO 8601) | | --after | | Schedule message after N minutes |
Block Kit メッセージ送信
# blocks を直接指定 (-m は通知用 fallback text になる)
slack-cli send -c general --blocks '[{"type":"section","text":{"type":"mrkdwn","text":"*hello*"}}]' -m "hello"
# ファイルから読み込み
slack-cli send -c general --blocks-file ./blocks.json -m "fallback"
# スレッド返信・予約送信とも併用可能
slack-cli send -c general -t 1234567890.123456 --blocks '[{"type":"divider"}]'--blocksと--blocks-fileは排他-m/-fは blocks と併用すると通知用 fallback text として送信される-m/-fなしでも blocks のみ送信できる- blocks は「
typeを持つ object の JSON 配列」であることを送信前に検証する
status command
Subcommands: set, clear, keep-alive, stop
status set
| Option | Short | Description | | ----------------- | ----- | ------------------------------------------------ | | --channel | -c | Target channel name or ID (required) | | --thread | -t | Thread parent timestamp (required) | | --text | | Status text (required) | | --loading-message | | Optional loading message; repeatable up to 10 | | --profile | | Use specific workspace profile |
status clear
| Option | Short | Description | | --------- | ----- | ------------------------------------ | | --channel | -c | Target channel name or ID (required) | | --thread | -t | Thread parent timestamp (required) | | --profile | | Use specific workspace profile |
status keep-alive
Refreshes status immediately and then every --interval seconds because Slack clears assistant
thread status after roughly two minutes. It stops when --max-duration elapses, --stop-file
exists, or SIGINT/SIGTERM is received. Stop-file checks run at least every 5 seconds even when
the refresh interval is longer. Every exit path sends a final clear request; clear failures are
ignored.
With --text-file, the CLI reads status text from the file on each 5-second poll. Non-empty
file content overrides --text; missing, empty, or unreadable files fall back to --text.
When the resolved text changes, keep-alive sends the new status immediately instead of waiting
for the next --interval refresh.
With --loading-message-file, the CLI reads a loading message from the file on each refresh.
Non-empty file content is sent as one loading_messages entry and overrides any
--loading-message arguments. Missing, empty, or unreadable files fall back to the repeatable
--loading-message values.
With --detach, the CLI starts the same keep-alive command in a detached child process without
--detach, writes the child PID to --pid-file, and exits immediately. Without --detach,
--pid-file writes the foreground process PID and is removed when keep-alive exits.
With --log-file, keep-alive appends timestamped activity logs to the file: startup parameters,
each setStatus success or failure with the error message, status text changes detected from
--text-file, and the stop reason. The option is passed through to the detached child, so
--detach runs stay traceable even though the child runs with stdio: 'ignore'. Log writes are
best-effort and never interrupt keep-alive.
| Option | Short | Description | | ---------------------- | ----- | ----------------------------------------------------- | | --channel | -c | Target channel name or ID (required) | | --thread | -t | Thread parent timestamp (required) | | --text | | Status text (required) | | --text-file | | Read dynamic status text from this file | | --interval | | Refresh interval in seconds (default: 80) | | --max-duration | | Maximum duration in seconds (default: 600) | | --stop-file | | Stop when this path exists | | --detach | | Run keep-alive in a detached background process | | --pid-file | | Write the keep-alive process ID to this file | | --log-file | | Append timestamped activity logs to this file | | --loading-message | | Optional loading message; repeatable up to 10 | | --loading-message-file | | Read dynamic loading message from this file | | --profile | | Use specific workspace profile |
status stop
Creates the optional stop-file, terminates the optional pid-file process with SIGTERM and then
SIGKILL after --timeout, removes the pid-file, and finally clears status as a backstop. Missing
files, dead processes, kill failures, and clear failures only print warnings; the command exits 0.
| Option | Short | Description | | ----------- | ----- | --------------------------------------------- | | --channel | -c | Target channel name or ID (required) | | --thread | -t | Thread parent timestamp (required) | | --stop-file | | Create this stop file before stopping | | --pid-file | | Read and stop the process ID from this file | | --timeout | | Seconds before SIGKILL after SIGTERM (default: 5) | | --profile | | Use specific workspace profile |
channels command
| Option | Short | Description | | ------------------ | ----- | -------------------------------------------------------------- | | --type | | Channel type: public, private, im, mpim, all (default: public) | | --include-archived | | Include archived channels | | --format | | Output format: table, simple, json (default: table) | | --limit | | Maximum number of channels to list (default: 100) |
history command
| Option | Short | Description | | -------------- | ----- | ------------------------------------------------------ | | --url | | Slack message permalink to retrieve | | --channel | -c | Target channel name or ID | | --number | -n | Number of messages to retrieve (default: 10) | | --since | | Get messages since specific date (YYYY-MM-DD HH:MM:SS) | | --thread | -t | Thread timestamp to retrieve complete thread messages | | --format | | Output format: table, simple, json (default: table) | | --tables | | Extract table blocks from retrieved messages | | --table-format | | Table output format: markdown, json, tsv |
unread command
| Option | Short | Description | | ------------ | ----- | --------------------------------------------------- | | --channel | -c | Get unread for specific channel | | --format | | Output format: table, simple, json (default: table) | | --count-only | | Show only unread counts | | --limit | | Maximum number of channels to display (default: 50) | | --mark-read | | Mark messages as read after fetching |
search command
| Option | Short | Description | | ---------- | ----- | --------------------------------------------------- | | --query | -q | Search query (required) | | --sort | | Sort by: score or timestamp (default: score) | | --sort-dir | | Sort direction: asc or desc (default: desc) | | --number | -n | Number of results per page, 1-100 (default: 20) | | --page | | Page number, 1-100 (default: 1) | | --format | | Output format: table, simple, json (default: table) |
edit command
| Option | Short | Description | | --------- | ----- | ---------------------------------------------- | | --channel | -c | Target channel name or ID (required) | | --ts | | Message timestamp to edit (required) | | --message | -m | New message text (required) |
delete command
| Option | Short | Description | | --------- | ----- | ---------------------------------------------- | | --channel | -c | Target channel name or ID (required) | | --ts | | Message timestamp to delete (required) |
upload command
| Option | Short | Description | | ---------- | ----- | ------------------------------------------------ | | --channel | -c | Target channel name or ID (required) | | --file | -f | File path to upload | | --content | | Text content to upload as snippet | | --filename | | Override filename | | --title | | File title | | --message | -m | Initial comment with the file | | --filetype | | Snippet type (e.g. python, javascript, csv) | | --thread | -t | Thread timestamp to upload as reply |
file download command
| Option | Short | Description | | ----------- | ----- | ------------------------------------------------ | | --id | | Slack file ID | | --url | | Slack message permalink containing the file | | --channel | -c | Channel name or ID | | --timestamp | -t | Message timestamp containing the file | | --thread | | Thread timestamp when downloading from a reply | | --index | | 1-based file index for messages with many files | | --output | -o | Output file path | | --dir | -d | Output directory |
reaction command
| Option | Short | Description | | ----------- | ----- | ---------------------------------------- | | --channel | -c | Channel name or ID (required) | | --timestamp | -t | Message timestamp (required) | | --emoji | -e | Emoji name without colons (required) |
Subcommands: add, remove
pin command
Subcommands: add, remove, list
pin add / pin remove
| Option | Short | Description | | ----------- | ----- | ------------------------------------ | | --channel | -c | Channel name or ID (required) | | --timestamp | -t | Message timestamp (required) |
pin list
| Option | Short | Description | | --------- | ----- | --------------------------------------------------- | | --channel | -c | Channel name or ID (required) | | --format | | Output format: table, simple, json (default: table) |
users command
Subcommands: list, info, lookup
users list
| Option | Short | Description | | -------- | ----- | --------------------------------------------------- | | --limit | | Maximum number of users to list (default: 100) | | --format | | Output format: table, simple, json (default: table) |
users info
| Option | Short | Description | | -------- | ----- | --------------------------------------------------- | | --id | | User ID (required) | | --format | | Output format: table, simple, json (default: table) |
users lookup
| Option | Short | Description | | -------- | ----- | --------------------------------------------------- | | --email | | Email address to look up (required) | | --format | | Output format: table, simple, json (default: table) |
scheduled command
Subcommands: list, cancel
scheduled list
| Option | Short | Description | | --------- | ----- | ---------------------------------------------------------- | | --channel | -c | Filter by channel name or ID | | --limit | | Maximum number of scheduled messages to list (default: 50) | | --format | | Output format: table, simple, json (default: table) |
scheduled cancel
| Option | Short | Description | | --------- | ----- | --------------------------------------- | | --channel | -c | Channel name or ID (required) | | --id | | Scheduled message ID (required) |
canvas command
Subcommands: read, list, write
canvas read
| Option | Short | Description | | -------- | ----- | --------------------------------------------------- | | --id | -i | Canvas ID (required) | | --format | | Output format: table, simple, json (default: table) |
canvas list
| Option | Short | Description | | --------- | ----- | --------------------------------------------------- | | --channel | -c | Channel name or ID (required) | | --format | | Output format: table, simple, json (default: table) |
canvas write
Writes markdown to an existing Canvas. It does not create a new Canvas.
| Option | Short | Description | | ---------- | ----- | ----------------------------------------------------------------- | | --id | -i | Canvas ID (required) | | --message | -m | Markdown content to write (required) | | --position | | Write position: end, start, replace (default: end) | | --yes | | Required when --position replace discards the whole Canvas content | | --profile | | Use specific workspace profile |
Required Permissions
Your Slack API token needs the following scopes:
chat:write- Send and edit messages; also required forstatuscommands using Slack'sassistant.threads.setStatusAPIchannels:read- List public channels and get channel infochannels:write- Set topic/purpose for public channelsgroups:read- List private channels and get channel infogroups:write- Set topic/purpose for private channelschannels:history- Read channel message historygroups:history- Read private channel message historyim:history- Read direct message historyim:write- Open DM channels for --user/--email DM sendingusers:read- Access user information for unread counts and user listingusers:read.email- Look up users by email addresssearch:read- Search messages (user token only, not supported with bot tokens)reactions:write- Add and remove reactionspins:read- List pinned items in a channelpins:write- Pin and unpin messagesfiles:write- Upload files and snippetsfiles:read- Download Slack files and list canvases linked to a channelcanvases:read- Read Canvas sectionscanvases:write- Write Canvas content
Advanced Features
Rate Limiting
The CLI includes built-in rate limiting to handle Slack API limits:
- Concurrent requests: 3
- Automatic retry with exponential backoff (max 3 retries)
- Graceful error handling for rate limit errors
Output Formats
Most commands support multiple output formats:
table(default) - Human-readable table formatsimple- Simplified text outputjson- Machine-readable JSON format
Markdown Support
Messages sent via the send command automatically support Slack's mrkdwn formatting:
*bold*for bold text_italic_for italic text~strikethrough~for strikethrough`code`for inline code```code blocks```for multiline code- Links are automatically hyperlinked
- User mentions:
<@USER_ID> - Channel mentions:
<#CHANNEL_ID>
License
MIT
