slack · diff

v1.0 to v1.2

74 added, 84 removed. Audit A to A.

---
name: slack
- description: Send messages, search history, and manage channels via Slack's Web API. Use when the user mentions Slack, a channel, a DM, or wants to post to a specific user/group.
+ description: Read and search accessible Slack content, then send user-confirmed messages as the connected bot.
when_to_use: |
- Trigger when the user wants to read or write something in Slack —
- send a message to a channel/DM, search history, list channels,
- upload a file, etc.
+ Use when the user wants to find or summarize Slack content the connected
+ app can access, or send a message to a channel or conversation the app
+ has joined.
connections: [slack]
allowed_tools: [Bash]
license: Apache-2.0
metadata:
author: acedatacloud
- version: "1.0"
+ version: "1.2"
---
- There is no first-party Slack CLI fit for daily use, so we drive the
- [Slack Web API](https://api.slack.com/methods) with `curl + jq`. The
- user's OAuth bearer token is in `$SLACK_TOKEN`; every call needs it as
- `Authorization: Bearer $SLACK_TOKEN`.
-
- The Slack API ALWAYS returns 200 — check the JSON `ok` field for success.
- A failed call has `{"ok": false, "error": "<reason>"}`. Surface the
- `error` value verbatim to the user when it occurs.
-
- **Always start with `auth.test`** to confirm the connection works AND
- to learn what bot user / team you're posting as. Many subsequent calls
- need the bot's user id (`auth.test` returns `user_id`).
+ Use the [Slack Web API](https://api.slack.com/methods) with the connected
+ bot token in `$SLACK_TOKEN`. Send it only to `https://slack.com/api/` over
+ HTTPS. Check the JSON `ok` field and HTTP status for every response; report
+ Slack's error value when a call fails. Respect `Retry-After` on HTTP 429.
- ## Recipes
+ Messages are sent as the AceDataCloud bot, not as the user's Slack account.
+ The app cannot upload files, join channels, or read arbitrary conversations
+ between other users. Channel and conversation history is available only
+ where the app has been added. Public channel search uses
+ `search:read.public`; do not imply that it searches private channels or
+ direct messages.
- ### Verify auth (always run first)
+ ## Verify the connected workspace
```sh
curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
https://slack.com/api/auth.test
- # {"ok": true, "team": "...", "team_id": "...", "user": "<bot>", "user_id": "U..."}
```
- ### Resolve a channel name to its ID (you'll need this a lot)
-
- ```sh
- curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
- "https://slack.com/api/conversations.list?limit=1000&types=public_channel,private_channel" \
- | jq -r --arg name "general" '.channels[] | select(.name == $name) | .id'
- ```
+ Use the returned team and bot user to check that the connection targets the
+ workspace the user intended.
- ### Post a message
+ ## List channels visible to the app
```sh
- curl -sS -X POST https://slack.com/api/chat.postMessage \
- -H "Authorization: Bearer $SLACK_TOKEN" \
- -H "Content-Type: application/json; charset=utf-8" \
- -d "$(jq -nc \
- --arg ch "C0123456789" \
- --arg text "Deploy complete." \
- '{channel:$ch, text:$text}')"
+ curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
+ https://slack.com/api/conversations.list \
+ --data-urlencode "types=public_channel,private_channel" \
+ --data-urlencode "limit=200"
```
- ### Reply in a thread
+ Follow `response_metadata.next_cursor` to paginate. Resolve channel names
+ to IDs from this response rather than inventing IDs.
+ ## Read channel history or a thread
+
```sh
- curl -sS -X POST https://slack.com/api/chat.postMessage \
- -H "Authorization: Bearer $SLACK_TOKEN" \
- -H "Content-Type: application/json; charset=utf-8" \
- -d "$(jq -nc \
- --arg ch "C0123456789" \
- --arg ts "1777656720.123456" \
- --arg text "Thanks!" \
- '{channel:$ch, thread_ts:$ts, text:$text}')"
+ curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
+ https://slack.com/api/conversations.history \
+ --data-urlencode "channel=C0123456789" \
+ --data-urlencode "limit=100"
+
+ curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
+ https://slack.com/api/conversations.replies \
+ --data-urlencode "channel=C0123456789" \
+ --data-urlencode "ts=1777656720.123456"
```
- ### Search messages
+ Read a private channel or direct message only if the app is a member. If
+ Slack returns `not_in_channel` or `channel_not_found`, ask the user to add
+ the app to that conversation. Do not try to join it automatically.
+ ## Search public-channel messages
+
```sh
- curl -sS -G \
- -H "Authorization: Bearer $SLACK_TOKEN" \
- "https://slack.com/api/search.messages" \
+ curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
+ https://slack.com/api/search.messages \
--data-urlencode "query=in:#engineering deploy" \
--data-urlencode "count=20"
```
- ### Send a DM to a user (by email)
+ If the API reports `missing_scope`, report that result rather than claiming
+ the search succeeded. The connection cannot search private channels or direct
+ messages.
- ```sh
- USER_ID=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
- "https://slack.com/api/users.lookupByEmail" \
- --data-urlencode "email=alice@example.com" \
- | jq -r '.user.id')
+ ## Resolve a member
- # DM channels are auto-created the first time you postMessage to a user id.
- curl -sS -X POST https://slack.com/api/chat.postMessage \
- -H "Authorization: Bearer $SLACK_TOKEN" \
- -H "Content-Type: application/json; charset=utf-8" \
- -d "$(jq -nc --arg ch "$USER_ID" --arg text "Hi from the bot." '{channel:$ch, text:$text}')"
+ ```sh
+ curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
+ https://slack.com/api/users.lookupByEmail \
+ --data-urlencode "email=alice@example.com"
```
- ### Upload a file to a channel
+ Use member details only to identify people in retrieved content. Do not send
+ unsolicited direct messages or enumerate members for outreach.
- Two-step: create an upload URL, then complete.
+ ## Send a message or thread reply
- ```sh
- UPLOAD=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
- "https://slack.com/api/files.getUploadURLExternal" \
- --data-urlencode "filename=report.pdf" \
- --data-urlencode "length=$(wc -c < report.pdf)")
- URL=$(echo "$UPLOAD" | jq -r '.upload_url')
- ID=$(echo "$UPLOAD" | jq -r '.file_id')
+ Before each send, resolve the exact workspace, channel or existing
+ conversation, and final message text. Call `request_action_confirmation`
+ with `kind: "generic"` and show those three values. Send only if the user
+ confirms. If the confirmation tool is unavailable, return a draft. If this
+ is an unattended run, send only when the saved task already authorizes that
+ exact destination and content; otherwise return a draft.
- curl -sS -T report.pdf "$URL"
+ The bot must already be a member of the target channel or conversation.
+ If Slack returns `not_in_channel` or `channel_not_found`, ask the user
+ to add the app there. Do not call `conversations.join`. Do not retry a
+ `chat.postMessage` request whose outcome is unknown; first check the
+ channel history to avoid duplicates.
- curl -sS -X POST https://slack.com/api/files.completeUploadExternal \
+ ```sh
+ curl -sS -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
- -d "$(jq -nc --arg fid "$ID" --arg ch "C0123456789" \
- '{files:[{id:$fid, title:"report.pdf"}], channel_id:$ch}')"
+ -d "$(jq -nc --arg ch "C0123456789" --arg text "Confirmed message" \
+ '{channel:$ch, text:$text}')"
```
- ## Notes
+ For a reply in an existing thread, include its exact `thread_ts` in the
+ payload. Check `ok`, `channel`, and `ts` in the response and report the
+ sent message link or channel and timestamp.
- - **`chat.postMessage` to a public channel requires the bot to be a
- member of that channel.** If you get `not_in_channel`, call
- `conversations.join` first (which also takes the channel id), then
- retry. Private channels and DMs need a manual invite — ask the user.
- - Always check `.ok` on the JSON response. `not_authed` / `invalid_auth`
- → ask the user to re-authorize at `studio.acedata.cloud/console/connectors`.
- - Channel ids start with `C` (channels), `D` (DMs), `G` (private). Don't
- invent ids — always look them up via `conversations.list` or
- `users.lookupByEmail`.
- - Slack rate-limits aggressively; `Retry-After` is in the response
- headers if you get a 429. Sleep and retry rather than parallelizing.
+ If `auth.test` returns `not_authed` or `invalid_auth`, ask the user to
+ reconnect Slack at `https://studio.acedata.cloud/console/connectors`.