Skip to content

TypeScript · ESM · Plugin Runtime

Zhin.js

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.

IM core <10MBNode ≥20.19MIT
zsh
$ 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)

Where do you want to start?

You don't need to learn the whole architecture upfront. Pick a goal — each path fits in one sitting.

Why Zhin.js

01

One codebase, 20+ platforms

QQ, WeChat, WeCom, DingTalk, Lark, Discord, Telegram, Slack, KOOK, LINE… Your code sees one unified message; adapters handle platform differences.

02

A feature is a file

commands/hello/index.ts is the /hello command. Middleware, JSX components, schedules, and AI tools work the same way — zero registration boilerplate.

03

Generation-isolated hot reload

Save to hot-reload. In-flight messages finish on the old version, and if new code throws on startup, the previous version keeps serving.

04

Develop with zero accounts

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.

05

Managed in the browser

Connect console.zhin.dev to your bot: send test messages, inspect logs, edit schema forms, and manage plugins with zero frontend deployment.

06

Opt-in AI (<10MB core)

The default install is a lean IM core under 10MB. Run npx zhin setup --ai to add LLMs, tools, 3-layer memory, and MCP.

What building with Zhin.js feels like

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.

tsx
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.

text
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):

bash
npm create zhin-app my-bot -y
cd my-bot && pnpm dev
  1. Instant local Sandbox: Open http://127.0.0.1:8068/sandbox and send /hello
  2. Remote Console: Or open console.zhin.dev with http://127.0.0.1:8068 and HTTP_TOKEN from .env
  3. Hot-reload on save: Edit any file under commands/ and test immediately without restarting

Where to go next