SuperAPI AI Directory

wx-cli

Data & analytics

View repository

Updated 10-16 06:19

About this skill

wx-cli

Triggers

  • Query WeChat chat history
  • WeChat message history
  • WeChat contacts
  • WeChat group members
  • WeChat group nicknames / group cards
  • WeChat favorites
  • wechat history / messages / contacts
  • wx-cli
  • Help me look in WeChat
  • Search WeChat messages

Prerequisites

  • macOS (Apple Silicon / Intel), Linux, or Windows
  • WeChat Desktop 4.x is installed andlogged in
  • Node.js >= 14 (npm install) or curl / build from source
  • First time wx init requires elevated privileges (macOS/Linux: sudo; Windows: administrator)

Note for new macOS users (common misconceptions)

  • No need to disable SIP
  • No need topre- codesign / ad-hoc re-sign WeChat (the default path does not modify WeChat.app)
  • Needlocal GUI Terminal(Terminal.app / iTerm, etc.), do not use SSH for the first init
  • If the system prompts for "Developer Tools" permission, please allow it; you can also go to "System Settings → Privacy & Security → Developer Tools" and check the terminal

Install

Source repository:botiverse/wx-cli(current private)。

Recommended: build from source (requires repository read permission + SSH)

git clone git@github.com:botiverse/wx-cli.git && cd wx-cli
cargo build --release
mkdir -p ~/.local/bin && cp target/release/wx ~/.local/bin/wx
wx --version

Upgrade an existing installation:

cd /path/to/wx-cli && git pull && cargo build --release && cp target/release/wx ~/.local/bin/wx

Other

  • When you have gh permission:gh release download -R botiverse/wx-cli -p 'wx-macos-arm64' -O ~/.local/bin/wx
  • Do notrely on public npm @jackwener/wx-cli(the registry version may be old)
  • Anonymous curl install.sh will 404 on a private repository

Initialization (first use, only once)

macOS

  1. Open and log in to WeChat
  2. Inlocal GUI Terminal , run:
sudo wx init
  1. If the shard key is missing (unknown_shards / match count too low), extend the LLDB hook, and open the relevant chats while waiting:
sudo wx key extract --hook-seconds 90

wx init will: detect the data directory → memory scan + LLDB hook to obtain the per-DB key → write to ~/.wx-cli/config.json and all_keys.json。

Do notrun codesign --force --deep --sign - /Applications/WeChat.appby default: it will mess up TCC and cause abnormal permissions for screenshots/official accounts, etc. Only consider the re-sign with side effects when attach fails in no-GUI scenarios such as SSH.

Linux

sudo wx init

Windows (administrator PowerShell)

wx init

After initialization is complete, subsequent queriesdo not require sudo, the daemon starts automatically on the first call; for daily queriesthe WeChat process is not required to be running all the time。

Pre-check:

wx doctor --json
wx key list --json

When key shards are missingonlyRecommended:sudo wx key extract --hook-seconds 90(open the relevant chats while waiting). Do not loop init --force。


Command quick reference

All commands output YAML by default, which saves tokens & is easier to read;--json can switch to JSON (convenient for jq processing, etc.).

Conversations and messages

# 最近 20 个会话
wx sessions

# 有未读消息的会话
wx unread

# 只看真人(私聊 + 群聊)的未读,过滤公众号与折叠入口
wx unread --filter private,group

# 上次检查后的新消息(增量)
wx new-messages
wx new-messages --json          # JSON 输出,适合 agent 解析

# 聊天记录(支持昵称/备注名)
wx history "张三"
wx history "张三" -n 2000
wx history "AI群" --since 2026-04-01 --until 2026-04-15 -n 100

# 全库搜索
wx search "关键词"
wx search "关键词" -n 500
wx search "会议" --in "工作群" --since 2026-01-01

history / search / export all support -n / --limit to specify the number of returned records. The default value is only to avoid outputting too much at once, not a hard upper limit.

sessions / unread / history / new-messages / stats outputs all include the chat_type field, based on which the agent can route accordingly:

Value Meaning username characteristics
private One-on-one private chat wxid_* or custom short ID
group Group chat *@chatroom
official_account Official accounts / Subscription accounts / Service accounts / System notifications gh_*、biz_*、mphelper、qqsafe、@opencustomerservicemsg
folded Collapsed entries (collapsed subscription accounts, aggregated entries for collapsed group chats) brandsessionholder、@placeholder_foldgroup

wx unread --filter Supports private / group / official / folded / all, comma-separated for multiple selections. Default all。

In group chat messages, last_sender、sender and stats.top_senders will preferentially display the group nickname (group card name). If the local database has no group nickname, it falls back to the contact remark, WeChat nickname, or username.

history / search / new-messages / attachments and stats.top_senders in a group context simultaneously output the stable identity trio:sender_username(stable wxid, used to distinguish members with the same name) / sender_contact_display(remark > nickname > wxid fallback) / sender_group_nickname(group card name, equivalent to the source of sender , eliminating the need for further string parsing). When the wxid cannot be resolved, these three fields are not output, avoiding empty strings polluting downstream filtering.

sessions / unread / history / search / new-messages / stats / attachments stdout is now uniformly a wrapper:

{
  "messages": [...],
  "meta": {
    "status": "ok",
    "unknown_shards": [],
    "chat_latest_timestamp": 1715750400,
    "chat_latest_db": "message/message_2.db",
    "session_last_timestamp": 1715760000
  }
}

Where:

  • status = possibly_stale_unknown_shards: A new message_N.dbthat the daemon does not recognize appears on disk; first run sudo wx key extract --hook-seconds 90
  • status = possibly_stale:session.db The latest time recorded is significantly ahead of the latest message found this time, so messages may be missed
  • status = windowed: This query is inherently a windowed/filtered partial view and should not be treated as the "full latest state"
  • --with-meta: Additionally returns per_shard_latest / cache_mode_per_shard
  • --debug-source: On the basis of --with-meta , further exposes the real shard_paths

Quoted messages (appmsg type=57) in the history / search / new-messages output are expanded into two lines: the first line is the current reply, and the second line starts with ↳ to display the quoted original text, for example:

[引用] 当前回复
  ↳ 发送者: 被引用内容

--type link / --type file will cover WeChat appmsg variants such as links, files, merged chat records, and quoted messages;search --type link will also match the decompressed and formatted quoted original text.

Contacts and Groups

# 联系人列表 / 搜索
wx contacts
wx contacts --query "李"

# 群成员列表
wx members "AI交流群"

wx members --json Each member contains:

  • username: WeChat internal username
  • display: Recommended display name, preferring the group nickname
  • contact_display: Contact remark or WeChat nickname
  • group_nickname: Group nickname; empty string when there is no record
  • is_owner: Whether they are the group owner

When an Agent displays group members, it preferentially uses display. When it is necessary to distinguish between group nicknames and contact names, then read group_nickname and contact_display。

Moments (SNS)

Three commands, each with a different purpose:

# 1) 互动通知(点赞 / 评论,默认仅未读)
wx sns-notifications
wx sns-notifications --include-read --since 2026-04-01 -n 100

# 2) 时间线:浏览本地缓存的朋友圈帖子
wx sns-feed                                    # 近 20 条
wx sns-feed --user "张三"                      # 只看某人
wx sns-feed --since 2026-04-01 --until 2026-04-18 -n 100

# 3) 全文搜索:在正文里找关键词
wx sns-search "关键词"
wx sns-search "婚礼" --user "李四" --since 2023-01-01 -n 50

Field distinction:

  • sns-notifications returns "notification" entries:type(like/comment)、from_nickname、content(comment text, empty for likes),feed_preview + feed_author(the corresponding original post)
  • sns-feed / sns-search returns "post" entries:author、content(Moments text),media、media_count(number of images/videos),location、timestamp;media The field contains each image's url/thumb/key/token/md5/enc_idx/size, for downstream image proxying or offline rendering.media_count = media.len(), counted by valid <media> child nodes parsed from the DOM (returns 0 for malformed XML)

Only saves Moments you have locally scrolled through (the WeChat app downloads on demand). Posts you have not scrolled through are not local, and no command can retrieve them.

Official Account Articles

Official account article pushes are stored in a separate biz_message_*.db shard, separate from ordinary message_0.db :

# 最近 50 篇(默认)
wx biz-articles

# 更多
wx biz-articles -n 200

# 限定公众号(名称模糊匹配 display name / username)
wx biz-articles --account "返朴"

# 时间范围(YYYY-MM-DD,发布时间,非接收时间)
wx biz-articles --since 2026-05-01 --until 2026-05-10

# 仅有未读消息的公众号,每号取最新 1 篇(适合"今天有什么新推送"扫描)
wx biz-articles --unread
wx biz-articles --unread --account "Datawhale"   # 与 --account 取交集

# 下游消费:拿 URL 做内容抓取
wx biz-articles --since 2026-05-10 --json | jq '.[].url'

Fields returned for each entry:account / account_username(gh_*)/ title / url(mp.weixin.qq.com link) / digest / cover_url / time + timestamp(article publish time) / recv_time_str + recv_time(the time when WeChat receives the push). Multi-article pushes will be expanded into multiple lines.

Attachment extraction (images)

The image itself in a chat is stored encrypted under xwechat_files/<wxid>/msg/attach/... (.dat), and can only be decoded using the md5 of the message_resource.db where the message is located + the platform-related image key. Two steps:

# 1) 先列出图片附件,拿到不透明的 attachment_id
wx attachments "张三"
wx attachments "AI群" --kind image -n 100
wx attachments "AI群" --since 2026-04-01 --until 2026-04-15

# 2) 用 attachment_id 把单个资源解密写到指定路径
wx extract <attachment_id> -o ~/Desktop/photo.jpg
wx extract <attachment_id> -o /tmp/x.jpg --overwrite

attachments outputs each entry with:attachment_id / kind(currently fixed at image)/ type / local_id / timestamp / time, and in group chats additionally with sender and the stable identity trio (same as above). The command name is kept as attachments so that the CLI does not break when it is later extended to other attachment types.

extract The report includes:md5 / dat_path / dat_size / output / output_size / format(the actually recognized image format: jpg / png / gif / webp / hevc, etc.) / decoder(the actually selected decoder:legacy_xor / v1_aes / v2)。

Supported decode tiers:

  • legacy XOR: early single-byte XOR, no magic (automatically inferred by detecting the format from the first byte of the file)
  • V1 fixed-AES(07 08 V1 08 07): AES-128-ECB + fixed key cfcd208495d565ef
  • V2 AES + XOR(07 08 V2 08 07): AES-128-ECB + raw + XOR; AES key platform-derived

V2 image key extraction (automatic on macOS / Windows; not yet supported on Linux):

  • macOS:kvcomm cache(key_<uin>_*.statistic The filename is taken from uin → md5(str(uin) + wxid)[:16])+ brute-force fallback;xor_key = uin & 0xff
  • Windows: scan Weixin.exe memory to match [A-Za-z0-9]{32|16} candidates, and reverse-verify by the V2 template ciphertext-block

Favorites and stats

# 全部收藏
wx favorites

# 按类型筛选:text / image / article / card / video
wx favorites --type image

# 搜索收藏内容
wx favorites --query "关键词"

# 聊天统计(发言人、消息类型、活跃时段)
wx stats "AI群"
wx stats "AI群" --since 2026-01-01

Export

# 导出为 Markdown(默认)
wx export "张三" --format markdown -o chat.md
wx export "张三" -n 2000 --format markdown -o chat.md

# 导出为 JSON
wx export "AI群" --since 2026-01-01 --format json -o chat.json

Daemon management

wx daemon status
wx daemon stop
wx daemon logs --follow

Agent usage suggestions

When query results need to be processed by a program, uniformly add --json:

wx sessions --json
wx new-messages --json
wx search "关键词" --json | jq '.results[0]'
wx history "张三" --json -n 50 | jq '.messages[0]'
wx history "张三" --json | jq '.meta'
wx history "张三" --json --with-meta | jq '.meta.cache_mode_per_shard'

The CHAT parameter supports nicknames, remark names, and WeChat IDs, with fuzzy matching. When you are unsure of the exact name, first use wx contacts --query to search.


Data file location

~/.wx-cli/
├── config.json       # 配置
├── all_keys.json     # 数据库密钥(敏感,勿分享)
├── daemon.sock       # Unix socket
├── daemon.pid / .log
└── cache/            # 解密后的数据库缓存

FAQ

Is it mandatory to disable SIP?: No. It is fine to leave SIP enabled; init uses the local Terminal + sudo.

Is it mandatory to ad-hoc re-sign WeChat?: Not needed by default. Consider it only when using SSH / no GUI and attach fails, and it has side effects.

After WeChat restarts, the key becomes invalid / new shards have no key: Run sudo wx key extract --hook-seconds 90again (WeChat must be running; open the relevant chat while waiting).

daemon is unresponsive:wx daemon stop and then call any command again to automatically restart it.

Cannot find the chat: Use wx contacts --query to confirm the nickname/remark name, or query directly by WeChat ID.

Why can only 500 messages be retrieved?: This is the default number of output entries, not a hard limit. Explicitly pass -n to do so, for example wx history "张三" -n 2000 or wx export "张三" -n 2000 -o chat.md。