It talks to QQ through NapCatQQ — OneBot 11 over a reverse WebSocket — and calls any OpenAI-compatible or Anthropic-native endpoint for the replies. Group chats and one-on-one private chats both go through the same pipeline.
QQ ──▶ NapCat ──OneBot 11 / reverse-WS──▶ max ──▶ LLM (OpenAI-compatible · Anthropic)
│
├──▶ Postgres · pgvector · blob store
└──▶ Docker · per-group sandbox · browser
- Agent loop — multi-turn tool calling, with
!killto cancel,!feedbackto steer a running turn,!btwto ask something else without disturbing it, and reaction-based status on the trigger message. - Persistence — every message in Postgres, images and videos content-addressed on disk, forwarded chats expanded inline. Pending media downloads survive a restart, and SIGTERM lets in-flight turns finish first.
- Memory — per-group and per-user facts injected into the prompt, written by an episode extractor when the conversation goes quiet (whole-arc extraction behind a watermark), consolidated by a nightly dream pass.
- Skills — progressive disclosure: a one-line index in the system prompt,
full manuals fetched on demand with
use_skill. Builtin manuals ship inside the binary (self-knowledge, sandbox, web, office — the docs double as the bot's self-image); DB rows add or shadow them at runtime via the admin API. - Multimodal — inline images, video and avatars on capable profiles; unrelated history images loaded on demand.
- Tools — web search, code sandbox (per-group Docker workspace), files, message search, browser (camoufox over MCP), bilibili, pins, poke.
- Multiple LLM profiles — OpenAI-compatible or Anthropic-native, switched at
runtime with
!model. - Commands —
!help,!model,!persona,!proactive,!memory,!clear,!pin,!btw,!feedback,!kill,!version, … - Admin panel — a loopback JSON API + baked-in web panel (sessions, skills, memories, permissions, tasks, usage, logs, full LLM call bodies).
- Optional: proactive triggering (a cheap intent classifier can start a turn on unaddressed chatter) and vector search (pgvector-backed semantic search over messages and memories).
@bot ping → pong, no LLM call. Full behaviour reference in
docs/features.md.
# 1. Enter the dev shell (--impure: devenv as a flake module)
direnv allow # or: nix develop --impure
# 2. Configure secrets
cp .env.example .env # NAPCAT_QQ, MAX_ACCESS_TOKEN, MAX_LLM_API_KEY
cp max.yaml.example max.yaml # persona, profiles, memory/embedding sections
# 3. Bring up Postgres (127.0.0.1:5433, db `max`, pgvector + pg_trgm)
devenv up
# 4. Bring up NapCat and log in
docker compose up -d napcatOpen http://localhost:6099 and scan the QR with the bot account's mobile QQ.
Login state persists to ./.napcat/, and the reverse-WS target
ws://host.docker.internal:8080/onebot is preconfigured. Private chat only works
with the bot account's QQ friends — that's QQ's rule, not ours.
# 5. Build the tool images (optional, but most tools need them)
sandbox-image/build.sh # code-execution sandbox
browser-image/build.sh # browser (multimodal profiles only)
# 6. Run — migrations apply on boot, the embed worker backfills on its own
cabal run maxThen, in QQ:
@bot ping → pong (fast path, no LLM call)
@bot 你好 → LLM reply
@bot !help → list of !cmd verbs
@bot !model list → available LLM profiles
@bot !memory → what the bot remembers here
Reply to a message and @bot … to hand the model the quoted context — including
an expanded 转发聊天记录, attached-file ids, and (on multimodal profiles) the
quoted message's images.
Three layered sources, first-Just wins per field:
- CLI flags —
max --helplists everything. - Environment —
MAX_LLM_API_KEY,MAX_DB_URL,MAX_PERSONA, … Devenv sources.envon shell entry. - YAML —
--config-file PATH,MAX_CONFIG,./max.yaml, or$XDG_CONFIG_HOME/max/config.yaml.
The only required value is one LLM api_key. Feature sections (search,
memory, embedding, intent, …) stay off when absent. See
.env.example and max.yaml.example for the
full schema.
cabal test max-test # in-memory: pure logic
cabal test max-test-db # DB integration; needs MAX_TEST_DB_URL| features.md | full behaviour reference |
| architecture.md | layout, data flow, durability, effect stack |
| development.md | tests, versioning, debugging |
| prompt-flow.md | the complete JSON of a real dispatch |
MIT © Hank Hogan