Project IM (WeCom)
Optional per-project WeCom bot — positioning, UI setup, pairing onboarding, gateway sidecar, MEDIA attachments, and browser dual-channel comparison.
Annodex Project IM lets collaborators ask questions about a fixed project directory from WeCom without opening the browser. Each project cwd can optionally bind one WeCom AI bot; the bot always runs with that cwd and cannot switch projects from chat.
This page is the dedicated IM guide (setup, pairing, gateway, attachments, and how IM differs from browser chat). For day-to-day workflow see Usage — Tools.
When to use IM
| Scenario | Recommended channel |
|---|---|
| Lab colleague asks on mobile: “Is QC done?” | WeCom IM |
| Interactive flowchart, UI prototype, Generative UI demo | Browser chat (show-widget) |
| Push PNG/PDF reports to WeCom | WeCom IM (MEDIA: attachments) |
| Review IM history, preview images, fork branches in browser | Browser (sessions marked [IM] in sidebar) |
One-line positioning: IM = mobile/collab entry + fixed-project agent; browser = full workspace (Generative UI, many sessions, file preview).
Dual channel (Generative UI is not deprecated)
Browser and WeCom use different Codex threads and different system prompts, but serve the same project:
| Capability | Browser chat | WeCom IM |
|---|---|---|
Generative UI (show-widget) | ✅ inline flowcharts, charts, UI demos | ❌ WeCom cannot embed HTML widgets |
| MEDIA: preview | ✅ hide tag, show inline image | ✅ gateway uploads native image/file |
| Session count | many browser sessions + branches | one IM thread per project |
| User isolation | per browser session | v1: all paired users share IM context |
| Sidebar label | normal sessions | IM thread shows blue [IM] badge |
Opening the IM thread in the browser still shows full history; existing show-widget and MEDIA: previews work in the browser. The IM system prompt (<wecom_im_channel>) only shapes new WeCom replies — it does not remove Generative UI from browser chat.
End-to-end setup (admin)
1. Enable IM in annodex
- Start annodex (
annodexornpm run devin the repo). - Open Settings → Project and select the project.
- Expand WeCom IM.
- Turn on WeCom bot for this project.
- Enter Bot ID and Bot secret from your WeCom AI bot console.
- Click Save IM settings.
- Copy the Pairing code (also stored in
{project}/.annodex/im.json).
The panel also shows a gateway status pill, one-click copy of annodex im-gateway, and Reset IM thread (clears the IM Codex session while keeping bot + pairing settings).
The project must be registered in annodex (opened at least once in the UI) so the gateway can discover it via GET /api/im/projects.
2. Run the gateway sidecar
The gateway is not part of the Next.js server. Run it in the same Linux account as annodex:
# Terminal 1 — annodex listening (default http://127.0.0.1:30121)
annodex
# Terminal 2 — same user
annodex im-gateway
# or: annodex-im-gatewayOn startup the gateway syncs its auth token from GET /api/im/gateway-token and polls GET /api/im/projects every 30s. Bot secrets are returned by the annodex server over the API — you do not copy secret files to another machine.
If you change IM settings (especially the first save), restart the gateway so the token stays in sync.
3. User pairing flow
Every WeCom message goes through pairing / allowlist checks before the agent runs.
| Step | What the user does | What annodex returns |
|---|---|---|
| First contact (not paired) | Sends any normal message | Instructions: project name + “Send pairing code XXXXXX to authorize…” — no agent run |
| Pairing | Sends the pairing code exactly, or PAIR XXXXXX (case-insensitive) | “Paired successfully…” — userid added to allowedUsers |
| Already paired | Sends the pairing code again | “You are already paired with this project bot.” |
| After pairing | Sends a normal question | Agent runs on the project IM Codex thread; reply streams to WeCom |
Direct messages: send the pairing code as plain text.
Group chats (default @mention rule): @ the bot, then send the pairing code (e.g. @MyBot ABC123). Until paired, @ messages that are not the pairing code still get instructions, not agent output.
Share the pairing code with collaborators out of band (email, wiki, etc.). One code works for many users — each WeCom userid is appended separately when they pair.
Alternatively, an admin can pre-authorize users by listing WeCom userid strings in Allowed WeCom user ids (one per line) and clicking Save IM settings — those users can chat without sending the code first.
Configure in Settings → Project → WeCom IM
| Control | Purpose |
|---|---|
| WeCom bot for this project | Master enable switch; toggling saves immediately |
| Bot ID / Bot secret | From WeCom AI bot console; leave secret blank to keep the stored value |
| Require @mention in group chats | Default on — group messages must @ the bot |
| Bound group chat id | Optional — restrict the bot to one group |
| Allowed WeCom user ids | Manual allowlist (one userid per line) |
| Save IM settings | Persist Bot ID, secret, group options, and allowlist |
| Regenerate pairing code | Invalidates the old code; unpaired users need the new code |
| Reset IM thread | Deletes IM session file and stops in-memory IM wrapper; next WeCom message starts a fresh Codex thread (pairing + bot settings kept) |
Footer panel (when enabled) shows Pairing code, IM session id, Gateway token prefix, and paths for {project}/.annodex/im.json vs server-side secrets.
In the sidebar, IM Codex threads show a blue [IM] badge before the title so you can tell them apart from normal browser sessions.
Charts and attachments (MEDIA:)
When the agent should send a diagram, QC plot, or exported file, it should save under the project directory and include:
MEDIA:/absolute/path/to/diagram.png| Channel | Behavior |
|---|---|
| Browser | Hide the MEDIA: line; inline preview PNG/JPG below the message (works alongside show-widget) |
| WeCom | Hide MEDIA: and show-widget in streamed text; gateway tries native image/file upload after streaming |
| Enterprise permission | WeCom behavior |
|---|---|
| Enabled bot image/file upload | Attachments sent as native image or file messages |
| Disabled or upload fails | A follow-up text message includes the local absolute path |
Replies should still mention file paths in plain text when upload may be disabled.
The IM Codex thread uses a dedicated system prompt (<wecom_im_channel>): save files and use MEDIA: tags; it does not inject browser show-widget rules into the IM thread. Each user message only adds a WeCom user: … prefix.
Cancel an in-progress task
While the agent is running, send 取消, 停止, cancel, or similar to abort the current IM turn. The gateway calls POST /api/im/cancel; if the message reaches the turn API while the session is busy, the same cancel path is used.
| Situation | Reply |
|---|---|
| Task running | 已取消当前任务。 |
| Idle | 当前没有可取消的任务。 |
IM session model
All paired users on a project share one Codex thread for IM (stored under im-sessions). IM conversation context is not isolated per WeCom user in v1.
Browser chat sessions remain separate from the IM thread. Use Reset IM thread when you want a fresh IM conversation context without re-pairing users.
Storage layout
| Path | Contents |
|---|---|
{project}/.annodex/im.json | enabled, botId, pairing code, allowlist, group options (safe to commit without secret) |
~/.config/annodex/im-secrets/<sha1(cwd)>.json | botSecret — written by annodex server; never returned by public GET APIs |
~/.config/annodex/im-sessions/<sha1(cwd)>.json | persistent IM Codex sessionId |
~/.config/annodex/im-gateway.json | gateway auth token (auto-created on first IM save) |
Override config root with ANNODEX_CONFIG_DIR (same variable for annodex and the gateway).
Gateway environment
| Variable | Purpose |
|---|---|
ANNODEX_URL / ANNODEX_HOST / ANNODEX_PORT | annodex base URL (default http://127.0.0.1:30121) |
ANNODEX_CONFIG_DIR | config root for secrets, sessions, and gateway token |
Multi-user / multi-account Linux
If annodex runs as user B but npm global packages were installed by user A:
- Same Linux account — simplest: run both
annodexandannodex im-gatewayas the service user. - Same
ANNODEX_CONFIG_DIR— if accounts differ, point both processes at one writable config directory (defaults to each user’s$HOME/.config/annodex). - Executable — if
annodex-im-gatewayreports “Permission denied”, install for the runtime user (npm install -g @seqyuan/annodex) or useannodex im-gatewayfrom a user-writable install.
export ANNODEX_CONFIG_DIR=/path/shared/with-annodex-server
annodex im-gatewayThe gateway warns when its config directory differs from the annodex server’s.
Streaming replies
The gateway calls POST /api/im/turn with Accept: text/event-stream. While the agent runs, WeCom sees:
(working Ns)while tools are running- Partial assistant text streamed with a fixed
streamId(300ms throttle) - Final message with
finish: true
Pairing and allowlist replies are short JSON responses (no streaming).
API reference (localhost)
| Endpoint | Method | Purpose |
|---|---|---|
/api/im/project?cwd= | GET | Public IM config + gateway token hint |
/api/im/project | PUT | Update IM settings from UI |
/api/im/project?cwd= | DELETE | Reset IM thread |
/api/im/projects | GET | Enabled projects for gateway (includes botSecret) |
/api/im/gateway-token | GET | Gateway token + configDir sync (localhost only) |
/api/im/session-ids | GET | All IM Codex sessionIds (sidebar [IM] badge) |
/api/im/turn | POST | One IM turn — JSON { ok, reply, sessionId?, paired? } |
/api/im/turn?stream=1 | POST | Same, but SSE events: status, delta, done (gateway uses this) |
/api/im/cancel | POST | Cancel the current IM task for a project |
Gateway auth: when im-gateway.json contains a token, requests must send Authorization: Bearer <token>. Without a token, localhost-only access is allowed. Web-auth: localhost requests to /api/im/* bypass login so the gateway works when password auth is enabled.
Example turn (JSON):
POST /api/im/turn
Content-Type: application/json
Authorization: Bearer <token>
{
"cwd": "/path/to/project",
"userId": "wecom-user-id",
"message": "Summarize QC status",
"chatId": null
}Send "message": "ABC123" (your pairing code) first for an unpaired userid to join the allowlist.
Related docs
- Usage — Tools — day-to-day workflow
- Configuration — IM paths
- Project Memory — separate from IM; promote facts to markdown explicitly
- Home — Generative UI — browser
show-widgetflowcharts and UI demos