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에서 보기