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.
From a plugin package directory:
npx @openclaw/plugin-inspectorThat 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 --ciinit --ci detects packageManager and common lockfiles. Pass
--package-manager pnpm, npm, yarn, or bun when you want to override it.
Add --scripts to write plugin:check and plugin:ci package scripts.
Use --dry-run to preview the files first.
Or install it as a dev dependency:
npm install --save-dev @openclaw/plugin-inspector
npx plugin-inspector checknpx @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
npx @openclaw/plugin-inspector init --ci --scripts --dry-run
npx @openclaw/plugin-inspector init --ci --scripts --dry-run --jsoncheck 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 --junitThat 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 --jsonUse --no-openclaw when CI should not compare against a local OpenClaw
checkout:
plugin-inspector check --no-openclawUse 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.jsonFor 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. SARIF/JUnit CI consumption
examples live alongside them.
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:
npx @openclaw/plugin-inspector check --runtime --mock-sdk --allow-execute--allow-execute is the explicit guard for modes that import plugin code. The
older PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 environment guard still works for
custom harnesses.
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 capture ./dist/index.js --mock-sdk --allow-executeMinimal package scripts:
{
"scripts": {
"plugin:check": "plugin-inspector inspect --no-openclaw",
"plugin:ci": "plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute"
}
}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: npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute
- 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.
For GitHub code scanning, use
examples/github-actions-code-scanning.yml; it uploads
reports/plugin-inspector.sarif through CodeQL's SARIF upload action.
For CI test-summary UIs, point JUnit ingestion at
reports/plugin-inspector.junit.xml. Copy-ready GitLab and CircleCI examples
live in examples/gitlab-ci-plugin-inspector.yml and
examples/circleci-plugin-inspector.yml.
Fixture-set configs are still supported for crabpot-style compatibility suites:
plugin-inspector report --config crabpot.config.json --out reportsUse fixture suites when one repo wants to inspect many plugins. Use plugin-root
check for normal plugin CI.
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.
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.
