
Weixin Agent Sdk
Connect a custom or hosted LLM backend to WeChat as a long-polling chatbot without exposing a public webhook server.
Overview
weixin-agent-sdk is an agent skill for the Build phase that wires a TypeScript Agent backend to WeChat using QR login, persisted credentials, and a long-polling message loop.
Install
npx skills add https://github.com/aradotso/trending-skills --skill weixin-agent-sdkWhat is this skill?
- Minimal TypeScript Agent interface with async chat(req) returning { text }
- One-time QR login via login() with credentials persisted under ~/.openclaw/
- start(agent) long-polling message loop via Clawbot channel—no public server required
- npm or pnpm install; Node.js >= 22 required
- Plug in OpenAI, Claude, or any custom backend behind the same Agent contract
Adoption & trust: 934 installs on skills.sh; 31 GitHub stars; 1/3 security scanners passed (skills.sh audits).
What problem does it solve?
You have an LLM or agent backend but no straightforward way to receive and reply on WeChat without hosting a public webhook endpoint.
Who is it for?
Indie builders adding WeChat as a distribution channel for an existing Claude, GPT, or custom agent with a Node 22+ TypeScript service.
Skip if: Teams that need official WeChat Open Platform server callbacks only, or builders not targeting WeChat/Clawbot at all.
When should I use this skill?
Triggers include connecting an AI agent to WeChat, OpenAI/Claude bridge setup, weixin-agent-sdk usage, and ACP agent WeChat integration.
What do I get? / Deliverables
After setup you run login once, implement Agent.chat, and start a persistent WeChat message loop that forwards user text to your backend and sends replies back.
- Running WeChat message loop via start(agent)
- Persisted login credentials after login()
Recommended Skills
Journey fit
WeChat channel wiring is an integration build task once you are implementing the product backend and agent loop. The SDK handles login, credential storage, and the message loop that bridges your Agent implementation to WeChat.
How it compares
Integration skill for WeChat long-polling via weixin-agent-sdk—not a generic MCP server or multi-channel messaging hub.
Common Questions / FAQ
Who is weixin-agent-sdk for?
Solo and indie developers who already have or plan a small TypeScript agent service and want WeChat users to chat with that logic through the SDK’s Agent interface.
When should I use weixin-agent-sdk?
During Build integrations when you need to connect OpenAI or Claude to WeChat, set up the weixin-agent-sdk message loop, or bridge an ACP-style agent backend without a public server.
Is weixin-agent-sdk safe to install?
Review the Security Audits panel on this Prism page and treat persisted credentials under ~/.openclaw/ as secrets on the host that runs login and start.
SKILL.md
READMESKILL.md - Weixin Agent Sdk
# weixin-agent-sdk > Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. `weixin-agent-sdk` is a TypeScript framework that bridges any AI backend to WeChat (微信) via the Clawbot channel. It uses long-polling to receive messages — no public server required — and exposes a minimal `Agent` interface so you can plug in OpenAI, Claude, or any custom logic in minutes. --- ## Installation ```bash # npm npm install weixin-agent-sdk # pnpm (monorepo) pnpm add weixin-agent-sdk ``` Node.js >= 22 required. --- ## Quick Start ### 1. Login (scan QR code once) ```typescript import { login } from "weixin-agent-sdk"; await login(); // Credentials are persisted to ~/.openclaw/ — run once, then use start() ``` ### 2. Implement the Agent interface ```typescript import { login, start, type Agent } from "weixin-agent-sdk"; const echo: Agent = { async chat(req) { return { text: `You said: ${req.text}` }; }, }; await login(); await start(echo); ``` --- ## Core API ### `Agent` Interface ```typescript interface Agent { chat(request: ChatRequest): Promise<ChatResponse>; } interface ChatRequest { conversationId: string; // Unique user/conversation identifier text: string; // Message text content media?: { type: "image" | "audio" | "video" | "file"; filePath: string; // Local path (already downloaded & decrypted) mimeType: string; fileName?: string; }; } interface ChatResponse { text?: string; // Markdown supported; auto-converted to plain text media?: { type: "image" | "video" | "file"; url: string; // Local path OR HTTPS URL (auto-downloaded) fileName?: string; }; } ``` ### `login()` Triggers QR code scan and persists session to `~/.openclaw/`. Only needs to run once. ### `start(agent)` Starts the message loop. Blocks until process exits. Automatically reconnects on session expiry. --- ## Common Patterns ### Multi-turn Conversation with History ```typescript import { login, start, type Agent } from "weixin-agent-sdk"; const conversations = new Map<string, string[]>(); const myAgent: Agent = { async chat(req) { const history = conversations.get(req.conversationId) ?? []; history.push(`user: ${req.text}`); const reply = await callMyAIService(history); history.push(`assistant: ${reply}`); conversations.set(req.conversationId, history); return { text: reply }; }, }; await login(); await start(myAgent); ``` ### OpenAI Agent (Full Example) ```typescript import OpenAI from "openai"; import { login, start, type Agent, type ChatRequest } from "weixin-agent-sdk"; import * as fs from "fs"; const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, baseURL: process.env.OPENAI_BASE_URL, // optional override }); const model = process.env.OPENAI_MODEL ?? "gpt-4o"; const systemPrompt = process.env.SYSTEM_PROMPT ?? "You are a helpful assistant."; type Message = OpenAI.Chat.ChatCompletionMessageParam; const histories = new Map<string, Message[]>(); const openaiAgent: Agent = { async chat(req: ChatRequest) { const history = histories.get(req.conversationId) ?? []; // Build user message — support image input const content: OpenAI.Chat.ChatCompletionContentPart[] = []; if (req.text) { content.push({ type: "text", text: req.text }); } if (req.media?.type === "image") { const imageData = fs.readFileSync(req.media.filePath).toString("base64"); content.push({ type: "image_url", i