
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 多裝置工作階段(QR 碼或手機號碼配對),且需在允許清單中為每個收件人授予傳送/讀取權限。支援 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 分