super-bot is an async QQ bot orchestration framework inspired by NoneBot.
The v1.1 direction is an LLM-facing dispatch hub: it learns capabilities from
external bot frameworks, decides whether a natural-language request should call
one of those capabilities, confirms risky or ambiguous requests, bridges the
call into the target framework, and routes results back to the right QQ account.
Documentation quick links: Deployment Checklist | External Evidence Capture | 简体中文
- Async-first event handling.
- Decorator-based plugin API.
- Protocol adapters that normalize raw payloads into common events.
- Capability cards and a JSON-backed capability index.
- Precise trigger and conservative confirmation gates for names such as
菲比. - Optional HTTP JSON LLM decision provider for capability selection, with deterministic local matching as the default.
- Source-level plugin scanning for Yunzai, AstrBot, NoneBot, GSUID Core, Koishi, and KiviBot.
- Deterministic learning, capability sync, version fingerprints, and source-missing disablement.
- Task orchestration with status messages, permission checks, bridge dispatch, result mode policy, and Trace logs.
- OneBot v11 reverse WebSocket transport primitives with
self_id -> connectionrouting. - Local Web control console on port
8612for status, capabilities, scanners, policies, traces/logs, and OneBot connections. - No mandatory runtime dependency for the framework core.
- Testable handlers and adapters.
from superbot import SuperBot, on_command, on_message
from superbot.adapters.onebot.v11 import OneBotV11Adapter
@on_command("ping")
async def ping(bot, event):
await bot.send(event, "pong")
@on_message()
async def echo(bot, event):
await bot.send(event, event.message.plain_text)
app = SuperBot()
app.register_adapter(OneBotV11Adapter())Handlers registered with the module-level decorators are copied into a
SuperBot instance when the app is created. Register those global decorators
before constructing the app, or pass an explicit PluginManager for fully
manual wiring.
Command names and aliases must be non-empty strings. Passing
aliases="pong" registers one alias, and command prefixes must be strings.
An adapter receives protocol-specific payloads and feeds normalized events into the app:
await app.feed_event(
"onebot.v11",
{
"post_type": "message",
"message_type": "private",
"self_id": 10000,
"user_id": 20000,
"message": "ping",
"raw_message": "ping",
},
)Install the core package from a source checkout:
python -m pip install -e .For a packaged install, use:
python -m pip install super-botThe optional reverse WebSocket server used by real NapCat or compatible OneBot
deployments requires the onebot-ws extra:
python -m pip install -e ".[onebot-ws]"
# or, from a package index:
python -m pip install "super-bot[onebot-ws]"After installation, the console scripts are sb, superbot-control,
superbot-smoke, superbot-evidence, superbot-capture-evidence,
superbot-acceptance, superbot-lab-acceptance, and superbot-readiness.
from superbot import CapabilityCard, CapabilityIndex, TriggerGate
from superbot.bridges import CapabilityCall, YunzaiBridge
index = CapabilityIndex([
CapabilityCard(
capability_id="image.draw",
framework="yunzai",
adapter="yunzai.source",
commands=["#bnn {prompt}"],
natural_language_triggers=["画图", "绘图", "出图"],
)
])
decision = TriggerGate(index).evaluate_text("菲比 帮我画图 小猫", session_id="demo")
card = index.get(decision.target_capability)
payload = YunzaiBridge().build(CapabilityCall(card=card, arguments=decision.arguments))
assert payload.payload["command"] == "#bnn 小猫"The runtime orchestrator connects the full documented flow:
from superbot import SuperBot
app = SuperBot()
orchestrator = app.enable_task_orchestrator()
# Incoming message events now run through the trigger -> permission -> bridge
# -> delivery flow before falling through to lower-priority handlers.The orchestrator only sends status text after should_call=true, capability
matching, confirmation, and permission checks have passed.
Pending confirmations expire after five minutes by default, so a later
“去执行” will not accidentally approve stale work.
Short English confirmation words such as y and n are matched as standalone
tokens, so ordinary words such as maybe or none do not accidentally confirm
or cancel a pending action.
Capability cards can set confirmation_policy to auto, always, or never;
always forces confirmation even for prefixed commands, while never disables
the conservative in-sentence confirmation.
Capability cards use delivery_mode="inherit" by default, which follows the
delivery policy default_mode. Set a card to superbot_send or
framework_direct_send only when that capability should ignore the global
default. Policy default_mode and policy overrides must be concrete modes:
superbot_send or framework_direct_send.
Policy override keys must be global, user:<id>, group:<id>,
capability:<capability_id>, framework:<framework>, or
plugin:<framework>:<plugin>. Unknown bare keys are rejected so typos do not
silently create policies that never match.
Permission policy sets such as owners, user_whitelist, and
group_blacklist accept a list of string IDs, or a single string for one ID;
surrounding whitespace is trimmed, and non-string or blank entries are rejected.
Capability-level permissions are also strict. The supported shape is
{"required": "owner"}; unknown permission fields, non-string required
values, and unsupported requirements are rejected before startup or API update.
By default, TriggerGate uses deterministic local matching so the framework has
no mandatory runtime dependency. Production deployments that want an external
LLM or model gateway to choose capabilities can either configure an
OpenAI-compatible chat completions provider directly, or keep using a custom
HTTP JSON decision endpoint.
For OpenAI-compatible providers, set the API base, API key, and model:
sb run --api-token $env:SUPERBOT_API_TOKEN --enable-task-orchestrator --llm-api-base https://api.example.com/v1 --llm-api-key $env:SUPERBOT_LLM_API_KEY --llm-model gpt-5.5The same values can be supplied by SUPERBOT_LLM_API_BASE,
SUPERBOT_LLM_API_KEY, SUPERBOT_LLM_MODEL, and
SUPERBOT_LLM_PROVIDER_NAME. When the upstream gateway supports OpenAI JSON
mode, add --llm-json-mode or set SUPERBOT_LLM_JSON_MODE=true to send
response_format: {"type": "json_object"} with chat completion requests; it is
off by default so existing custom gateways keep their current behavior. The Web
control console exposes an AI provider
panel where operators can save the same OpenAI-compatible provider settings,
toggle JSON mode, test connectivity, and see a redacted key preview. Leaving
the key input blank while saving keeps the existing saved key; use the
dashboard Clear key action to revoke the saved secret while keeping the API
base, model, timeout, and JSON-mode settings. When
the production acceptance page says the AI provider is configured and tested,
it means the current provider type and current model have at least one
successful dashboard model-test trace; saving settings alone is not enough.
When
--llm-provider .superbot/llm-provider.json is passed, dashboard edits are
saved back to that file and are reused on the next sb run. That JSON file
stores the API key in
plaintext on the local machine; protect its file permissions in production, or
prefer environment variables / a system credential store for the key.
The legacy provider mode is a custom HTTP JSON decision endpoint:
sb run --api-token $env:SUPERBOT_API_TOKEN --enable-task-orchestrator --llm-decision-url http://127.0.0.1:9000/decide --llm-decision-token $env:SUPERBOT_LLM_DECISION_TOKENSUPERBOT_LLM_DECISION_URL and SUPERBOT_LLM_DECISION_TOKEN provide the same
values from the environment. The provider receives the message, the bot-name
stripped body, session ID, prefix status, and the enabled capability cards. It
must return JSON with should_call, target_capability, arguments,
confidence, reason, and confirmation_required. A response may be returned
directly, under a decision key, or as JSON text in
choices[0].message.content from an OpenAI-compatible gateway.
Provider decisions are fail-closed: unknown or disabled capability IDs are
rejected, provider errors do not fall back to unsafe execution, and capability
confirmation policies such as always still force confirmation even when the
provider says no confirmation is needed. --validate-config checks the provider
URL, timeout, and token configuration. Pass --strict-validate-config when
warning diagnostics should block deployment.
For live provider evidence, require the optional smoke probe after startup:
superbot-smoke --control-url http://127.0.0.1:8612 --api-token $env:SUPERBOT_API_TOKEN --require-llm-decision-provider --llm-decision-url http://127.0.0.1:9000/decide --llm-decision-token $env:SUPERBOT_LLM_DECISION_TOKEN --llm-decision-smoke-message "superbot draw smoke kitten"The smoke probe posts the same standard decision payload shape used by the runtime and fails closed when the provider is unreachable, returns malformed JSON, or selects a capability that is not enabled in the running service.
External framework plugins can be scanned into capability cards:
from superbot.scanners import ScannerRegistry
registry = ScannerRegistry(index)
registry.configure("yunzai", r"C:\path\to\Yunzai")
registry.configure("nonebot", r"C:\path\to\NoneBot")
result = registry.scan("yunzai")Source scanners extract common command declarations as well as aliases, arrays,
sets, and tuple-style command lists for Yunzai, AstrBot, NoneBot, GSUID Core,
Koishi, and KiviBot projects.
Scanner roots can point at a whole framework checkout, a configured plugin
directory, or one plugin package. Single-plugin packages with nested helper
modules are scanned as one plugin, and loose Yunzai plugin files such as
plugins/paint.js are learned alongside directory-style plugins.
Automatically learned capability IDs are namespaced as
framework.plugin.intent, for example yunzai.paint.image.draw, so multiple
plugins with the same broad intent do not overwrite each other. The broad intent
is also stored in metadata.capability_kind. Plugin names are normalized for
stable IDs, while the original name is preserved in metadata.plugin_name.
When a configured framework is scanned again, learned source facts such as
commands, source paths, and fingerprints refresh, while operator-managed policy
fields such as enabled state, delivery mode, confirmation policy, risk level,
and permissions are preserved. A source-missing scan does not overwrite an
operator-disabled capability, so a later source recovery will not silently
re-enable something an operator turned off.
The dashboard includes a framework scanning guide backed by
GET /api/scanners/onboarding. It lists supported frameworks, configured roots,
whether each root exists outside the SuperBot repository, learned capability
counts, and next actions. It is read-only and does not run scan-all; use the
dashboard scan button or POST /api/scanners/scan-all to refresh learned
capabilities.
OneBotV11Adapter includes a multi-account connection registry. NapCat or
BotShepherd instances should connect to one shared reverse WebSocket URL. The
default NapCat/OneBot URL shape is ws://<ip>:4612/onebot/v11/ws; on a local
machine that is usually ws://127.0.0.1:4612/onebot/v11/ws. self_id is read
from X-Self-ID or from event payloads. Surrounding whitespace is trimmed from
self_id, and a blank value is treated as missing. API calls are routed back
through the matching connection, and echo waiters are isolated per connection.
When a reverse WebSocket disconnects, pending OneBot API calls for that
connection fail immediately instead of waiting for the request timeout.
The dashboard includes a NapCat onboarding guide backed by
GET /api/onebot/onboarding. It reports the recommended URL, NapCat fields,
whether the WS token is enabled, real self_id connection counts, a smoke
command, and next steps. The response uses environment-variable placeholders
and does not echo the current token.
When --onebot-token is set, reverse WebSocket clients must provide the token
as Authorization: Bearer <token>, X-SuperBot-Token: <token>, or
?token=<token> / ?access_token=<token>. The Bearer scheme is
case-insensitive, and header or query token values may include surrounding
whitespace. Programmatic access_token values are trimmed on server creation.
Custom --onebot-path values are trimmed, deduplicated, and must start with
/; invalid paths fail during startup so a typo does not leave a server
running on an unreachable endpoint. Runtime validation also reports empty,
duplicate, or non-slash-prefixed OneBot paths when a deployment is assembled
programmatically.
The recommended packaged startup command is sb run, matching the concise
runtime-entry style used by framework CLIs such as NoneBot nb run and AstrBot
astrbot run. The older superbot-control command remains available as a
compatibility entry point and as the lower-level control CLI for initialization,
validation, scanning, and direct control-server operations.
Initialize the persistent runtime stores before the first deployment:
superbot-control --init-config .superbotThe initializer creates .superbot/capabilities.json,
.superbot/policies.json, .superbot/scanners.json, and
.superbot/llm-provider.json when they are missing
and reports existing files without overwriting them.
Production startup example:
$env:SUPERBOT_API_TOKEN = -join ((48..57 + 65..90 + 97..122) | Get-Random -Count 40 | ForEach-Object { [char]$_ })
$env:SUPERBOT_ONEBOT_TOKEN = -join ((48..57 + 65..90 + 97..122) | Get-Random -Count 40 | ForEach-Object { [char]$_ })
sb run --capabilities .superbot/capabilities.json --policies .superbot/policies.json --scanners .superbot/scanners.json --llm-provider .superbot/llm-provider.json --api-token $env:SUPERBOT_API_TOKEN --onebot-ws --onebot-token $env:SUPERBOT_ONEBOT_TOKEN --scan-on-start --enable-task-orchestrator --require-production-configIf the HTTP control port cannot be bound, the CLI exits with a clear startup
error instead of emitting a traceback. When --port 0 or --onebot-port 0 is
used for an ephemeral local run, runtime status and CLI output report the real
bound port.
Use --require-production-config for deployment starts. It runs a strict
startup gate after any --scan-on-start refresh and rejects weak production
posture such as missing control or OneBot tokens, missing persistent store
files, missing task orchestrator, missing OneBot reverse WebSocket, no enabled
scanner, no enabled learned capability, non-loopback control binding, or
disabled high-risk owner enforcement. It also rejects placeholder token values
such as change-me, ws-change-me, secret, and token.
Load local decorator-based plugin packages at startup with --plugins:
sb run --plugins my_bot_plugins --onebot-ws --enable-task-orchestratorPlugin package imports are recursive, so handlers registered from nested subpackages are available before the app starts.
For operational sync without starting long-running servers, scan all configured framework roots once and persist learned capabilities:
superbot-control --capabilities .superbot/capabilities.json --scanners .superbot/scanners.json --scan-onceUse --scan-on-start when the service should refresh configured scanners before
binding the HTTP and WebSocket ports. Startup exits with code 2 if any scanner
reports an error; pass --allow-scan-errors-on-start only when you explicitly
want a degraded start after partial scan failure. When startup is rejected for
scanner errors, partial successful scan results are not persisted to the
capability store.
When --require-production-config is also set, the production gate runs after
the scan refresh so newly learned capabilities can satisfy the deployment
posture check before the service starts accepting traffic.
Scan-all results are per-framework; a broken configured root reports error
without preventing other configured scanners from completing. Filesystem
permission and I/O errors, including unreadable source files, are reported the
same way with the source path in the error message. Disabled scanners are
returned with skipped=true and skipped_reason="disabled". --scan-once
prints the same JSON summary and exits with code 2 if any scanner reports an
error, so CI and deployment scripts can fail fast on broken scanner roots or
bad source files. Source scanners ignore common generated/cache directories
inside plugin roots and skip metadata/config-only directories that do not expose
runtime command declarations, so stale build output and empty package metadata
do not become learned capabilities.
Validate configuration without starting servers:
sb run --capabilities .superbot/capabilities.json --policies .superbot/policies.json --scanners .superbot/scanners.json --llm-provider .superbot/llm-provider.json --validate-configThe validator prints JSON diagnostics and exits with code 2 when any error
diagnostic is present. Warnings such as disabled API tokens or disabled scanner
roots are reported without failing the command unless
--strict-validate-config is also passed. Use strict validation for deployment
gates when warning diagnostics should block release. Malformed capability,
policy, or scanner JSON files are reported as JSON load diagnostics so
automation can consume the failure consistently. Permission policy ID fields are
also audited: blank IDs, non-string IDs, and unsupported collection shapes are
reported before startup.
Pass --require-production-config with --validate-config to preview the same
production posture gate used by deployment startup. This mode treats warnings as
deployment blockers and adds checks for tokens, persistent stores, task
orchestration, OneBot reverse WebSocket, enabled scanners, enabled capabilities,
loopback control binding, and high-risk owner enforcement.
Once the service is running, GET /api/diagnostics exposes the same diagnostics
engine through the token-protected control API. The live API accepts
strict=true and production=true query flags, and redacts URL credentials,
query strings, fragments, and secret-like diagnostic fields.
sb run --capabilities .superbot/capabilities.json --policies .superbot/policies.json --scanners .superbot/scanners.json --llm-provider .superbot/llm-provider.json --api-token $env:SUPERBOT_API_TOKEN --onebot-ws --onebot-token $env:SUPERBOT_ONEBOT_TOKEN --enable-task-orchestrator --validate-config --require-production-configAfter a deployment is running, use the smoke checker to produce machine-readable evidence for control API health, policy posture, loaded capabilities, configured scanners, and visible OneBot connections:
superbot-smoke --control-url http://127.0.0.1:8612 --api-token $env:SUPERBOT_API_TOKEN --require-control-api-token --require-loopback-control-host --require-task-orchestrator --require-high-risk-owner-policy --require-persistent-stores --require-writable-stores --require-capabilities --require-enabled-capability --require-scanners --require-enabled-scanner --require-clean-scan --require-onebot-connection --expect-delivery-mode superbot_send --expect-owner 10000 --expect-self-id 10000 --expect-scanner yunzai --expect-enabled-scanner yunzai --expect-framework yunzai --expect-enabled-framework yunzai --expect-trace scanner:scan_all_completedThe smoke checker prints JSON and exits with code 2 when any required check
fails. URL, token, and expected-value arguments may include surrounding
whitespace, which is trimmed before checks run; blank expected values fail as
configuration errors instead of being ignored. It can require deployment
hardening signals such as control API token enforcement, loopback-only control
binding, task-orchestrator enablement, delivery default mode, configured policy
owners, high-risk owner enforcement, persistent store paths, files, and
writability, configured scanners, specific enabled scanners, loaded
capabilities, enabled capabilities, enabled framework capabilities, clean live
scanner runs, and visible OneBot connections. When
--require-clean-scan is set, it runs /api/scanners/scan-all, fails on any
scanner error, fails if any enabled scanner is missing from the scan-all
results, and refreshes capabilities before evaluating capability expectations.
Use --expect-trace stage:message, such as
--expect-trace scanner:scan_all_completed, to require audit evidence from the
running service. It can also verify that the reverse WebSocket endpoint accepts
a handshake:
superbot-smoke --control-url http://127.0.0.1:8612 --api-token $env:SUPERBOT_API_TOKEN --onebot-ws-url ws://127.0.0.1:4612/onebot/v11/ws --onebot-token $env:SUPERBOT_ONEBOT_TOKEN --onebot-self-id "superbot-smoke" --require-onebot-smoke-connection --require-onebot-connection --expect-self-id superbot-smoke --expect-trace onebot:connection_registeredThe optional WebSocket handshake briefly registers the supplied smoke
self_id, so use a dedicated value that cannot collide with a real QQ account.
When --require-onebot-smoke-connection is set, the smoke checker keeps the
socket open long enough to verify that /api/connections reports that
self_id, and the same connection snapshot can satisfy --require-onebot-connection
and --expect-self-id. The OneBot reverse WebSocket also records lifecycle
traces such as onebot:connection_registered and
onebot:connection_unregistered, so the same smoke run can require connection
audit evidence with --expect-trace.
Use superbot-acceptance to prepare persistent stores, preview the production
gate, and print the startup, smoke, OneBot smoke, external evidence, and
capture_before / capture_after commands for an acceptance window. Use
superbot-capture-evidence to save control API snapshots before and after a
real QQ trigger; when a raw NapCat action log is provided, it checks for
send_group_msg or send_private_msg evidence. Final production verification
requires that raw log evidence; screenshots are supplementary human-review
evidence only. Pass --napcat-action-screenshot <path> when a non-empty
screenshot should also be recorded in capture-summary.json.
Pass superbot-acceptance preflight --with-scan when scanner roots are
available before the acceptance window; it runs scan-once first, saves
.superbot/acceptance/scan.json, and fails if scanner refresh reports an
error before validation.
superbot-acceptance commands also emits artifact_commands: copy those
PowerShell redirection commands when you want the required smoke, OneBot smoke,
external evidence, capture result, and verify JSON files saved directly under
.superbot/acceptance/.
The same payload includes readiness_gaps, a token-safe list of missing real
acceptance inputs such as OneBot self_id, external framework roots, trigger
message, QQ group/user target, and NapCat raw action log. Use it before opening
the real QQ trigger window so incomplete parameters fail early instead of at the
final capture or verify step.
The generated production start and preflight commands pass
--llm-provider CONFIG_DIR/llm-provider.json by default, so AI provider settings
saved from the Web console are loaded again during the acceptance restart.
The same payload includes acceptance_steps, an ordered runbook for the
acceptance window: preflight, start service, connect NapCat/OneBot, smoke,
external evidence, pre-trigger capture, optional NapCat log baseline copy, real
QQ trigger, post-trigger capture, and final verify.
The generated post-trigger capture command includes
--wait-for-capture-ok --wait-deadline 30 --wait-interval 2, so it polls until
the control snapshots and capture checks pass, or records failed attempts in
wait-attempts.json when the deadline expires.
When --napcat-action-log is supplied, the generated artifact_commands also
include napcat_action_log_baseline, a pre-trigger copy command for the raw log;
the generated post-trigger capture command passes that baseline with
--baseline-napcat-action-log so only newly added send actions can satisfy the
NapCat raw-log evidence gate.
Parseable JSON/JSONL action records are checked for successful status or
retcode, and for a successful record matching qq_group_id or qq_user_id
when trigger target metadata is supplied.
Pass the pre-trigger traces.json to the after capture with
--baseline-traces to require dispatch, bridge, and send traces added by the
trigger rather than stale entries from an earlier run. Post-trigger captures
also require a rendered bridge command, the selected capability in bridge
traces, and a delivery target matching the captured QQ group or user. Use
--expect-capability-id <id> when the acceptance trigger must prove a specific
learned capability was selected. Declared self_id, framework-root,
post-trigger, bridge, delivery-target, capability, trigger/bridge/delivery same-dispatch_id
closed-loop, send-trace, raw-log, and optional screenshot expectations are folded into the capture gate, so insufficient
evidence exits non-zero instead of looking like a successful capture. The source checkout also
keeps python tools/production_acceptance.py ... and
python tools/capture_external_evidence.py ... wrappers for local development.
After the acceptance window, run
superbot-acceptance verify --config-dir .superbot --require-capture-summary
to check the saved preflight.json, smoke.json, onebot-smoke.json,
external-evidence.json, any generated scan.json, capture-before-result.json,
capture-after-result.json, and post-trigger capture-summary.json artifacts
as one gate. The default generated command layout stores the capture summary at
.superbot/acceptance/after/capture-summary.json.
When the post-trigger capture used the generated wait mode, the final summary
also records wait.satisfied; wait-attempts.json keeps the failed pre-success
polling attempts for diagnosis.
The final verify gate also cross-checks the capture summary for declared
NapCat action evidence: raw logs are required and must pass
existence/readability/send-action checks, baseline-backed raw logs must pass
new_napcat_* checks, and any declared screenshots must pass
existence/file/non-empty checks.
The capture summary must also declare the trigger message and at least one QQ
target (qq_group_id or qq_user_id); a trigger text without the real group or
private-user target is rejected by final production verification.
For final production verification, the embedded gate_result from
superbot-evidence must also be present, ok, and have no failed summary or
check entries. The standalone capture-summary.json must match the embedded
summary inside capture-after-result.json, so swapped or stale capture files
fail verification.
A capture with no declared real self_id, framework root, trigger metadata, or
NapCat action log/screenshot is only a snapshot and fails the external capture
gate.
See docs/deployment-checklist.md and
docs/external-evidence-capture.md for the
runtime, scanner, OneBot, smoke, and end-to-end dispatch evidence required
before calling a deployment complete.
For the final external-evidence gate, require the real NapCat or compatible
OneBot self_id and the real framework checkout path that should have been
scanned:
superbot-evidence --control-url http://127.0.0.1:8612 --api-token $env:SUPERBOT_API_TOKEN --expect-onebot-self-id 10000 --expect-framework-root yunzai=C:\bots\YunzaiThe evidence checker prints JSON and exits with code 2 when evidence is
insufficient. It rejects reserved smoke identities such as superbot-smoke,
runs live /api/scanners/scan-all, requires the configured scanner root to
match the provided path, requires the scan to discover plugins and learned
capabilities, and requires connection and scan traces in the running service.
It uses raw traces internally for those checks, but its saved evidence.traces
output is reduced to a redacted audit summary with stage, message, dispatch,
self_id, capability, framework, action, rendered-command presence, and target
metadata only; raw payloads, prompts, commands, tokens, and secret-like fields
are not kept in external-evidence.json.
Framework roots under the current workspace are rejected by default so local
fixtures are not mistaken for external framework evidence; use
--allow-workspace-framework-root only for lab harnesses.
This repository can verify the local tooling, startup gates, smoke checks, and artifact validators, but it does not contain the live external evidence itself. A deployment is still unfinished until an operator captures artifacts from a real NapCat or compatible OneBot connection, a real framework checkout outside this workspace, and a real QQ trigger. The completion boundary is:
superbot-acceptance verify --config-dir .superbot --require-capture-summaryreportsok: true.superbot-evidencereportsok: truefor the realself_idand framework root.- The post-trigger
capture-summary.jsonreportscapture_ok: truewith an emptycapture_failureslist. - If wait mode was used, the post-trigger
capture-summary.jsonreportswait.satisfied: true. - The post-trigger
capture-summary.jsoncontains rendered bridge-command traces, selected capability traces, and delivery target matches for the captured QQ group or user. - The NapCat action log proves the matching
send_group_msg/send_private_msgresult for the trigger target; final production verify no longer accepts screenshot-only NapCat evidence. When a raw action-log baseline was captured before the trigger, the proof must come from a new send action absent from that baseline.
When an app has a registered OneBotV11Adapter, app.create_task_orchestrator()
uses a OneBot message-command executor by default. Bridge payloads such as
#bnn 小猫 are sent to the originating group or private chat so the target
framework bot can respond there. The orchestrator registers message-command
bridges for Yunzai, AstrBot, NoneBot, GSUID Core, Koishi, and KiviBot learned
capabilities, so command-based plugins from those frameworks can be invoked
through the same QQ session when their command templates are known.
Message-command bridges render named template slots from decision arguments;
unknown slots such as {location} or {target} fall back to the parsed
prompt, and empty slots are removed instead of being sent literally.
OneBot API responses must be JSON objects; malformed protocol responses are
reported as API errors rather than treated as successful sends.
The optional reverse WebSocket server requires:
pip install "super-bot[onebot-ws]"If --onebot-ws is used without the optional dependency, the control CLI fails
before starting the HTTP control server and reports the missing package.
Codex automations and parallel agents should keep this project moving through a repeatable readiness loop: inspect the next highest-priority gap, implement a small bounded change, run the relevant unit/smoke checks, clean generated artifacts, and then continue with the next gap until real external acceptance evidence is available.
Each continuation round should treat these local checks as the baseline:
superbot-readinessThe readiness command runs the full unit suite, compileall, wheel build
smoke, editable-install and wheel-install console entrypoint checks,
sb run --validate-config, live sb run startup smoke against /health and
authenticated /api/status, and the lab acceptance harness. When websockets
is already installed it also runs the focused real WebSocket tests; pass
--with-onebot-ws-extra to create a temporary venv, install .[onebot-ws], and
force those checks.
The local lab acceptance chain is available as:
superbot-lab-acceptance --output-dir .superbot/lab-acceptance/latest --reset-output-dirIt creates a temporary Yunzai fixture, runs scanner refresh, starts the real
control API with an in-memory fake OneBot client, triggers a fake QQ group
message, captures before/after evidence, and runs acceptance verify. Its
artifacts are marked lab_only: true and are never a substitute for production
NapCat/QQ evidence.
The remaining continuation priorities are:
- Keep readiness coverage aligned with any new production gate or command.
- Keep
README.mdandREADME.zh-CN.mdupdated together whenever startup, acceptance, or evidence commands change.
Final completion still requires the external evidence boundary above: real
NapCat or compatible OneBot self_id, a real framework checkout outside this
repository, a real QQ trigger, post-trigger dispatch and delivery capture,
NapCat send-action evidence, and
superbot-acceptance verify --require-capture-summary passing against those
saved artifacts.
from superbot import SuperBot
app = SuperBot()
server = app.create_control_server(port=8612)
server.start()After installation, the same server is available as:
sb run --capabilities .superbot/capabilities.json --policies .superbot/policies.json --scanners .superbot/scanners.jsonWhen --capabilities or capability_store_path is provided, capability edits
and scanner results are saved back to that JSON file. When --policies or
policy_store_path is provided, delivery and permission policy changes are
saved back to that JSON file. When --scanners or scanner_store_path is
provided, scanner framework/root configuration is saved back to that JSON file.
If a configured store write fails, the control API rejects the request and
rolls runtime state back to the last in-memory value instead of leaving memory
ahead of disk.
Capability JSON loads are strict: list/object/boolean fields must have the
right shape, capability_id must be non-empty and unique, and
delivery_mode, confirmation_policy, and risk_level must use supported
values before the runtime starts. Unknown top-level capability fields are
rejected; put plugin/operator-specific extension data in metadata. Capability
string fields, string-list entries, and choice values are trimmed when loaded
from JSON or written through the control API, and duplicate capability_id
values are detected after trimming.
Permission policy JSON also rejects non-string entries inside owner,
whitelist, and blacklist lists.
Scanner JSON loads and scanner API updates also require string framework and
non-empty string root_path values, and scanner file objects reject unknown
top-level fields. Scanner framework and root_path values are trimmed when
loaded from JSON, written through the API, or configured programmatically.
Static scanner files reject duplicate framework entries after trimming so one
scanner does not silently overwrite another during startup.
Scanner API updates preserve existing scanner metadata unless a replacement
metadata object is provided.
When --api-token or api_token is provided, control API endpoints require
Authorization: Bearer <token> or X-SuperBot-Token: <token>; /health
remains unauthenticated for local health checks. Query-string tokens are
ignored by /api endpoints so secrets are not exposed through browser history,
logs, or Referer headers. The built-in dashboard shell can be opened at /;
enter the token in the dashboard or open /#token=<token> to store it in
sessionStorage. Dashboard API calls send the token with X-SuperBot-Token
instead of placing it in API URLs. The Bearer scheme is case-insensitive, and
header token values are trimmed before constant-time comparison.
The Web control console shows runtime status, learned capabilities, OneBot
connection snapshots, production completion, the current highest-priority
blocker, a next-action center, runtime diagnostics, traces/logs, policies, and
scanner configuration. It also includes an AI provider panel for OpenAI-compatible
model base URLs, API keys, model names, redacted saved-key status, and a live
provider test, plus a production startup guide that shows token-safe validate,
restart, and preflight commands. It is
the operator-facing place to confirm that NapCat is connected to the default
reverse WebSocket URL ws://<ip>:4612/onebot/v11/ws, inspect recent dispatch
activity, review production posture, run controlled OneBot status/login/test
message actions, review policy state, configure the LLM provider, and run
scanner refreshes without hand-writing API requests.
Technical JSON previews in the dashboard are kept under collapsed "technical
details" blocks by default, so operators can read the human-facing summaries
first and only expand raw diagnostic context when troubleshooting. This includes
LLM provider test output, controlled OneBot action responses, scanner run
results, acceptance previews, and artifact summaries.
Dashboard refreshes load each section independently: if one API endpoint fails,
that section shows a localized error while the rest of the console continues to
render.
Dangerous LLM provider actions such as clearing the saved provider or clearing
the saved key require a browser confirmation. The OneBot test action form also
checks self_id, target, message, and the explicit send confirmation before
posting send_private_msg or send_group_msg.
Command blocks in the startup guide and next-action center include one-click
copy controls. They copy the rendered token-safe command text only; secrets stay
as environment-variable placeholders.
For deployments, SUPERBOT_API_TOKEN and SUPERBOT_ONEBOT_TOKEN can provide
the same secrets without placing them in the process command line; explicit CLI
flags take precedence. CLI and environment token values are trimmed at startup.
Programmatic api_token values are trimmed when the control server is created.
The minimal endpoints are:
GET /api/statusGET /api/diagnosticsGET /api/startup/onboardingGET /api/acceptance/statusGET /api/actions/statusGET /api/artifacts/statusGET /api/capabilitiesGET /api/capabilities/onboardingPOST /api/capabilities/{capability_id}GET /api/scannersGET /api/scanners/onboardingPOST /api/scannersPOST /api/scanners/{framework}/scanPOST /api/scanners/scan-allGET /api/policiesGET /api/policies/onboardingPOST /api/policiesGET /api/llm/providerPOST /api/llm/providerPOST /api/llm/provider/testGET /api/onebot/onboardingGET /api/connectionsPOST /api/onebot/actionGET /api/traces
The bundled dashboard exposes the same scanner controls: add or update scanner
roots, mark scanners enabled or disabled, run one scanner, or run scan-all.
It also shows live diagnostics from the same engine as sb run --validate-config;
use /api/diagnostics?strict=true&production=true to check the production gate
from a running service. GET /api/startup/onboarding powers the production
startup guide: it is read-only and returns redacted token state, persistent
store status, next-step blockers, and copyable commands for validating config,
restarting with --llm-provider .superbot/llm-provider.json, and running
preflight. It only uses $env:SUPERBOT_API_TOKEN and
$env:SUPERBOT_ONEBOT_TOKEN placeholders, and does not echo the real control
token, OneBot token, or LLM provider key. GET /api/acceptance/status is a
read-only production acceptance overview: it summarizes production diagnostics,
the current real OneBot/framework/capability/LLM gaps, saved
.superbot/acceptance artifact verification, and an operator runbook with
environment-variable token placeholders. It also exposes the same token-safe
readiness_gaps list as superbot-acceptance commands, so the dashboard can
show missing self IDs, external framework roots, trigger text, QQ targets, or
NapCat raw-log parameters before the real trigger window. It does not trigger
scan-all on page load and does not echo the current control or OneBot token.
The production acceptance panel includes a session-only evidence-parameter form
for the real trigger message, QQ group or user target, expected capability IDs,
NapCat raw action log, and optional screenshots; applying it refreshes the
acceptance overview and generated runbook without writing those values to the
persistent stores. The same panel renders a copyable acceptance command package
from artifact_commands, preferring commands that redirect smoke, evidence,
capture, and verify output into .superbot/acceptance/ so operators do not have
to pull required commands from the raw JSON preview. The first command block in
that package is a "copy all" bundle with ordered comments for the whole
acceptance window; the following blocks still allow copying one command at a
time.
GET /api/actions/status powers the next-action center: it read-only aggregates
acceptance blockers plus the startup, NapCat, scanner, capability, policy, LLM,
and artifact guides into a prioritized operator queue with dashboard anchors and
token-safe commands. Its response includes those acceptance readiness gaps for
the right-side operator checklist, using the same evidence parameters when the
dashboard form is filled. It only returns redacted context and
environment-variable placeholders, never the real control token, OneBot token,
or LLM provider key.
GET /api/artifacts/status powers the dashboard
artifact center: it only summarizes .superbot/acceptance and
.superbot/readiness file status, the latest readiness run, and bounded JSON
metadata, without returning raw logs, command lines, or secret-like fields.
GET /api/onebot/onboarding powers the NapCat onboarding guide: it returns the
recommended reverse WebSocket URL, NapCat settings, token status, real and smoke
connection counts, a smoke command, and next steps without exposing the real
token.
GET /api/scanners/onboarding powers the framework scanning guide: it checks
scanner configuration, external repository roots, learned capability counts, and
next actions without automatically running scan-all.
GET /api/capabilities/onboarding powers the capability enablement guide: it is
read-only and summarizes learned/enabled/unavailable capabilities, risk levels,
owner-required capability counts, framework totals, persistent store status, and
recommended first capabilities to review before production smoke.
GET /api/policies/onboarding powers the security policy guide: it is read-only
and explains whether owner QQ IDs, high-risk owner confirmation, policy store
persistence, and whitelist/blacklist counts are ready for production. It can
surface recent candidate user/group IDs from redacted traces, but it does not
modify policy and does not echo tokens.
POST /api/onebot/action is a controlled test surface,
not a general OneBot proxy: it requires a control API token, only allows
get_status, get_login_info, send_private_msg, and send_group_msg, and
send actions require confirm_send=true.
Scanner configuration changes record control:scanner_configured trace entries
with the effective framework, root, enabled state, and metadata.
Control API errors are returned as JSON objects with error.status,
error.code, and error.message, including authentication and validation
failures.
POST request bodies must be UTF-8 JSON objects no larger than 1 MiB; malformed,
misencoded, or oversized bodies return JSON 400 errors.
Capability, policy, and scanner update payloads reject unsupported fields so
typos such as owner, risk, or enabledd do not silently become no-ops.
Capability, scanner, and trace API responses also recursively coerce common
extension values such as datetime, path-like objects, sets, tuples, non-string
mapping keys, and non-finite floats into JSON-safe values before returning or
persisting them. This keeps plugin-provided metadata from breaking the control
surface.
The in-process capability index, trace log, scanner registry, policy objects,
and OneBot connection snapshots are protected for the local control server's
HTTP threads reading state while the bot runtime updates it.
GET /api/capabilities accepts framework, enabled, q/query, limit,
and offset query parameters. GET /api/traces accepts stage, message,
q/query, limit, offset, and redacted. Trace responses are redacted by
default for the dashboard; redacted=false requires a configured control API
token, and evidence tooling uses it only with that token when it needs raw audit
payloads for closed-loop verification.
Both endpoints keep their original list field and add a page object with
total, count, offset, and limit.
GET /api/status reports whether each configured store exists and is writable,
including parent-directory and file-level writability signals used by
superbot-smoke --require-writable-stores.
superbot.core: application container, bot runtime, events, messages, and control-flow exceptions.superbot.plugins: decorator-based plugin manager and handler dispatch.superbot.adapters: protocol adapter interfaces and implementations.superbot.adapters.onebot: OneBot protocol implementations.superbot.utils: small shared internal helpers.
Public imports should prefer from superbot import .... Internal framework code
should import from the concrete subpackage it belongs to, such as
superbot.core.events or superbot.plugins.manager.
Run the tests with:
python -m unittest discover -s testsThe CI workflow runs the same core gate on Python 3.10, 3.11, and 3.12:
python -m unittest discover -s tests -v
python -m compileall -q superbot tests
python -m pip wheel . --wheel-dir "$env:TEMP\superbot-wheel-verify"
python -m superbot.cli --help
python -m superbot --help
python -m superbot.cli run --help
python -m superbot.cli run --api-token dev-api-token --validate-config
python -m superbot.cli run --api-token dev-api-token --llm-decision-url http://127.0.0.1:9999/decide --validate-config
python -m superbot.cli run --api-token dev-api-token --validate-config --strict-validate-config
python -m superbot.cli run --api-token dev-api-token --validate-config --require-production-config
python -m superbot.control --help
python -m superbot.control.production_acceptance --help
python -m superbot.control.external_evidence_capture --help
python -m superbot.control.evidence --help
python -m superbot.control.lab_acceptance --help
python -m superbot.control.readiness --help
python -m superbot.control.smoke --help
superbot-acceptance --help
superbot-lab-acceptance --help
superbot-readiness --help
sb --help
sb run --help
sb run --api-token dev-api-token --validate-config
sb run --api-token dev-api-token --validate-config --strict-validate-config
superbot-control --help
superbot-capture-evidence --help
superbot-evidence --help
superbot-smoke --helpThe superbot-control and python -m superbot.control entries remain
compatibility checks for the lower-level control CLI. Production startup and
runtime validation should use sb run.
In the Codex desktop runtime used for this repository, the bundled Python path is:
C:\Users\Administrator\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe -m unittest discover -s tests -vInstall super-bot[onebot-ws] or websockets>=12 to enable the optional real
reverse WebSocket server/client integration tests; otherwise those tests are
skipped and the fake transport coverage still runs.
With the optional dependency installed, run the focused WebSocket checks with:
python -m unittest tests.test_core.CoreTests.test_onebot_reverse_ws_real_websockets_server_roundtrip_when_available tests.test_core.CoreTests.test_control_smoke_onebot_ws_handshake_when_available tests.test_core.CoreTests.test_control_smoke_onebot_ws_connection_visible_when_available tests.test_core.CoreTests.test_control_smoke_onebot_ws_trace_expectation_when_available -v