Smart Discord thread archiving. Use when: (1) running periodic thread cleanup, (2) evaluating whether Discord threads should be archived. Agent reads thread messages, judges conversation status, and archives concluded threads.
Scan active Discord threads, collect trustworthy participation facts, classify each thread, archive resolved threads, and report every decision.
guildId — Guild to scanchannelId — Parent channel to scanlogChannel — Report channeloperationalThreadPrefixes — Optional comma-separated prefixes; default 🤖 mode — apply (default) or dry-runCall thread-list exactly once with both guildId and channelId:
message(action="thread-list", channel="discord", guildId="<guildId>", channelId="<channelId>")
Never scan the whole guild. If empty, deliver the no-thread report and stop.
Read references/judgment-guide.md in full before evaluating threads.
Skip pinned threads and report skip/pinned.
Read the latest five messages exactly once:
message(action="read", channel="discord", target="channel:<thread_id>", limit=5)
Determine the latest message by timestamp or numeric Discord ID; provider array order is not a facts contract.
If the latest message is a bot question, return keep/bot_question_unanswered immediately. Do not paginate or call the classifier.
If the five-message window contains a human, participation collection is complete.
If all five are bots, read the latest 20 messages exactly once with no cursor. Never repeat this no-cursor window.
Inspect the thread starter and its referenced_message. A bot-authored type-21 starter with referenced_message.author.bot=false is human-initiated. Record humanInitiated=true and hadHistoricalHumanParticipation=true; include the referenced human message in normalized facts when its ID and content are available.
If no human is known yet, paginate:
seenIds from collected message IDs.oldestId to the numerically smallest collected ID.limit=20 with before=<oldestId>.seenIds and add new IDs.An empty raw page or raw page shorter than 20 reaches the start. A repeated/unchanged cursor, a page with no new IDs before reaching the start, a missing ID, or an API failure makes collection incomplete. Stop and set historyScanComplete=false.
Never stop at an arbitrary page count and never issue the same cursor twice.
Deduplicate by ID and sort oldest to newest by numeric Discord ID. Serialize JSON with a structured writer, not hand-escaped shell text.
{
"name": "thread name",
"pinned": false,
"lastMessageAgeMinutes": 123,
"messageOrder": "oldest_to_newest",
"historyScanComplete": true,
"humanInitiated": true,
"hadHistoricalHumanParticipation": true,
"messages": [
{"messageId": "123", "content": "...", "isBot": false},
{"messageId": "124", "content": "...", "isBot": true}
],
"operationalThreadPrefixes": ["🤖 "]
}
Set historyScanComplete=true only after finding historical human participation or reaching the thread start. Recent-window absence of human never proves bot-only history.
python3 <skill_dir>/scripts/classify-thread.py < /tmp/thread-facts-<thread_id>.json
Call the classifier at most once per thread. Never override a non-uncertain result. Treat facts_invalid and facts_incomplete as keep decisions. Keep a latest unanswered human request or bot question, including operational threads. A new human request invalidates earlier closure; a later answer still follows the normal idle gate. A prefixed thread is operational only when complete facts prove no historical human participation.
bash <skill_dir>/scripts/archive-thread.sh <thread_id>
Dry-run:
bash <skill_dir>/scripts/archive-thread.sh --dry-run <thread_id>
Report non-2xx responses as archive_failed_<status>.
Strict icons:
✅ archived⏸️ kept⏭️ pinned/skipped🧪 would archive in dry-run🗂️ Thread 归档 · HH:MM
✅ thread名 — 归档:reason_code,一句话原因
⏸️ thread名 — 保留:reason_code,一句话原因
⏭️ thread名 — 跳过(pinned)
归档 X / 保留 Y / 跳过 Z
Dry-run title: 🗂️ Thread 归档 dry-run · HH:MM. If empty:
🗂️ Thread 归档 · HH:MM
⏸️ 无 Thread
Every listed thread appears exactly once.
message(action="send", channel="discord", target="channel:<logChannel>")
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer