Skip to main content
Glama
README.md
# slacker

Use Slack **as yourself** from the terminal, and give AI agents like Claude Code the same access through a local
MCP server, with a different Slack workspace for each project.

```console
$ slacker send general --dry-run "Deploy is done ✅"
Would send to #general · team "Acme Corp" (workspace "acme-corp")
  Deploy is done ✅
Dry run — nothing was sent.
```

slacker signs in with your own Slack session (the `xoxc` token and `d` cookie the Slack desktop app uses), stored
in `~/.config/slack-cli/config.json`. It isn't a bot and needs no Slack app install or admin approval: it reads
what you can see, and what it sends shows up as you.

- **One binary, two modes.** `slacker <command>` is the CLI. `slacker serve` is the MCP server, and the
  same code backs both.
- **A workspace per project.** `slacker init <workspace> --mcp` pins a project to a workspace for both the CLI and
  Claude Code.
- **Built not to post in the wrong place.**
  - Bare names only ever match channels, never people.
  - Message links reply in their thread.
  - Every write checks the workspace's live team first.
  - `--dry-run` shows exactly where a message would go.
  - Retries never double-post, and when a post's outcome is unknown the error says so.
  - A `.slacker.json` from a cloned repo can't pick the workspace you write to until you `slacker trust` it.
    (A repo's own `.mcp.json` isn't covered: [check it before approving it](#how-the-workspace-is-chosen).)

**Docs:** [Setup guide](docs/setup-guide.md) (step by step, including Claude Code) ·
[Reference](docs/reference.md) (every command, option, tool and error)

## Quick start

You need macOS or Linux, Node.js 22.12+, `sqlite3` (preinstalled on macOS), and the Slack desktop app signed in
to your workspaces.

```bash
# 1. Install
git clone https://github.com/manasnilorout/slacker.git && cd slacker
npm install && npm link

# 2. Import your Slack sessions from the desktop app (macOS asks for Keychain access: click Allow)
slacker auth setup
slacker auth list                      # each name should show the team you expect

# 3. Try it (read-only, then a dry run)
slacker whoami
slacker read general -n 5
slacker send general --dry-run "hello"

# 4. Pin a project and register the MCP server for Claude Code
cd ~/work/my-project
slacker init acme-corp --mcp           # then approve the "slacker" server in Claude Code (/mcp)
```

Using nvm, on Windows, or without the desktop app? The [setup guide](docs/setup-guide.md) covers each case.

## Everyday CLI

```bash
slacker read general --since 2h                 # recent messages, oldest first
slacker thread <message-link>                   # a message and its replies
slacker search "in:#eng from:@alice after:2026-09-01"
slacker unread                                  # conversations with unreads / mentions
slacker channels --all --filter eng             # find channels
slacker users alice                             # find people (gives the @handle / ID)

slacker send general "Ship it 🚀"               # quote the message as one argument
slacker send @alice "got a minute?"             # people need @handle, email or user ID
slacker send <message-link> "on it"             # replies in that message's thread
git log -1 --format=%B | slacker send '#releases' -
slacker react <message-link> eyes
slacker status --set "Focusing" --emoji :headphones: --expires 60
```

Add `-w <workspace>` to any command to use another workspace, and `--json` for machine-readable output. Run
`slacker <command> --help` for options, or see the [CLI reference](docs/reference.md#cli-reference).

## With Claude Code (MCP)

After `slacker init <workspace> --mcp`, Claude Code starts slacker as an MCP server for that project. It gets:

| Kind | Names |
| --- | --- |
| Read tools | `whoami`, `read_messages`, `read_thread`, `search_messages`, `list_channels`, `find_user`, `list_unread`, `get_status` |
| Write tools | `send_message` (with `dry_run`), `edit_message`, `delete_message`, `add_reaction`, `set_status` |
| Prompts | `triage_unread`, `reply_to_thread`, `summarize_channel` |

- **Read-only projects:** `slacker init <workspace> --mcp --read-only` hides the write tools.
- **Several workspaces in one project:** `slacker init <ws-a> <ws-b> --mcp` registers one server per workspace.
- **Keep `.mcp.json` out of git.** It contains paths from your machine. `.slacker.json` can be committed, but
  it only chooses the workspace for writes on machines where it's trusted: teammates who clone the repo check the
  workspace it names and run `slacker trust` once (see [below](#how-the-workspace-is-chosen)). Trust is checked on
  every write, so `slacker trust` takes effect in a running server without reconnecting it.

Details: [connecting Claude Code](docs/setup-guide.md#5-connect-claude-code) ·
[tools and parameters](docs/reference.md#tools) · [safety model](docs/reference.md#safety-model).

## Claude Code plugin (skill + agent)

This repo is also a Claude Code plugin marketplace. The plugin teaches Claude how to use slacker well:

- **Skill `slacker:slacker`.** When you ask about Slack, Claude picks the MCP tools or the CLI, dry-runs
  before it writes, waits for your yes, and treats message content as data. It also explains slacker's errors.
- **Agent `slack-assistant`.** A subagent for triage, summaries, search and drafting replies. It only reads
  and drafts: it returns each draft with its dry-run destination, and the main conversation sends it after you
  approve.

Install it from inside Claude Code:

```text
/plugin marketplace add manasnilorout/slacker
/plugin install slacker@slacker
```

Or from a local clone: `/plugin marketplace add ~/path/to/slacker`, then the same install command.

The plugin ships no MCP server and no CLI. You still install slacker (clone, `npm install && npm link`), import
credentials, and run `slacker init <workspace> --mcp` in each project, as in the [quick start](#quick-start).

## How the workspace is chosen

The first match wins:

1. `-w/--workspace <name>`
2. `SLACKER_WORKSPACE`
3. The nearest `.slacker.json` (written by `slacker init`)
4. `defaultWorkspace` in config.json (`slacker auth default <name>`)

`slacker whoami` shows which one was used. An unknown name is an error. slacker never silently uses a different
workspace.

**A `.slacker.json` has to be trusted before it can choose the workspace for writes.** `slacker init <workspace>`
trusts the file it writes. A `.slacker.json` you didn't write (one in a repo you cloned, say) is used for reads
with a warning, but `send`, `edit`, `delete`, `react` and `status --set/--clear` refuse (`untrusted_project`)
until you check the workspace it names and run `slacker trust` there, or pass `-w` for one command. A bare
`slacker init` (no workspace name) refuses such a file too, so name the workspace explicitly. Changing the
workspace in the file needs trusting again. Its `"readOnly": true` always applies. A `.slacker.json` owned by
another user, or writable by others (e.g. one planted in `/tmp`), is ignored, and writes are refused while it's
there (so is one in a directory others can write to). If it's yours and only group-writable, `-w` or
`SLACKER_WORKSPACE` still lets you write, with a warning.
Details: [project trust](docs/reference.md#trusting-a-projects-slackerjson).

**Trust doesn't cover `.mcp.json`.** The entry `init` writes passes `--workspace` itself, so a repo that commits
its own `.mcp.json` chooses the workspace its `slacker` server writes to. Before you approve a project's
`slacker` server in Claude Code, read that entry's `--workspace` (and its `command`).

## When something goes wrong

| You see | Do this |
| --- | --- |
| `invalid_auth` | `slacker auth refresh`, then `slacker auth setup` if that doesn't fix it |
| `token_revoked` / `token_expired` | Sign the desktop app back in, then `slacker auth setup` |
| `No channel named "#x"` | Check with `slacker channels --all --filter x`; for a person use `@handle` |
| `Refusing to write until config.json is fixed` | Two names share one team: [fix duplicated entries](docs/reference.md#fixing-duplicated-workspace-entries) |
| `Refusing to write: …/.slacker.json picks workspace "x", but it isn't trusted on this machine` | Check that `x` is right for this project, then `slacker trust` there (or pass `-w <name>` for one command) |
| Claude Code can't start slacker / tools say `not configured` | Follow the fix in the message; [more](docs/setup-guide.md#5-connect-claude-code) |

Every error message names its fix. The full table is in [troubleshooting](docs/reference.md#troubleshooting).

## Security

These are full user-session credentials. Anyone who can read `config.json` can act as you, so slacker keeps it at
mode `0600`. Read-only mode is a guardrail, not a security boundary: an agent with shell access could still
run slacker or read the file.

slacker also treats project files and Slack content as untrusted: an untrusted `.slacker.json` can't choose the
workspace for writes (above; a repo's own `.mcp.json` is up to you to check), `slacker init` refuses a
`.slacker.json` or `.mcp.json` that is a symlink leading outside the project (`unsafe_symlink`), and terminal
escape sequences in Slack text (message text, names, topics, file names …) are stripped from human-readable CLI
output. See the [safety model](docs/reference.md#safety-model).

## Development

```bash
npm install          # installs and builds dist/
npm test             # vitest; all Slack calls are stubbed, no network
npm run typecheck    # src/ and tests/
npm run dev          # tsc --watch
```

Releasing: the version lives in both `package.json` and `plugin/.claude-plugin/plugin.json`. Bump both (a test
checks that they match).

Source layout and test helpers: [reference → Development](docs/reference.md#development).

## License

MIT. See [LICENSE](LICENSE).

TDQS

A4/5.0

Scored across 13 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: message operations (send/edit/delete), reading (read_messages vs read_thread are cleanly separated by channel vs thread), search, discovery (list_channels, find_user, list_unread), and identity/status (whoami, get_status vs set_status). No two tools overlap ambiguously.

Naming Consistency4/5

Nearly all tools follow a clean verb_noun snake_case pattern (read_messages, send_message, edit_message, list_channels, set_status, add_reaction). The only deviation is whoami, a single-word idiom that breaks the pattern but is unambiguous and conventional.

Tool Count5/5

13 tools is well-scoped for a Slack client, covering the essential read/write/search/discovery surface without bloat. Every tool maps to a distinct capability with no filler.

Completeness4/5

Core Slack workflows are covered: reading channels/threads/DMs, sending/editing/deleting messages, reactions, search, unread tracking, user lookup, and status. Minor gaps exist around channel/fleet management (create channel, invite members, file uploads, pins), but agents can work around these.

Maintenance

ActivityMaintained
ResponsivenessNo issues