TypeScript · ESM · Plugin Runtime
Write once in TypeScript. Run your bot on QQ, WeChat, Lark, DingTalk, Discord, Telegram, and 20+ chat platforms. File-based commands, cross-platform JSX cards, leak-free hot reload, and opt-in AI agents — managed from the browser.
$ npm create zhin-app my-bot -y && cd my-bot && pnpm dev
✔ Bot started — open http://127.0.0.1:8068/sandbox to chat immediately (no account or model key needed)You don't need to learn the whole architecture upfront. Pick a goal — each path fits in one sitting.
Zero platform accounts or API keys — get your first reply in the local /sandbox or Remote Console.
10-min Quick Start STEP 2 · BUILDWrite commands, cards & AI toolsCommands, cross-platform JSX button cards, middleware, cron jobs, and AI tools — drop a file in a folder and save to hot-reload.
Plugin Authoring STEP 3 · SHIPConnect platforms & go liveRun npx zhin setup --adapters for QQ / WeChat / Lark / Discord and deploy to production.
Choose an adapter NO-CODE · OPERATEOperators & group ownersRead messages, edit form settings, configure welcomes & reminders, and approve risky actions in Console.
Operator GuideQQ, WeChat, WeCom, DingTalk, Lark, Discord, Telegram, Slack, KOOK, LINE… Your code sees one unified message; adapters handle platform differences.
commands/hello/index.ts is the /hello command. Middleware, JSX components, schedules, and AI tools work the same way — zero registration boilerplate.
Save to hot-reload. In-flight messages finish on the old version, and if new code throws on startup, the previous version keeps serving.
Open http://127.0.0.1:8068/sandbox for an instant simulated chat window — build and test everything without a platform account or model key.
Connect console.zhin.dev to your bot: send test messages, inspect logs, edit schema forms, and manage plugins with zero frontend deployment.
The default install is a lean IM core under 10MB. Run npx zhin setup --ai to add LLMs, tools, 3-layer memory, and MCP.
File-based command + Cross-platform JSX card (commands/poll/index.tsx): renders native interactive buttons where supported, and automatically degrades to numbered text choices on plain-text platforms.
import { defineCommand } from 'zhin.js/command';
export default defineCommand({
description: 'Start a quick poll',
params: { topic: { type: 'text', default: 'Ship v1.2 today?' } },
execute: ({ params }) => (
<card title={`📊 ${params.topic}`}>
<text>Click a button (or reply with its number):</text>
<button label="👍 Yes" onClick={(m) => `${m.$sender.name} voted Yes`} />
<button label="🤔 Wait" onClick={(m) => `${m.$sender.name} voted Wait`} />
</card>
),
});Auto-discovered convention folders: no manual wiring, hot-reloaded on save.
my-bot/
├── plugin.ts # Root plugin entry: definePlugin()
├── commands/poll/index.tsx # /poll command (auto-discovered)
├── middlewares/… # runs on every message
├── tools/weather/index.ts # tools the AI can call (optional)
└── zhin.config.yml # configVersion: 2 (plugins & platforms)Up and running in 3 steps (no platform accounts or API keys):
npm create zhin-app my-bot -y
cd my-bot && pnpm devhttp://127.0.0.1:8068/sandbox and send /hellohttp://127.0.0.1:8068 and HTTP_TOKEN from .envcommands/ and test immediately without restartingWhere to go next