slack-skillv1.0.0latest
by ryan321
Send messages, read channel history, search conversations, reply in threads, manage reactions, look up users, and upload files in Slack. Uses the official @slack/web-api SDK with bot tokens. Search requires a separate user token.
Install
https://clawskills.io/api/skills/slack-skill/releases/1.0.0/SKILL.mdGive this URL to your OpenClaw agent to install.
Agent prompt
Fetch the skill from https://clawskills.io/api/skills/slack-skill/releases/1.0.0/SKILL.md and follow its Quick Start section to install, configure, and verify the slack-skill skill (v1.0.0).
Or copy this full prompt to give your agent.
SKILL.md
---
name: slack-skill
version: 1.0.0
url: https://clawskills.io/api/skills/slack-skill/releases/1.0.0/SKILL.md
artifact_sha256: 5cc85c482e5d8f7b70a2c9eb8b1ca49bad62d4ea1929dafb9686a87a5ffc5f54
signature: RLaYUWEF4Eq6/nOCmsk2qxvv5NDcEFx1W36MMqtmRVUVVpkMv4YAfM2Lse/IdQ5fOQAPGqaN7zFikg4TQDoGAg==
key_id: 625b196966442b38cf1c7188ba15fa81
verify: https://clawskills.io/docs/verification
---
# Slack Skill
Send messages, read channels, search conversations, and manage a Slack workspace using the official `@slack/web-api` Node.js SDK.
---
## Overview
- **What it does:**
Lets an AI agent interact with Slack — send messages, read channel history, search messages, list channels and users, upload files, reply in threads, and manage reactions via the `@slack/web-api` SDK.
- **When to use it:**
When the user wants to interact with Slack: posting updates to channels, reading conversation history, searching for information across the workspace, or managing channels.
- **Requirements:**
- OS: macOS / Linux / Windows
- Runtime: Node.js 18+
- Accounts: Slack workspace with a Slack app configured (Bot Token with appropriate scopes)
---
## Quick start
### Install
```bash
npm install @slack/web-api@7.14.0
```
### Configure
Add your credentials in the **OpenClaw runtime environment** (Control UI env editor if available, process env, or `.env`):
```bash
# Required — set in OpenClaw runtime environment:
# SLACK_BOT_TOKEN — Bot User OAuth Token (starts with xoxb-)
#
# Optional — set in OpenClaw runtime environment:
# SLACK_USER_TOKEN — User OAuth Token (starts with xoxp-), required for search
#
# Get your tokens from: https://api.slack.com/apps > Your App > OAuth & Permissions
```
### Verify
```bash
node -e "const{WebClient}=require('@slack/web-api');new WebClient(process.env.SLACK_BOT_TOKEN).auth.test().then(r=>console.log(JSON.stringify(r,null,2)))"
```
**Expected result:**
Prints JSON with your bot's `user_id`, `team_id`, `team`, and `bot_id`, confirming authentication works.
---
## Core tasks
### Send a message to a channel
```text
Send a message to the #general channel saying "Hello from my agent!"
```
### Read channel history
```text
Show me the last 10 messages from the #engineering channel.
```
### Search messages
```text
Search Slack for messages mentioning "deployment issue" and show the top results.
```
*Requires a user token (`xoxp-`) with `search:read` scope. Bot tokens cannot search.*
### List channels
```text
List all public channels in the workspace with their names and topics.
```
### Reply in a thread
```text
Reply in the thread on message timestamp 1234567890.123456 in #general saying "Thanks for the update!"
```
### Add a reaction to a message
```text
Add a thumbsup reaction to the latest message in #announcements.
```
### Look up a user by email
```text
Look up the Slack user with email address alice@example.com and show their name and ID.
```
### Upload a file to a channel
```text
Upload the file ./report.csv to the #reports channel.
```
### Delete a message
```text
Delete the message with timestamp 1234567890.123456 in #general.
```
---
## SDK usage reference
This skill uses the `@slack/web-api` npm package (no MCP server). The agent must write Node.js code to interact with the Slack API. Below is the complete reference for constructing the client and calling each endpoint.
### Client initialization
```javascript
const { WebClient } = require('@slack/web-api');
// Bot client — for most operations
const bot = new WebClient(process.env.SLACK_BOT_TOKEN);
// User client — required for search.messages (bot tokens can't search)
const user = process.env.SLACK_USER_TOKEN
? new WebClient(process.env.SLACK_USER_TOKEN)
: null;
```
### Verify authentication
```javascript
const result = await bot.auth.test();
// result => { ok: true, url: 'https://team.slack.com/', team: 'Team Name', user: 'bot-name', team_id: 'T...', user_id: 'U...', bot_id: 'B...' }
```
### Send a message
```javascript
const result = await bot.chat.postMessage({
channel: '#general', // channel name or ID (C...)
text: 'Hello from my agent!',
});
// result => { ok: true, channel: 'C...', ts: '1234567890.123456', message: { text, ts, user, ... } }
```
With rich formatting (Block Kit):
```javascript
const result = await bot.chat.postMessage({
channel: '#general',
text: 'Fallback text for notifications',
blocks: [
{ type: 'section', text: { type: 'mrkdwn', text: '*Bold* and _italic_' } },
],
});
```
### Reply in a thread
```javascript
const result = await bot.chat.postMessage({
channel: '#general',
text: 'Thread reply text',
thread_ts: '1234567890.123456', // timestamp of the parent message
});
```
### Delete a message
```javascript
const result = await bot.chat.delete({
channel: 'C...', // channel ID
ts: '1234567890.123456', // message timestamp
});
// result => { ok: true, channel: 'C...', ts: '1234567890.123456' }
```
### Read channel history
```javascript
const result = await bot.conversations.history({
channel: 'C...', // channel ID (use conversations.list to find it)
limit: 10,
});
// result.messages => [{ type: 'message', user: 'U...', text: '...', ts: '...', reactions: [...] }, ...]
```
To get a channel ID from a name:
```javascript
const channels = await bot.conversations.list({ types: 'public_channel', limit: 200 });
const channel = channels.channels.find(c => c.name === 'general');
const channelId = channel.id; // 'C...'
```
### Read thread replies
```javascript
const result = await bot.conversations.replies({
channel: 'C...',
ts: '1234567890.123456', // parent message timestamp
limit: 20,
});
// result.messages => [parent_message, reply1, reply2, ...]
```
### List channels
```javascript
const result = await bot.conversations.list({
types: 'public_channel',
limit: 100,
exclude_archived: true,
});
// result.channels => [{ id: 'C...', name: 'general', topic: { value: '...' }, purpose: { value: '...' }, num_members: 42 }, ...]
```
For pagination:
```javascript
let cursor;
const allChannels = [];
do {
const result = await bot.conversations.list({
types: 'public_channel',
limit: 200,
cursor,
});
allChannels.push(...result.channels);
cursor = result.response_metadata?.next_cursor;
} while (cursor);
```
### Search messages (requires user token)
```javascript
// IMPORTANT: search requires a user token (xoxp-), not a bot token
if (!user) throw new Error('SLACK_USER_TOKEN is required for search');
const result = await user.search.messages({
query: 'deployment issue',
sort: 'timestamp',
sort_dir: 'desc',
count: 10,
});
// result.messages.matches => [{ text, username, channel: { name }, ts, permalink }, ...]
```
### Add a reaction
```javascript
await bot.reactions.add({
channel: 'C...',
name: 'thumbsup', // emoji name without colons
timestamp: '1234567890.123456',
});
```
### Remove a reaction
```javascript
await bot.reactions.remove({
channel: 'C...',
name: 'thumbsup',
timestamp: '1234567890.123456',
});
```
### Look up a user by email
```javascript
const result = await bot.users.lookupByEmail({
email: 'alice@example.com',
});
// result.user => { id: 'U...', name: 'alice', real_name: 'Alice Smith', profile: { email, image_72, ... } }
```
### Get user info
```javascript
const result = await bot.users.info({
user: 'U...', // user ID
});
// result.user => { id, name, real_name, profile, is_admin, is_bot, tz, ... }
```
### List workspace users
```javascript
const result = await bot.users.list({ limit: 100 });
// result.members => [{ id, name, real_name, profile, is_bot, deleted, ... }, ...]
```
### Upload a file
```javascript
const fs = require('fs');
const result = await bot.filesUploadV2({
channel_id: 'C...',
file: fs.createReadStream('./report.csv'),
filename: 'report.csv',
title: 'Monthly Report',
initial_comment: 'Here is the latest report.',
});
```
### Get channel info
```javascript
const result = await bot.conversations.info({
channel: 'C...',
});
// result.channel => { id, name, topic, purpose, num_members, is_archived, ... }
```
### Resolving channel names to IDs
Many Slack API methods require channel IDs (e.g., `C0123456789`), not names. Use this pattern:
```javascript
async function resolveChannel(bot, name) {
const cleanName = name.replace(/^#/, '');
const result = await bot.conversations.list({ types: 'public_channel', limit: 200 });
const ch = result.channels.find(c => c.name === cleanName);
if (!ch) throw new Error(`Channel #${cleanName} not found`);
return ch.id;
}
```
### Scopes reference
| Scope | Required for |
|---|---|
| `channels:read` | List channels, get channel info |
| `channels:history` | Read messages in public channels |
| `groups:read` | List private channels |
| `groups:history` | Read messages in private channels |
| `chat:write` | Send messages, reply in threads |
| `chat:write.public` | Post to channels the bot hasn't joined |
| `reactions:write` | Add/remove reactions |
| `reactions:read` | List reactions on messages |
| `users:read` | List users, get user info |
| `users:read.email` | Look up users by email |
| `files:write` | Upload files |
| `files:read` | List and access file metadata |
| `search:read` | Search messages (user token only) |
### Error handling pattern
```javascript
try {
const result = await bot.chat.postMessage({ channel: '#general', text: 'Hello!' });
console.log('Sent:', result.ts);
} catch (err) {
if (err.data?.error === 'channel_not_found') {
console.error('Channel not found — check the name or invite the bot');
} else if (err.data?.error === 'not_in_channel') {
console.error('Bot is not in this channel — use /invite @bot-name');
} else if (err.data?.error === 'missing_scope') {
console.error('Missing scope:', err.data?.needed);
} else if (err.code === 429) {
const retryAfter = err.headers?.['retry-after'] || 30;
console.error(`Rate limited — retry after ${retryAfter}s`);
} else {
console.error('Slack API error:', err.data?.error || err.message);
}
}
```
---
## Environment variable contract
| Variable | Purpose | Required | Where to set |
|---|---|---|---|
| `SLACK_BOT_TOKEN` | Bot User OAuth Token (starts with `xoxb-`) | Yes | OpenClaw runtime environment |
| `SLACK_USER_TOKEN` | User OAuth Token (starts with `xoxp-`), for search | Optional | OpenClaw runtime environment |
| `SLACK_DEFAULT_CHANNEL` | Default channel for messages | Optional | `env` block in `openclaw.json` |
Credentials set in the OpenClaw runtime environment are automatically available to scripts executed by the agent.
---
## Configuration
* **Secrets / credentials required:**
* `SLACK_BOT_TOKEN` — Bot User OAuth Token (starts with `xoxb-`). Required for all bot operations.
* `SLACK_USER_TOKEN` — User OAuth Token (starts with `xoxp-`). Optional; required only for `search.messages` and other user-scoped methods.
* **How to obtain credentials:**
1. Go to https://api.slack.com/apps and click "Create New App" > "From scratch"
2. Name your app and select a workspace
3. Go to "OAuth & Permissions" in the sidebar
4. Under "Bot Token Scopes", add scopes (see scopes reference in SDK usage section)
5. Click "Install to Workspace" and authorize
6. Copy the "Bot User OAuth Token" (`xoxb-...`)
7. (Optional) Under "User Token Scopes", add `search:read` for message search. Copy the "User OAuth Token" (`xoxp-...`).
* **Config files used:**
* No config files — this is an SDK-only skill. Credentials are read from environment variables at runtime.
* **How to reset / re-auth:**
* Go to https://api.slack.com/apps > Your App > "Install App" and click "Reinstall to Workspace"
* Update your environment variables with the new token
* Re-run the Verify command to confirm
---
## Security & Guardrails
### Secrets handling
* Never paste bot tokens or user tokens into chat.
* Always use environment variables (`SLACK_BOT_TOKEN`, `SLACK_USER_TOKEN`).
* If authentication fails with `invalid_auth` or `token_revoked`, recommend the user regenerate their token immediately.
* Never pass tokens as command-line arguments (visible in `ps` output).
### Confirmations (before risky actions)
* Always confirm with the user before:
* Sending a message to a channel (visible to all channel members)
* Posting in a thread (notifies thread participants)
* Uploading files (shared with channel members)
* Deleting messages (`chat.delete`)
* Inviting/removing users from channels
* Show the exact message text and target channel before sending.
### Rate limits
* Slack enforces rate limits per method (typically 1 request per second for posting, higher for reads).
* Do not retry aggressively on `429` responses — read the `Retry-After` header and wait.
* Prefer batched reads (e.g., `conversations.history` with `limit`) over repeated single-message fetches.
* The `@slack/web-api` SDK has built-in automatic retries for rate limits when `rejectRateLimitedCalls` is not set.
### Data minimization
* Return summaries by default — do not dump full API responses unless the user asks.
* Avoid logging or echoing tokens in output.
* When reading history, use `limit: 10` unless the user requests more.
* Strip unnecessary metadata (internal IDs, bot profiles) from responses before presenting.
### Permissions / scopes
* **Minimum bot scopes:** `channels:read`, `channels:history`, `chat:write`
* **Recommended bot scopes:** add `reactions:write`, `users:read`, `users:read.email`, `files:write` as needed
* **Optional user scopes:** `search:read` (for message search)
* **Least privilege:** Start with `channels:read` and `chat:write`. Add more scopes only as needed for specific tasks.
### Network access
* **Domains used:**
* `slack.com` — all Slack Web API requests
* `files.slack.com` — file uploads and downloads
### Local storage
* **Writes to:** Nothing — this skill does not write to the filesystem beyond the installed npm package in `node_modules/`.
* **Does not access:** SSH keys, browser profiles, keychains, password stores, or any local files.
### Revoke / rotate
* Revoke tokens: https://api.slack.com/apps > Your App > "OAuth & Permissions" > "Revoke All OAuth Tokens"
* Rotate tokens: Reinstall the app to your workspace to generate new tokens; update environment variables; re-run the Verify command.
---
## Troubleshooting
* **Error:** `invalid_auth`
* Fix: Check that `SLACK_BOT_TOKEN` is set and starts with `xoxb-`. Regenerate the token if needed.
* **Error:** `channel_not_found`
* Fix: The bot must be invited to the channel first. Use `/invite @your-bot-name` in the channel, or use the channel ID instead of the channel name.
* **Error:** `not_in_channel`
* Fix: The bot needs to join the channel before reading history. Invite it with `/invite @your-bot-name` or add the `chat:write.public` scope to post without joining.
* **Error:** `missing_scope`
* Fix: The bot token lacks the required scope. Go to your app's "OAuth & Permissions" page, add the missing scope, and reinstall the app.
* **Error:** `ratelimited` (HTTP 429)
* Fix: Wait for the duration specified in the `Retry-After` header. The SDK handles this automatically by default.
* **Problem:** "Search returns nothing"
* Fix: `search.messages` requires a **user token** (`xoxp-`), not a bot token. Set `SLACK_USER_TOKEN` and initialize a separate `WebClient` with it.
---
## Release notes
* v1.0.0:
* Initial release
* Send messages, read history, search, list channels, thread replies, reactions, user lookup, file uploads, delete messages
* Uses `@slack/web-api@7.14.0`
---
## Links
* Package: https://www.npmjs.com/package/@slack/web-api
* Package repo: https://github.com/slackapi/node-slack-sdk
* API methods: https://api.slack.com/methods
* Scopes reference: https://api.slack.com/scopes
* Developer portal: https://api.slack.com/apps
* Block Kit Builder: https://app.slack.com/block-kit-builder
---
## Publisher
* **Publisher:** @Agentopolis
Security Guardrails
secrets/credential handlingconfirmation before risky actionsrate limitingdata minimizationpermissions/scopesnetwork access disclosurelocal storage disclosuretoken revocation/rotation
Releases
1.0.0listedcurrent
2/15/2026External Interfaces
Secrets & Environment Variables
SLACK_BOT_TOKENSLACK_USER_TOKENSLACK_DEFAULT_CHANNEL
Packages
npm install @slack/web-api@7.14.0
Languages
javascript
Network Domains
api.slack.comteam.slack.comwww.npmjs.comgithub.comapp.slack.comslack.comfiles.slack.com
File System Access
./report.csv
Files Included (1)
SKILL.md15.9 KB