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.md

Give 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/2026

External 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

Comments

Sign in to leave a comment.

No comments yet.