Model or dataset
stablyai/agent-slack avatar
stablyai/agent-slack

Zero config auth, an AppleScript permission you have to enable by hand, and a compose command that posts

Slack automation CLI for AI agents

576 stars84 forksTypeScriptMIT

At a glance

What is it?
agent-slack is a TypeScript CLI that gives coding agents Slack read and write access without registering a Slack app: it authenticates by reading Slack Desktop's local data, falling back to pulling tokens out of a browser. That convenience is the whole design, and it is where the sharp edges sit, along with a compose command that sends instead of drafting when no browser is present.
Who is it for?
agent-slack is a good fit when you already run an agent on your own machine and want it to read and write Slack as you, and a poor fit for a shared host, a CI runner you do not control, or any environment where an agent should not hold your session credentials. Two things to check before you wire it into anything.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 67 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 12, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • stablyai/agent-slack576 ★ · +42
Star history
Repository2026-09-132026-11-12
stablyai/agent-slack534576

42 Stars in the last 60 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Zero config auth means reading Slack Desktop, then falling back to your browser

The stated guiding principle is that authentication just works if you have Slack Desktop, with fallbacks available. On macOS and Windows the default path reads Slack Desktop's local data, and the documentation notes you do not need to quit Slack first. If that fails on macOS, it tries extraction from Chrome, Brave or Firefox. There are manual commands for each of those, plus `auth whoami` to check the result and `auth test` to verify it.

The alternative is to hand it credentials yourself, and here are the two documented shapes:

bash
export SLACK_TOKEN="xoxc-..."      # browser token
export SLACK_COOKIE_D="xoxd-..."   # cookie d
agent-slack auth test

A standard Slack token works too, `SLACK_TOKEN="xoxb-..."` for a bot or user token. And the command map lists an `auth parse-curl` subcommand that appears nowhere in the authentication section, which describes only the desktop and browser imports.

What none of this involves is a Slack app you register. There is no OAuth flow, no client id and no scope grant page, because the CLI is not authenticating as an application. It is authenticating as you, with the credentials your desktop client or browser session already holds. That is what removes the setup step, and it is also the whole security profile of the tool in one sentence: a live session credential sits on disk somewhere the agent can reach, and every read and write happens under your own permissions rather than a reviewed scope list.

The browser fallback needs a browser security setting enabled by hand

The browser extraction path has a prerequisite, and the documentation puts it in a note rather than in the setup flow:

> `import-brave` / `import-chrome` read tokens from a logged-in Slack tab via AppleScript. Both browsers ship with Allow JavaScript from Apple Events disabled by default, so enable it in View then Developer before running these commands. macOS will prompt for your password the first time.

That setting is off by default for a reason. Allowing JavaScript from Apple Events lets an external process drive the open tab, which is exactly the capability the token extraction needs and exactly the capability that turns a stray script into one that can read and submit whatever page is open. Turning it on is a browser wide permission, not a per site one, so the setting you loosen for `agent-slack` also applies to every other tab you have open at the same time.

The note says macOS will prompt for your password the first time, which is the system asking for permission to control the browser through Apple Events rather than an authentication step for Slack. So the zero config claim costs two things on this path: a browser permission that stays enabled afterwards, and a password prompt that looks like something else. Neither is reversible from inside the CLI, and the README does not say what turning the setting back off affects. Firefox appears in the fallback list and the manual commands but not in this note, so whether it needs the same permission is not stated.

`message compose` sends the supplied text when no browser is attached

Compose opens a Slack style WYSIWYG editor in your browser, with bold, italic, strikethrough, links, lists, quotes, code and code blocks, and it supports `--no-unfurl` to suppress link previews and thread replies. After sending, the editor shows a link back to the posted message. It reads like a drafting tool with a human in the loop.

Then one line changes the picture:

> `message compose` is send-capable. In CI, it skips the browser editor and immediately sends supplied text; do not use it for a compose-only request in a noninteractive environment.

So the same command has two behaviours chosen by whether a browser is available. With one, it is a drafting tool a human reviews. Without one, it posts whatever text it was handed. The second case is the one an agent triggers most often, because an agent runs headless by definition, and the failure mode is an unwanted message in a real channel rather than an error. The documentation's own advice is that you should probably use the skill for your agent rather than reading the examples, which makes this worse: the path an agent is steered towards is the path where compose does not compose.

The guiding principle lists human in the loop as a design value, qualified as applying when appropriate, and explicitly not in CI environments. Those two statements are in tension. In a headless environment there is no human to loop in, and the tool responds by removing the confirmation step rather than refusing the send.

A documented filter example ends at an unfinished flag, and one auth command is never explained

The examples section pairs one positive filter with its negative counterpart. The positive case is complete, filtering on an `:eyes:` reaction with an oldest timestamp and a limit:

bash
agent-slack message list "#general" --with-reaction eyes --oldest "1770165109.000000" --limit 20

The negative case, the one for messages that do not carry `:dart:`, is the line after it:

bash
agent-slack message list "#general" --wi

`--wi` is not a flag. It is the beginning of one, cut off mid word. There is no matching negative option documented anywhere else in the visible material, so the example that is supposed to show how to exclude a reaction shows a command that cannot run. The most useful demonstration of the filter feature is the broken one, and a reader copying it gets an argument error instead of a list of messages.

The same kind of gap exists on the authentication side. The command map lists six subcommands under `auth`, including `import-brave`, `import-chrome`, `import-firefox`, `import-desktop`, `test` and `whoami`, and the authentication section covers five of them in an example block. The sixth, `parse-curl`, is listed and never explained. The README instructs you to treat the installed CLI's help output as authoritative for commands and flags, which is an honest answer to documentation that lags the code, but it means the examples here are the parts to distrust.

Slack native drafts depend on endpoints the documentation admits are undocumented

There are two ways to get text toward a message. Compose opens your own editor. The draft commands go through Slack itself, so a draft appears in your Slack client on mobile and desktop, ready for you to review and send.

The mechanism is the part worth reading:

> These commands use Slack's undocumented internal `drafts.*` client endpoints (the same ones the Slack app uses), authenticated with your own browser session. They act only as you, on your own drafts, and nothing is exposed that

The visible text ends mid sentence there, so the scope claim is stated but not finished. What is clear is that this path needs browser style authentication, the `xoxc` and `xoxd` pair rather than a bot token, and that it depends on private client endpoints rather than the public Web API. The dependency has consequences the repository cannot test. There is no public contract behind those endpoints, no version negotiation and no deprecation notice, so a Slack side change surfaces as a runtime failure in a code path that nothing in the test suite would have flagged. The `@slack/web-api` dependency covers the public surface; the drafts path sits outside it.

The scoping sentence is also doing real work. Acting on your own drafts, as yourself, means the blast radius of a mistake is your own drafts rather than a channel, which is a materially different risk from the send capable compose command in the same tool.

The published package ships dist and bin, but not the skill directory

The repository tree contains `skills/`, and the agent skill at `skills/agent-slack/` is described as compatible with Claude Code, Codex and Cursor, installable through skills.sh with `npx skills add stablyai/agent-slack` or through `bash ./scripts/install-skill.sh`. The published npm package does not contain it. The `files` allowlist in `package.json` is exactly four entries: `dist`, `bin/agent-slack.js`, `README.md` and `LICENSE`.

So the two documented ways to get this project give you different halves. `npx skills add` pulls from the repository and gets the skill. `npm i -g agent-slack` gets the CLI and not the skill. That is a reasonable packaging decision for a CLI with a filesystem footprint rather than an error, and it is invisible to anyone who installs globally and then reads a README section telling them a skill exists.

The build scripts explain the rest. `build` targets Bun, while `build:npm` targets Node with `--packages=external` and marks `bun:sqlite` and `node:sqlite` as external, which leaves those two modules resolved at runtime instead of bundled. `prepublishOnly` runs the Node build, so the npm artifact is always the Node target. The `engines` field requires Node 22.5 or newer, consistent with a runtime that needs `node:sqlite`. The package version, 0.10.2, matches the newest release tag, so the two do not disagree.

Three install routes, one of them unpinned, and two patch releases five minutes apart

Three installation paths, one command each. The recommended one pipes a shell script straight into a shell:

bash
curl -fsSL https://raw.githubusercontent.com/stablyai/agent-slack/main/install.sh | sh

That URL names the `main` branch, not a tag, so this route runs whatever is at the head of the default branch at that moment, with no version in the command and no checksum to compare against. The npm route is pinned by package version if you pin it yourself, `npm i -g agent-slack` takes the newest. The Nix route is `nix run github:stablyai/agent-slack`, which resolves through the flake in the tree. After installation there is also `agent-slack update`, a self updater that detects whether you arrived by npm, by Bun or as a binary, so the update story depends on which of the three you chose.

The repository carries the artefacts for all of them: `bun.lock` for the Bun path, `flake.nix`, `flake.lock` and a `nix/` directory for the Nix path, `install.sh` and a `bin/` launcher. Linting and formatting run through oxlint and oxfmt, tests through `bun test`, and a pre-commit hook runs lint fixing, formatting and a staged add on every commit.

The release cadence is unusually tight at one end. v0.10.0 and v0.10.1 were both published on 2026-09-02, four and a half minutes apart. v0.10.2 followed on 2026-09-04, and the last push is dated 2026-09-07. Thirty two issues are open against 541 stars and 70 forks, which is a large open share for a project of that size and worth reading before you assume each feature request is on a roadmap.

Pruned JSON saves tokens and loses the difference between absent and empty

The first guiding principle is token efficiency, and the implementation is blunt about it. Slack data commands output aggressively pruned JSON with `null` and empty fields removed, while help, update and some authentication setup commands output text. Attached files are auto downloaded and returned as absolute local paths, and bullet lists in outgoing messages render as native Slack rich text.

For an agent on a context budget this is the right trade in most cases. Slack objects carry many fields that are null most of the time, and an agent paying per token for every one of them pays a tax on every message it reads. The cost of the pruning is that absence and emptiness become the same thing on the wire. A field that is missing from the output could mean the value is null upstream, or that the field did not apply to this message, or that the printer dropped it. An agent cannot tell those apart without a second request, which defeats the saving.

The file handling is the part with a wider blast radius. Auto downloading means a message with an attachment causes a write to the machine's filesystem at a path the CLI chooses, and the returned absolute path is what the agent then reasons about. That is a reasonable design for an agent that needs to look at an image, and it is also a download path from a channel you may not fully trust, executed with the privileges of whoever is running the agent. Nothing in the visible documentation describes a size limit, a type allowlist or a quarantine location.

Editorial conclusion

agent-slack is a good fit when you already run an agent on your own machine and want it to read and write Slack as you, and a poor fit for a shared host, a CI runner you do not control, or any environment where an agent should not hold your session credentials. Two things to check before you wire it into anything. Decide whether the compose behaviour is acceptable, because with no browser attached the command sends the supplied text immediately rather than opening an editor, and the same command's name suggests otherwise. And decide whether the undocumented drafts endpoints are worth the coupling, since a Slack side change breaks them without anything in this repository failing. Whatever you choose, read your workspace terms and the Slack terms before pointing an agent at a channel, and treat the machine you install this on as holding a live session token from the moment authentication succeeds.

Frequently asked questions

How does agent-slack authenticate without a Slack app?

It reads Slack Desktop local data by default without needing Slack quit, falls back to Chrome, Brave or Firefox token extraction on macOS, and also accepts `SLACK_TOKEN` and `SLACK_COOKIE_D` or a standard xoxb or xoxp token. No app registration or scope grant is involved.

What does agent-slack message compose do in CI?

It skips the browser editor and immediately sends the supplied text. The README states it is send capable and warns against using it for a compose only request in a noninteractive environment.

Do the agent-slack draft commands need a bot token?

No. They require browser style authentication with the xoxc and xoxd pair and use Slack's undocumented internal `drafts.*` client endpoints, so drafts appear natively in your own Slack client for review before sending.

How do I install agent-slack, and which route should I use?

Three documented routes: `curl -fsSL https://raw.githubusercontent.com/stablyai/agent-slack/main/install.sh | sh`, `npm i -g agent-slack` which needs Node 22.5 or newer, or `nix run github:stablyai/agent-slack`. The curl route names the main branch rather than a tag.

Does the agent-slack npm package include the agent skill?

No. The `files` allowlist in package.json is `dist`, `bin/agent-slack.js`, `README.md` and `LICENSE`, so the skill directory is available from the repository through `npx skills add stablyai/agent-slack` rather than from the published package.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. stablyai/agent-slack on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stablyai-agent-slack.svg)](https://hysenlabs.com/projects/stablyai-agent-slack)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/stablyai-agent-slack.svg)](https://hysenlabs.com/projects/stablyai-agent-slack)

Was this useful?