AgentStack
SKILL verified MIT Self-run

Slack

skill-thevibeworks-claude-code-docs-slack · by thevibeworks

A Claude skill from thevibeworks/claude-code-docs.

No reviews yet
0 installs
11 views
0.0% view→install

Install

$ agentstack add skill-thevibeworks-claude-code-docs-slack

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Slack? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Setup tips & tricks — Slack × CMA webhook bridge

Things that aren't obvious from the docs and tend to cost debugging time.


Mental model

Two webhooks, one bridge

  • Slack → bridge (/slack/events) fires on @mention. Payload carries channel, ts, thread_ts, user, text.
  • Anthropic → bridge (/cma-webhook) fires on session idle. Payload carries only the CMA session ID.

Neither carries the agent's output. Both are just signals with IDs.

The webhook is a doorbell, not a delivery

Anthropic's session.status_idled payload is deliberately thin — {type, id}. You follow up with sessions.retrieve(id) (metadata) and sessions.events.list(id) (output). Push the signal, pull the data.

metadata is the entire routing state

On kickoff, set metadata: {slack_channel, slack_thread_ts, slack_team}. When the idle webhook arrives later with only a session ID, retrieve the session, read those keys back, and chat.postMessage to exactly the right thread — with nothing stored in the bridge itself. This is what makes it stateless.

Slack's 3-second ack window

Slack retries any event that doesn't get a 2xx within 3 seconds. The bridge must return before the CMA session finishes. So: verify the signature, dedupe on event_id, fire kickoffAgentSession() without awaiting it, and return 204 immediately.


Gotchas

Use a developer sandbox, not your company workspace

Slack's Developer Program sandboxes give you a free Enterprise Grid org to test in — admin rights, fake users/channels, no risk of installing a half-built bot into production. This is not the "agent quickstart" — it's Developer Program → Sandboxes:

  1. Join the Slack Developer Program → activate via email → accept ToS.
  2. From the program dashboard: Provision Sandbox → pick empty or pre-loaded with fake users/channels → click again.
  3. Finish setup from the email invite — you become Primary Org Owner; name the org and create at least one workspace inside it.
  4. Create your app against that sandbox workspace and develop normally.

OAuth scope ≠ event subscription

Adding app_mentions:read under OAuth & Permissions → Bot Token Scopes grants permission to see mentions. It does not cause Slack to deliver them. You must also go to Event Subscriptions, toggle it On, set the Request URL, and add app_mention under "Subscribe to bot events." Two separate pages. Miss the second one and you get zero deliveries with no error anywhere.

xoxb- vs xapp- — two tokens, two pages, easy to grab the wrong one

| Token | Prefix | Page | Used for | |---|---|---|---| | Bot User OAuth Token | xoxb- | OAuth & Permissions (after install) | chat.postMessagethis is the one you want | | App-Level Token | xapp- | Basic Information → App-Level Tokens | Socket Mode WebSocket only |

chat.postMessage with an xapp- token fails with invalid_auth. The xoxb- token only exists after you've added at least one bot scope and clicked Install/Reinstall to Workspace.

Bridge must be running before you save the Request URL

Saving the Event Subscriptions URL triggers an immediate url_verification POST. If nothing is listening on the tunnel you get "Your URL didn't respond" and the URL won't save. Start bun run dev first, then paste the URL.

Anthropic webhooks are workspace-scoped

The endpoint you register in Console only receives events for sessions in that same workspace. If your ANTHROPIC_API_KEY is from workspace A but you registered the endpoint in workspace B: zero deliveries, silently. Match the workspace picker on the Webhooks page to the Workspace column on your API key.

A workspace webhook fires for every session in the workspace

Not just yours. If the Anthropic workspace is shared with other agents, scripts, or teammates, every session.status_idled in that workspace hits your endpoint. Your handler has to filter:

  • Retrieve-then-filter, always first. sessions.retrieve(id) → check for your slack_channel metadata key → bail with 204 if absent. Do this before events.list() or any other work; otherwise unrelated sessions throw 404 deeper in the handler.
  • Catch 404/403 on sessions.retrieve — sessions created under other API keys in the same workspace aren't readable by yours.
  • For production, use a dedicated Anthropic workspace. Each unrelated session costs one retrieve() call just to discard it; a workspace that only contains this agent's sessions avoids that entirely.

unwrap() needs a plain header map

client.beta.webhooks.unwrap(body, {headers}) (SDK ≥ 0.95.1) wants Record, not a fetch Headers object. Pass Object.fromEntries(req.headers).

event.id is your idempotency key

Anthropic retries failed deliveries with the same top-level event.id. Slack retries with the same event_id inside the body. Dedupe on both. Return 2xx once you've either handled or ignored the event — anything else triggers a retry, and ~20 consecutive Anthropic failures auto-disables your endpoint.


Local dev checklist

  1. ngrok http 3000 → note the public URL.
  2. bun run setup → copy CLAUDE_AGENT_ID / CLAUDE_ENVIRONMENT_ID into .env.local. Don't overwrite them later when you paste in the Slack secrets.
  3. Slack app → OAuth & Permissions → Bot Token Scopes: app_mentions:read, chat:write (+ im:history for DMs) → Install to Workspace → copy xoxb-…SLACK_BOT_TOKEN.
  4. Slack app → Basic Information → copy Signing SecretSLACK_SIGNING_SECRET.
  5. Anthropic Console → Manage → Webhooks: /cma-webhook, subscribe session.status_idled + session.status_terminated → copy whsec_…ANTHROPIC_WEBHOOK_SIGNING_KEY. Same workspace as your API key.
  6. bun run dev — server must be up before step 7.
  7. Slack app → Event Subscriptions → On → Request URL /slack/events → Verified ✓ → add bot event app_mentionSave Changes → reinstall if prompted.
  8. In Slack: /invite @your-bot to a channel, then @your-bot hello.

Debugging a silent failure

  • Nothing in the bridge log at all → Slack isn't reaching you. Check curl localhost:4040/api/requests/http (ngrok's request log). No /slack/events POSTs = Event Subscriptions not saved, or Socket Mode is on.
  • [agent] kickoff logged but no reply → ngrok log shows /cma-webhook POSTs? If none: Anthropic workspace mismatch or endpoint not saved. If 401: ANTHROPIC_WEBHOOK_SIGNING_KEY mismatch. If 204 but no Slack post: SLACK_BOT_TOKEN is wrong (check for xapp-) or missing chat:write scope.
  • 400 Invalid agent ID.env.local still has the agent_... placeholder. Re-paste the real ID from bun run setup.
  • not_in_channel from chat.postMessage/invite @your-bot to the channel first.

Production notes

  • Replace ngrok with a real deploy. Nothing else changes.
  • Replace the in-memory seenEventIds Sets with Redis/DB for multi-instance idempotency.
  • For a distributed (multi-workspace) Slack app, swap the static SLACK_BOT_TOKEN for a per-team store keyed on metadata.slack_team; add the Slack OAuth flow.
  • Each @mention starts a fresh CMA session (no memory across turns). For threaded conversations, cache thread_ts → session_id and send follow-ups via sessions.events.send instead of sessions.create.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.