Skip to content
Agent Orchestration
Skill

/slack-channel-monitor

This skill should be used when the user asks to "monitor a Slack channel", "watch Slack for messages", "create a Slack bot that responds to mentions", "set up an OpenHands Slack integration", "trigger OpenHands from Slack", "respond to @openhands in Slack", or "poll Slack

BOOST
From plugin
extensions
17185 skills4 commands
Install
$ npx -y skills add openhands/extensions --skill slack-channel-monitor --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/slack-channel-monitor

Context preview

The summary Claude sees to decide when to auto-load this skill.

This skill should be used when the user asks to "monitor a Slack channel", "watch Slack for messages", "create a Slack bot that responds to mentions", "set up an OpenHands Slack integration", "trigger OpenHands from Slack", "respond to @openhands in Slack", or "poll Slack

SKILL.md

slack-channel-monitor.SKILL.md
name: slack-channel-monitor
description: >
  This skill should be used when the user asks to "monitor a Slack channel",
  "watch Slack for messages", "create a Slack bot that responds to mentions",
  "set up an OpenHands Slack integration", "trigger OpenHands from Slack",
  "respond to @openhands in Slack", or "poll Slack channels for a trigger
  phrase". Guides the user through creating a cron automation that watches up
  to 10 Slack channels and starts an OpenHands conversation whenever a
  configurable trigger phrase is detected.
triggers:
  - /slack-monitor:poll

Slack Channel Monitor

Create a cron automation that polls up to 10 Slack channels every minute. Windows PowerShell equivalents for the setup, packaging, upload, and API-check shell snippets are in `references/windows.md`. When a message containing the **trigger phrase** (default: `@openhands`) is detected it:

1. Adds a 👀 reaction to the triggering message. 2. Opens an OpenHands conversation with the message and recent channel context. 3. Posts a reply in the Slack thread with a link to the conversation.

On every subsequent run:

  • New Slack thread replies are forwarded only when they contain the trigger

phrase, so unrelated conversation in the thread is ignored.

  • When the conversation finishes (or errors), the agent's final response is

posted back to the Slack thread.

  • Completed conversations stay in a short follow-up watch window, allowing

triggered Slack replies to continue the same OpenHands conversation.

> Runs on a local Agent Canvas (`dev:automation` stack) and on OpenHands Cloud > and Enterprise. On Cloud and Enterprise each conversation is started through > the OpenHands API in a sandbox of its own, with the user's own settings, and > the automation keeps its state in the automation service's KV store.

---

Prerequisites

Required secrets

Verify that at least one of the following secrets is set in **OpenHands Settings → Secrets** before proceeding:

| Secret name | Token type | Minimum scopes | |---|---|---| | `SLACK_BOT_TOKEN` | Bot (`xoxb-…`) | `channels:history`, `channels:read`, `reactions:write`, `chat:write` | | `SLACK_USER_TOKEN` | User (`xoxp-…`) | Same as bot, plus `search:read` for multi-channel efficiency |

Check with:

# For bot token:
curl -s https://slack.com/api/auth.test -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print('ok' if d.get('ok') else d.get('error'))"

# For user token:
curl -s https://slack.com/api/auth.test -H "Authorization: Bearer $SLACK_USER_TOKEN" \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print('ok' if d.get('ok') else d.get('error'))"

If neither token is present, inform the user and stop - the automation cannot function without Slack credentials.

Optional secret

| Secret name | Default | Purpose | |---|---|---| | `OPENHANDS_URL` | `http://localhost:8000` | Base URL used to build conversation links posted in Slack (local Agent Canvas only; on OpenHands Cloud and Enterprise the links open the deployment's own Canvas) |

---

Setup Workflow

Follow these steps in order.

Step 1 - Collect channels

Ask the user: *"Which Slack channels should be monitored? You can provide channel names (e.g. `#general`) or IDs (e.g. `C0123456789`)."*

**If the user provides channel names**, resolve them to IDs:

SLACK_TOKEN="${SLACK_BOT_TOKEN:-$SLACK_USER_TOKEN}"
curl -s "https://slack.com/api/conversations.list?types=public_channel,private_channel&limit=200&exclude_archived=true" \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  | python3 -c "
import json, sys
data = json.load(sys.stdin)
if not data.get('ok'):
    print('ERROR:', data.get('error'))
    exit(1)
names = set(n.lstrip('#') for n in ['CHANNEL_NAMES_HERE'.split(',')])
for ch in data.get('channels', []):
    if ch['name'] in names:
        print(f\"{ch['name']} → {ch['id']}\")
"

Replace `CHANNEL_NAMES_HERE` with the comma-separated names the user provided.

**If `conversations.list` returns `missing_scope` or `not_authed`:** Inform the user: *"The token doesn't have permission to list channels. Please provide the channel IDs directly (right-click a channel in Slack → Copy link - the last path segment starting with `C` is the ID)."*

**If the bot token lacks `channels:read`** for private channels, the user can either invite the bot first (`/invite @botname`) or switch to a user token.

Collect up to 10 channel IDs. Record them as a Python list literal, e.g.:

["C0123456789", "C9876543210"]

Step 2 - Collect trigger phrase

Ask the user: *"What trigger phrase should OpenHands respond to? (Press Enter to use the default: `@openhands`)"*

Accepted values: any non-empty string unlikely to appear accidentally, e.g. `@openhands`, `jazz hands`, `take-me-to-funky-town`.

Step 3 - Generate the automation script

Read `scripts/main.py` from this skill's directory and **copy it verbatim**. Apply exactly three constant substitutions near the top of the file:

> **Do not reimplement, simplify, or hand-write a replacement script.** > The template already contains the correct secret-loading, state-path, > conversation-creation, and context-forwarding logic. Only the three > configuration constants below should change unless syntax validation fails.

| Placeholder | Replace with | |---|---| | `TRIGGER_PHRASE = "@openhands"` | `TRIGGER_PHRASE = "{user_phrase}"` | | `CHANNEL_IDS: list[str] = []` | `CHANNEL_IDS: list[str] = {channel_id_list}` | | `DEFAULT_OPENHANDS_URL = "http://localhost:8000"` | `DEFAULT_OPENHANDS_URL = "{url}"` (keep default if user has no preference) |

Write the customised script to a temporary directory:

mkdir -p /tmp/slack-monitor-build
# copy scripts/main.py to /tmp/slack-monitor-build/main.py
# then replace only the three constants above

Validate syntax before packaging:

python3 -m py_compile /tmp/slack-monitor-build/main.py && echo "Syntax OK"
``
Read more
Ships withextensions

This repository is the public extensions registry for OpenHands. It contains reusable, shareable skills, plugins, and Agent Canvas Apps that customize agent behavior and interfaces. Skills overview docs: SDK skill guide:

Get the whole plugin

Other skills on extensions.