Sends messages, searches history, resolves channels, and manages DMs via Slack's Web API using curl and jq.
How this skill is triggered — by the user, by Claude, or both
Slash command
/acedatacloud-ai-media:slackWhen 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.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
There is no first-party Slack CLI fit for daily use, so we drive the
There is no first-party Slack CLI fit for daily use, so we drive the
Slack Web API 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).
curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
https://slack.com/api/auth.test
# {"ok": true, "team": "...", "team_id": "...", "user": "<bot>", "user_id": "U..."}
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'
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 -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/search.messages" \
--data-urlencode "query=in:#engineering deploy" \
--data-urlencode "count=20"
USER_ID=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
"https://slack.com/api/users.lookupByEmail" \
--data-urlencode "[email protected]" \
| jq -r '.user.id')
# 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}')"
Two-step: create an upload URL, then complete.
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')
curl -sS -T report.pdf "$URL"
curl -sS -X POST https://slack.com/api/files.completeUploadExternal \
-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}')"
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..ok on the JSON response. not_authed / invalid_auth
→ ask the user to re-authorize at auth.acedata.cloud/user/connections.C (channels), D (DMs), G (private). Don't
invent ids — always look them up via conversations.list or
users.lookupByEmail.Retry-After is in the response
headers if you get a 429. Sleep and retry rather than parallelizing.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub acedatacloud/skills --plugin acedatacloud-ai-tools