| .github | ||
| docs | ||
| examples | ||
| src | ||
| test | ||
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
OpenClaw Plugin Inspector
plugin-inspector is the offline compatibility check for OpenClaw plugins. Run
it from a plugin root to inspect package metadata, openclaw.plugin.json, SDK
imports, api.on(...), api.register*, and optional runtime registration
capture.
Quick Start
From a plugin package directory:
npx @openclaw/plugin-inspector
That runs check, writes report artifacts to reports/, and exits non-zero
when compatibility breakages are found.
Add a local config and GitHub Actions workflow:
npx @openclaw/plugin-inspector init --ci
Or install it as a dev dependency:
npm install --save-dev @openclaw/plugin-inspector
npx plugin-inspector check
Commands
npx @openclaw/plugin-inspector check
npx @openclaw/plugin-inspector inspect
npx @openclaw/plugin-inspector ci --no-openclaw
npx @openclaw/plugin-inspector config
npx @openclaw/plugin-inspector check --plugin-root ./plugins/weather
npx @openclaw/plugin-inspector init --ci --package-manager pnpm
check and inspect read the current directory as one plugin unless
--plugin-root is set. inspect is the friendly author-facing alias; check
is kept for scripts. Both write:
reports/plugin-inspector-report.jsonreports/plugin-inspector-report.mdreports/plugin-inspector-issues.md
Use CI-native outputs when you want annotations or test-summary ingestion:
plugin-inspector inspect --no-openclaw --sarif --junit
That also writes:
reports/plugin-inspector.sarifreports/plugin-inspector.junit.xml
config prints the resolved plugin root, fixture id, seams, and capture
settings before CI runs:
plugin-inspector config --json
Use --no-openclaw when CI should not compare against a local OpenClaw
checkout:
plugin-inspector check --no-openclaw
Use either plugin-inspector.config.json or a package.json
pluginInspector block when CI needs stable fixture metadata, expected seams,
or runtime capture defaults:
{
"version": 1,
"plugin": {
"id": "weather",
"priority": "high",
"seams": ["dynamic-tool"],
"sourceRoot": "src",
"expect": {
"registrations": ["registerTool"]
}
},
"capture": {
"mockSdk": true
},
"openclaw": {
"defaultCheckoutPath": "../openclaw"
}
}
Then run:
plugin-inspector check --config plugin-inspector.config.json
For a single plugin package, the same config can live in package.json:
{
"scripts": {
"plugin:check": "plugin-inspector inspect --no-openclaw"
},
"pluginInspector": {
"version": 1,
"plugin": {
"id": "weather",
"priority": "high",
"seams": ["dynamic-tool"],
"sourceRoot": "src"
},
"capture": {
"mockSdk": true
}
}
}
init --ci writes this shape for you, plus
.github/workflows/plugin-inspector.yml. Copy-ready examples also live in
examples/plugin-inspector.config.json and
examples/package-json-plugin-inspector.json and
examples/github-actions-plugin-inspector.yml.
Runtime Capture
Runtime capture imports plugin entrypoints in an isolated subprocess and records
the registrations made during register(api). It is opt-in because it executes
plugin code:
PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector check --runtime --mock-sdk
By default, runtime capture uses a generated mock for openclaw/plugin-sdk and
common external packages so plugin code can load in clean CI without OpenClaw
installed. Use --real-sdk only when the plugin workspace already has real SDK
dependencies installed and you intentionally want to test that path.
Runtime capture writes:
reports/plugin-inspector-runtime-capture.jsonreports/plugin-inspector-runtime-capture.md
You can also capture one entrypoint directly:
PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector capture ./dist/index.js --mock-sdk
CI
Minimal package scripts:
{
"scripts": {
"plugin:check": "plugin-inspector inspect --no-openclaw",
"plugin:ci": "PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector ci --no-openclaw --runtime --mock-sdk"
}
}
GitHub Actions without a local dev dependency:
name: plugin-inspector
on:
pull_request:
push:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 24
cache: npm
- run: npm ci
- run: PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk
- uses: actions/upload-artifact@v5
if: always()
with:
name: plugin-inspector-reports
path: reports/plugin-inspector-*
ci writes the normal report, CI summary, SARIF, and JUnit files by default.
Pass --no-sarif or --no-junit only if your CI surface cannot consume them.
Fixture Suites
Fixture-set configs are still supported for crabpot-style compatibility suites:
plugin-inspector report --config crabpot.config.json --out reports
Use fixture suites when one repo wants to inspect many plugins. Use plugin-root
check for normal plugin CI.
Mocking Model
Default inspection is static, offline, and credential-free. Runtime capture is the only mode that imports plugin code.
When --mock-sdk is enabled, the inspector generates temporary modules for
openclaw/plugin-sdk subpaths and unresolved external packages discovered in
the plugin import graph. The mock SDK captures registrations; it does not call
network services, launch OpenClaw, run provider SDKs, or emulate service
lifecycle side effects.
Use the mock lane for plugin compatibility CI. Keep live provider/service tests in the plugin repo behind their own credentials and explicit opt-in flags.
Scope
Default inspection is offline and credential-free. It reads manifests, package
metadata, and source files, then reports observed api.on(...),
api.register*, define*, SDK imports, and manifest contracts.
OpenClaw target checkout parsing is limited to public compatibility registries,
SDK package exports, manifest types, hooks, and captured registrar metadata.
Cold import capture, synthetic contract probes, and runtime capture are explicit opt-in modes. Live lanes stay credential-gated and must never run in default CI.