annodex

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

ScenarioRecommended channel
Lab colleague asks on mobile: “Is QC done?”WeCom IM
Interactive flowchart, UI prototype, Generative UI demoBrowser chat (show-widget)
Push PNG/PDF reports to WeComWeCom IM (MEDIA: attachments)
Review IM history, preview images, fork branches in browserBrowser (sessions marked [IM] in sidebar)

One-line positioning: IM = mobile/collab entry + fixed-project agent; browser = full workspace (Generative UI, many sessions, file preview).

Annodex IM architecture: WeCom user, gateway, Annodex server, Codex thread, and config paths

Dual channel (Generative UI is not deprecated)

Browser and WeCom use different Codex threads and different system prompts, but serve the same project:

Browser chat vs WeCom IM capabilities
CapabilityBrowser chatWeCom 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 countmany browser sessions + branchesone IM thread per project
User isolationper browser sessionv1: all paired users share IM context
Sidebar labelnormal sessionsIM 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

  1. Start annodex (annodex or npm run dev in the repo).
  2. Open Settings → Project and select the project.
  3. Expand WeCom IM.
  4. Turn on WeCom bot for this project.
  5. Enter Bot ID and Bot secret from your WeCom AI bot console.
  6. Click Save IM settings.
  7. 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-gateway

On 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

WeCom IM pairing: first message, send code, paired, normal chat

Every WeCom message goes through pairing / allowlist checks before the agent runs.

StepWhat the user doesWhat annodex returns
First contact (not paired)Sends any normal messageInstructions: project name + “Send pairing code XXXXXX to authorize…” — no agent run
PairingSends the pairing code exactly, or PAIR XXXXXX (case-insensitive)“Paired successfully…” — userid added to allowedUsers
Already pairedSends the pairing code again“You are already paired with this project bot.”
After pairingSends a normal questionAgent 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

ControlPurpose
WeCom bot for this projectMaster enable switch; toggling saves immediately
Bot ID / Bot secretFrom WeCom AI bot console; leave secret blank to keep the stored value
Require @mention in group chatsDefault on — group messages must @ the bot
Bound group chat idOptional — restrict the bot to one group
Allowed WeCom user idsManual allowlist (one userid per line)
Save IM settingsPersist Bot ID, secret, group options, and allowlist
Regenerate pairing codeInvalidates the old code; unpaired users need the new code
Reset IM threadDeletes 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:)

MEDIA tag flow: agent saves file, reply tag, browser preview, WeCom upload

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
ChannelBehavior
BrowserHide the MEDIA: line; inline preview PNG/JPG below the message (works alongside show-widget)
WeComHide MEDIA: and show-widget in streamed text; gateway tries native image/file upload after streaming
Enterprise permissionWeCom behavior
Enabled bot image/file uploadAttachments sent as native image or file messages
Disabled or upload failsA 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.

SituationReply
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

PathContents
{project}/.annodex/im.jsonenabled, botId, pairing code, allowlist, group options (safe to commit without secret)
~/.config/annodex/im-secrets/<sha1(cwd)>.jsonbotSecret — written by annodex server; never returned by public GET APIs
~/.config/annodex/im-sessions/<sha1(cwd)>.jsonpersistent IM Codex sessionId
~/.config/annodex/im-gateway.jsongateway auth token (auto-created on first IM save)

Override config root with ANNODEX_CONFIG_DIR (same variable for annodex and the gateway).

Gateway environment

VariablePurpose
ANNODEX_URL / ANNODEX_HOST / ANNODEX_PORTannodex base URL (default http://127.0.0.1:30121)
ANNODEX_CONFIG_DIRconfig 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:

  1. Same Linux account — simplest: run both annodex and annodex im-gateway as the service user.
  2. Same ANNODEX_CONFIG_DIR — if accounts differ, point both processes at one writable config directory (defaults to each user’s $HOME/.config/annodex).
  3. Executable — if annodex-im-gateway reports “Permission denied”, install for the runtime user (npm install -g @seqyuan/annodex) or use annodex im-gateway from a user-writable install.
export ANNODEX_CONFIG_DIR=/path/shared/with-annodex-server
annodex im-gateway

The 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)

EndpointMethodPurpose
/api/im/project?cwd=GETPublic IM config + gateway token hint
/api/im/projectPUTUpdate IM settings from UI
/api/im/project?cwd=DELETEReset IM thread
/api/im/projectsGETEnabled projects for gateway (includes botSecret)
/api/im/gateway-tokenGETGateway token + configDir sync (localhost only)
/api/im/session-idsGETAll IM Codex sessionIds (sidebar [IM] badge)
/api/im/turnPOSTOne IM turn — JSON { ok, reply, sessionId?, paired? }
/api/im/turn?stream=1POSTSame, but SSE events: status, delta, done (gateway uses this)
/api/im/cancelPOSTCancel 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.

On this page