# @kentcdodds/slack ## Intent Provide reusable, headless Slack helpers that let Kody read conversations the authorizing user can access and send explicitly confirmed messages as that user, never as a bot. ## What it does - List conversations (public/private channels, DMs, group DMs) - List workspace users (resolve message authors) - Read conversation history and thread replies - Preview (`dryRun`) or send (`confirm: true`) a message as the authorizing user - Smoke-check that the saved token is a **user** token, not a bot token ## Prerequisites / setup Create a Slack app for the target workspace and save a Kody OAuth integration named **`slack`** using Slack's user-only OAuth flow. 1. Redirect URL: `https://kody.codes/connect/oauth` 2. Authorize URL: `https://slack.com/oauth/v2_user/authorize` 3. Token URL: `https://slack.com/api/oauth.v2.user.access` 4. API host: `slack.com` 5. Flow: confidential; scope separator: comma 6. Required user-token scopes: `chat:write`, `channels:history`, `channels:read`, `groups:history`, `groups:read`, `im:history`, `im:read`, `mpim:history`, `mpim:read`, `users:read` 7. Workspace admins may need to approve the app. Private channels and DMs are limited to conversations the authorizing user can access. 8. Agents: see [`AGENTS.md`](./AGENTS.md) for import paths and smoke checks. ### OAuth scope errors Use only the User Token Scopes listed above (they match [Slack's published scope catalog](https://docs.slack.dev/reference/scopes/)). If Slack returns `invalid_scope` (sometimes "incorrect scope"), the authorize URL's `scopes=` includes a name Slack does not recognize — for example `projects:read` is not a Slack OAuth scope. Strip unknown scopes and retry. ## Done when - OAuth integration `slack` is connected with a user token (not a bot token) - Smoke test passes (`user_id` present, no `bot_id`) - Reads work for conversations the user can access - Sends require `confirm: true`; dry runs never call Slack