
wa — safe WhatsApp automation
io.github.yolo-labz由 GitHub 账号 yolo-labz 发布v2.3.0更新于 Oct 25, 2026
Safety-first WhatsApp tools: draft-gated sends, enforced rate limits, append-only audit.
概览
本地 MCP 服务器,让助手通过带安全管制的守护进程读取和发送 WhatsApp 消息,默认将发送内容转为草稿等待人工批准。
- 可以做什么
- 通过强制执行的安全管线发送或起草文本与媒体消息,并可安排稍后发送;草稿队列可列出并批准待审草稿。搜索已同步消息、获取某个聊天的近期消息、列出活跃聊天、解析联系人并读取群组信息。等待匹配的入站回复并转写语音消息。查看守护进程连接与会话状态,支持只读模式和工具集范围限制。
- 适用场景
- 当你希望 AI 代理操作个人 WhatsApp 账号——起草或发送消息、检索历史、等待回复——同时保留人工审批和速率限制时使用。不适合群发消息或多租户网关场景。
- 运行要求
- 以本地桌面进程(stdio)运行,可通过签名安装包或 wa 命令行工具的 mcp serve 子命令启动。需要运行 wa 守护进程并已配对 WhatsApp 多设备会话(二维码或手机号配对),且需在允许名单中为每个收件人授予发送/读取权限。支持 macOS 和 Linux。
安装
在 SourceWeft 中
- 打开 控制台中的 wa — safe WhatsApp automation,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
wa
Personal WhatsApp automation CLI + daemon, written in Go.
A hexagonal Go daemon that owns a WhatsApp Multi-Device session and a thin JSON-RPC client that talks to it — safe enough to let a language model send messages on your behalf, crash-safe enough to survive a power loss mid-migration, and paranoid enough to refuse every destructive flag you might expect.
[CI] [Release] [Go] [License] [Conventional Commits] [Nix flake] [OpenSSF Scorecard] [SLSA L2] [Verified by Sigstore]
Quickstart · Install · Manual · Architecture · Security · Contributing · Português (BR)
Capability
Pattern. Persistent WhatsApp daemon over a Unix socket — one wad process holds the Multi-Device session, ratchet store, and websocket; a thin wa JSON-RPC client invokes it.
Trade-off. ~30 MB RSS per profile and a 5–8 s cold connect, in exchange for sub-second warm-call latency on every subsequent wa send. Per-call session reattachment is avoided entirely.
Use when. A shell pipeline, cron job, or Claude Code plugin needs to dispatch WhatsApp messages with predictable latency and a non-overridable safety pipeline (default-deny allowlist + rate limiter + warmup ramp + append-only audit log) sitting below every RPC path.
Demo
Every frame is real output from the binaries in this repo, recorded against a
throwaway unpaired daemon in a private temp directory. doctor honestly warns
that the device is unpaired (and may flag missing backups in the fresh sandbox).
No real account data is used. The revoke command is help only, not a mutation.
The recording is generated, never hand-edited. The source of truth is the
plain-text docs/assets/wa-demo.tape; regenerate
the GIF, MP4, WebM, static PNG and captured text with one command:
Prefer playback controls or reduced motion? Use MP4, WebM, the static frame, or the text equivalent. Recording notes cover isolation, safety controls, byte budgets and checks. Playback is 1× and silent; no live sends are demonstrated.
How wa compares
Closest peers in the reverse-engineered-WhatsApp ecosystem:
For multi-tenant REST gateways see EvolutionAPI or WAHA — different shape of problem, listed in What this is NOT.
What this is
Two binaries, one repo:
wad— long-running daemon that owns the WhatsApp session, the SQLite ratchet store, and the websocket toweb.whatsapp.com. Runs undersystemd(Linux),launchd(macOS), or a NixOS module. Single-instance per profile, never as root.wa— thin JSON-RPC client that speaks towadover a unix socket. This is what shell scripts, cron jobs, and Claude Code plugins actually invoke.
It is built on go.mau.fi/whatsmeow — the library that powers mautrix-whatsapp at production scale — because it is the only reverse-engineered WhatsApp library actively maintained in 2026. It also ships a safety-first MCP server (wa mcp serve) so an AI agent drives WhatsApp through the same non-bypassable safety pipeline — draft-gated by default. See MCP server.
What this is NOT
- Not a bulk-messaging tool. The rate limiter is non-overridable and there is no
--forceflag anywhere. - Not a multi-tenant SaaS. Each
wainstall is scoped to one person, with optional multi-profile isolation for work/personal splits. - Not a Matrix bridge. Use
mautrix-whatsappif that's what you want. - Not a REST gateway. Use
EvolutionAPIorWAHAif that's what you want. - Not the official WhatsApp Cloud API. This project uses the reverse-engineered Multi-Device protocol via
whatsmeow.
Quickstart
The recipient flag is spelled --to, --jid, or --group depending on the command; --chat <jid> is accepted as a universal alias on all of them (the original flags still work).
For the full tour including multi-profile setup, shell completion, migration, and the audit log, see docs/manual.md.
MCP server
wa mcp serve exposes the daemon to AI agents over the Model Context Protocol (stdio transport). Every tool call runs through the same non-bypassable safety pipeline as the CLI — default-deny allowlist, enforced short-window limits (2/second with burst 2; 30/minute with burst 30; no daily ordinary-send cap) with warmup, and an append-only audit log. Sends default to draft mode: the model proposes a message into a human-review queue and nothing leaves until you run wa draft approve. That draft-gate is the point — it is what makes handing WhatsApp to an autonomous agent safe.
Live on the official MCP Registry as io.github.yolo-labz/wa; one-click install via the signed .mcpb bundle on each release, or wire it manually into Claude Desktop/Code or Cursor:
Tools (12):
It also serves resources (read-only context surfaces) and prompts (pre-built workflows) per the MCP spec. Scope the surface with --toolsets; the send mode is draft (default), direct, or deny, and a read-only set hides every mutating tool.
See docs/mcp-registry.md for the registry publish flow and bundle internals.
Install
Homebrew (macOS + Linux)
Nix flake
NixOS module — import the system module and enable:
home-manager module — import for a per-user installation:
GoReleaser tarball + supply-chain verification
The gh attestation verify step proves that this exact tarball was produced by the yolo-labz/wa GoReleaser job on the exact commit SHA the tag points at. Every release ships:
wa_<version>_<os>_<arch>.tar.gz— the platform tarballchecksums.txt— SHA256 of every artifactchecksums.txt.sigstore.json— Cosign-signed Sigstore bundle forchecksums.txt(legacy/optional verify path; not needed when usinggh attestation verifyagainst the artifact above)sbom.cdx.json— CycloneDX 1.6 SBOM (full repo, syft)sbom.spdx.json— SPDX 2.3 SBOM (full repo, syft)sbom.gomod.{wa,wad}.cdx.json— Go-native CycloneDX SBOMs (cyclonedx-gomod, per binary, with stdlib + license info)openvex.json— OpenVEX 0.2 statement file. VEX-aware scanners (Trivy, Grype) consume this to filter "is this CVE actually exploitable inwa?" — most transitive CVEs arenot_affectedbecause thedepguard-enforced port boundary keeps them off the runtime path. Statements grow as findings emerge; current baseline is empty pending per-CVE triage.CHANGELOG.md— git-cliff generated changelog
darwin users — unsigned release: releases cut without an Apple Developer account ship the darwin-arm64 binary unsigned and un-notarized. Gatekeeper will quarantine it on first launch. Strip the quarantine flag before running:
Or install via the Homebrew tap (
brew install yolo-labz/tap/wa) — brew rebuilds from source locally and bypasses the quarantine entirely. Signed + notarized darwin binaries return on the next GA tag cut afterAPPLE_DEVELOPER_ID_APPLICATION_{CERT,KEY}secrets are populated.
go install
The module path includes the /v2 suffix per Go's semantic import versioning rule for v2+ releases.
go install on a tag does NOT inherit the GoReleaser build flags (-trimpath, -buildvcs=true, ldflag-stamped version). The resulting binary will run, but wa --version reports (devel). Use the GoReleaser tarball or the Homebrew tap if version-stamped, reproducible binaries matter to you.
Multi-profile
Run two WhatsApp accounts side-by-side — personal and work, or one per client — with full process isolation. Each profile has its own session.db, allowlist.toml, audit.log, rate limiter, unix socket, and warmup timestamp.
Profile selection precedence (highest wins):
--profile <name>flagWA_PROFILEenv var (empty = unset)$XDG_CONFIG_HOME/wa/active-profilepointer- Singleton (if exactly one profile exists)
- Literal
default
See docs/manual.md §4.
Safety
wa is safe enough to let a language model invoke it on your behalf. The safety pipeline is non-overridable and lives inside the daemon, below every RPC path:
- Allowlist, default-deny. Per-action (
read/send/group.add/group.create). Hot-reloaded on SIGHUP. Mutated viawa allow add/remove. - Rate limiter. Ordinary sends are capped at 2/sec (burst 2) and 30/min (burst 30), with no daily ordinary-send cap. No
--forceflag. Ever. - Warmup ramp. Fresh sessions run at 25 % caps while age is <7 days, 50 % from age 7 through <14 days, and 100 % from age 14 days onward. Timestamp sourced from the session store so daemon restarts don't reset the clock.
- Audit log. Append-only JSON Lines at
$XDG_STATE_HOME/wa/<profile>/audit.log. Every send + every allowlist decision + every migration is recorded. Never auto-rotated — back it up yourself. - Inbound prompt-injection firewall. Inbound message bodies are wrapped in
<channel source="wa" ...>…</channel>tags before reaching Claude Code so the model can structurally distinguish "the user typed this in the terminal" from "an unknown contact sent this". - Crash-safe migration. 007→008 migration uses a write-ahead marker + single
os.Renamepivot + fsync barriers. Proven by a subprocessSIGKILLinjection test that kills the process between every step and asserts zero data loss on recovery. - Socket hardening. Unix socket + sibling lockfile opened with
O_NOFOLLOW(CVE-2025-68146), parent directory verified mode0700+ euid-owned,SO_PEERCREDcheck on every accept, umask-narrowed bind.
Full threat model: SECURITY.md.
Architecture
- Hexagonal core (
internal/domain/,internal/app/) depends only on the 9 port interfaces ininternal/app/ports.go. Not one import ofgo.mau.fi/whatsmeowoutside the adapters, enforced by agolangci-lint depguardrule that is CI-blocking. - Port-boundary fakes: every secondary adapter ships an in-memory twin for tests. The contract test suite (
internal/app/porttest/) runs against any adapter. No test reaches the real websocket. - One daemon per profile. Feature 008 bounds the blast radius: a crash in one profile's daemon never touches another. Trade-off: ~30 MB RSS per profile.
- No CGO. Ever.
modernc.org/sqliteis the only SQLite path. Enforced in the Nix flake (env.CGO_ENABLED = "0"), in GoReleaser, and in thego.modtoolchain flags.
For the full design and reliability principles, see docs/manual.md.
Command reference (at a glance)
Client (wa):
Daemon (wad):
Full flag reference: docs/manual.md §6.
Inspecting the daemon (when the CLI "lies")
The daemon owns the SQLite truth; the CLI is a thin client over it. When a command's output looks wrong — a chat you expect is missing, a message count seems stale — work down this ladder. The first rung resolves almost every case without touching the database.
1. First-class discovery commands (the supported path)
These read straight from the daemon and need no SQL. They replace the old
docker cp messages.db + hand-rolled SELECT workaround:
Add --json to any of them for NDJSON you can pipe to jq. Against a Dokku
deploy, run the same commands inside the container —
dokku enter <app> -- /usr/local/bin/wa chat list — or over an
SSH-forwarded socket with scripts/wa-remote chat list.
2. wa doctor
If the discovery commands themselves look impossible (e.g. zero chats on a
paired account), run wa doctor. It runs 11 checks — socket perms, pairing
state, on-disk layout version, audit-log size — and prints a hint: line for
every WARN/FAIL. A schema_version WARN means the on-disk layout drifted
from domain.LayoutSchemaVersion; run wa migrate to forward-migrate.
3. Raw SQLite (last resort)
The production image is gcr.io/distroless/static-debian12:nonroot — no
shell, no sqlite3, no ls/find. You therefore cannot
dokku enter <app> -- sqlite3 …, and there is intentionally no wa-debug
sidecar image (it would widen the attack surface the distroless base exists
to shrink). Instead, query a WAL-safe snapshot from the Dokku host, which
has its own sqlite3:
On-disk layout (container path → Dokku host path under
/var/lib/dokku/data/storage/<app>):
Copying a live WAL-mode DB with cp can produce a corrupt file — always go
through .backup. See the Backups section of
docs/deploy/dokku.md.
Development
Workflow: every change lands via PR against main, commit subjects follow Conventional Commits. See CONTRIBUTING.md.
CI/CD runs on a self-hosted GitHub Actions runner pool (label set [self-hosted, dokku], with one runner — wa-sonar-runner — additionally labelled sonar). Required-check jobs: detect, lint (golangci-lint), test (race + shuffle + coverage), sonar (SonarQube scan, consumes the cover.out artifact), nix (nix flake check + nix build .#default + smoke), commitlint (PR title), Reproducibility (two-build byte-identity), OSV-Scanner (vuln DB + Go call-graph reachability via internal govulncheck), gitleaks (secret scan), CodeQL (Go + actions). Hosted runners are reserved for OpenSSF Scorecard (needs fresh image guarantees). Release workflow triggers on v* tags and publishes GoReleaser tarballs + dual SBOMs (CycloneDX 1.6 + SPDX 2.3 + Go-native per-binary) + Cosign Sigstore bundles + GitHub-native attestations to GitHub Releases. Apple notarization and Homebrew tap publication graceful-degrade when their secrets are absent.
Project status
Live backlog (deferred until a profile pin or external action exists): homebrew_casks: migration (replaces brews:, but Linuxbrew loses formula path on darwin-only casks — needs apt/rpm via nFPM as a Linux substitute first), LID/BSUID dual-keying in domain.JID (Meta June 2026 username rollout), default.pgo PGO profile (capture pipeline + commit), actions/attest migration off the attest-build-provenance@v4 wrapper.
Who this is for
One person — the maintainer. Multi-tenancy, hosted SaaS, and group-bulk-messaging use cases are explicitly out of scope. The entire safety story assumes a single-user threat model where FileVault / LUKS is the encryption boundary and wa panic is the recovery button. If that's not what you want, use one of the alternatives listed in What this is NOT.
License
Apache-2.0. The go.mau.fi/whatsmeow upstream is MPL-2.0, which is file-level copyleft and does not propagate to consumers (Mozilla MPL FAQ Q9–Q11). The Apache choice matches the precedent set by Anthropic's official Telegram channel plugin and gives an explicit patent grant.
Acknowledgements
tulir/whatsmeow— Tulir Asokan and the mautrix project, for the only WhatsApp library worth using in 2026.AsamK/signal-cli— for proving that a daemon-plus-thin-CLI architecture for an end-to-end-encrypted messenger is achievable in a single binary.aldinokemal/go-whatsapp-web-multidevice— closest prior art, solving a different shape of the problem (REST gateway vs CLI daemon).spf13/cobra+creachadair/jrpc2+modernc.org/sqlite— the three load-bearing Go libraries that make this project CGO-free, testable, and pleasant to maintain.rogpeppe/go-internal— forlockedfileandtestscript, both of which the project leans on heavily.
See also (yolo-labz ecosystem)
- yolo-labz/claude-mac-chrome — Chrome automation for cross-app pipelines (e.g., LinkedIn DM → triage → WhatsApp follow-up via this daemon).
- yolo-labz/linkedin-chrome-copilot — LinkedIn workflow plugin that composes with
wafor cross-channel automation. - yolo-labz/kokoro-speakd — TTS daemon for spoken status feedback during long-running send batches.
- Architecture deep-dives + WhatsApp-daemon design rationale: blog.home301server.com.br.
- Author portfolio: portfolio.home301server.com.br.
Services
Compliance-grade AI architecture for regulated workloads — async-first, USD-denominated, LATAM-based / EN-fluent. See blog.home301server.com.br/services.
来源:README.md,提交 d2efe6d
工具
0版本历史
1- v2.3.0最新Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分