{"id":43683730,"url":"https://github.com/stablyai/agent-slack","last_synced_at":"2026-04-15T02:01:04.817Z","repository":{"id":336552906,"uuid":"1149299036","full_name":"stablyai/agent-slack","owner":"stablyai","description":"Slack automation CLI for AI agents","archived":false,"fork":false,"pushed_at":"2026-03-30T09:42:11.000Z","size":483,"stargazers_count":360,"open_issues_count":8,"forks_count":30,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-02T08:40:36.143Z","etag":null,"topics":["agent","automation","cli","slack"],"latest_commit_sha":null,"homepage":"https://www.stably.ai","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stablyai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-04T00:33:03.000Z","updated_at":"2026-04-01T16:52:44.000Z","dependencies_parsed_at":"2026-03-01T02:01:03.161Z","dependency_job_id":null,"html_url":"https://github.com/stablyai/agent-slack","commit_stats":null,"previous_names":["stablyai/agent-slack"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/stablyai/agent-slack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablyai%2Fagent-slack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablyai%2Fagent-slack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablyai%2Fagent-slack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablyai%2Fagent-slack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stablyai","download_url":"https://codeload.github.com/stablyai/agent-slack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablyai%2Fagent-slack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31536473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","automation","cli","slack"],"created_at":"2026-02-05T02:12:34.785Z","updated_at":"2026-04-08T02:03:34.216Z","avatar_url":"https://github.com/stablyai.png","language":"TypeScript","readme":"# agent-slack\n\nSlack automation CLI for AI agents (TypeScript + Bun).\n\nGuiding principle:\n\n- **Token-efficient** — (compact JSON, minimal duplication, and empty/null fields pruned) so LLMs can consume results cheaply.\n- **Zero-config auth** — Auth just works if you have Slack Desktop (with fallbacks available). No Python dependency.\n- **Human-in-the-loop** — When appropriate (not in CI environments), loop humans in. Ex: `message draft`\n  \u003cimg width=\"1228\" height=\"741\" alt=\"image\" src=\"https://github.com/user-attachments/assets/92ecbb71-18ca-4516-a874-c83c154b0709\" /\u003e\n\n## Getting started\n\nInstall via Bun (recommended):\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/stablyai/agent-slack/main/install.sh | sh\n```\n\nOR npm global install (requires Node \u003e= 22.5):\n\n```bash\nnpm i -g agent-slack\n```\n\nOR run via Nix flake:\n\n```bash\nnix run github:stablyai/agent-slack\n```\n\n## At a glance\n\n- **Read**: fetch a message, browse channel history, list full threads\n- **Search**: messages + files (with filters)\n- **Artifacts**: auto-download snippets/images/files to local paths for agents\n- **Write**: reply, edit/delete messages, add reactions (bullet lists auto-render as native Slack rich text)\n- **Channels**: list conversations, create channels, and invite users by id/handle/email\n- **Canvas**: fetch Slack canvases as Markdown\n\n## Agent skill\n\nThis repo ships an agent skill at `skills/agent-slack/` compatible with Claude Code, Codex, Cursor, etc\n\n**Install via [skills.sh](https://skills.sh)** (recommended):\n\n```bash\nnpx skills add stablyai/agent-slack\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eManual installation\u003c/summary\u003e\n    \n```bash\nbash ./scripts/install-skill.sh\n```\n\n\u003c/details\u003e\n\n## Command map (high level)\n\n```text\nagent-slack\n├── update                         # self-update (detects npm/bun/binary)\n├── auth\n│   ├── whoami\n│   ├── test\n│   ├── import-desktop\n│   ├── import-chrome\n│   ├── import-firefox\n│   └── parse-curl\n├── message\n│   ├── get   \u003ctarget\u003e             # fetch 1 message (+ thread meta )\n│   ├── list  \u003ctarget\u003e             # fetch thread or recent channel messages\n│   ├── send  \u003ctarget\u003e \u003ctext\u003e      # send / reply (supports --attach)\n│   ├── draft \u003ctarget\u003e [text]      # open Slack-like editor in browser\n│   ├── edit  \u003ctarget\u003e \u003ctext\u003e      # edit a message\n│   ├── delete \u003ctarget\u003e            # delete a message\n│   └── react\n│       ├── add    \u003ctarget\u003e \u003cemoji\u003e\n│       └── remove \u003ctarget\u003e \u003cemoji\u003e\n├── channel\n│   ├── list                        # list conversations (user-scoped or all)\n│   ├── new                         # create channel\n│   └── invite                      # invite users to channel\n├── user\n│   ├── list\n│   └── get \u003cuser\u003e\n├── search\n│   ├── all      \u003cquery\u003e           # messages + files\n│   ├── messages \u003cquery\u003e\n│   └── files    \u003cquery\u003e\n├── workflow\n│   ├── list    \u003cchannel\u003e          # workflows bookmarked in a channel\n│   ├── preview \u003ctrigger-id\u003e       # trigger metadata (no side effects)\n│   ├── get     \u003cid\u003e               # workflow definition + form fields\n│   └── run     \u003ctrigger-id\u003e       # trip a workflow trigger\n└── canvas\n    └── get \u003ccanvas-url-or-id\u003e     # canvas → markdown\n```\n\nNotes:\n\n- Output is **always JSON** and aggressively pruned (`null`/empty fields removed).\n- Attached files are auto-downloaded and returned as absolute local paths.\n\n## Authentication (no fancy setup)\n\nOn macOS and Windows, authentication happens automatically:\n\n- Default: reads Slack Desktop local data (no need to quit Slack)\n- Fallbacks: if that fails, tries Chrome/Firefox extraction (macOS)\n\nYou can also run manual imports:\n\n```bash\nagent-slack auth whoami\nagent-slack auth import-desktop\nagent-slack auth import-chrome\nagent-slack auth import-firefox\nagent-slack auth test\n```\n\nAlternatively, set env vars:\n\n```bash\nexport SLACK_TOKEN=\"xoxc-...\"      # browser token\nexport SLACK_COOKIE_D=\"xoxd-...\"   # cookie d\nagent-slack auth test\n```\n\nOr use a standard Slack token (xoxb/xoxp):\n\n```bash\nexport SLACK_TOKEN=\"xoxb-...\"\nagent-slack auth test\n```\n\n## Targets: URL or channel\n\n`message get` / `message list` accept either a Slack message URL or a channel reference:\n\n- URL: `https://workspace.slack.com/archives/\u003cchannel\u003e/p\u003cdigits\u003e[?thread_ts=...]`\n- Channel: `#general` (or bare `general`) or a channel ID like `C0123...`\n\nIn practice:\n\n```bash\n# Get a single message by channel + ts\nagent-slack message get \"#general\" --ts \"1770165109.628379\"\n\n# List a full thread by channel + thread root ts\nagent-slack message list \"#general\" --thread-ts \"1770165109.000001\"\n```\n\nIf you have multiple workspaces configured and you use a channel **name** (`#channel` / `channel`), you must pass `--workspace` (or set `SLACK_WORKSPACE_URL`).\n`--workspace` accepts a full URL or a unique substring selector:\n\n```bash\nagent-slack message get \"#general\" --workspace \"https://stablygroup.slack.com\" --ts \"1770165109.628379\"\nagent-slack message get \"#general\" --workspace \"stablygroup\" --ts \"1770165109.628379\"\n```\n\n## Examples\n\n\u003e [!TIP]\n\u003e You should probably just use the skill for your agent instead of reading below.\n\n### Read messages / threads\n\n```bash\n# Single message (+ thread summary if threaded)\nagent-slack message get \"https://workspace.slack.com/archives/C123/p1700000000000000\"\n\n# Full thread for a message\nagent-slack message list \"https://workspace.slack.com/archives/C123/p1700000000000000\"\n\n# Recent channel messages (browse channel history)\nagent-slack message list \"#general\" --limit 20\n\n# Recent channel messages that are marked with :eyes:\nagent-slack message list \"#general\" --with-reaction eyes --oldest \"1770165109.000000\" --limit 20\n\n# Recent channel messages that do not have :dart:\nagent-slack message list \"#general\" --without-reaction dart --oldest \"1770165109.000000\" --limit 20\n```\n\nOptional:\n\n```bash\n# Include reactions + which users reacted\nagent-slack message get \"https://workspace.slack.com/archives/C123/p1700000000000000\" --include-reactions\n```\n\n### Draft a message (browser editor)\n\nOpens a Slack-like WYSIWYG editor in your browser for composing messages with full formatting support (bold, italic, strikethrough, links, lists, quotes, code, code blocks).\n\n```bash\n# Open editor for a channel\nagent-slack message draft \"#general\"\n\n# Open editor with initial text\nagent-slack message draft \"#general\" \"Here's my update\"\n\n# Reply in a thread\nagent-slack message draft \"https://workspace.slack.com/archives/C123/p1700000000000000\"\n```\n\nAfter sending, the editor shows a \"View in Slack\" link to the posted message.\n\n### Reply, edit, delete, and react\n\n```bash\nagent-slack message send \"https://workspace.slack.com/archives/C123/p1700000000000000\" \"I can take this.\"\nagent-slack message send \"#alerts-staging\" \"here's the report\" --attach ./report.md\nagent-slack message edit \"https://workspace.slack.com/archives/C123/p1700000000000000\" \"I can take this today.\"\nagent-slack message delete \"https://workspace.slack.com/archives/C123/p1700000000000000\"\nagent-slack message react add \"https://workspace.slack.com/archives/C123/p1700000000000000\" \"eyes\"\nagent-slack message react remove \"https://workspace.slack.com/archives/C123/p1700000000000000\" \"eyes\"\n```\n\nChannel mode requires `--ts`:\n\n```bash\nagent-slack message edit \"#general\" \"Updated text\" --workspace \"myteam\" --ts \"1770165109.628379\"\nagent-slack message delete \"#general\" --workspace \"myteam\" --ts \"1770165109.628379\"\n```\n\nAttach options for `message send`:\n\n- `--attach \u003cpath\u003e` upload a local file (repeatable)\n\n### List, create, and invite channels\n\n```bash\n# List conversations for current user (users.conversations)\nagent-slack channel list\n\n# List conversations for a specific user\nagent-slack channel list --user \"@alice\" --limit 50\n\n# List all workspace conversations (conversations.list)\nagent-slack channel list --all --limit 100\n\n# Create a public channel\nagent-slack channel new --name \"incident-war-room\"\n\n# Create a private channel\nagent-slack channel new --name \"incident-leads\" --private\n\n# Invite users by id, handle, or email\nagent-slack channel invite --channel \"incident-war-room\" --users \"U01AAAA,@alice,bob@example.com\"\n\n# Invite external Slack Connect users by email (restricted by default)\nagent-slack channel invite --channel \"incident-war-room\" --users \"partner@vendor.com\" --external\n\n# External invite with permission for invitees to invite others\nagent-slack channel invite --channel \"incident-war-room\" --users \"partner@vendor.com\" --external --allow-external-user-invites\n```\n\nNotes:\n\n- `channel list` returns a single page plus `next_cursor`; use `--cursor` to fetch the next page.\n- `channel list --all` and `channel list --user` are mutually exclusive.\n- `--external` maps to `conversations.inviteShared` and expects email targets.\n- External invites default to restricted mode (`external_limited=true`); add `--allow-external-user-invites` to disable that restriction.\n- External invites require Slack Connect permissions/scopes in your workspace.\n\n### Message get vs list\n\n**`message get`** fetches a single message. If the message is in a thread, it also returns thread metadata (reply count, participants) but **not** the full thread contents:\n\n```json\n{\n  \"message\": { \"ts\": \"...\", \"text\": \"...\", \"user\": \"U123\", ... },\n  \"thread\": { \"ts\": \"...\", \"length\": 6 }\n}\n```\n\n**`message list`** fetches all replies in a thread, or recent channel messages when no thread is specified. Use this when you need the full conversation:\n\n```json\n{\n  \"messages\": [\n    { \"ts\": \"...\", \"text\": \"...\", \"user\": \"U123\", ... },\n    { \"ts\": \"...\", \"text\": \"...\", \"user\": \"U456\", ... }\n  ]\n}\n```\n\nWhen to use which:\n\n- Use `get` to check a single message or see if there's a thread worth expanding\n- Use `list` to read an entire thread conversation\n- Use `list` on a channel (without `--thread-ts`) to browse recent channel messages\n- Use `list` with `--with-reaction` / `--without-reaction` plus `--oldest` to filter channel history by reaction markers\n\n### Files (snippets/images/attachments)\n\n`message get/list` auto-download attached files to an agent-friendly temp directory and return file metadata in `message.files[]`, including `name` when Slack provides the original filename and `path` for the local download. Failed downloads keep the attachment entry, preserve `message.files[].path` with a local `.download-error.txt` file, and include `message.files[].error`. `search messages` and `search all` use the same attachment shape for message results, while `search files` skips entries whose download fails.\n\n- macOS default: `~/.agent-slack/tmp/downloads/`\n\nAgents can read those paths directly (e.g. snippets as `.txt`, images as `.png`).\n\n### Search (messages + files)\n\n```bash\n# Search both messages and files\nagent-slack search all \"smoke tests failed\" --channel \"#alerts\" --after 2026-01-01 --before 2026-02-01\n\n# Search messages only\nagent-slack search messages \"stably ai\" --user \"@stablyai\" --channel general\n\n# Search files only (downloads files and returns local paths)\nagent-slack search files \"testing\" --content-type snippet --limit 10\n```\n\nTips:\n\n- For reliable results, include `--channel ...` (channel-scoped search scans history/files and filters locally).\n- Use `--workspace \u003curl-or-unique-substring\u003e` when using `#channel` names across multiple workspaces.\n\n\u003c!-- AI search (assistant.search.*) is described in design.doc but not currently implemented. --\u003e\n\n### Users\n\n```bash\n# List users (email requires appropriate Slack scopes; fields are pruned if missing)\nagent-slack user list --workspace \"https://workspace.slack.com\" --limit 200 | jq .\n\n# Get one user by id or handle\nagent-slack user get U12345678 --workspace \"https://workspace.slack.com\" | jq .\nagent-slack user get \"@alice\" --workspace \"https://workspace.slack.com\" | jq .\n```\n\n### Fetch a Canvas as Markdown\n\n```bash\nagent-slack canvas get \"https://workspace.slack.com/docs/T123/F456\"\nagent-slack canvas get \"F456\" --workspace \"https://workspace.slack.com\"\n```\n\n## Developing / Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://stably.ai\"\u003e\n    \u003cimg src=\"https://public-artifacts.stably.ai/logo-white-with-bg.png\" height=\"96\" alt=\"Stably\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003e\n  \u003ca href=\"https://stably.ai\"\u003eStably\u003c/a\u003e\n\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  Code. Ship. \u003cs\u003eTest.\u003c/s\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://docs.stably.ai/\"\u003e\u003cstrong\u003eDocumentation\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"https://stably.ai/\"\u003e\u003cstrong\u003eHomepage\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cbr/\u003e\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablyai%2Fagent-slack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstablyai%2Fagent-slack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablyai%2Fagent-slack/lists"}