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 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.
What this skill does
# Slack Channel Monitor
Create a cron automation that polls up to 10 Slack channels every minute.
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:
- Replies in the thread are forwarded to the running conversation.
- When the conversation finishes (or errors), the agent's final response is
posted back to the Slack thread.
> **Local mode only.** This automation targets the local OpenHands setup
> (`dev:automation` stack). A cloud/webhook-based variant is out of scope here.
---
## 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:
```bash
# 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 |
---
## 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:
```bash
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.:
```python
["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:
```bash
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:
```bash
python3 -m py_compile /tmp/slack-monitor-build/main.py && echo "Syntax OK"
```
Then run a quick integrity check to confirm the template structure is still
present and only the configuration block was customised:
```bash
grep -n 'TRIGGER_PHRASE = "' /tmp/slack-monitor-build/main.py
grep -n 'CHANNEL_IDS: list\[str\] =' /tmp/slack-monitor-build/main.py
grep -n 'DEFAULT_OPENHANDS_URL = "' /tmp/slack-monitor-build/main.py
grep -n 'def get_secret' /tmp/slack-monitor-build/main.py
grep -n 'def _state_file_path' /tmp/slack-monitor-build/main.py
grep -n 'def create_conversation' /tmp/slack-monitor-build/main.py
```
If any of those checks fail, stop and re-copy the template instead of trying to
repair a hand-written variant.
### Step 4 - Package and upload
Determine the Automation backend URL and auth from the `<RUNTIME_SERVICES>`
block in your system context:
- Use the **Automation backend** `url_from_agent` as `OPENHANDS_HOST`
- Auth: `X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY`
If no Automation backend is listed in `<RUNTIME_SERVICES>`, stop and tell
the user to start the full automation stack.
```bash
tar -czf /tmp/slack-monitor.tar.gz -C /tmp/slack-monitor-build .
# OPENHANDS_HOST: read from <RUNTIME_SERVICES> Automation backend url_from_agent
OPENHANDS_HOST="<automation-url-from-runtime-services>"
TARBALL_PATH=$(curl -s -X POST \
"${OPENHANDS_HOST}/api/automation/v1/uploads?name=slack-channel-monitor" \
-H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
-H "Content-Type: application/gzip" \
--data-binary @/tmp/slack-monitor.tar.gz \
| python3 -c "import json,sys; print(json.load(sys.stdin)['tarball_path'])")
echo "Uploaded: $TARBALL_PATH"
```
If the upload fails with a size error, the tarball must be under 1 MB.
`main.py` is under 15 KB so this should never trigger.
### Step 5 - Create the automation
```bash
curl -s -X POST "${OPENHANDS_HOST}/api/automation/v1" \
-H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Slack Channel Monitor\",
\"trigger\": {\"type\": \"cron\", \"schedule\": \"* * * * *\"},
\"tarball_path\": \"$TARBALL_PATH\",
\"entrypoint\": \"python3 main.py\",
\"timeout\": 55
}" | python3 -m json.tool
```
A 55-second timeout keeps runs well within the 60-second cron window.
Record the returned `id` - share it with the user as confirmation.
### Step 6 - Confirm
Tell the user:
> โ
**Slack Channel Monitor** is running!
>
> - Automation ID: `{id}`
> - Channels: `{channel list}`
> - Trigger phrase: `{phrase}`
> - Polling every minute via cron `* * * * *`
> - State file: `~/.openhands/workspaces/automation-state/slack_poller_{id}.json`
>
> Send a message containing `{phrase}` in any monitored channel to test it.
> The bot will react with ๐ and reply with a link to the new conversation.
---
## Runtime Behaviour (per poll)
Each cron run executes `main.py`, which runs **10 polling iterations** (every
5 seconds) within the 55-second timeout window. Each iteration:
1. **Loads state** from the JSON file (see `references/state-schema.md`).
2. **Resolves the Slack token** - checks `SLACK_USER_TOKEN` then `SLACK_BOT_TOKEN`.
3. **Fetches new messages:**
- User tokenRelated in Productivity
gitea-workflow
IncludedOrchestrate agile development workflows for Gitea repositories using the tea CLI. Use when working with Gitea-hosted repos and asking to 'run the workflow', 'continue working', 'what's next', 'complete the task cycle', 'start my day', 'end the sprint', 'implement the next task', or wanting guided step-by-step development assistance. Keywords: workflow, orchestrate, agile, task cycle, sprint, daily, implement, review, PR, standup, retrospective, gitea, tea.
microsoft-graph-gateway
IncludedRoute Microsoft Graph work in this workspace. Use when users want to read or write Outlook mail, calendar events, contacts, OneDrive or SharePoint files, Teams, Planner, To Do, users, groups, directory data, or arbitrary Microsoft Graph endpoints from VS Code. Prefer WorkIQ for common read scenarios. Use Microsoft Graph for write actions and gap-read scenarios that need exact Graph properties, filters, permissions, or endpoints.
copilotkit
IncludedUse when building with CopilotKit โ setup, development, integrations, debugging, upgrading, or contributing. Routes to the appropriate specialized skill based on the task.
wordly-wisdom
IncludedProvides calibrated decision analysis using Charlie Munger-style multiple mental models, inversion, incentive mapping, circle-of-competence checks, misjudgment audits, second-order effects, and forecast updates. Use when the user asks for an oracle take, a hard call, a decision memo, a premortem, an outside view, a red-team, a sanity-check, what am I missing, think this through, or wants a strategy, hire, investment, plan, product, partnership, or major life choice analysed. Avoid for simple factual lookups or time-sensitive legal, medical, or market questions without fresh evidence.
swain-session
IncludedSession management and project status dashboard. Owns the full session lifecycle (start/work/close/resume), focus lane, bookmarks, worktree detection, and tab naming. Also serves as the project status dashboard โ shows active epics, progress, actionable next steps, blocked items, tasks, GitHub issues, and recommendations. Worktree creation is deferred to swain-do task dispatch (SPEC-195). Triggers on: 'session', 'status', 'what's next', 'dashboard', 'overview', 'where are we', 'what should I work on', 'show me priorities', 'bookmark', 'focus on', 'session info'.
gandi
IncludedComprehensive Gandi domain registrar integration for domain and DNS management. Register and manage domains, create/update/delete DNS records (A, AAAA, CNAME, MX, TXT, SRV, and more), configure email forwarding and aliases, check SSL certificate status, create DNS snapshots for safe rollback, bulk update zone files, and monitor domain expiration. Supports multi-domain management, zone file import/export, and automated DNS backups. Includes both read-only and destructive operations with safety controls.