
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
wechat-acp
Advanced tools
Bridge WeChat direct messages to any ACP-compatible AI agent.
wechat-acp logs in with the WeChat iLink bot API, polls incoming 1:1 messages, forwards them to an ACP agent over stdio, and sends the agent reply back to WeChat.
npxStart with a built-in agent preset:
npx -y wechat-acp@latest --agent copilot
Or use a raw custom command:
npx -y wechat-acp@latest --agent "npx my-agent --acp"
On first run, the bridge will:
~/.wechat-acpEvery push to main is automatically published to npm under the next dist-tag, so you can try unreleased changes without waiting for a tagged release:
npx -y wechat-acp@next --agent copilot
These versions are tagged <base>-next.<UTC-timestamp>.<short-sha> (e.g. 0.7.1-next.202605311530.abc1234, where 0.7.1 is the next patch above whatever @latest is). They are built from main after CI passes, but have not been through a release review — expect rough edges. Stable users should keep using wechat-acp@latest.
List the bundled presets:
npx wechat-acp agents
Current presets:
copilotclaudegeminiqwencodexopencodeopenclawkirohermeskimipiThese presets resolve to concrete command + args pairs internally, so users do not need to type long npx ... commands.
wechat-acp --agent <preset|command> [options]
wechat-acp agents
wechat-acp inject --text <text>
wechat-acp stop
wechat-acp status
Options:
--agent <value>: built-in preset name or raw agent command--cwd <dir>: working directory for the agent process--login: force QR re-login and replace the saved token--daemon: run in background after startup--config <file>: load JSON config file--instance <name>: run as a named, isolated instance. See "Running multiple instances" below.--idle-timeout <minutes>: session idle timeout, default 1440 (use 0 for unlimited)--max-sessions <count>: maximum concurrent user sessions, default 10--inbox-dir <dir>: directory where received binary files are saved (default: <storage.dir>/inbox). The agent sees the absolute saved path in the prompt and can read the file directly.--no-inbox: do not save received files; the agent only sees a size notice.--hide-thoughts: do not forward agent thinking to WeChat (default: forwarded)--show-diffs: forward ACP file diffs to WeChat (default: hidden)--hide-images: do not forward agent image output to WeChat (default: forwarded)--hide-audio: do not forward agent audio output to WeChat (default: forwarded)--hide-resources: do not forward agent resources or generated file attachments to WeChat (default: forwarded)inject --text <text>: enqueue a local text message for the running daemon-V, --version: print version and exit-h, --help: show helpExamples:
npx -y wechat-acp@latest --agent copilot
npx -y wechat-acp@latest --agent claude --cwd D:\code\project
npx -y wechat-acp@latest --agent "npx @github/copilot --acp"
npx -y wechat-acp@latest --agent gemini --daemon
By default everything (saved login token, daemon pid/log, sync state, telemetry id) lives under ~/.wechat-acp/, which means a single machine can only host one bridge at a time. Pass --instance <name> to namespace all of that under ~/.wechat-acp/instances/<name>/ and run several bridges side by side, each with its own WeChat account and project directory.
Typical setup: WeChat account 1 drives project A, WeChat account 2 drives project B.
# Terminal 1: scan with WeChat account 1
npx -y wechat-acp@latest --instance projA --agent copilot --cwd D:\code\repo-a
# Terminal 2: scan with WeChat account 2
npx -y wechat-acp@latest --instance projB --agent copilot --cwd D:\code\repo-b
The first run of each instance prints its own QR code. Tokens are saved per instance, so subsequent runs reuse them independently.
The stop and status subcommands also honor --instance:
npx -y wechat-acp@latest status --instance projA
npx -y wechat-acp@latest stop --instance projB
Without --instance, paths fall back to ~/.wechat-acp/ exactly as before, so existing installs are unaffected.
You can provide a JSON config file with --config.
Example:
{
"agent": {
"preset": "copilot",
"cwd": "D:/code/project",
"showDiffs": true
},
"session": {
"idleTimeoutMs": 86400000,
"maxConcurrentUsers": 10
}
}
You can also override or add agent presets:
{
"agent": {
"preset": "my-agent"
},
"agents": {
"my-agent": {
"label": "My Agent",
"description": "Internal team agent",
"command": "npx",
"args": ["my-agent-cli", "--acp"]
}
}
}
Bridge slash commands like /acp-config and /acp-cancel have fixed
built-in names that may not feel natural to everyone, and can clash with
slash commands built into the underlying agent. You can map any bridge
command to one or more custom aliases via the commandAliases config map:
{
"commandAliases": {
"/acp-cancel": ["/cancel", "/取消", "取消"],
"/acp-config": ["/config", "/设置"]
}
}
With this config:
/取消 cancels the current turn (same as /acp-cancel), and
/取消 all works like /acp-cancel all./设置 lists ACP session config (same as /acp-config), and
/设置 set <configId> <value> works like /acp-config set ....Two alias styles are supported:
/, e.g. /cancel) behave like the
built-in commands: they match the command token and may be followed by
arguments (/cancel all). They must not contain whitespace./, e.g. 取消) match only when
they equal the entire message. This is handy for WeChat voice input,
where saying /取消 out loud feels unnatural — a transcribed 取消
triggers the command. Because they require an exact full-message match,
they take no arguments.Notes:
/acp-config, /acp-cancel, /acp-prompt-start, or /acp-prompt-done).idleTimeoutMs to 0 to disable idle cleanup).wechat-acp reserves a bridge-level chat command for inspecting and changing ACP session configuration without exposing a UI picker in WeChat:
/acp-config
/acp-config set <configId> <value>
Examples:
/acp-config
/acp-config set model gpt-5-mini
/acp-config set mode plan
/acp-config set reasoning_effort low
Notes:
configId values come directly from the ACP agent's configOptions, so the exact list depends on the configured agent.wechat-acp itself and is not forwarded to the underlying agent.commandAliases (see Customizing bridge command names).WeChat does not offer a stop button for an in-flight agent turn, so the bridge exposes a chat command instead:
/acp-cancel
/acp-cancel all
Behavior:
/acp-cancel sends session/cancel to the agent for the current turn. The in-flight prompt() resolves with stopReason: "cancelled", any partial output already streamed is delivered to WeChat with a [cancelled] suffix, and the next queued message (if any) is processed as usual./acp-cancel all does the same and also drops every message that was queued behind the current turn. Local injections (wechat-acp inject) waiting on those queued messages are rejected.wechat-acp itself and is not forwarded to the underlying agent.commandAliases (see Customizing bridge command names).WeChat does not allow sending images, files, and text in a single message. To work around this, the bridge provides a buffering mode that collects multiple messages and sends them to the agent as one combined request:
/acp-prompt-start
/acp-prompt-done
Usage:
/acp-prompt-start to enter buffering mode. The bridge replies with a confirmation./acp-prompt-done to flush the buffer. All collected content is combined into a single agent request.This avoids triggering multiple agent turns (and multiple replies) when a user needs to send mixed content.
/acp-prompt-done is sent with nothing buffered, the bridge replies with a warning and no agent request is made./acp-prompt-start is sent while already buffering, the bridge reminds the user and keeps the existing buffer.wechat-acp itself and is not forwarded to the underlying agent.wechat-acp inject lets local automation enqueue a text message for the running daemon. The daemon treats it like an incoming direct message from the target user, sends it to the configured ACP agent, and replies through WeChat.
This is useful for cron or launchd jobs, for example a daily AI news prompt:
npx wechat-acp inject --instance main --text "今日 AI 资讯"
Targets:
last-active-user--to <wechat-user-id>The daemon learns last-active-user from real incoming WeChat messages and stores the latest userId + contextToken under the instance storage directory. If no user has messaged the bot yet, ask the target user to send any message once, then retry the injection.
Injected messages are stored as JSON files under:
~/.wechat-acp/inject/
~/.wechat-acp/instances/<name>/inject/
The queue is file-based:
inject/
├── pending/
├── processing/
├── done/
└── failed/
inject only writes to pending/; the daemon moves files through the other directories as it processes them. If the daemon is not running, the message remains queued and will be processed after the daemon starts.
For longer prompts, use a file:
npx wechat-acp inject --instance main --file ./prompt.txt
Example Linux cron entry:
0 7 * * * /usr/local/bin/wechat-acp inject --instance main --text "今日 AI 资讯"
When a WeChat user sends a binary file (PDF, image, audio recording exported as a file, ZIP, etc.), wechat-acp downloads and decrypts it from the WeChat CDN, then saves it to disk so the ACP agent can read it by absolute path. The agent receives a text block like:
[Received file: 报告.pdf (484067 bytes) — saved to: /Users/me/.wechat-acp/inbox/2026-05-21T09-29-12-492Z-报告.pdf]
Any ACP agent that can read local files (Copilot CLI, Claude Code, Codex, …) can then open the saved path with its normal file tools.
Defaults:
<storage.dir>/inbox, i.e. ~/.wechat-acp/inbox by default, or ~/.wechat-acp/instances/<name>/inbox when --instance is used.<ISO-timestamp>-<original-name>, with filesystem-unsafe characters in the original name replaced by _. Unicode (including Chinese) filenames are preserved.find ~/.wechat-acp/inbox -mtime +30 -delete if you want to prune.Overrides:
--inbox-dir /some/path — write files somewhere else (handy if you want them under iCloud Drive, a project folder, etc.)--no-inbox — keep the pre-0.3 behavior where the file buffer is dropped after download and the agent only sees [Received file: name, N bytes].Text-typed files (.md, .json, source code, …) and images keep their previous behavior: their content is embedded inline in the prompt as a resource / image block, no disk write needed.
When the ACP agent advertises HTTP MCP support, wechat-acp injects a local
attach_file tool into the session. The agent can call it with a file it
created under the configured working directory, and the bridge sends that
snapshot back as a WeChat file message. Files whose type is a supported image
are delivered as native WeChat images instead of file cards.
The MCP server listens only on a random 127.0.0.1 port, requires a
process-local bearer token, rejects browser-origin requests, and only reads
regular files whose resolved path stays inside the agent working directory.
Files are limited to 25 MiB, kept briefly in memory, and consumed once.
This also handles standard ACP resource_link output and Copilot CLI's
rawOutput.contents[type=resource_link] compatibility shape. Agents that do
not support HTTP MCP injection or do not forward resource links cannot use the
active attach_file flow. --hide-resources disables both the tool injection
and outbound resource/file delivery.
By default, runtime files are stored under:
~/.wechat-acp
This directory is used for:
telemetry-id, see Telemetry section)inbox/ — binary files received from WeChat (see "Receiving files"); disable with --no-inbox or relocate with --inbox-dirstate.json — last active user and context token for local injectioninject/ — local injected message queueWhen --instance <name> is used, the same files live under ~/.wechat-acp/instances/<name>/ instead, fully isolated from other instances.
For local development:
npm install
npm run build
Run the built CLI locally:
node dist/bin/wechat-acp.js --help
Watch mode:
npm run dev
wechat-acp collects anonymous usage telemetry via Azure Application Insights to help understand which agent presets are used and to detect crashes.
To disable telemetry, set the WECHAT_ACP_TELEMETRY environment variable to 0, false, or off before running:
WECHAT_ACP_TELEMETRY=0 npx wechat-acp --agent copilot
What is collected (18 event types only):
app.start / app.stop — process lifecycle, agent preset name, daemon flag, uptimelogin.success / login.failure / token.reused — WeChat login outcomes (no token, no QR URL)message.received — message arrived; only the categorical kind (text / image / voice / file / video / empty) and a hashed user idmessage.injected — local injection queued for processing; only target kind (last-active-user / explicit) and a hashed user idcommand.acp_config.view — /acp-config invoked to list options; whether a session exists and the option countcommand.acp_config.set — /acp-config set succeeded; configId, option type (select / boolean), and the resolved option value (all from the agent's declared configOptions, never the user's raw input)command.acp_cancel — /acp-cancel invoked; whether the queue was drained, whether an in-flight turn was actually cancelled, and how many queued messages were droppedcommand.buffer_start — /acp-prompt-start invoked to enter buffering modecommand.buffer_done — /acp-prompt-done invoked to flush buffer; number of content blocks collectedsession.created — new ACP session openedprompt.completed — ACP turn finished; agent preset, stop reason, duration, reply lengthreply.sent — reply pushed back to WeChat; segment count, total lengthreply.image.sent: image reply pushed back to WeChat; byte size, MIME type, durationreply.audio.sent: audio reply pushed back to WeChat as a file message; byte size, MIME type, durationreply.file.sent: agent-generated file pushed back to WeChat; byte size, MIME type, durationPlus exception reports for monitor, prompt, reply, reply.image, reply.audio, reply.file, artifact_mcp, auth, agent_spawn, enqueue, buffer, command, and state failures.
What is never collected: message bodies, filenames, voice transcripts, image URLs, login tokens, QR codes, raw agent command strings, environment variables, working directory paths, raw WeChat user IDs.
User IDs are sha256-hashed with a per-install salt stored in ~/.wechat-acp/telemetry-id. The salt is generated on first run and never leaves your machine. Delete the file to rotate it.
MIT
FAQs
Bridge WeChat to any ACP-compatible AI agent
The npm package wechat-acp receives a total of 146 weekly downloads. As such, wechat-acp popularity was classified as not popular.
We found that wechat-acp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.