iLink-compatible multiplexer hub for WeChat ClawBot — connect one WeChat account to multiple AI agent backends running on different machines or workspaces, with zero client-side code changes.
WeChat ClawBot's iLink API enforces an exclusive lock: only one process can poll getupdates at a time. If you run Recursive on your Mac, Recursive on a server, and OpenClaw on your laptop — they all fight for the same connection, and only one wins.
iLink Hub is a transparent iLink proxy:
[WeChat User]
↕ real iLink protocol
[iLink Hub] ← the sole connection holder
↕ emulated iLink API (same HTTP endpoints, same protocol)
┌───────────────┐ ┌────────────────────┐ ┌────────────────┐
│Recursive (Mac)│ │Recursive (Server) │ │OpenClaw (etc.) │
│base_url=hub │ │base_url=hub │ │base_url=hub │
│token=vhub_abc │ │token=vhub_def │ │token=vhub_xyz │
└───────────────┘ └────────────────────┘ └────────────────┘
Clients don't need any code changes — just point WEIXIN_BASE_URL at the Hub and use a virtual token. The Hub handles multiplexing, routing, and token mapping transparently.
- iLink-compatible API — any existing iLink client works out-of-the-box
- Multi-backend routing — route messages to different backends via WeChat commands
- Context-token mapping — real context tokens never leak to clients; persisted across restarts
- QR code login — scan once, token saved to DB
- Multi-database — SQLite (default), PostgreSQL, MySQL via
DATABASE_URL - Full persistence — client registrations, routing state, and context mappings survive restarts
- Web admin panel — manage clients and copy config at
/hub/ui - Admin auth — protect
/hub/endpoints withILINK_ADMIN_TOKENenv var - Bounded queues — per-client message buffer capped at 200 to prevent OOM
- Prometheus metrics — counters and gauges at
/metrics - Friendly fallback — when all backends are offline, WeChat users get an instant reply
- Pre-built binaries — download from GitHub Releases (Linux/macOS/Windows), no Rust required
- Health checks — auto-marks offline clients after 90s idle
- Docker support — single-command deployment, multi-arch image (amd64 + arm64)
# Linux x86_64
curl -Lo ilink-hub https://github.com/jeffkit/ilink-hub/releases/latest/download/ilink-hub-linux-x86_64
chmod +x ilink-hub && sudo mv ilink-hub /usr/local/bin/
# macOS Apple Silicon
curl -Lo ilink-hub https://github.com/jeffkit/ilink-hub/releases/latest/download/ilink-hub-macos-aarch64
chmod +x ilink-hub && sudo mv ilink-hub /usr/local/bin/
# macOS Intel
curl -Lo ilink-hub https://github.com/jeffkit/ilink-hub/releases/latest/download/ilink-hub-macos-x86_64
chmod +x ilink-hub && sudo mv ilink-hub /usr/local/bin/Windows: download
ilink-hub-windows-x86_64.exefrom Releases.
# Install
cargo install ilink-hub
# Step 1: QR login (save token to DB)
ilink-hub login
# Step 2: Start Hub
ilink-hub serve --addr 0.0.0.0:8765
# Step 3: Open web admin panel
# Visit http://your-hub.example.com:8765/hub/ui
# Step 4: Register each backend (CLI or via the web UI)
ilink-hub register --hub-url http://your-hub.example.com \
--name mac-home --label "Mac Home"
# Outputs:
# WEIXIN_BASE_URL=http://your-hub.example.com
# WEIXIN_TOKEN=vhub_xxxxxxxxxxxxxxxx# docker-compose.yml
services:
ilink-hub:
image: ghcr.io/jeffkit/ilink-hub:latest
restart: unless-stopped
ports:
- "8765:8765"
volumes:
- ilink-hub-data:/data
environment:
DATABASE_URL: sqlite:/data/ilink-hub.db
# ILINK_TOKEN: your-token # Optional: skip QR login if you have a token
volumes:
ilink-hub-data:docker compose up -d
# First login (interactive):
docker compose exec ilink-hub ilink-hub loginDATABASE_URL=postgres://user:pass@localhost/ilink_hub ilink-hub serveSend these from WeChat to control the Hub:
| Command | Effect |
|---|---|
/list |
List all registered backends and their status |
/use <name> |
Switch active backend (e.g. /use mac-home) |
/broadcast <text> |
Send a message to all online backends |
/status |
Show Hub status (online/total clients) |
# ~/.recursive/config.toml
[weixin]
base_url = "http://your-hub.example.com"
token = "vhub_xxxxxxxxxxxxxxxx"Or via environment:
WEIXIN_BASE_URL=http://your-hub.example.com
WEIXIN_TOKEN=vhub_xxxxxxxxxxxxxxxx
recursive weixinlet bot = WeChatBot::new(BotOptions {
base_url: Some("http://your-hub.example.com".to_string()),
token: "vhub_xxxxxxxxxxxxxxxx".to_string(),
..Default::default()
});# ~/.openclaw/openclaw.json
{
"channels": {
"weixin": {
"base_url": "http://your-hub.example.com",
"token": "vhub_xxxxxxxxxxxxxxxx"
}
}
}The Hub exposes the full iLink API surface plus Hub-specific management endpoints:
| Method | Path | Description |
|---|---|---|
POST |
/ilink/bot/getupdates |
Long-poll for messages (30s timeout) |
POST |
/ilink/bot/sendmessage |
Send reply (context_token auto-translated) |
POST |
/ilink/bot/sendtyping |
Send typing indicator |
POST |
/ilink/bot/getconfig |
Get typing ticket |
POST |
/ilink/bot/getuploadurl |
Get CDN upload URL |
Authentication: Same as real iLink — Authorization: Bearer <vtoken> header.
| Method | Path | Description |
|---|---|---|
POST |
/hub/register |
Register a new backend client |
GET |
/hub/clients |
List all registered clients (includes vtoken) |
GET |
/hub/ui |
Web admin panel (browser UI) |
GET |
/metrics |
Prometheus-format metrics |
GET |
/health |
Health check |
Admin auth: Set ILINK_ADMIN_TOKEN=<secret> on the Hub. Then pass Authorization: Bearer <secret>
when calling /hub/register or /hub/clients. If the env var is unset, these endpoints are open (suitable
for local dev / private networks).
ilink-hub/
├── src/
│ ├── ilink/
│ │ ├── types.rs — Complete iLink protocol types (mirrors ilinkai.weixin.qq.com)
│ │ ├── upstream.rs — Real iLink poller (exponential backoff, auto-reconnect)
│ │ └── login.rs — QR login flow (terminal QR rendering)
│ ├── hub/
│ │ ├── registry.rs — Client registry (vtoken management)
│ │ ├── router.rs — Message routing + WeChat command parser
│ │ ├── queue.rs — Per-client queues + context_token mapping
│ │ └── health.rs — Background health checker
│ ├── server/
│ │ └── routes.rs — iLink-compatible HTTP handlers
│ ├── store/
│ │ └── mod.rs — sqlx database layer (SQLite/PostgreSQL/MySQL)
│ └── main.rs — CLI: serve / login / register / clients
├── Dockerfile — Multi-stage build
└── .github/workflows/ci.yml
WeChat sends message
↓
Hub polls real iLink getupdates → receives InboundMessage
↓
Router: parse WeChat command or determine target client
↓
Map real context_token → virtual context_token (stored in DB)
↓
Push to target client's queue (notify waiting getupdates long-poll)
↓
Client's getupdates returns the message
↓
Client processes, sends sendmessage with virtual context_token
↓
Hub resolves virtual → real context_token
↓
Hub forwards sendmessage to real iLink
↓
WeChat receives reply ✓
- Deploy behind HTTPS — use a reverse proxy (Nginx, Caddy) with TLS
- Restrict
/hub/admin endpoints — add IP allowlist or Bearer token auth to admin routes - Use PostgreSQL for production — SQLite works but isn't suited for high-concurrency deployments
- Rotate virtual tokens periodically — re-register clients with a new name to get fresh vtokens
- Keep Hub on private network — only expose port 8765 if needed; ideally put Nginx in front
server {
listen 443 ssl;
server_name hub.example.com;
# Only allow your backend IPs to access admin endpoints
location /hub/ {
allow 192.168.1.0/24;
deny all;
proxy_pass http://localhost:8765;
}
# iLink API open to registered clients
location /ilink/ {
proxy_pass http://localhost:8765;
proxy_set_header Host $host;
}
location /health {
proxy_pass http://localhost:8765;
}
}| Project | Protocol for clients | Multi-machine | Standalone |
|---|---|---|---|
| iLink Hub (this) | ✅ iLink-compatible | ✅ Yes | ✅ Yes |
| OpeniLink Hub | ❌ Custom WebSocket/SDK | ✅ Yes | ✅ Yes |
| HermesClaw | ❌ Local proxy only | ❌ No | ✅ Yes |
| wechat-clawbot | HTTP webhook | ✅ Yes | ✅ Yes |
| OpenClaw bindings | ❌ OpenClaw-specific | ❌ Same machine | ✅ Yes |
MIT © 2026 jeffkit