A terminal-based Slack client built with Go and Bubble Tea. Navigate Slack with familiar shell commands.
- Browse channels and direct messages
- View and send messages
browsecommand - Interactive message browser with thread view and reply supportlivecommand - Live mode with real-time updates and message sending- Real-time updates via Socket Mode (optional)
- OAuth authentication - Easy browser-based login
- Shell-like UI - Familiar command interface
- Channel creation - Create public/private channels with
mkdircommand - Multi-workspace support - Switch with
sourcecommand - Pipe support - Search with
ls | grepandcat | grep - Notifications - Terminal bell, desktop notifications, title updates, visual alerts
- Tab completion - Auto-complete channel and user names with
cd - Admin commands - Bulk join/leave channels with
sudo app install/remove
# Install with go install
go install github.com/polidog/slack-shell/cmd/slack-shell@latest
# Or build from source
git clone https://github.com/polidog/slack-shell.git
cd slack-shell
go build ./cmd/slack-shell- Go to https://api.slack.com/apps
- Click Create New App → From scratch
- Enter an App name (e.g.,
My TUI Client) and select your workspace - Click Create App
- Select OAuth & Permissions from the left menu
- Scroll to the Scopes section
- Add the following User Token Scopes:
| Scope | Description |
|---|---|
channels:read |
List public channels |
channels:write |
Create public channels, join/leave channels |
channels:history |
Read public channel messages |
groups:read |
List private channels |
groups:write |
Create private channels |
groups:history |
Read private channel messages |
im:read |
List DMs |
im:history |
Read DM messages |
im:write |
Send DMs |
mpim:read |
List group DMs |
mpim:history |
Read group DM messages |
users:read |
View user info |
chat:write |
Send messages |
team:read |
View workspace info (for prompt display) |
- On the OAuth & Permissions page, find Redirect URLs
- Click Add New Redirect URL
- Enter the following and click Add → Save URLs:
https://localhost:8080/callback
- Select Basic Information from the left menu
- In the App Credentials section:
- Copy the
Client ID - Click Show on
Client Secretand copy it
- Copy the
# Set environment variables
export SLACK_CLIENT_ID="your-client-id"
export SLACK_CLIENT_SECRET="your-client-secret"
# Run
./slack-shellA browser will open automatically with the Slack authorization page. Click Allow to complete authentication.
Note: You may see a "This connection is not secure" warning during the OAuth callback. This is because a self-signed certificate is used. Click "Advanced" → "Proceed to localhost" to continue.
slack> ls # List channels
slack> ls dm # List DMs only
slack> cd #general # Enter a channel
slack> cd @john # Enter a DM
slack> .. # Go back to channel list
slack> mkdir #new-channel # Create a public channel
slack> mkdir -p #private # Create a private channel
slack> cat # Show messages (default 20)
slack> cat -n 50 # Show 50 messages
slack> browse # Interactive message browser
slack> live # Live mode with real-time updates
slack> send Hello world # Send a message
slack> pwd # Show current channel
slack> source ~/work.yaml # Switch workspace
slack> help # Show help
slack> exit # Exit
# Pipe support
slack> ls | grep dev # Search channels by name
slack> cat | grep error # Search messages by content
# Admin commands
slack> sudo app install # Join all public channels
slack> sudo app install #ch1 #ch2 # Join specific channels
slack> sudo app remove # Leave all public channels
slack> sudo app remove #ch1 #ch2 # Leave specific channels
slack> ls
Channels:
# general
# random
# dev
Direct Messages:
@ alice
@ bob
slack> cd #general
Entered #general
#general> cat
[10:30] alice: Good morning everyone
[10:32] bob: Morning!
└─ 3 replies
#general> send Hello!
Message sent.
# Normal startup (interactive mode)
./slack-shell
# One-liner execution (-c option)
./slack-shell -c "ls"
./slack-shell -c "cd #general && cat -n 5"
./slack-shell -c "cd @john && send Good morning"
./slack-shell -c "ls | grep dev"
# Logout (delete saved credentials)
./slack-shell logout
# Generate sample config file
./slack-shell config init # Create at ~/.config/slack-shell/config.yaml
./slack-shell config init ~/work.yaml # Create at specified path
./slack-shell config init ~/work.yaml -f # Overwrite if existsGenerate a sample configuration file with all available options documented.
# Create default config
./slack-shell config init
# Create workspace-specific config for use with `source` command
./slack-shell config init ~/work-slack.yaml
./slack-shell config init ~/personal-slack.yaml
# Then switch workspaces in the app
slack> source ~/work-slack.yamlThe -c option executes commands without entering interactive mode.
Useful for scripting and cron jobs.
# Chain multiple commands with && or ;
./slack-shell -c "cd #general && send Daily standup starting!"
# Pipes work too
./slack-shell -c "cd #general && cat | grep meeting"
# Example: Scheduled message with cron
0 9 * * 1-5 /path/to/slack-shell -c "cd #general && send Good morning everyone!"| Key | Action |
|---|---|
↑ / ↓ |
Navigate command history |
Tab |
Auto-complete channel/user names for cd |
Ctrl+C |
Exit application |
Ctrl+L |
Refresh screen |
q |
Exit browse/live mode |
j / k |
Navigate messages in browse/live mode |
Enter |
View thread in browse/live mode |
r |
Reply in browse/live mode |
i |
New message in live mode |
The browse command provides an interactive interface for browsing and replying to messages.
#general> browse # Start interactive browserBrowse mode key bindings:
| Key | Action |
|---|---|
↑ / k |
Move to previous message |
↓ / j |
Move to next message |
Enter |
View thread replies |
r |
Reply to selected message (creates/extends thread) |
Esc |
Close thread view / cancel input |
q |
Exit browse mode |
The sudo command provides administrative operations for managing the app's channel membership.
Join public channels to receive messages via Socket Mode.
# Join all public channels
slack> sudo app install
Installing app to all public channels...
✓ #general
✓ #random
✓ #dev
Done: 50 joined, 5 skipped, 0 failed
# Join specific channels only
slack> sudo app install #dev #engineering #alerts
Installing app to 3 channel(s)...
✓ #dev
✓ #engineering
✓ #alerts
Done: 3 joined, 0 skipped, 0 failedLeave public channels.
# Leave all public channels (except #general)
slack> sudo app remove
# Leave specific channels
slack> sudo app remove #random #old-projectNote: These commands require the
channels:writescope for user tokens orchannels:joinscope for bot tokens.
Press Tab while typing a cd command to auto-complete channel and user names.
slack> cd # # Tab → show channel candidates
slack> cd #gen # Tab → complete to #general
slack> cd @ # Tab → show user candidates
slack> cd @ali # Tab → complete to @alice
cd #+ Tab: Complete channel names onlycd @+ Tab: Complete user names (DM recipients) onlycd+ Tab: Show both channels and users- Multiple Tabs: Cycle through candidates
Use the source command to switch between workspaces.
# Create workspace config files
cat > ~/work-slack.yaml << EOF
slack_token: xoxp-your-work-token
EOF
cat > ~/personal-slack.yaml << EOF
slack_token: xoxp-your-personal-token
EOF
# Switch in the app
slack> source ~/work-slack.yaml
Switched to workspace: Work Inc.
work> source ~/personal-slack.yaml
Switched to workspace: Personal
personal>Receive notifications when messages arrive in other channels.
| Type | Description |
|---|---|
| Terminal Bell | Beep sound via \a character |
| Desktop | OS native notifications (Linux/macOS/Windows) |
| Title | Show unread count in terminal title (e.g., Slack Shell (3)) |
| Visual | Display notification area at top of screen |
Add a notifications section to ~/.config/slack-shell/config.yaml:
notifications:
enabled: true
bell:
enabled: true
mentions_only: false
desktop:
enabled: true
mentions_only: false
title:
enabled: true
format: "Slack Shell (%d)"
base_title: "Slack Shell"
visual:
enabled: true
max_items: 5
dismiss_after: 10
mute_channels: []
dnd: falseFor real-time message streaming (required for live command):
- Enable Socket Mode in your Slack App settings
- Go to Basic Information → App-Level Tokens and create a new token
- Token Name: any name (e.g.,
socket-token) - Scope:
connections:write
- Token Name: any name (e.g.,
- Set the generated token (
xapp-prefix):
export SLACK_APP_TOKEN="xapp-your-app-token"~/.config/slack-shell/config.yaml (or $XDG_CONFIG_HOME/slack-shell/config.yaml):
Note: For backward compatibility,
~/.slack-shell/config.yamlis also supported.
# OAuth authentication (recommended)
client_id: your-client-id
client_secret: your-client-secret
# Or direct token
slack_token: xoxp-your-token
# Socket Mode (optional, required for live mode)
app_token: xapp-your-app-token
# Callback port (default: 8080)
redirect_port: 8080
# Prompt customization (optional)
prompt:
format: "{workspace} {location}> "
# Display customization (optional)
display:
name_format: "display_name" # display_name, real_name, or usernameConfigure how user names are displayed in messages:
display:
# Options:
# "display_name" - Display name (falls back to real name, then username)
# "real_name" - Real name (falls back to display name, then username)
# "username" - Username only
name_format: "display_name"This mirrors the Slack desktop app's "Display Name" setting.
Customize the prompt display with template variables in ~/.config/slack-shell/config.yaml:
prompt:
format: "slack-shell > {workspace}{location}"| Variable | Description | Example |
|---|---|---|
{workspace} |
Workspace name | MyCompany |
{location} |
Current channel/DM with prefix | #general, @alice, or empty |
{channel} |
Channel name only (no prefix) | general |
{user} |
User name only (no prefix) | alice |
# Default format
prompt:
format: "{workspace} {location}> "
# Result: MyCompany #general>
# Shell-style
prompt:
format: "slack-shell > {workspace}{location}"
# Result: slack-shell > MyCompany#general
# Minimal
prompt:
format: "{location}$ "
# Result: #general$
# With brackets
prompt:
format: "[{workspace}:{channel}]$ "
# Result: [MyCompany:general]$Customize the startup message, banner, and auto-execute commands in ~/.config/slack-shell/config.yaml:
startup:
# Single line welcome message
# Available variables: {workspace}
message: "Welcome to Slack Shell - {workspace}"
# Multi-line banner (overrides message if set)
banner: |
╔═══════════════════════════════════════╗
║ Slack Shell v1.0 ║
║ Workspace: {workspace} ║
╚═══════════════════════════════════════╝
# Commands to execute automatically at startup
init_commands:
- "cd #general"
- "cat -n 5"| Option | Description |
|---|---|
message |
Single line welcome message (default: "Welcome to Slack Shell - {workspace}") |
banner |
Multi-line ASCII art banner (overrides message if set) |
init_commands |
List of commands to execute at startup (like .bashrc) |
startup:
message: "Welcome back! Entering #general..."
init_commands:
- "cd #general"Environment variables:
export SLACK_CLIENT_ID="your-client-id"
export SLACK_CLIENT_SECRET="your-client-secret"
./slack-shellOr config file ~/.config/slack-shell/config.yaml:
client_id: your-client-id
client_secret: your-client-secretexport SLACK_TOKEN="xoxp-your-token"
./slack-shell- Verify environment variables or config file are set correctly
- For OAuth, both Client ID and Client Secret are required
- Manually copy the URL shown in terminal and open in browser
- Verify Client ID is correct
- Ensure Slack App hasn't been deleted
- Verify all required scopes are added
- Reinstall the Slack App to your workspace
- Verify
SLACK_APP_TOKENis set - Ensure Socket Mode is enabled
./slack-shell logoutgo build ./cmd/slack-shellgo test ./...slack-shell/
├── cmd/slack-shell/main.go # Entry point
├── internal/
│ ├── app/app.go # Application initialization
│ ├── config/config.go # Configuration management
│ ├── oauth/oauth.go # OAuth flow
│ ├── notification/ # Notification system
│ │ ├── config.go
│ │ ├── notification.go
│ │ ├── manager.go
│ │ ├── bell.go
│ │ ├── desktop.go
│ │ ├── title.go
│ │ └── visual.go
│ ├── slack/ # Slack API client
│ │ ├── client.go
│ │ ├── channels.go
│ │ ├── messages.go
│ │ ├── threads.go
│ │ └── realtime.go
│ └── shell/ # Shell UI components
│ ├── model.go
│ ├── commands.go
│ ├── parser.go
│ ├── browse.go
│ └── output.go
├── go.mod
├── go.sum
└── README.md
MIT