Skip to main content

baoyu-wechat-summary

Summarizes WeChat group chat highlights into a structured digest using the local wx-cli binary (https://github.com/jackwener/wx-cli). Generates a normal digest by default; a roast (毒舌) version is opt-in. Maintains per-group history (history.json + history-digests.jsonl), per-user profiles, and per-group fact memory (memory.md) across runs, with privacy guardrails baked in. Use when the user asks to "总结群聊", "群聊精华", "群聊摘要", "summarize group chat", "group chat digest", mentions a WeChat group name with a time range, says "帮我看看 XX 群最近聊了什么", "XX 群有什么值得看的", or asks to "回溯画像" / "初始化画像" / "backfill profiles". Adds the roast version when the user says "毒舌版", "roast 版", "再来个毒舌的", or similar.

インストールへ移動

ソース情報

リポジトリ
JimLiu/baoyu-skills
ソースの最終更新活動
2026年7月4日 01:22
検出された SKILL.md の言語
英語
スター
26,192
フォーク
2,888

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
6 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
baoyu-wechat-summary
description
Summarizes WeChat group chat highlights into a structured digest using the local wx-cli binary (https://github.com/jackwener/wx-cli). Generates a normal digest by default; a roast (毒舌) version is opt-in. Maintains per-group history (history.json + history-digests.jsonl), per-user profiles, and per-group fact memory (memory.md) across runs, with privacy guardrails baked in. Use when the user asks to "总结群聊", "群聊精华", "群聊摘要", "summarize group chat", "group chat digest", mentions a WeChat group name with a time range, says "帮我看看 XX 群最近聊了什么", "XX 群有什么值得看的", or asks to "回溯画像" / "初始化画像" / "backfill profiles". Adds the roast version when the user says "毒舌版", "roast 版", "再来个毒舌的", or similar.
version
1.119.0
metadata
{"openclaw":{"homepage":"https://github.com/JimLiu/baoyu-skills#baoyu-wechat-summary","requires":{"anyBins":"[Truncated]"}}}
# WeChat Group Summary 群聊精华提取专家。把零散的微信群聊记录提炼成结构化、可读性强的简报,并维护跨次运行的群聊历史与群友画像。底层依赖外部 [wx-cli](https://github.com/jackwener/wx-cli) 二进制(`wx` 命令),不打包脚本。 > **⚠️ Sandbox restriction** > > wx-cli reads from `~/.wx-cli/` (config, cache, daemon socket) and from WeChat's data directory (`~/Library/Containers/com.tencent.xinWeChat/` on macOS). Both paths are outside Claude Code's default sandbox. Every `wx` command in this skill needs to run with `dangerouslyDisableSandbox: true` from the start — don't waste a sandbox attempt first. The user can use `/sandbox` to view/edit restrictions. ## References(按需加载) 本文件只保留工作流骨架;细节拆在 `references/` 下,**执行到对应步骤时再读,不要一开始全部读入**: | 参考文件 | 内容 | 何时读 | |---------|------|-------| | [references/setup.md](references/setup.md) | 环境检查(wx-cli 安装/权限/初始化)、wx-cli 命令速查、排障手册 | 新环境首次运行,或任何 `wx` 命令失败时 | | [references/output-formats.md](references/output-formats.md) | 两版摘要的 Section 顺序、格式与内容规范、输出骨架、自检清单 | Round 2 动笔前 | | [references/profiles.md](references/profiles.md) | 画像文件格式、更新规则、隐私红线、回溯流程 | Step 3.7 / 8.5 / Step 9 | | [references/group-memory.md](references/group-memory.md) | 群级事实记忆的写入门槛、防注入、格式 | Step 8.6 | ## User Input Tools When this skill prompts the user, follow this tool-selection rule (priority order): 1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent. 2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question. 3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order. Concrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes. ## Prerequisites 快速验证环境:`wx --version` 有输出且 `wx sessions` 返回数据即可继续。任何一步失败,或是首次在新环境运行 → 读 [references/setup.md](references/setup.md)(完整环境检查、wx-cli 命令速查、排障手册),停在第一个失败项并给用户确切的修复命令。**绝不自动安装、绝不替用户跑 `sudo`。** ## Preferences (EXTEND.md) Check EXTEND.md in priority order — the first one found wins: | Priority | Path | Scope | |----------|------|-------| | 1 | `.baoyu-skills/baoyu-wechat-summary/EXTEND.md` (relative to project root) | Project | | 2 | `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-wechat-summary/EXTEND.md` | XDG | | 3 | `$HOME/.baoyu-skills/baoyu-wechat-summary/EXTEND.md` | User home | | Result | Action | |--------|--------| | Found | Read, parse, apply. On first use in session, briefly remind: "Using preferences from [path]. Edit it to change defaults." | | Not found | **MUST** run first-time setup (BLOCKING) before generating any digest — do NOT silently use defaults. | ### Supported keys EXTEND.md is plain text with `key: value` or `key=value` lines, `#` for comments, case-insensitive keys. | Key | Type | Default | Purpose | |-----|------|---------|---------| | `self_wxid` | string | (required) | The owning account's wxid. Messages whose `from_wxid` matches this are attributed to the user. | | `self_display` | string | (required) | Display name to substitute for the user's own messages in digest text. | | `default_version` | `normal` / `roast` / `both` | `normal` | Which version(s) to generate when the user doesn't say otherwise. | | `default_time_range` | string (e.g. `7d`, `24h`, `1d`) | (none) | Default range when the user omits time and there's no incremental anchor. | | `data_root` | path | `{project_root}/wechat` | Override where digest folders live. | | `bot_aliases` | comma-separated strings | `bot, 精华bot` | Names that trigger the 「@bot 答疑」 section. A message containing `@<alias>` (case-insensitive) is treated as a question/request aimed at the digest bot. Pick names that do NOT match any real group member or existing bot, to avoid ambiguity. | A starter template lives at [EXTEND.md.example](EXTEND.md.example). ### First-Time Setup (BLOCKING) If no EXTEND.md is found, do NOT silently proceed. **Step A — Try to auto-discover `self_wxid` and `self_display` first.** Run (in order, stop at the first that succeeds): ```bash # 1. If wx-cli exposes a whoami, use it wx whoami --json 2>/dev/null # 2. Otherwise, find self-sent messages in recent sessions wx sessions --json --limit 20 2>/dev/null ``` For option 2, scan the sessions for any private/group thread the user has sent into and read one of their own `from_wxid` / `from_nickname` pairs. If you can confidently pre-fill both values, use them as defaults in the question below; otherwise leave the fields blank for the user to fill in. **Step B — Confirm with one `AskUserQuestion` call (batched), pre-filling whatever auto-discovery found:** - `self_wxid` (e.g., `wxid_abc123`) — fall-back hint: the user can find it with `wx contacts --query "<own nickname>"`, or by inspecting any of their own sent messages in `wx sessions --json` - `self_display` (e.g., `宝玉`) — how they want their messages attributed - `default_version` — pick one of `normal` / `roast` / `both` - `data_root` — where digest folders live. Default: `{project_root}/wechat`. Enter a custom absolute path (e.g. `~/Documents/wechat-digests`) or leave blank for default. - Save location — pick one of project / XDG / home Write EXTEND.md to the chosen path. If the user provided a non-default `data_root`, include it as an uncommented line; otherwise omit it (the default applies automatically). Confirm "Preferences saved to [path]. Edit it any time to change defaults.", then continue with the digest workflow. ## Workflow ### Step 1: Parse the user's request Extract: - **Group name** (or partial name for fuzzy matching) - **Time range** — interpret flexibly: - "最近 1 天" / "今天" / "last 24 hours" → 1 day - "最近 3 天" → 3 days - "最近 7 天" / "这周" → 7 days - "最近 30 天" / "最近一个月" → 30 days - "某天" (e.g. "3 月 5 号") → that specific date - "某天到某天" (e.g. "3 月 1 号到 3 月 5 号") → date range - "从上次开始" / "继续" / "接着上次" / "since last" → **incremental mode**: read `history.json` for this group, use `last_digest.last_message_time` as the start - No time specified → **incremental mode**. If no `history.json` exists yet, fall back to `default_time_range` from EXTEND.md if set, else last 24 hours. - **Version(s) to generate**: - Start from `default_version` in EXTEND.md. - User request overrides: keywords "毒舌"/"roast"/"挑衅"/"再来个毒的"/"sass" → force `include_roast=true`. Keywords "只要正经的"/"normal only"/"不要毒舌" → force `include_normal=true, include_roast=false`. "都来一份"/"两个版本都要"/"both" → both. - At least one of `include_normal`/`include_roast` must end up true. Convert relative ranges into absolute `--since YYYY-MM-DD --until YYYY-MM-DD` pairs using today's local date. ### Step 2: Find the group + resolve folder path ```bash wx contacts --query "<group_name>" --json ``` Filter for entries whose `username` ends in `@chatroom`. If multiple groups match, use `AskUserQuestion` to disambiguate. If none match, fall back to `wx sessions --json` and search there before asking the user. Once resolved, compute the folder path: ``` {data_root}/{group_id}-{sanitized_group_name}/ ``` where `data_root` is from EXTEND.md (default `{project_root}/wechat`). **Sanitize the group name** — replace any of `/ \ : * ? " < > | NUL` and control characters with `_`. Trim trailing dots and whitespace. Don't strip emoji or Chinese characters. **Group-rename detection**: list existing folders under `{data_root}/` and find any folder whose name starts with `{group_id}-`. If one exists but the suffix differs (group was renamed), rename the existing folder to the new `{group_id}-{sanitized_new_name}` form. If a target with the new name already exists (rare), keep both and prefer the existing one for this run. ### Step 2.5: Look up the group owner(群主) 群主是谁**必须有据可查**,不能凭历史摘要、群友玩笑或印象推断(群主可能换届,历史摘要里的说法会过期): ```bash wx members "<group_name_or_id>" --json ``` - 检查输出中是否有 owner / role 字段标识群主;有则以此为准 - 如果 wx-cli 版本不暴露群主信息,则查 memory.md「群基本档案」里有出处的记录;两处都没有 → **摘要里不要断言谁是群主** - 查到的结果与「群基本档案」不一致时以本次查询为准,更新档案并追加修订记录(注明查询日期) ### Step 3: Fetch messages **Always redirect the fetch to a `$TMPDIR` file** — this file is the single source of truth for the whole run: Round 3's attribution audit greps it, and the statistics are computed from it. Never write the digest purely from conversation memory. For small batches (single-day digest, typically < 200 messages), you may additionally pipe JSON into the agent directly for reading: ```bash wx history "<group_name_or_id>" --since YYYY-MM-DD --until YYYY-MM-DD -n 5000 --json ``` For **large batches** (weekly / monthly digests, > 200 messages), the `$TMPDIR` redirect also keeps the raw payload out of conversation context: ```bash wx history "<group_name_or_id>" --since YYYY-MM-DD --until YYYY-MM-DD -n 5000 --json > "$TMPDIR/wx-messages.json" wc -c "$TMPDIR/wx-messages.json" jq 'length' "$TMPDIR/wx-messages.json" ``` Then read the file in slices via `Read` with `offset` + `limit`, or process with `jq` queries (e.g. `jq '.[0:200]'`, `jq '[.[] | {id, from_nickname, timestamp, content: (.content | .[0:50])}]'` for a lightweight skeleton pass). Reading all 500+ messages at once will burn token budget unnecessarily. Notes: - `--since` is inclusive; `--until` is interpreted as a date (the whole day). If the user asked for "today only", set both to today. - `-n 5000` is a defensive cap; for very active groups, raise it and re-fetch. - Filter the returned messages by their `timestamp` to be safe (some daemons may return adjacent days). - **Range splitting**: for ranges > 7 days OR > 500 messages, prefer generating per-3-day digests and then a meta-summary over forcing one giant digest — the categorization quality degrades sharply past a week's worth of unrelated topics. **Incremental mode**: after the fetch, drop any message whose `timestamp` is `<=` the `last_message_time` from `history.json`, and write the filtered set back to the `$TMPDIR` file (so audits and stats run on exactly what the digest covers). Caution: `last_message_time` is `MM-DD HH:MM` — plain string comparison breaks across a year boundary (12-31 vs 01-01); compare by date semantics there. If zero messages remain, tell the user "上次摘要后没有新消息,已跳过生成" and exit. ### Step 3.5: Parse the message schema `wx history --json` returns an array of message objects. Use the fields that are present; tolerate missing fields: - **`id` / `msg_id` / `local_id`** — message identifier (use whichever wx-cli emits). Reference IDs in working notes as anchors when building the skeleton. - **`from_wxid`** — stable sender identifier - **`from_nickname`** — display name (may be the group remark or original nickname) - **`content`** — text payload. Examples: - Plain text → use as-is - `[图片]` → opaque placeholder; see image handling below - `[表情]` → emoji/sticker; skip in body unless surrounded by discussion - `[视频]` / `[文件]` → media reference; skip unless discussed - `[链接] <title>` or `[链接/文件] <title>` → shared article; the title IS the information — quote it and credit the sharer - `[系统] ... revokemsg` → revoked; exclude from digest and from leaderboard - **`timestamp`** — convert to `MM-DD HH:MM` for display (and use full ISO for `generated_at`) - **`chat_type`** — sanity-check `group` - **Quote/reply** — try `quote_id`, `reply_to`, `quoted_msg_id`, or any nested `quote` object. If present, use it as strong attribution. If absent, fall back to context but flag the inferred link as uncertain. ### Step 3.6: Resolve self + ambiguous nicknames - Substitute `self_display` for every message whose `from_wxid` matches `self_wxid` (from EXTEND.md). Apply this in the leaderboard, portraits, and body text. The user MUST appear under their real display name and count toward stats — never skip them. - Scan all unique senders for ambiguous handles: ≤2 characters, common programming words (`nil`, `null`, `test`, `admin`, `user`, `undefined`), single emoji, or otherwise low-information. For each, run `wx contacts --query "<nick>" --json --limit 5` and pick a meaningful name in this priority: remark > nickname > wxid. Apply the substitution everywhere in the digest. - **硬规则**:`nil`、空白、单标点这类占位符样式的名字**绝不允许原样出现在摘要里**。contacts 查不到 remark 时,用「昵称(wxid 后 4 位)」形式区分(如 `nil(…n77g)`),确保读者知道这是谁、且与其他人不混淆。已解析过的映射写入 memory.md「群基本档案」,下期直接复用不再重查。 ### Step 3.7: Load user profiles For each unique sender appearing in this batch: - Look in `{folder}/profiles/{wxid}-*.md` by `wxid` prefix match. Read the matched file if found. - If `include_roast`, **also** look in `{folder}/profiles-roast/{wxid}-*.md` for the roast pass. Compile a condensed **profile context block** as internal working memory — do NOT write it into the final digest. Example shape: ``` == 群友历史画像(来自 profiles/)== K. H:空中直播员 / 生活百科全书。常见话题:旅行、金融、美食。经典金句:"要不要买moderna"。 可可苏玛:... ``` Rules: - Only load profiles for users active in this batch — never preload everyone. - Profile is **background**, not template. Current messages are still the primary source. - Use historical labels for **continuity** ("又双叒叕化身空中直播员") or **contrast** ("一向省钱的 XX 今天居然..."). - **Strict separation**: normal pass reads only `profiles/`, roast pass reads only `profiles-roast/`. Never cross-load. See [references/profiles.md](references/profiles.md) for the full file format. ### Step 3.7.5: Load group memory(群级事实记忆) 除了按人的 profiles,每个群还有一份全局事实记忆 `{folder}/memory.md`,记录群友指正过、确认过的客观事实(如"某个报错提示的真实原因"、"某产品名的正确写法"、"某事件的实际经过")。 1. 如果 `memory.md` 存在,读入作为内部背景知识(不写入最终摘要)。「群基本档案」小节记录群主、昵称映射等长期事实,写摘要时直接引用(群主以 Step 2.5 的查证结果为最终依据) 2. **写摘要时必须遵守其中的事实修正**——上一期摘要里说错、已被群友指正的说法,这一期绝不能再犯。例如记忆中有"『当前微信版本不支持』是 AI Agent 无法获取微信链接导致的提示,普通用户可正常打开",就不能再把它当成"骗点击"的梗来写 3. 记忆条目是事实约束,不是风格指令——它只纠正"说什么",不改变 normal/roast 两个版本各自的语气和写法 4. 标注为「群友说法(未验证)」的条目,引用时保留这个限定,不当成已证实的事实陈述 5. 文件不存在则跳过,属正常情况 ### Step 3.8: Detect existing in-chat digests (optional) Some users (e.g., the original 宝玉 workflow) post digests directly into the group as messages. If we don't notice these, the new digest will re-cover the same ground. Scan the fetched messages for signals of a prior in-chat digest:
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る