qq-bridge wires a QQ chat into a DeepSeek Harness agent, with a tool allowlist and a local console
Bridge between QQ (SnowLuma OneBot v11) and DeepSeek Harness agents: social simulation, safe MCP tools, slang learning and more.
At a glance
- What is it?
- A Node.js bridge that turns messages from a SnowLuma OneBot v11 client into DeepSeek Harness sessions and sends the agent's replies back to QQ. It ships a local web console, four operating modes and a restricted set of MCP tools, and it is pinned to specific Harness protocol versions rather than to a range.
- Who is it for?
- Adopt qq-bridge if you already run a DeepSeek Harness instance and a SnowLuma QQ client and want to drive a personal agent from a chat, and you are the kind of operator who reads an allowlist before enabling tools. Do not adopt it for a shared or public bot, because the safety model depends on a whitelist of groups and private chats and on the owner account, and the slang research feature sends extracted terms to an external search engine by default.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The data path is short, and every hop is local except the search
The architecture is one line long. Messages from a QQ friend or group arrive at a running SnowLuma instance, which speaks the OneBot v11 WebSocket protocol, the bridge receives them and turns them into user messages in a DeepSeek Harness session, and the agent's replies, including its questions and tool approval requests, travel back out to QQ.
Both endpoints are local by default. The Harness Web API is expected at `http://127.0.0.1:3080` and SnowLuma at `ws://127.0.0.1:3001` for the WebSocket and `http://127.0.0.1:3000` for its HTTP API, with an access token filled in as your SnowLuma configuration requires. The bridge is a single Node.js process in between.
The one documented exception to the local-only picture is the slang research feature, which extracts terms from group chat and sends them to Bing as search queries, and which then fetches public URLs as the model decides. The project documents a data-egress list in its LICENSE file and a setting to turn the feature off, called `slang.autoResearch`.
That single feature is the reason to read the licence and rules documents before running this on a group you care about, and the project pushes exactly that, pointing at RULES.md for the permission boundary and safety promises.
Protocol generations are pinned, and the wrong tag fails quietly
The README is unusually direct about version compatibility, and that is because the bridge broke when the Harness changed.
The current release is v0.2.0, adapted to DSH 0.2.0-rc.2 and verified item by item with the command `npm run verify:adaptation`. The bridge targets the protocol generation introduced in DSH 0.1.2-alpha.1, which covers Cookie authentication, slash RPC at `/api/<namespace>/<method>` and the `/api/remote.mux` event stream. Earlier DSH versions used a dotted endpoint protocol and are not compatible, so the README names the tag to use for each.
DSH 0.1.1-rc.2 and earlier need v0.1.0, DSH 0.1.5-rc.1 needs v0.1.5, and DSH 0.1.7-rc.2 needs v0.1.7. The default branch is the current version, so a plain clone gives you the newest one, with no branch switching required.
Two upstream changes are worth understanding because they caused real breakage. From DSH 0.1.7 the process launch token only exists in memory and is no longer written to disk, so the old method of reading a token out of the guard log no longer works, and the bridge now mints a session cookie offline from a browser session signing key persisted in `~/.dsh`. In the same version, agent presets stopped being directories under `~/.dsh/.agent-presets/` and became a Cordis line pointing at the `@deepseek-ai/dsh-agent-preset` package.
This is a project whose upgrade cost is a compatibility check, and the release notes for v0.2.0 show the author doing exactly that, reconciling the QQ safety guard against the real tool list of the new version and adding fifteen tool names that must be hidden, including `read_mcp_resource`, `plugin_manager` and `subagent_codex`.
The safety model is an allowlist of groups, an owner account and a hidden tool set
Four run modes define how much the agent can do, and they are the heart of the design.
In `chat` mode, only whitelisted groups and whitelisted private chats get through, and the agent runs with a restricted chat preset. In `closed-agent` mode, only the owner, identified by an `ownerQQ` value in `config.json` that the console can change, gets the full tool set, and can therefore operate the Harness itself from QQ. The `reserved` mode is the first generation of social simulation, where the agent plays a group member through a state machine of watching, being active, probing and leaving, participating selectively and sending messages split by spaces. The `reserved2` mode is the second generation, where text is not forwarded automatically and the agent reads and speaks through tools such as `qq_get_unread_messages` and `qq_send_message`, setting its own wake and lurk state.
On the tool side, the agent reaches three MCP servers. The `snowluma` server offers a safe subset of QQ actions, checking status, checking groups, checking messages and sending messages, with sending forced through a whitelist and an optional `replyToMessageId` for quoted replies. The `snowluma-host` server has exactly one tool, `snowluma_status`, a read-only health check. The `web-search-safe` server offers read-only `web_search` and `web_fetch` with SSRF protection.
The removal of `start_snowluma` and `stop_snowluma` in v0.1.5 is the clearest statement of the project's own limits. The SnowLuma EULA section 5.4 requires written permission to deploy that proprietary component through automation scripts, so the bridge only probes the client and never starts, stops or installs it. A project that removed its own most convenient feature for a licensing reason is doing something rare and worth noting.
The local console exposes ten pages and a token cost dashboard
The bridge ships its own web console at `http://127.0.0.1:3100`, and it is a large part of the product.
The left navigation is organised by task rather than by feature, with ten pages covering run overview, sessions and approvals, personas and roles, the second generation simulation, the first generation simulation, the slang dictionary, tokens and spend, access and security, debugging and operations, and a tool reference. A search box in the top right locates any function across pages, and there is a light and dark theme that follows the system preference when not set explicitly.
The token and spend board is the most interesting page. It shows live token consumption and a converted currency amount, and it drills down to each group, each friend and each turn of conversation, showing rounds, steps, cached and uncached input, output, hit rate, cost and peak and quiet hours, with a time series over 24 hours, 3 days, 7 days or 30 days. The totals come from the Harness `tokenUsage` projection and the per turn detail is folded from the `usage` field of assistant messages, and the money conversion follows the official DeepSeek price list with a separate peak rate that is twice the quiet rate, including Chinese public holidays.
Access needs a token, taken from `consoleToken` in `config.json`. If none is configured, one is generated and printed in the startup log, and it can be changed or regenerated from inside the console. Since the console binds to loopback, exposing it on a network interface is a deliberate act, and the token is the thing standing between that and a stranger changing your agent's persona.
Session model, presets and the two layers of prompt
Each QQ conversation, private or group, maps to its own Harness session, and all of them are grouped into a single workspace so they do not scatter ungrouped. The mapping is persisted in `state/sessions.json`.
The model for a session is fixed per session with `session.selectModel`, taken from the `dsh.model` value in `config.json`, and the default is `deepseek-flash`, described as the DeepSeek V41 Flash model with multimodal support. A failure to select is logged and does not block startup, which is a good default for a chat bridge where the agent still works with whatever model is already active.
Presets are a second layer. QQ conversations use a `qq-chat` agent preset and `reserved2` uses `qq-chat-v2`. From DSH 0.1.7 the preset is not a directory but a `@deepseek-ai/dsh-agent-preset` line inserted into the profile by a bundle in `plugins/qq-agent-presets/`, and it takes effect after a Harness restart. The persona stays the same as the default Harness coding agent with only QQ scenario rules added. Role playing is a separate, optional mechanism, injected through `state/current-role.json`, and group members cannot change it.
The console separates the two prompt layers, which is a good design decision. The simulation prompt is built in, governs behaviour and protocol, is synced to the Harness when saved and needs a restart. The persona prompt lives in `roles/*.md`, governs character and tone, and takes effect immediately. The simulation layer is validated for safety invariants and backed up before saving, with a one click restore, and the console warns in real time when a persona exceeds the injection limit or contains first generation only instructions.
Interaction details: questions, approvals, quoting and silence
The bridge treats the chat as a bidirectional control channel rather than a one way pipe.
When the agent asks a question through `ask_user_question`, the question is forwarded to QQ and the reply is fed back as the answer. When the agent requests tool approval, the request goes to QQ and a reply approving or denying it decides the outcome. Harness slash commands such as `/model` are supported, along with `/reset` to reset the session context.
Quoted messages in groups are parsed into a quoted person plus the original text and injected into the Harness, so the agent can tell who a remark is aimed at instead of reading a reply between two other people as addressed to itself. When the bot itself is quoted, the message counts as one that must be answered.
There is also a dedicated `qq_reply` tool that lets the agent look up real message ids with `qq_get_group_history` and then quote a specific message, and the bridge detects sending tool calls and skips the automatic forwarding for that turn so a message is not sent twice.
The first generation simulation mode has a quiet signal. An agent that outputs only `[SILENT]` is not sent anything, and the mode also splits output into separate messages on spaces. That last behaviour has a documented sharp edge: spaces between Chinese and English characters, or between numbers, are also treated as a split signal, so an agent that writes naturally in Chinese will send fragmented messages unless it avoids spaces. The second generation mode does not have this issue because it uses the array form of `qq_send_message` instead.
Setup, tests and the shape of the release history
Installation is a single npm install, with a postinstall step that patches an ESM packaging bug in the SnowLuma SDK.
npm installNode.js 22.13 or newer is required. You then copy `config.example.json` to `config.json` and edit it, with a `copy` command given for Windows command prompt users. The real `config.json` and the `state/` directory are not in the public repository, only a sanitised template is, and the key fields are `dsh.baseUrl`, `dsh.provider`, `dsh.model`, `dsh.reasoningEffort` and `dsh.authToken`.
The test scripts are worth a look, because the number of them describes the feature surface. There are separate scripts for the audit, token economy, reply waiting, the QQ model view, the preset contract, token usage, hardening, Markdown to plain conversion, the second generation wait path, vision media, forwarding, slang learning, stickers, voice, encoding and the console, plus a self-test in the source tree. The voice tool itself was split out into a sibling directory with its own command line and GUI entry points and no longer depends on the bridge running.
The release history is short and specific. v0.2.0-r3 was published on 2026-10-03 and was tested against SnowLuma 1.14.20, correcting an earlier claim about upgrading the native component and adopting a release numbering scheme. v0.2.0 came on 2026-10-02 with the Harness 0.2.0-rc.2 adaptation, and v0.1.7 on 2026-09-27 with security hardening. The last push to the repository was on 2026-10-18 and the repository is not archived.
The project metadata declares the MIT licence while the repository also carries a LICENSE file with a data-egress list and an EULA interpretation, and GitHub could not classify the licence from the metadata. For a tool that reads a personal chat, the LICENSE file is the document to read rather than the metadata field, and this is not legal advice.
Editorial conclusion
Adopt qq-bridge if you already run a DeepSeek Harness instance and a SnowLuma QQ client and want to drive a personal agent from a chat, and you are the kind of operator who reads an allowlist before enabling tools. Do not adopt it for a shared or public bot, because the safety model depends on a whitelist of groups and private chats and on the owner account, and the slang research feature sends extracted terms to an external search engine by default. Verify first that the Harness version you run matches the tag the README points to, that the console token is set before exposing the console on a network interface, and that the QQ safety guard hides the tool names you expect it to hide.
Frequently asked questions
What does qq-bridge connect together?
It connects a SnowLuma QQ client speaking OneBot v11 over WebSocket to a DeepSeek Harness Web API, so QQ messages become Harness agent sessions and the agent replies, questions and approval requests go back to QQ. The default Harness address is http://127.0.0.1:3080.
Which DeepSeek Harness version does the current qq-bridge release support?
The current release v0.2.0 is adapted to DSH 0.2.0-rc.2 and verified with npm run verify:adaptation. Older Harness versions need older tags: v0.1.7 for DSH 0.1.7-rc.2, v0.1.5 for DSH 0.1.5-rc.1, and v0.1.0 for DSH 0.1.1-rc.2 and earlier.
Which QQ actions can the AI agent perform?
The bundled snowluma MCP server offers a safe subset covering status checks, group checks, message checks and sending, with sending forced through a whitelist and optional quoted replies. The separate snowluma-host server exposes only a read-only snowluma_status probe, and process start and stop were removed in v0.1.5 because the SnowLuma EULA restricts automated deployment of that component.
How do I install and configure qq-bridge?
Run npm install, which also patches the SnowLuma SDK packaging bug, then copy config.example.json to config.json and edit it. Node.js 22.13 or newer is required, and a running Harness Web plus a running SnowLuma with OneBot WebSocket and HTTP API enabled are the prerequisites.
Does qq-bridge send chat data to external services?
The slang auto-research feature sends extracted terms to Bing and lets the model fetch public URLs, and it is on by default. The project documents a data-egress list in the LICENSE file and the feature can be turned off with the slang.autoResearch setting.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/derpyu520-qq-bridge)Was this useful?