How to Connect OpenClaw to QQ with NapCat and OneBot v11: A Memory-Sharing Agent Deployment Guide

This article explains how to connect an OpenClaw Agent to QQ reliably through NapCatQQ, OneBot v11, and Docker, enabling long-term memory inheritance, long-context reasoning, and full-duplex message delivery. It focuses on solving three common issues: container file desynchronization, incorrect command argument order, and ghost connection freezes in QQ. Keywords: OpenClaw, NapCatQQ, OneBot v11.

This architecture turns QQ into a persistent interaction endpoint for OpenClaw

The goal of the original solution is straightforward: bypass the stricter risk controls on the Telegram desktop client and use a secondary QQ account as the message ingress, while preserving the OpenClaw official Agent’s long-term memory, system persona, and toolchain capabilities.

This means the bridge layer must not call an external LLM API directly. Instead, it must forward QQ messages to the local openclaw agent. Only then can QQ and Telegram share the same “brain.”

The technical specification snapshot clarifies the stack

Parameter Details
Core Language Python 3
Container Environment Docker
Communication Protocol WebSocket, OneBot v11
Message Ingress NapCatQQ
Agent Core OpenClaw Kernel
Key Dependencies asyncio, websockets, json
Typical Port 3001
Original Project Popularity Star count not provided in the source

The overall architecture consists of two containers and one bridge script

The Docker network on the host machine allows the containers to remain isolated while still communicating with each other. The NapCatQQ container simulates QQ login and exposes a OneBot v11 WebSocket interface. The OpenClaw Kernel container runs the Agent and mounts the Python bridge script.

The bridge script does not generate replies. Its role is to route messages: receive QQ private messages, call the local OpenClaw Agent, and send the result back to QQ through the same path. The benefit is that memory, persona, and tool invocation all stay on the official OpenClaw execution path.

image AI Visual Insight: This diagram shows the dual-container collaboration path inside the host Docker network: NapCatQQ serves as the QQ protocol access layer and exposes WebSocket, while OpenClaw Kernel acts as the inference and memory hub. The two communicate through an internal network address, and the bridge script runs on the kernel side to handle message forwarding, context reuse, and unified outbound control.

The most important design choice is not connectivity but a unified gateway

Many failed integrations are not caused by a broken WebSocket connection. They happen because the message flow is routed into the wrong inference entry point. If the bridge script is changed to call APIs such as DeepSeek directly, OpenClaw’s memory and toolchain are bypassed, which leads to a fragmented experience: QQ can talk, but it no longer feels like the same agent.

Therefore, the best approach is to let the bridge layer handle only input and output, while all actual inference always goes through openclaw agent. This is a classic unified gateway routing architecture.

import asyncio

async def call_openclaw_agent(user_message: str, target_qq: str) -> str:
    # Key point: global arguments must appear before the agent subcommand
    process = await asyncio.create_subprocess_exec(
        "openclaw", "--no-color", "agent",
        "--to", target_qq,
        "--message", user_message,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    stdout, stderr = await process.communicate()
    # Return stdout on success, or the error output on failure
    return stdout.decode().strip() if process.returncode == 0 else stderr.decode().strip()

This code invokes the native OpenClaw Agent as a local subprocess instead of calling an external model API directly.

Container files do not synchronize automatically, and that determines your debugging workflow

The first high-frequency trap is simple: “I updated the script on the host, but the container still runs the old code.” The reason is equally simple: Docker container file systems are isolated by default, so changes under /root/ on the host are not automatically mapped into /home/node/ inside the container.

If you do not explicitly overwrite the file and restart the container, all debugging will continue against an outdated script. Typical symptoms include apparent freezes, repeated errors, or behavior that does not match the source code you just edited.

# 1. Copy the updated script from the host into the container
sudo docker cp /root/qq_ears_brain.py openclaw_kernel:/home/node/qq_ears_brain.py

# 2. Restart the container to clear old processes and stale in-memory state
sudo docker restart openclaw_kernel

# 3. Run in the foreground to inspect startup logs and runtime output directly
sudo docker exec -it openclaw_kernel python3 /home/node/qq_ears_brain.py

These three commands force the bridge script to sync, clear stale process state, and verify in foreground mode whether the issue has been fixed.

Incorrect command argument order can break Agent invocation completely

The second trap comes from CLI argument placement. The unknown option '--no-color' error mentioned in the original text does not mean OpenClaw lacks support for that argument. It means the argument was placed in the wrong position.

In standard Linux CLI semantics, global arguments must appear after the main command and before the subcommand. Therefore, the correct order is openclaw --no-color agent, not openclaw agent --no-color. This small detail is enough to make the entire bridge layer fail silently.

A successful QQ connection does not guarantee message delivery, because NapCat can enter a ghost freeze state

The third trap is the most subtle. The logs show a successful login, and the script reports no errors, yet the main QQ account receives nothing. In most cases, the problem is not in the code. The QQ server has already invalidated the session unilaterally, while NapCat still holds a local token that looks valid but is no longer usable.

In this state, the bridge program continues to run normally, but it is effectively sending data into the void. The fix is not a code change. You need to force-refresh the session state from the account side.

# Restart the NapCat container and prepare to log in again
docker restart napcat_core

# Watch the login logs continuously and wait for a QR code or success message
docker logs --tail 50 -f napcat_core

These two commands reset the NapCat session and use real-time logs to confirm whether the system has entered the QR-code reauthentication flow.

The standard recovery procedure for ghost freezes should include a forced logout on the account side

Use the following sequence: first, open device management for the secondary QQ account on your phone and forcibly log out suspicious Linux, iPad, or Mac sessions; then restart the NapCat container; next, watch the logs and scan the QR code to log in again; finally, restart the OpenClaw container and the bridge script.

If you only restart the container without invalidating the server-side token, the connection often does not recover fully. This is the most commonly overlooked step in this class of issues.

A stable bridge should minimize responsibilities and explicitly filter message sources

The best practice for the bridge script is to handle only private messages from a designated QQ user. This prevents group chat noise or unrelated accounts from polluting the context. The flow should remain minimal: receive messages, filter the source, call the Agent, and send the reply.

import asyncio
import json
import websockets

WS_URL = "ws://172.16.0.1:3001"
TARGET_QQ = "123456789"

async def main():
    # Establish a long-lived WebSocket connection to NapCat
    async with websockets.connect(WS_URL, ping_interval=20) as ws:
        while True:
            msg = await ws.recv()
            data = json.loads(msg)
            # Only process private messages from the target QQ account to avoid context bleed
            if data.get("post_type") == "message" and str(data.get("user_id")) == TARGET_QQ:
                user_msg = data.get("raw_message", "").strip()
                reply_text = await call_openclaw_agent(user_msg, TARGET_QQ)
                await ws.send(json.dumps({
                    "action": "send_private_msg",
                    "params": {"user_id": int(TARGET_QQ), "message": reply_text}
                }))

asyncio.run(main())

This code implements full-duplex QQ messaging over WebSocket and routes all replies through the OpenClaw Agent.

This solution demonstrates that reusing kernel capabilities is better than reimplementing them

From an engineering perspective, this is more than a simple QQ bot integration tutorial. It is a practical example of kernel capability reuse. Through a unified gateway, external channels are responsible only for access, while core intelligence, memory, and tools remain centralized in the OpenClaw kernel.

This pattern is more stable than writing a separate model invocation path for every platform, and it aligns better with long-term maintainability. If you later integrate another IM platform, you can simply reuse the same Agent invocation chain.

FAQ

Why is it not recommended for the bridge script to call an LLM API directly?

Because doing so bypasses the OpenClaw Agent’s long-term memory, system persona, and local toolchain. In the end, QQ and Telegram become two inconsistent agents instead of sharing the same kernel.

Why does the container output stay the same after I modify the Python script?

Because files on the host do not synchronize automatically into the container. You must use docker cp to overwrite the script inside the container, then restart the container to clear stale processes before validating the result.

NapCat logs show that it is online, but QQ still does not receive messages. What should I do?

Most likely the session has entered a ghost freeze state. You should first force-log out the abnormal login device from the mobile QQ app, then restart NapCat, wait for the QR-code login flow, and finally restart the OpenClaw bridge chain.

AI Readability Summary: This article reconstructs a complete OpenClaw-to-QQ integration workflow, focusing on Docker networking, NapCatQQ, OneBot v11, and local Agent gateway invocation. It systematically summarizes three core pitfalls—file overwrite issues, CLI argument order, and QQ ghost disconnects—and provides reusable bridge code.