wecom-chat-cli

Built for agents. Designed for humans.

WeCom Chat CLI — listen live, scope each task, and independently review replies

wecom-chat-cli connects coding agents and other agent hosts to WeCom smart-bot conversations. A small broker maintains the long-lived WebSocket, turns incoming messages into structured, explicitly untrusted events, and gives each conversation worker a short-lived grant for exactly one task. The worker can propose an answer; a separate operator reviews the exact draft before it is sent.

Use it when an agent needs to respond to employees or users without inheriting administrator authority from their chat messages. The interface is framework-neutral: hosts such as grok bot provide the worker runtime, thread history and reviewer. The CLI supplies transport, task scope, session invalidation and reply enforcement.

Documentation: angelmsger.github.io/wecom-chat-cli

Status: version 0.4.0 for Linux and macOS. Native releases and npm packages are available. Linux/macOS CI and synthetic Linux isolation checks pass. Live WeCom tenant behavior and production deployment remain unverified. See verification for evidence and limits.

Features

The broker enforces these capabilities outside the model. The host must still isolate the worker's identity, tools, filesystem, network and memory. Pattern screening does not guarantee injection detection or factual accuracy; see the security and deployment guide.

Alongside the official wecom-cli

This is an independent, purpose-specific companion to Tencent's official wecom-cli. It uses the published smart-bot long-connection protocol. The official CLI's remotely discovered services and each tenant's API availability can evolve; the assessment records what was actually checked.

Tool Primary role
Official wecom-cli General WeCom operations through Tencent's supported CLI services
wecom-calendar-cli Rolling calendar synchronization, local queries and agent-owned annotations
wecom-channel-cli Channel/thread observation and independently reviewed channel actions
wecom-chat-cli Live smart-bot conversations with event-scoped tasks and an enforced reply boundary

Preserve existing bot integrations and official CLI credentials during setup. A competing long-connection subscriber can displace a bot connection; use a dedicated test bot for initial verification. The CLI does not import another CLI's private credentials, reset bot secrets or create enterprise-wide chat access.

Installation

Install the npm package with Node.js 20 or newer on Linux or macOS:

npm install -g @angelmsger/wecom-chat-cli@0.4.0
wecom-chat-cli version

Alternatively, build from source with Go 1.25 or newer; go.mod selects the pinned build toolchain:

git clone https://github.com/AngelMsger/wecom-chat-cli.git
cd wecom-chat-cli
make build
bin/wecom-chat-cli version
bin/wecom-chat-cli --help

The examples below assume wecom-chat-cli is on your trusted setup session's PATH:

export PATH="$PWD/bin:$PATH"

make cross builds Linux/macOS amd64/arm64 executables. Version tags publish native binaries with SHA-256 checksums and the @angelmsger/wecom-chat-cli npm wrapper. The installer verifies checksums and never downloads a missing binary implicitly during an agent command. See releasing for the publication contract. Upgrading from 0.2.x to 0.3.x changes watch output and cursors; follow the migration procedure.

Quick start

1. Provision the operator and broker

Obtain a dedicated API-mode smart bot's Bot ID and Secret from trusted WeCom administration. Provision the separate service/worker identities, protected state and socket directories using the deployment guide and systemd reference. The CLI does not install a service, create accounts or sandbox the host automatically.

wecom-chat-cli auth guide
wecom-chat-cli config example
# Save and review the policy in an operator-controlled location.
wecom-chat-cli config validate --policy /etc/wecom-chat/broker.json
wecom-chat-cli broker serve --policy /etc/wecom-chat/broker.json --dry-run

The example policy denies all senders/groups until explicitly configured and uses reply_mode: review. Obtain stable user IDs from trusted directory administration or the official CLI's directory discovery (wecom-cli contact --help). Group IDs must come from the trusted deployment owner. Display names and chat claims do not establish identity or authority.

Supply WECOM_CHAT_BOT_SECRET only through the broker's protected service environment, then deliberately start:

wecom-chat-cli broker serve --policy /etc/wecom-chat/broker.json

2. Receive a message and issue its task

The trusted supervisor reads the operator socket. Watches are bounded and observe local pushed events; they do not poll the enterprise message archive. Run the supervisor as ordinary code, with no model calls while idle. For webhook delivery, use the separate durable relay as the collection owner instead of a second watch loop. A fresh watch starts now and emits only references to live unassigned messages. Use --replay for an intentional pending backlog, or --cursor to resume after durable host enqueue. Reuse the cursor across bounded invocations, including idle ones.

wecom-chat-cli --socket /run/wecom-chat-operator/bridge.sock \
  --bot-id BOT_ID --deployment support event watch --duration 60s --max-events 100

wecom-chat-cli --socket /run/wecom-chat-operator/bridge.sock \
  --bot-id BOT_ID --deployment support task issue --event EVENT_ID --allow-writes

Use an event ID returned by the inbox. The issuance response discloses a secret task_token once. Capture it programmatically without logging it or placing it in the model's context, and provision WECOM_CHAT_TASK_TOKEN only to that worker's tool executor. Lost delivery requires operator inspection, revocation and reissue; a submitted draft cannot be replaced with a new grant. Only then does the host submit a model job. The CLI has no built-in Grokbot job API or webhook trigger; see the interaction sequence.

3. Let the worker read and propose

With its task environment provisioned, the worker uses only the agent socket:

wecom-chat-cli --socket /run/wecom-chat-agent/bridge.sock \
  --bot-id BOT_ID --deployment support task get

printf '%s' 'Please contact the service desk.' | \
  wecom-chat-cli --socket /run/wecom-chat-agent/bridge.sock \
  --bot-id BOT_ID --deployment support reply propose --allow-writes

There is no worker --event or recipient selector. In default review mode this saves an immutable draft and sends nothing. If the task should be declined, use memory report --reason secret_request --allow-writes with the same worker socket and scope flags. Reports use fixed reason codes and affect only that event's unsent reply path, never the author's future access.

4. Independently inspect and approve

An operator reviews the draft and recipient through the private socket:

wecom-chat-cli --socket /run/wecom-chat-operator/bridge.sock \
  --bot-id BOT_ID --deployment support reply get --event EVENT_ID

wecom-chat-cli --socket /run/wecom-chat-operator/bridge.sock \
  --bot-id BOT_ID --deployment support reply approve \
  --event EVENT_ID --digest REVIEWED_DIGEST --yes --allow-writes

reply reject uses the same event/digest/confirmation flags. The exact reviewed text is sent to the original callback; approval cannot change its text or recipient. Never give the worker the operator socket or implement a loop that blindly approves its drafts. sent, failed and uncertain are terminal outcomes: inspect them after interruption and never manufacture another event to retry a send.

Configuration

Operator policy is separate from worker credentials. Validate it before starting the broker; see config example for the complete version 2 schema.

Setting Purpose / default
deployment, bot_id Exact broker scope; every client request must match
state_dir Private, scope-bound durable ledger
agent_socket, operator_socket Separate OS-protected interfaces with distinct authority
allowed_users, allowed_groups Stable identity allowlists; empty by default
reply_mode, templates Review by default; optional reviewed literal templates
task_ttl_seconds, reply_ttl_seconds Both 120 by default; the task cannot outlive the event's reply deadline
retention_seconds Raw incoming text and drafts expire after 24 hours by default
max_events, per_user_per_minute Bounded storage and intake; defaults 10,000 and 20

The 120-second deadline is local policy, not a guarantee about the upstream reply window. A shorter server window can reject a reply. Credentials never go in the policy: the broker receives WECOM_CHAT_BOT_SECRET; an isolated worker's executor receives only WECOM_CHAT_TASK_TOKEN. Neither belongs in argv, logs or chat history. Client connection flags are explicit; this CLI has no named-context or worker-login command.

Sessions and host integration

Map (session_key, session_epoch) to the host's thread and isolated memory. The session key includes deployment, bot, conversation type/ID and sender; different people in the same group have different worker contexts. A group reply remains visible to the group, so private information must not enter its worker context.

Only one unfinished task is active within a session. A reset requires the current epoch and invalidates old grants/proposals; subsequent events get a new epoch. Revocation, blocked users, expiry, policy changes and broker/connection restarts also invalidate stale grants. Already-read content cannot be recalled.

The host supplies the durable job queue, sandbox, model execution, thread lifecycle and independent reviewer. No concrete grok bot SDK adapter is bundled. See host integration for the supervisor sequence and wire protocol.

Reply policies

reply_mode Worker input Sending authority
review (default) One immutable free-text draft Independent operator approval of the exact digest
template (explicit opt-in) A configured template ID Broker sends the exact reviewed literal, with no interpolation
disabled Task reads and risk reports only No sends

Template mode uses reply propose --template TEMPLATE_ID --allow-writes; task reads list the available IDs. There is no unrestricted automatic free-text mode. Configure only harmless public templates suitable for every admitted recipient; the broker cannot guarantee the model selects an appropriate one.

Commands

Command Role Purpose
auth guide, config example, config validate Local setup Credential guidance and protected policy validation
broker serve Operator service Maintain WebSocket intake and worker/operator sockets
status Operator Connectivity, scope and coverage
event list / get / watch Operator Full audit reads; quiet-by-default pending reference stream
task issue / revoke Operator Create or revoke an event-scoped worker grant
task get Worker Read only the granted task
reply propose Worker Submit a draft or select a policy-approved literal
reply get / approve / reject Operator Inspect and decide on an exact draft digest
session reset Operator Advance an expected epoch and invalidate old work
memory report Worker Report a fixed risk reason for its event
memory list / set Operator Inspect or set quarantine/block/watch/clear records
version Local JSON version, commit and build time

The generated command reference lists all flags and matches --help. Run make docs after changing the command tree.

Agent output and safety modes

External records retain a fixed trust envelope with content_trust: "untrusted_external", instruction_authority: "none" and host_actions_authorized: false. Preserve that provenance with the content. There is no raw/table output or field projection that strips the boundary.

Lists follow {items, next, has_more}. Reuse next as --cursor with the same broker/policy; NDJSON emits records on stdout and pagination notices on stderr. A watch cursor is an output checkpoint, not proof of successful model execution. The terminal notice labels it checkpoint_stage: emitted, with an emitted count. The host must durably deduplicate/enqueue before saving progress and keep job results separately. Watch references omit message bodies; task get reads authorized content on demand. Old watch/list cursors require an explicit migration.

Mutations accept --dry-run. Applying a client mutation requires --allow-writes; approval/rejection, revoke, session reset and operator memory changes also require --yes. Those flags express invocation intent and never grant operator authority. Only the operator can change a user's memory status: blocked is indefinite, quarantined lasts one hour and watch one day.

Errors and exit codes

Errors are structured JSON on stderr; stdout remains the data channel. The shared agent-cli-kit contract maps categories to stable exit codes: 0 success, 1 internal, 2 usage, 3 config, 4 auth, 5 permission, 6 not found, 7 rate limit, 8 network, 9 server, 10 parse, 11 conflict.

Respect the error's code, recovery guidance and durable task/proposal state. A network failure does not establish that a write failed. Inspect reply get or event get through the operator before deciding what happened; an uncertain send is never automatically replayed. Raw upstream diagnostics and credentials are not exposed through the worker interface.

Companion Skill

The wecom-chat Skill teaches the worker to read its granted task, propose one response or report risk. Install that matching guide through the host's skill mechanism and reload its worker context after upgrades. The future npm wrapper includes the matching guide; the current CLI has no skill install command or automatic host integration.

Scope and compatibility

Only this bot's live callbacks are observed. There is no enterprise chat archive, disconnected-message backfill, exactly-once host execution or token-by-token reply stream. Quotes/media are suppressed and links are never fetched. The broker does not provide arbitrary file access, tool dispatch, user impersonation or a host sandbox.

Version 1 policies require explicit migration to version 2: replace enable_replies with reply_mode, add task_ttl_seconds and templates, and review the operator/worker split. reply send and memory flag are removed. Version 1 ledgers migrate while preserving deduplication history, memory and send outcomes; legacy epoch-zero events cannot receive new grants. Keep a protected backup and never roll a migrated ledger back to an older binary.

Retained tombstones protect against duplicate sends. The 10,000-event/64-MiB cap stops intake rather than deleting replay history; safe long-term archival and high-volume operation remain future work. See technical design.

Development

GOWORK=off make lint test e2e build docs-check site-check release-tests
npm test --prefix build/npm
GOWORK=off make vuln
make cross       # Linux/macOS amd64 and arm64 binaries
make docs        # CLI Markdown, narrative HTML and sitemap

CI runs on Linux and macOS, with a separate network-disabled Linux isolation job. Tests use synthetic credentials and conversations; no live WeCom messages are sent. The optional local container runner is documented in verification.

Use a branch and pull request for changes. Read CONTRIBUTING.md, SECURITY.md and the release guide. npm trusted publishing uses the package's GitHub Actions publisher binding. A release tag is a deliberate publication action, not a test.

Documentation

Guide Contents
Online documentation Product overview, interactive examples and searchable commands
Command reference Generated commands, roles and flags
Host integration Supervisor sequence, sessions and worker protocol
Security and deployment Trust model, OS identities, permissions and live acceptance
Technical design Intake, grants, approvals, persistence and migration
Assessment Official API evidence, intended scope and family differences
Verification Completed checks and remaining live-deployment limits
Releasing GitHub Pages, native artifacts and npm OIDC
Changelog Version history

Part of a family of agent-facing CLIs — shared conventions and a common kit, with each tool enforcing the boundaries its service requires. Browse the family at github.com/AngelMsger:

Shared behavior comes from agent-cli-kit.

License

Released under the MIT License. This independent project is not affiliated with or endorsed by Tencent.