From fxl
Scan Slack for unanswered DMs, @mentions, and replies to your threads since the last scan. Drafts replies and asks permission before sending each one.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fxl:slack-monitor [setup | review | (no args to scan)][setup | review | (no args to scan)]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Scans Slack for messages that need your attention since
Scans Slack for messages that need your attention since
the last scan, drafts replies, and asks your approval
before sending anything. State file I/O uses
scripts/state.js (Node.js built-ins only) for atomic
reads and writes; Slack communication uses MCP
integrations.
The skill's base directory is provided by Claude Code
in the Base directory for this skill: header when the
skill loads. Use that path directly as
SKILL_SCRIPTS_DIR.
SKILL.md — core workflow (this file)
README.md — user-facing documentation
agents/
monitor-prompt.md — isolated monitor agent prompt
workflow/ — on-demand workflow details:
SETUP.md — first-run setup wizard
GUARDRAILS.md — safety limits and rules
HANDLE.md — message handling + learning
REVIEW.md — review modes + formatting
DM-REVIEW.md — DM review reply processing
FORMATS.md — state file schemas
templates/ — default files for first run
Token optimization: Only this file (SKILL.md) is
loaded on every cycle. The workflow/ files are
Read on demand — only when the specific feature is
needed (e.g., HANDLE.md only when actionable messages
are found). On idle cycles with no new messages, none
of the workflow files are read.
All configuration lives in ${CLAUDE_PLUGIN_DATA}/CLAUDE.md
(YAML frontmatter). Read the frontmatter only (not
the body) at the start of each cycle.
---
userId: UXXXXXXXXXX
workspaceDomain: myteam.slack.com
channels:
groups:
autoReply: true
autoReplyConfidence: 90
draftMode: false
scanOnly: false
reviewMode: remote-control
interval: 15
activeInterval: 1
offhoursInterval:
timezone: America/New_York
startHour: 7
endHour: 16
days: 1-5
maxAutoReply: 5
maxDmNotify: 10
maxSends: 15
maxQueue: 25
---
Required: userId, workspaceDomain
scanOnly: true disables all outbound messages during the monitor
cycle — no auto-replies, no DMs, no drafts. Items are queued to
pending_review.json only. Process them with /slack-monitor review.
Combine with --allowedTools (see README) for the strongest injection
defense: even a successful injection cannot send messages if the send
tools are not available in the session.
reviewMode options:
remote-control (default) — queue items non-blocking; user
processes with /slack-monitor review (works locally or via
/remote-control)direct — blocking inline review at the terminal each cycleslack (legacy) — DM yourself in Slack; unreliable because
Slack does not notify you of your own messagesThe setup wizard (and migration check) runs when
${CLAUDE_PLUGIN_DATA}/CLAUDE.md does not exist, or
when the user passes setup as an argument:
/slack-monitor setup.
When triggered, Read
$SKILL_SCRIPTS_DIR/workflow/SETUP.md and follow the wizard.
All persistent state lives at ${CLAUDE_PLUGIN_DATA}/.
This path is provided by the Claude plugin framework
(cross-platform).
CLAUDE.md — config (frontmatter) + knowledge (body)last_scan — ISO 8601 UTC timestamppending_review.json — messages awaiting reviewsearch_cache.json — thread read cachesaved_messages.md — log of sent repliespeople/ — per-person profilesFor file format details, Read
$SKILL_SCRIPTS_DIR/workflow/FORMATS.md when needed.
Parse $ARGUMENTS before doing anything else:
| Argument | Action |
|---|---|
setup | Read workflow/SETUP.md and run wizard |
review | Process pending review queue (see below) |
stop | Cancel scheduled cron, confirm to user |
| (none) | Run monitor cycle (see below) |
review argument)Processes all items in pending_review.json interactively.
Works with /remote-control or directly at the terminal.
Remote-control detection: Check whether the session context
contains a Base directory for this skill: ... remote-control ...
header. If yes, note it in the output so the user knows responses
will be routed via remote-control.
Run:
node "$SKILL_SCRIPTS_DIR/scripts/state.js" pending-list \
--data "$CLAUDE_PLUGIN_DATA"
Parse the JSON output. If the array is empty, report "No pending items." and stop.
Read $SKILL_SCRIPTS_DIR/workflow/REVIEW.md for formatting rules.
For each item in the queue (oldest first):
a. Display the message context:
[N of M] From: {from} · {channel} · {time}
> {message_text}
{if thread_context: Thread: > {thread_context}}
1. Concise ({confidence}%) {if recommended: ★}
> {concise draft}
2. Detailed ({confidence}%) {if recommended: ★}
> {detailed draft}
3. Casual ({confidence}%) {if recommended: ★}
> {casual draft}
b. Use AskUserQuestion with choices:
1 — Send concise2 — Send detailed3 — Send casualskip — Don't replycustom — Type a custom replyc. Execute the choice (per REVIEW.md formatting/threading rules). Remove the item from the queue:
node "$SKILL_SCRIPTS_DIR/scripts/state.js" pending-remove "<item.id>" \
--data "$CLAUDE_PLUGIN_DATA"
Append to saved_messages.md.
After all items, report: N sent, N skipped, queue now empty.
In parallel, Read:
${CLAUDE_PLUGIN_DATA}/CLAUDE.md — parse YAML frontmatter only.
If missing, run setup (see above).${CLAUDE_PLUGIN_DATA}/last_scan — ISO 8601 timestamp.
If missing, default to 15 minutes ago.Compute current_time (current UTC ISO 8601 timestamp).
Read $SKILL_SCRIPTS_DIR/agents/monitor-prompt.md.
Resolve timezone: if the timezone config field is empty or missing,
run:
node "$SKILL_SCRIPTS_DIR/scripts/detect-timezone.js"
Use the output (e.g. America/Los_Angeles) as the resolved timezone.
Otherwise use the configured value as-is.
Dispatch Agent with model: haiku and the monitor prompt.
Pass the following as part of the prompt text:
SKILL_SCRIPTS_DIR=<resolved path>CLAUDE_PLUGIN_DATA=<resolved path>timezone
replaced by the resolved value from step 4)last_scan=<timestamp>current_time=<timestamp>Receive the MONITOR_SUMMARY block from the agent.
State writes (last_scan, search_cache.json) are handled by the
monitor agent (see agents/monitor-prompt.md Step 5).
Run:
node "$SKILL_SCRIPTS_DIR/scripts/state.js" checkpoint-clear \
--data "$CLAUDE_PLUGIN_DATA"
(Clears the checkpoint in the parent context where plugin data dir permissions are established.)
Schedule next scan using CronList, CronDelete, CronCreate:
local_hour and local_dow from current_time using
the resolved timezone from step 4.local_hour >= endHour or
local_hour < startHour or local_dow outside days):
offhoursInterval is set → recurring cron at that intervalstartHour:03 on next active dayactive: true in MONITOR_SUMMARY → use activeIntervalintervalCronList to find any existing slack-monitor cron.CronDelete it, then
CronCreate with the correct schedule.CronCreate with the correct schedule.Report to user:
messages_found: N (DMs: N / mentions: N / threads: N)auto_sent: Nqueued: N this cyclepending_queue_depth: N total awaiting reviewactive: true|false<time>pending_queue_depth > 0: append
→ Run /slack-monitor review to process.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub frankledo/claude-skills --plugin agents-view-tools