| name | slack-personal |
| description | Read, send, search, and manage Slack messages and DMs via the slk CLI. Supports multiple workspaces with switching. Use when the user asks to check Slack, read channels or DMs, send Slack messages, search Slack, check unreads, manage drafts, view saved items, switch Slack workspaces, or interact with Slack workspace. Also use for heartbeat Slack checks. Triggers on "check slack", "any slack messages", "send on slack", "slack unreads", "search slack", "slack threads", "draft on slack", "read slack dms", "message on slack", "switch workspace", "slack workspaces". |
| homepage | https://github.com/kimjisub/slack-personal-cli |
| metadata | {"moltbot":{"emoji":"💬","requires":{"bins":["slk"]},"install":[{"id":"npm","kind":"node","package":"github:kimjisub/slack-personal-cli","bins":["slk"],"label":"Install slack-personal-cli from GitHub"}],"os":["darwin"]}} |
slack-personal-cli — Slack CLI
Session-based Slack CLI for macOS. Auto-authenticates from the Slack desktop app — no tokens, no OAuth, no app installs. Acts as your user (xoxc- session tokens).
vs other Slack options: unlike the official Slack MCP (slackapi/slack-mcp-plugin, OAuth, one workspace) or korotovsky/slack-mcp-server (bring-your-own xoxc/xoxd/xoxp/xoxb token, one workspace per token), slk needs no token setup and works across all signed-in workspaces at once (-A). It's a CLI, so a human and an agent (over Bash) use the same tool. Unique commands: inbox -A (cross-workspace unread digest), owed (mentions you haven't answered), search -A. macOS-only; full-account access. See README "How it compares" for the full table.
Setup & updates
You're reading this as an already-registered skill, so registration itself is done. This section is for the agent maintaining the install. The skill has two parts that must stay version-aligned:
- the
slk binary on PATH — what actually talks to Slack
- this
SKILL.md — the command reference you're reading
New commands land in both at once, so a stale binary or a stale skill file will disagree. Keep them on the same version.
First-time install from scratch (neither part exists yet — e.g. registering this skill in a brand-new harness) is a human bootstrap step, not something to run from here. See the README → Install.
1. Check current state
slk --version
slk auth
2. Install the binary (only if missing)
This repo is the package; it is not on the npm registry. Requires Node.js ≥ 18 and macOS with the Slack desktop app installed and logged in.
npm install -g github:kimjisub/slack-personal-cli
3. Check whether an update is available
Updating only matters once installed, so check before acting. Compare the installed binary against the latest on main:
slk --version
curl -s https://raw.githubusercontent.com/kimjisub/slack-personal-cli/main/package.json \
| grep '"version"'
An update is worth doing when the two versions differ, or when a command documented in this file isn't recognized by the installed binary (a sign the skill file is ahead of the binary). If they already match, do nothing — there's no update to apply.
4. Apply the update — confirm with the user first
Updating replaces a global binary and overwrites the registered skill file. Both modify the user's machine, so do not run these automatically. Tell the user the installed → latest version jump and ask before proceeding. Once they agree, refresh both parts together so they stay aligned:
npm install -g github:kimjisub/slack-personal-cli
curl -sL https://raw.githubusercontent.com/kimjisub/slack-personal-cli/main/SKILL.md \
-o ~/.claude/skills/slack-personal/SKILL.md
After step (b), re-read the refreshed SKILL.md before relying on any newly documented command — the copy you started from may predate it. Confirm the result with slk --version.
How to invoke
Always call the CLI as slk <command>. The global binary is on PATH and is the correct invocation path for every harness (Claude Code, Codex, Copilot CLI, Gemini CLI, plain shell).
Do NOT use node <path>/bin/slk.js as a workaround. That pattern was a necessary fallback only before v0.3.1, when a process.argv[1] vs import.meta.url mismatch caused the global slk to exit silently from symlinked installs. v0.3.1+ resolves the symlink before comparing, so the global binary works correctly. If slk produces no output, upgrade instead of falling back to node:
slk --version
npm install -g github:kimjisub/slack-personal-cli
Commands
slk auth
slk channels
slk dms
slk users
slk read <channel> [count]
slk read @username [count]
slk read <channel> --threads
slk read <channel> --from 2026-02-01
slk thread <channel> <ts> [count]
slk search <query> [count]
slk owed [--days N]
slk send <channel> <message>
slk send <channel> <message> --thread <ts>
slk edit <channel> <ts> <message>
slk delete <channel> <ts>
slk react <channel> <ts> <emoji>
slk unreact <channel> <ts> <emoji>
slk pin <channel> <ts>
slk save <channel> <ts>
slk join <channel>
slk mark <channel>
slk reply <channel> <ts> <message>
slk message link <channel> <ts>
slk message show <channel> <ts>
slk message context <channel> <ts> [before] [after]
slk upload <file> <channel>
slk download <file_id> [out_path]
slk status "<text>" [emoji] [--for N]
slk dnd <minutes>
slk workspace list
slk workspace use <name|domain|id>
slk workspace current
slk inbox activity
slk inbox unread
slk inbox saved [count] [--all]
slk inbox starred
slk channel pins <channel>
slk draft list
slk draft channel <channel> <message>
slk draft thread <ch> <ts> <message>
slk draft dm <user_id|@username> <message>
slk draft drop <draft_id>
slk inbox unread -w candid
slk inbox unread -A
SLACK_CLI_WORKSPACE=candid slk owed
slk search "deploy" -A
slk owed -A --days 14
slk inbox unread -A --json | jq .
Channel accepts name (general), ID (C08A8AQ2AFP), @username for DMs, or user ID (U07RQTFCLUC).
Auth
Automatic — extracts session tokens from Slack desktop app's LevelDB (localConfig_v2) + decrypts cookie from macOS Keychain.
First run: macOS will show a Keychain dialog asking to allow access to "Slack Safe Storage":
- Allow — one-time access, prompted again next time
- Always Allow — permanent, no future prompts (convenient but any process running as your user can extract credentials silently)
- Deny — blocks access, slk cannot authenticate
Token cache: ~/.local/slack-personal-cli/token-cache.json — auto-validated, auto-refreshed on invalid_auth.
Cookie cache: ~/.local/slack-personal-cli/cookie-cache.json — decrypted Slack d cookie fallback, written mode 0600 after a successful interactive Keychain read.
Active workspace: ~/.local/slack-personal-cli/active-workspace — stores the selected team ID. Delete to reset to default.
Runtime coordination: ~/.local/slack-personal-cli/runtime/ — shared pacing + 429 cooldown state for concurrent local slk processes.
If auth fails (token rotated, Slack logged out):
rm ~/.local/slack-personal-cli/token-cache.json ~/.local/slack-personal-cli/cookie-cache.json
slk auth
If Slack is visibly logged in and slk workspace list works, but slk auth says Keychain access failed from a background agent, run slk auth once from a normal interactive Terminal after installing this version. That refreshes the token + cookie cache so background agents can reuse it without showing a macOS Keychain prompt.
Slack desktop app must be installed and logged in. Does not need to be running if credentials are cached.
Workspaces
All workspaces logged in to the Slack desktop app are available. Tokens are extracted from localConfig_v2 in LevelDB.
slk workspace list
slk workspace current
slk workspace use candid
slk workspace use unipad-team
slk workspace use T05BFH4UW5T
slk auth
The workspace use command matches against workspace name, domain, or team ID (case-insensitive, partial match supported). After switching, all subsequent commands operate on the selected workspace until switched again.
Reading Threads
Threads require a Slack timestamp. Use --ts to get it, then read the thread or act on one exact message:
slk read general 10 --ts
slk thread general 1769753479.788949
slk reply general 1769753479.788949 "on it"
slk send general "same effect via send" --thread 1769753479.788949
slk message link general 1769753479.788949
slk message show general 1769753479.788949
slk message context general 1769753479.788949 2 2
Agent Workflow Examples
- Heartbeat/cron unread check —
slk inbox unread → slk read <channel> for channels that need attention
- Save & pick up — Human saves threads in Slack ("Save for later"). Agent runs
slk inbox saved during heartbeat, reads full threads with slk thread, summarizes or extracts action items
- Daily channel digest —
slk read <channel> 100 across key channels → compile decisions, open questions, action items → slk send daily-digest "📋 ..."
- Weekly DM summary —
slk read @boss 200 --from 2026-02-01 --threads → extract action items, decisions, context
- Thread monitoring —
slk thread <channel> <ts> to inspect the thread, then slk reply <channel> <ts> "..." or slk send <channel> "..." --thread <ts> to answer in place
- Message-level navigation —
slk message link <channel> <ts> for the permalink, slk message show <channel> <ts> for the exact item, slk message context <channel> <ts> for surrounding context
- Draft for human review —
slk draft channel <channel> "..." posts to Slack's editor UI for human to review before sending
- Search-driven context —
slk search "deployment process" or slk channel pins <channel> to pull context before answering questions
- Concurrent local automation — Multiple agents or cron jobs can invoke
slk safely; requests are paced through one shared local runtime lane and 429 cooldowns propagate automatically
Live Slack integration tests
The repo now supports opt-in real-Slack integration tests in tests/live-slack.test.js.
- Default
npm test remains safe because the live file auto-skips unless SLK_LIVE_TESTS=1 is set.
- Read-only live verification requires:
SLK_LIVE_TESTS=1
SLK_LIVE_CHANNEL
SLK_LIVE_MESSAGE_TS
- Write verification additionally requires:
SLK_LIVE_ALLOW_WRITE=1
SLK_LIVE_THREAD_TS
Run:
npm test
SLK_LIVE_TESTS=1 SLK_LIVE_CHANNEL=general SLK_LIVE_MESSAGE_TS=1769753479.788949 npm run test:live
SLK_LIVE_TESTS=1 SLK_LIVE_ALLOW_WRITE=1 SLK_LIVE_CHANNEL=general SLK_LIVE_MESSAGE_TS=1769753479.788949 SLK_LIVE_THREAD_TS=1769753479.788949 npm run test:live
The write tests intentionally require a second opt-in so they do not post to Slack by accident.
Limitations
- macOS only — uses Keychain + Electron storage paths
- Session-based — acts as your user, not a bot. Be mindful of what you send
- Draft drop may fail with
draft_has_conflict if Slack has that conversation open
- Session token expires on logout — keep Slack app running or rely on cached token
-A is paced by the rate limiter — sweeping many workspaces is serialized
(~1.2s/request), so a full cross-workspace run can take a while
- Non-ASCII workspace names can't always be recovered from the desktop app's
LevelDB (multi-byte names lose information during extraction). Labels fall back
to the workspace domain in that case, and IDs/domains are unaffected, so
commands and
-w <name|id> still work correctly
Missing Features & Issues
Create PR or Report Issue at: https://github.com/kimjisub/slack-personal-cli