Quick start
You need Linux, Bun 1.3 or newer, a working bubblewrap (the run_js sandbox; startup fails without it, see docs/deploy.md), at least one Discord or Telegram bot, and credentials for a model provider. Video frames additionally need ffmpeg (including ffprobe) on the host; without it everything else works and videos become a [视频] placeholder.
macOS development also needs brew install sqlite so Bun can load sqlite-vec. The first startup downloads the default Chinese embedding model (about 96 MB) into data/models (under your custom dataDir if set), requiring network access; later starts reuse that cache; neither is needed with features.history set to false. The vector part of message search (related counts, semantic search) always uses this model; topics share it when events is enabled.
git clone https://github.com/beiwater/jingmei.git
cd jingmei
bun install
bun run jingmei initinit is the recommended way to configure: an interactive wizard that creates jingmei.config.json, .env and personas/<id>.md, so you never hand-edit JSON. It first asks Recommended / Minimal / Custom (Recommended = every core feature on, no add-ons; Minimal = every core feature off, no embedding model download; Custom = pick core features and add-ons one by one, asking for parameters only for the add-ons you pick). Then it asks for the platform(s), each bot token (masked, and verified live with the same call the bot makes, showing the bot's name), the server / channel ids (the group ids on Telegram), the persona id and name, and the model (DeepSeek with DEEPSEEK_API_KEY, or sign in later with bun run jingmei login). ROUTING_SECRET is generated randomly; secrets go only into .env (mode 0600), never into the JSON. init refuses to run when jingmei.config.json or .env already exists, never overwrites anything, and needs an interactive terminal. It ends by printing the next steps (including the Discord invite link).
After it finishes:
Edit
personas/<id>.md: the character's identity, voice and boundaries.bun run jingmei doctor: a read-only self-check of the config, therun_jssandbox, model credentials, bot tokens and permissions (Message Content Intent, privacy mode, group ids), and ffmpeg / fonts / sqlite-vec / the embedding cache for the features you enabled. One OK / WARN / FAIL line each, with a fix hint.Start:
bashbun run start
To configure by hand instead (or to script deployments), the wizard does the equivalent of:
cp jingmei.config.example.json jingmei.config.json
cp .env.example .env
cp personas/template.en.md personas/luna.md- Edit
personas/luna.md: the character's identity, voice and boundaries. - Edit
jingmei.config.json: fill in your Discord server ID and channel ID. The example has a single Discord character; Telegram, voice, Jev and the rest are in Optional features, and fields are in Configuration reference. - Edit
.env: bot tokens,ROUTING_SECRET(any long random string) and API keys. The format iskey: value, notKEY=value. - Provide model credentials, either way:
- The example persona uses DeepSeek
deepseek-flash; just setDEEPSEEK_API_KEYin.env. On startup a catalog entry for this model (without the key) is written todata/pi-agent/models.json. - Other providers: for subscription accounts (Claude Pro/Max, ChatGPT Plus/Pro, GitHub Copilot, ...) run
bun run jingmei loginand pick a provider to sign in with OAuth. Credentials go to<dataDir>/pi-agent/auth.json; the bot uses them on startup and refreshes tokens automatically.bun run jingmei logoutremoves them. On a server without a browser, open the printed link on your own machine, then paste the final redirect URL or code back into the terminal.bun run jingmei modellists every model that has credentials. Alternatively put that provider's API key variable (for exampleOPENAI_API_KEY) in the process environment..envis read only by this project and, apart fromDEEPSEEK_API_KEY, is not passed to Pi.
- The example persona uses DeepSeek
- Run
bun run jingmei doctorto self-check, thenbun run start.
Startup validates the configuration, verifies every bot token, and checks that every persona's model exists and is authenticated. Configuration errors are listed all at once; an invalid token or unavailable model also stops startup. Then @-mention or reply to a character in the group.
When started in the foreground on a terminal, a fox-girl-loader animation plays while the bot gets ready and shows ✓ Ready when done; startup logs are held and printed once it finishes. Under systemd or any other non-terminal output nothing is drawn and logs stream as usual.

