Skip to content

Trirrin/openclaw-napcat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenClaw NapCat Channel

Standalone native OpenClaw channel plugin for NapCat / OneBot v11.

This plugin is built for OpenClaw-native channel semantics first, with NapCat / QQ transport underneath. Forward WebSocket is the primary deployment path. Reverse WebSocket and HTTP fallback are implemented in the same plugin.

What This Plugin Does

Supported in v1:

  • Private chat ingress and replies
  • Group chat ingress and @bot replies
  • DM access control with pairing, allowlist, open, and disabled
  • Group access control with mention gating, allowlists, and per-group overrides
  • Outbound text replies
  • Outbound QQ image messages from direct image URLs or Markdown image links in model output
  • Forward WebSocket transport
  • Reverse WebSocket transport
  • HTTP fallback transport
  • Self-message suppression, event dedupe, and forward WebSocket reconnect
  • Group patrol for selected groups

Implemented but not promised as a stable v1 contract:

  • More advanced media and file workflows
  • QQ-specific moderation actions
  • Reactions
  • Guild or channel variants outside plain OneBot v11 private and group messages

If you need a full QQ platform SDK, this is the wrong thing. This plugin is a production-focused OpenClaw channel transport for the common message path.

Requirements

  • Node.js 22 or newer
  • OpenClaw installed and working
  • NapCat configured with OneBot v11 enabled
  • An OpenClaw agent with valid provider auth if you expect real model replies

Install

Install dependencies and build the plugin:

npm install
npm run build

Link the plugin into OpenClaw:

openclaw plugins install --link ./

Inspect that OpenClaw sees the plugin as a channel plugin:

openclaw plugins inspect napcat --runtime --json

Quick Start

Forward WebSocket

Forward WebSocket is the default and recommended mode.

In this mode:

  • NapCat exposes a OneBot v11 WebSocket endpoint
  • This plugin connects to NapCat

Add a channel account:

openclaw channels add \
  --channel napcat \
  --account main \
  --name qq-main \
  --http-host 127.0.0.1 \
  --http-port 3001 \
  --webhook-path /onebot/v11 \
  --token YOUR_NAPCAT_TOKEN

Important: OpenClaw's generic setup flags use transport-neutral names. In this plugin they map like this:

  • --http-host -> wsHost
  • --http-port -> wsPort
  • --webhook-path -> wsPath
  • --token -> accessToken

Then start the gateway:

openclaw gateway run

Verify channel status:

openclaw channels list --all

Expected result for a configured account looks like this:

NapCat / OneBot v11 main (qq-main): installed, configured, enabled

NapCat Side

For forward WebSocket, configure NapCat so its OneBot v11 endpoint is available at the same host, port, path, and token used by this plugin.

Default values used by this plugin are:

  • Host: 127.0.0.1
  • Port: 3001
  • Path: /onebot/v11

Do not assume your NapCat build uses the same path by default. If NapCat is configured for /onebot/v11/ws, /onebot, or something else, change wsPath to match reality.

Provider Auth

Transport can be healthy while replies still fail.

If the gateway logs an error like Missing API key for provider "openai", the NapCat transport is already working. What is broken is your OpenClaw agent auth. Configure provider auth for the target agent before calling this a transport failure.

Configuration

Single-Account Config

A single account can be configured directly under channels.napcat:

{
  "channels": {
    "napcat": {
      "name": "qq-main",
      "enabled": true,
      "wsMode": "forward",
      "wsHost": "127.0.0.1",
      "wsPort": 3001,
      "wsPath": "/onebot/v11",
      "accessToken": "change-me",
      "ignoreSelfMessage": true,
      "dmPolicy": "pairing",
      "groupPolicy": "open",
      "groupRequireMention": true
    }
  }
}

Multi-Account Config

You can also define named accounts under channels.napcat.accounts.

Top-level fields act as shared defaults for named accounts. If you also want a real inline default account in addition to named accounts, set a top-level name.

{
  "channels": {
    "napcat": {
      "groupRequireMention": true,
      "ignoreSelfMessage": true,
      "accessToken": "shared-token",
      "accounts": {
        "main": {
          "name": "qq-main",
          "wsMode": "forward",
          "wsHost": "127.0.0.1",
          "wsPort": 3001,
          "wsPath": "/onebot/v11"
        },
        "ops": {
          "name": "qq-ops",
          "wsMode": "reverse",
          "wsHost": "0.0.0.0",
          "wsPort": 6700,
          "wsPath": "/onebot/v11"
        }
      }
    }
  }
}

Default-account rules:

  • If accounts is absent, the inline config is the default account
  • If accounts exists and also contains default, that named default account is the default account
  • If accounts exists and top-level name is set, the inline config becomes the default account and named accounts are additional accounts
  • If accounts exists but top-level name is not set, no synthetic default account is created; the first named account becomes the effective default account

That last rule matters because production systems should not invent ghost accounts from schema defaults.

Transport Modes

forward

Default mode.

{
  "wsMode": "forward",
  "wsHost": "127.0.0.1",
  "wsPort": 3001,
  "wsPath": "/onebot/v11",
  "accessToken": "change-me"
}

Use this when NapCat exposes a WebSocket server and OpenClaw should connect out to it.

reverse

{
  "wsMode": "reverse",
  "wsHost": "0.0.0.0",
  "wsPort": 6700,
  "wsPath": "/onebot/v11",
  "accessToken": "change-me"
}

Use this when OpenClaw should host a WebSocket endpoint and NapCat should connect in.

http

{
  "wsMode": "http",
  "wsHost": "127.0.0.1",
  "wsPort": 5701,
  "wsPath": "/onebot/v11",
  "httpBaseUrl": "http://127.0.0.1:3000",
  "accessToken": "change-me"
}

In HTTP mode:

  • OpenClaw listens for inbound OneBot POST events on wsHost:wsPort/wsPath
  • OpenClaw sends outbound actions to NapCat using httpBaseUrl

httpBaseUrl should point at NapCat's HTTP API root, not at OpenClaw.

Access Control

Direct Messages

dmPolicy supports:

  • pairing: require OpenClaw pairing unless sender is already approved
  • allowlist: allow only explicitly approved senders
  • open: allow everyone
  • disabled: deny all DMs

allowFrom is the DM allowlist.

Group Messages

groupPolicy supports:

  • allowlist
  • open
  • disabled

groupRequireMention defaults to true.

That default is intentional. A production QQ group should not get ambient bot replies unless you explicitly choose that behavior.

groupAllowFrom restricts who may trigger replies when groupPolicy is allowlist.

Per-group overrides live under groups.<groupId>:

{
  "groups": {
    "123456789": {
      "enabled": true,
      "requireMention": false,
      "allowFrom": ["10001", "10002"]
    }
  }
}

Patrol

Patrol is intentionally narrow. It only runs for groups listed in monitorGroups.

Relevant options:

  • monitorGroups: group IDs eligible for patrol
  • autoIntervene: enable or disable patrol
  • autoCheckIntervalMs: periodic patrol interval
  • autoCheckMessageThreshold: patrol after this many buffered messages
  • autoIntervenePrompt: patrol instruction template
  • noReplyToken: exact token the model must return when nothing should be sent

Minimal example:

{
  "monitorGroups": ["123456789"],
  "autoIntervene": true,
  "autoCheckIntervalMs": 300000,
  "autoCheckMessageThreshold": 20,
  "noReplyToken": "__NAPCAT_NO_REPLY__"
}

If the model returns the configured noReplyToken exactly, the plugin suppresses the patrol reply.

Outbound Behavior

The outbound adapter is intentionally simple:

  • Plain reply text is sent as a QQ text message
  • mediaUrl, mediaUrls, and Markdown image links like ![alt](https://...) are extracted and sent as QQ image messages
  • Duplicate image URLs are removed
  • Empty text created by stripping Markdown image links is cleaned up before sending

If you expect rich QQ-native cards, reactions, or custom structured payloads everywhere, that is outside the stable v1 contract.

Logging and Reliability

Defaults are conservative:

  • ignoreSelfMessage: true
  • forward WebSocket reconnect is enabled
  • inbound event dedupe is enabled
  • group mention is required by default
  • patrol is disabled by default

Optional inbound event logging:

  • inboundLogEnabled
  • inboundLogDir
  • inboundLogMaxLines

Production Checklist

Before you call this deployed, verify all of this:

  • NapCat and OpenClaw agree on mode, host, port, path, and token
  • The target OpenClaw agent has provider auth configured
  • groupRequireMention is left enabled unless you deliberately want ambient group replies
  • dmPolicy and groupPolicy match your safety model
  • monitorGroups contains only groups you actually want patrol to watch
  • Gateway auth token is persisted instead of relying on a startup-generated runtime token
  • Reverse WebSocket or HTTP listen addresses are not exposed wider than necessary
  • Inbound logging is disabled unless you truly need it and have a retention plan

Troubleshooting

The plugin keeps reconnecting

Usually one of these is wrong:

  • wsMode
  • wsHost
  • wsPort
  • wsPath
  • accessToken

Forward WebSocket reconnect loops are a symptom, not a feature.

Group messages arrive but no reply is sent

Check these first:

  • groupRequireMention may still be true
  • the message may not actually mention the bot account
  • groupPolicy may be disabled or allowlist
  • groups.<groupId> may override the default behavior

The bot replies with a provider auth error

That means transport is fine and your OpenClaw agent auth is not.

HTTP mode receives events but replies fail

Check httpBaseUrl. It must point at NapCat's OneBot HTTP API root.

Multi-account config behaves strangely

Read the default-account rules above. The plugin will not create fake default accounts from schema defaults.

Development

Run the full local check:

npm run check

This runs TypeScript build plus the automated test suite.

Repository Layout

  • src/index.ts: plugin entrypoint
  • src/channel.ts: channel definition and OpenClaw integration
  • src/config.ts: config resolution, setup mapping, and policy helpers
  • src/controller.ts: runtime dispatch, routing, transport lifecycle, and patrol
  • src/transports.ts: forward WS, reverse WS, and HTTP transport adapters
  • src/normalize.ts: OneBot v11 inbound normalization
  • src/outbound.ts: outbound text and image planning
  • openclaw.plugin.json: checked-in manifest and config schema

License and Compatibility

This repository targets the OpenClaw plugin contract used by openclaw@2026.5.27 and Node.js 22+.

About

Standalone OpenClaw channel plugin for NapCat / OneBot v11 with forward WS, reverse WS, and HTTP fallback.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors