Files
openclaw/docs/plugins/manifest.md

242 lines
13 KiB
Markdown

---
summary: "Plugin manifest + JSON schema requirements (strict config validation)"
read_when:
- You are building an OpenClaw plugin
- You need to ship a plugin config schema or debug plugin validation errors
title: "Plugin Manifest"
---
# Plugin manifest (openclaw.plugin.json)
This page is for the **native OpenClaw plugin manifest** only.
For compatible bundle layouts, see [Plugin bundles](/plugins/bundles).
Compatible bundle formats use different manifest files:
- Codex bundle: `.codex-plugin/plugin.json`
- Claude bundle: `.claude-plugin/plugin.json` or the default Claude component
layout without a manifest
- Cursor bundle: `.cursor-plugin/plugin.json`
OpenClaw auto-detects those bundle layouts too, but they are not validated
against the `openclaw.plugin.json` schema described here.
For compatible bundles, OpenClaw currently reads bundle metadata plus declared
skill roots, Claude command roots, Claude bundle `settings.json` defaults, and
supported hook packs when the layout matches OpenClaw runtime expectations.
Every native OpenClaw plugin **must** ship a `openclaw.plugin.json` file in the
**plugin root**. OpenClaw uses this manifest to validate configuration
**without executing plugin code**. Missing or invalid manifests are treated as
plugin errors and block config validation.
See the full plugin system guide: [Plugins](/tools/plugin).
For the native capability model and current external-compatibility guidance:
[Capability model](/plugins/architecture#public-capability-model).
## What this file does
`openclaw.plugin.json` is the metadata OpenClaw reads before it loads your
plugin code.
Use it for:
- plugin identity
- config validation
- auth and onboarding metadata that should be available without booting plugin
runtime
- config UI hints
Do not use it for:
- registering runtime behavior
- declaring code entrypoints
- npm install metadata
Those belong in your plugin code and `package.json`.
## Minimal example
```json
{
"id": "voice-call",
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {}
}
}
```
## Rich example
```json
{
"id": "openrouter",
"name": "OpenRouter",
"description": "OpenRouter provider plugin",
"version": "1.0.0",
"providers": ["openrouter"],
"providerAuthEnvVars": {
"openrouter": ["OPENROUTER_API_KEY"]
},
"providerAuthChoices": [
{
"provider": "openrouter",
"method": "api-key",
"choiceId": "openrouter-api-key",
"choiceLabel": "OpenRouter API key",
"groupId": "openrouter",
"groupLabel": "OpenRouter",
"optionKey": "openrouterApiKey",
"cliFlag": "--openrouter-api-key",
"cliOption": "--openrouter-api-key <key>",
"cliDescription": "OpenRouter API key",
"onboardingScopes": ["text-inference"]
}
],
"uiHints": {
"apiKey": {
"label": "API key",
"placeholder": "sk-or-v1-...",
"sensitive": true
}
},
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": {
"type": "string"
}
}
}
}
```
## Top-level field reference
| Field | Required | Type | What it means |
| --------------------- | -------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `id` | Yes | `string` | Canonical plugin id. This is the id used in `plugins.entries.<id>`. |
| `configSchema` | Yes | `object` | Inline JSON Schema for this plugin's config. |
| `enabledByDefault` | No | `true` | Marks a bundled plugin as enabled by default. Omit it, or set any non-`true` value, to leave the plugin disabled by default. |
| `kind` | No | `"memory"` \| `"context-engine"` | Declares an exclusive plugin kind used by `plugins.slots.*`. |
| `channels` | No | `string[]` | Channel ids owned by this plugin. Used for discovery and config validation. |
| `providers` | No | `string[]` | Provider ids owned by this plugin. |
| `providerAuthEnvVars` | No | `Record<string, string[]>` | Cheap provider-auth env metadata that OpenClaw can inspect without loading plugin code. |
| `providerAuthChoices` | No | `object[]` | Cheap auth-choice metadata for onboarding pickers, preferred-provider resolution, and simple CLI flag wiring. |
| `skills` | No | `string[]` | Skill directories to load, relative to the plugin root. |
| `name` | No | `string` | Human-readable plugin name. |
| `description` | No | `string` | Short summary shown in plugin surfaces. |
| `version` | No | `string` | Informational plugin version. |
| `uiHints` | No | `Record<string, object>` | UI labels, placeholders, and sensitivity hints for config fields. |
## providerAuthChoices reference
Each `providerAuthChoices` entry describes one onboarding or auth choice.
OpenClaw reads this before provider runtime loads.
| Field | Required | Type | What it means |
| ------------------ | -------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `provider` | Yes | `string` | Provider id this choice belongs to. |
| `method` | Yes | `string` | Auth method id to dispatch to. |
| `choiceId` | Yes | `string` | Stable auth-choice id used by onboarding and CLI flows. |
| `choiceLabel` | No | `string` | User-facing label. If omitted, OpenClaw falls back to `choiceId`. |
| `choiceHint` | No | `string` | Short helper text for the picker. |
| `groupId` | No | `string` | Optional group id for grouping related choices. |
| `groupLabel` | No | `string` | User-facing label for that group. |
| `groupHint` | No | `string` | Short helper text for the group. |
| `optionKey` | No | `string` | Internal option key for simple one-flag auth flows. |
| `cliFlag` | No | `string` | CLI flag name, such as `--openrouter-api-key`. |
| `cliOption` | No | `string` | Full CLI option shape, such as `--openrouter-api-key <key>`. |
| `cliDescription` | No | `string` | Description used in CLI help. |
| `onboardingScopes` | No | `Array<"text-inference" \| "image-generation">` | Which onboarding surfaces this choice should appear in. If omitted, it defaults to `["text-inference"]`. |
## uiHints reference
`uiHints` is a map from config field names to small rendering hints.
```json
{
"uiHints": {
"apiKey": {
"label": "API key",
"help": "Used for OpenRouter requests",
"placeholder": "sk-or-v1-...",
"sensitive": true
}
}
}
```
Each field hint can include:
| Field | Type | What it means |
| ------------- | ---------- | --------------------------------------- |
| `label` | `string` | User-facing field label. |
| `help` | `string` | Short helper text. |
| `tags` | `string[]` | Optional UI tags. |
| `advanced` | `boolean` | Marks the field as advanced. |
| `sensitive` | `boolean` | Marks the field as secret or sensitive. |
| `placeholder` | `string` | Placeholder text for form inputs. |
## Manifest versus package.json
The two files serve different jobs:
| File | Use it for |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `openclaw.plugin.json` | Discovery, config validation, auth-choice metadata, and UI hints that must exist before plugin code runs |
| `package.json` | npm metadata, dependency installation, and the `openclaw` block used for entrypoints and setup or catalog metadata |
If you are unsure where a piece of metadata belongs, use this rule:
- if OpenClaw must know it before loading plugin code, put it in `openclaw.plugin.json`
- if it is about packaging, entry files, or npm install behavior, put it in `package.json`
## JSON Schema requirements
- **Every plugin must ship a JSON Schema**, even if it accepts no config.
- An empty schema is acceptable (for example, `{ "type": "object", "additionalProperties": false }`).
- Schemas are validated at config read/write time, not at runtime.
## Validation behavior
- Unknown `channels.*` keys are **errors**, unless the channel id is declared by
a plugin manifest.
- `plugins.entries.<id>`, `plugins.allow`, `plugins.deny`, and `plugins.slots.*`
must reference **discoverable** plugin ids. Unknown ids are **errors**.
- If a plugin is installed but has a broken or missing manifest or schema,
validation fails and Doctor reports the plugin error.
- If plugin config exists but the plugin is **disabled**, the config is kept and
a **warning** is surfaced in Doctor + logs.
See [Configuration reference](/gateway/configuration) for the full `plugins.*` schema.
## Notes
- The manifest is **required for native OpenClaw plugins**, including local filesystem loads.
- Runtime still loads the plugin module separately; the manifest is only for
discovery + validation.
- Only documented manifest fields are read by the manifest loader. Avoid adding
custom top-level keys here.
- `providerAuthEnvVars` is the cheap metadata path for auth probes, env-marker
validation, and similar provider-auth surfaces that should not boot plugin
runtime just to inspect env names.
- `providerAuthChoices` is the cheap metadata path for auth-choice pickers,
`--auth-choice` resolution, preferred-provider mapping, and simple onboarding
CLI flag registration before provider runtime loads. For runtime wizard
metadata that requires provider code, see
[Provider runtime hooks](/plugins/architecture#provider-runtime-hooks).
- Exclusive plugin kinds are selected through `plugins.slots.*`.
- `kind: "memory"` is selected by `plugins.slots.memory`.
- `kind: "context-engine"` is selected by `plugins.slots.contextEngine`
(default: built-in `legacy`).
- `channels`, `providers`, and `skills` can be omitted when a plugin does not
need them.
- If your plugin depends on native modules, document the build steps and any
package-manager allowlist requirements (for example, pnpm `allow-build-scripts`
- `pnpm rebuild <package>`).