Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled

Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
2026-07-05 09:36:54 +00:00
parent 3216769225
commit bedb527145
21108 changed files with 6010766 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
---
summary: "Contributor guide for adding a new shared capability to the OpenClaw plugin system"
read_when:
- Adding a new core capability and plugin registration surface
- Deciding whether code belongs in core, a vendor plugin, or a feature plugin
- Wiring a new runtime helper for channels or tools
title: "Adding capabilities (contributor guide)"
sidebarTitle: "Adding capabilities"
---
<Info>
This is a **contributor guide** for OpenClaw core developers. If you are
building an external plugin, see [Building plugins](/plugins/building-plugins)
instead. For the deep architecture reference (capability model, ownership,
load pipeline, runtime helpers), see [Plugin internals](/plugins/architecture).
</Info>
Use this when OpenClaw needs a new shared domain such as embeddings, image
generation, video generation, or some future vendor-backed feature area.
The rule:
- **plugin** = ownership boundary
- **capability** = shared core contract
Do not wire a vendor directly into a channel or a tool. Define the capability first.
## When to create a capability
Create a new capability only when **all** of these are true:
1. More than one vendor could plausibly implement it.
2. Channels, tools, or feature plugins should consume it without caring about the vendor.
3. Core needs to own fallback, policy, config, or delivery behavior.
If the work is vendor-only and no shared contract exists yet, define the contract first.
## The standard sequence
1. Define the typed core contract.
2. Add plugin registration for that contract.
3. Add a shared runtime helper.
4. Wire one real vendor plugin as proof.
5. Move feature/channel consumers onto the runtime helper.
6. Add contract tests.
7. Document the operator-facing config and ownership model.
## What goes where
| Layer | Owns |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Core** | Request/response types; provider registry and resolution; fallback behavior; config schema with propagated `title`/`description` docs metadata on nested object, wildcard, array-item, and composition nodes; runtime helper surface. |
| **Vendor plugin** | Vendor API calls, vendor auth handling, vendor-specific request normalization, and registration of the capability implementation. |
| **Feature/channel plugin** | Calls `api.runtime.*` or the matching `plugin-sdk/*-runtime` helper. Never calls a vendor implementation directly. |
## Provider and harness seams
Use **provider hooks** when the behavior belongs to the model provider contract rather than the generic agent loop. Examples include provider-specific request params after transport selection, auth-profile preference, prompt overlays, and follow-up fallback routing after model/profile failover.
Use **agent harness hooks** when the behavior belongs to the runtime that is executing a turn. Harnesses can classify explicit protocol outcomes such as empty output, reasoning without visible output, or a structured plan without a final answer so the outer model fallback policy can make the retry decision.
Keep both seams narrow:
- Core owns the retry/fallback policy.
- Provider plugins own provider-specific request/auth/routing hints.
- Harness plugins own runtime-specific attempt classification.
- Third-party plugins return hints, not direct mutations of core state.
## File checklist
For a new capability, expect to touch these areas:
- `src/<capability>/types.ts`
- `src/<capability>/...registry/runtime.ts`
- `src/plugins/types.ts`
- `src/plugins/registry.ts`
- `src/plugins/captured-registration.ts`
- `src/plugins/contracts/registry.ts`
- `src/plugins/runtime/types-core.ts`
- `src/plugins/runtime/index.ts`
- `src/plugin-sdk/<capability>.ts`
- `src/plugin-sdk/<capability>-runtime.ts`
- One or more bundled plugin packages.
- Config, docs, tests.
## Worked example: image generation
Image generation follows the standard shape:
1. Core defines `ImageGenerationProvider`.
2. Core exposes `registerImageGenerationProvider(...)`.
3. Core exposes `api.runtime.imageGeneration.generate(...)` and `.listProviders(...)`.
4. Vendor plugins (`comfy`, `deepinfra`, `fal`, `google`, `litellm`, `microsoft-foundry`, `minimax`, `openai`, `openrouter`, `vydra`, `xai`) register vendor-backed implementations.
5. Future vendors register the same contract without changing channels/tools.
The config key is intentionally separate from vision-analysis routing:
- `agents.defaults.imageModel` analyzes images.
- `agents.defaults.imageGenerationModel` generates images.
Keep those separate so fallback and policy remain explicit.
## Embedding providers
Use `registerEmbeddingProvider(...)` / contract `embeddingProviders` for
reusable vector embedding providers. This contract is intentionally broader
than memory: tools, search, retrieval, importers, or future feature plugins
can consume embeddings without depending on the memory engine. Memory search
also consumes generic `embeddingProviders`.
The older memory-specific registration API and `memoryEmbeddingProviders`
contract are deprecated. Use `registerEmbeddingProvider` and
`embeddingProviders` for all new embedding providers.
## Review checklist
Before shipping a new capability, verify:
- No channel/tool imports vendor code directly.
- The runtime helper is the shared path.
- At least one contract test asserts bundled ownership.
- Config docs name the new model/config key.
- Plugin docs explain the ownership boundary.
If a PR skips the capability layer and hardcodes vendor behavior into a channel/tool, send it back and define the contract first.
## Related
- [Plugin internals](/plugins/architecture) — capability model, ownership, load pipeline, runtime helpers.
- [Building plugins](/plugins/building-plugins) — first-plugin tutorial.
- [SDK overview](/plugins/sdk-overview) — import map and registration API reference.
- [Creating skills](/tools/creating-skills) — companion contributor surface.

View File

@@ -0,0 +1,224 @@
---
summary: "Expose selected Gateway control-plane methods through the bundled, opt-in admin-http-rpc plugin"
read_when:
- Building host tooling that cannot use the Gateway WebSocket RPC client
- Exposing Gateway admin automation behind a private trusted ingress
- Auditing the security model for HTTP access to Gateway methods
title: "Admin HTTP RPC plugin"
---
The bundled `admin-http-rpc` plugin exposes an allowlisted set of Gateway control-plane methods over HTTP, for trusted host automation that cannot keep a Gateway WebSocket connection open.
It ships with OpenClaw but is disabled by default; when disabled, the route is not registered. When enabled, it adds `POST /api/v1/admin/rpc` on the same listener as the Gateway (`http://<gateway-host>:<port>/api/v1/admin/rpc`).
Enable it only for private host tooling, tailnet automation, or a trusted internal ingress. Never expose this route directly to the public internet.
## Before you enable it
Admin HTTP RPC is a full operator control-plane surface: any caller that passes Gateway HTTP auth can invoke the allowlisted methods below. Enable it only when all of these are true:
- The caller is trusted to operate the Gateway.
- The caller cannot use the WebSocket RPC client.
- The route is reachable only on loopback, a tailnet, or a private authenticated ingress.
- You have reviewed the allowed methods and they match the automation you plan to run.
For OpenClaw clients and interactive tools that can keep a Gateway WebSocket connection open, use WebSocket RPC instead.
## Enable
Enable the bundled plugin:
<Tabs>
<Tab title="CLI">
```bash
openclaw plugins enable admin-http-rpc
openclaw gateway restart
```
</Tab>
<Tab title="Config">
```json5
{
plugins: {
entries: {
"admin-http-rpc": { enabled: true },
},
},
}
```
</Tab>
</Tabs>
The route is registered during plugin startup, so restart the Gateway after changing plugin config.
Disable it when you no longer need the HTTP surface:
```bash
openclaw plugins disable admin-http-rpc
openclaw gateway restart
```
## Verify the route
Use `health` as the smallest safe request:
```bash
curl -sS http://<gateway-host>:<port>/api/v1/admin/rpc \
-H 'Authorization: Bearer <gateway-token>' \
-H 'Content-Type: application/json' \
-d '{"method":"health","params":{}}'
```
A successful response has `ok: true`:
```json
{
"id": "generated-request-id",
"ok": true,
"payload": {
"status": "ok"
}
}
```
When the plugin is disabled, the route returns `404` because it is not registered.
## Authentication
The plugin route uses Gateway HTTP auth.
Common authentication paths:
- shared-secret auth (`gateway.auth.mode="token"` or `"password"`): `Authorization: Bearer <token-or-password>`
- trusted identity-bearing HTTP auth (`gateway.auth.mode="trusted-proxy"`): route through the configured identity-aware proxy and let it inject the required identity headers
- private-ingress open auth (`gateway.auth.mode="none"`): no auth header required
## Security model
Treat this plugin as a full Gateway operator surface.
- Enabling the plugin intentionally offers access to the allowlisted admin RPC methods at `/api/v1/admin/rpc`.
- The plugin declares the reserved `contracts.gatewayMethodDispatch: ["authenticated-request"]` manifest contract, which is what lets its Gateway-authenticated HTTP route dispatch control-plane methods in process. This is not a sandbox: the contract prevents accidental use of reserved SDK helpers, but trusted plugins still run in the Gateway process.
- Shared-secret bearer auth (`token`/`password` modes) proves possession of the gateway operator secret; narrower `x-openclaw-scopes` headers are ignored on that path and normal full operator defaults are restored.
- Trusted identity-bearing HTTP auth (`trusted-proxy` mode) honors `x-openclaw-scopes` when present.
- `gateway.auth.mode="none"` means this route is unauthenticated if the plugin is enabled. Use that only behind a private ingress you fully trust.
- Requests dispatch through the same Gateway method handlers and scope checks as WebSocket RPC, after the plugin route auth passes.
- Keep this route on loopback, tailnet, or a private trusted ingress. Do not expose it directly to the public internet. Use separate gateways when callers cross trust boundaries.
## Request
```http
POST /api/v1/admin/rpc
Authorization: Bearer <gateway-token>
Content-Type: application/json
```
```json
{
"id": "optional-request-id",
"method": "health",
"params": {}
}
```
Fields:
- `id` (string, optional): copied into the response. A UUID is generated when omitted.
- `method` (string, required): allowed Gateway method name.
- `params` (any, optional): method-specific params.
The default max request body size is 1 MB.
## Response
Success responses use the Gateway RPC shape:
```json
{
"id": "optional-request-id",
"ok": true,
"payload": {}
}
```
Gateway method errors use:
```json
{
"id": "optional-request-id",
"ok": false,
"error": {
"code": "INVALID_REQUEST",
"message": "bad params"
}
}
```
HTTP status follows the error code:
| Error code | HTTP status |
| -------------------------- | ----------- |
| `INVALID_REQUEST` | 400 |
| `APPROVAL_NOT_FOUND` | 404 |
| `NOT_LINKED`, `NOT_PAIRED` | 409 |
| `UNAVAILABLE` | 503 |
| `AGENT_TIMEOUT` | 504 |
| any other code | 500 |
## Allowed methods
- discovery: `commands.list`
Returns the HTTP RPC method names allowed by this plugin.
- gateway: `health`, `status`, `logs.tail`, `usage.status`, `usage.cost`, `gateway.restart.request`
- config: `config.get`, `config.schema`, `config.schema.lookup`, `config.set`, `config.patch`, `config.apply`
- channels: `channels.status`, `channels.start`, `channels.stop`, `channels.logout`
- web: `web.login.start`, `web.login.wait`
- models: `models.list`, `models.authStatus`
- agents: `agents.list`, `agents.create`, `agents.update`, `agents.delete`
- approvals: `exec.approvals.get`, `exec.approvals.set`, `exec.approvals.node.get`, `exec.approvals.node.set`
- cron: `cron.status`, `cron.list`, `cron.get`, `cron.runs`, `cron.add`, `cron.update`, `cron.remove`, `cron.run`
- devices: `device.pair.list`, `device.pair.approve`, `device.pair.reject`, `device.pair.remove`
- nodes: `node.list`, `node.describe`, `node.pair.list`, `node.pair.approve`, `node.pair.reject`, `node.pair.remove`, `node.rename`
- tasks: `tasks.list`, `tasks.get`, `tasks.cancel`
- diagnostics: `doctor.memory.status`, `update.status`
Other Gateway methods are blocked until they are intentionally added.
## WebSocket comparison
The normal Gateway WebSocket RPC path remains the preferred control-plane API for OpenClaw clients. Use admin HTTP RPC only for host tooling that needs a request/response HTTP surface.
Shared-token WebSocket clients without a trusted device identity cannot self-declare admin scopes during connect. Admin HTTP RPC deliberately follows the existing trusted HTTP operator model: when the plugin is enabled, shared-secret bearer auth is treated as full operator access for this admin surface.
## Troubleshooting
`404 Not Found`
: The plugin is disabled, the Gateway has not restarted since enabling it, or the request is going to a different Gateway process.
`401 Unauthorized`
: The request did not satisfy Gateway HTTP auth. Check the bearer token or the trusted-proxy identity headers.
`405 Method Not Allowed`
: The request used something other than `POST`.
`413 Payload Too Large`
: The request body exceeded the 1 MB limit.
`400 INVALID_REQUEST`
: The request body is not valid JSON, the `method` field is missing, or the method is not in the plugin allowlist.
`503 UNAVAILABLE`
: The Gateway method handler is unavailable. Check Gateway logs and retry after the Gateway finishes startup.
## Related
- [Operator scopes](/gateway/operator-scopes)
- [Gateway security](/gateway/security)
- [Remote access](/gateway/remote)
- [Plugin manifest](/plugins/manifest#contracts-reference)
- [SDK subpaths](/plugins/sdk-subpaths)

View File

@@ -0,0 +1,13 @@
---
summary: "Redirects to Building Plugins (registering tools section)"
read_when:
- Legacy link to agent-tools
title: "Registering tools"
---
This page has moved. See [Building Plugins: Registering agent tools](/plugins/building-plugins#registering-agent-tools).
## Related
- [Building plugins](/plugins/building-plugins)
- [Plugin SDK setup](/plugins/sdk-setup)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,483 @@
---
summary: "Plugin internals: capability model, ownership, contracts, load pipeline, and runtime helpers"
read_when:
- Building or debugging native OpenClaw plugins
- Understanding the plugin capability model or ownership boundaries
- Working on the plugin load pipeline or registry
- Implementing provider runtime hooks or channel plugins
title: "Plugin internals"
sidebarTitle: "Internals"
---
This is the **deep architecture reference** for the OpenClaw plugin system. For practical guides, start with one of the focused pages below.
<CardGroup cols={2}>
<Card title="Install and use plugins" icon="plug" href="/tools/plugin">
End-user guide for adding, enabling, and troubleshooting plugins.
</Card>
<Card title="Building plugins" icon="rocket" href="/plugins/building-plugins">
First-plugin tutorial with the smallest working manifest.
</Card>
<Card title="Channel plugins" icon="comments" href="/plugins/sdk-channel-plugins">
Build a messaging channel plugin.
</Card>
<Card title="Provider plugins" icon="microchip" href="/plugins/sdk-provider-plugins">
Build a model provider plugin.
</Card>
<Card title="SDK overview" icon="book" href="/plugins/sdk-overview">
Import map and registration API reference.
</Card>
</CardGroup>
## Public capability model
Capabilities are the public **native plugin** model inside OpenClaw. Every native OpenClaw plugin registers against one or more capability types:
| Capability | Registration method | Example plugins |
| ---------------------- | ------------------------------------------------ | ------------------------------ |
| Text inference | `api.registerProvider(...)` | `anthropic`, `openai` |
| CLI inference backend | `api.registerCliBackend(...)` | `anthropic`, `openai` |
| Embeddings | `api.registerEmbeddingProvider(...)` | Provider-owned vector plugins |
| Speech | `api.registerSpeechProvider(...)` | `elevenlabs`, `microsoft` |
| Realtime transcription | `api.registerRealtimeTranscriptionProvider(...)` | `openai` |
| Realtime voice | `api.registerRealtimeVoiceProvider(...)` | `google`, `openai` |
| Media understanding | `api.registerMediaUnderstandingProvider(...)` | `google`, `openai` |
| Transcripts source | `api.registerTranscriptSourceProvider(...)` | `discord` |
| Image generation | `api.registerImageGenerationProvider(...)` | `fal`, `google`, `openai` |
| Music generation | `api.registerMusicGenerationProvider(...)` | `fal`, `google`, `minimax` |
| Video generation | `api.registerVideoGenerationProvider(...)` | `fal`, `google`, `qwen` |
| Web fetch | `api.registerWebFetchProvider(...)` | `firecrawl` |
| Web search | `api.registerWebSearchProvider(...)` | `brave`, `firecrawl`, `google` |
| Channel / messaging | `api.registerChannel(...)` | `matrix`, `msteams` |
| Gateway discovery | `api.registerGatewayDiscoveryService(...)` | `bonjour` |
<Note>
A plugin that registers zero capabilities but provides hooks, tools, discovery services, or background services is a **legacy hook-only** plugin. That pattern is still fully supported.
</Note>
### External compatibility stance
The capability model is landed in core and used by bundled/native plugins today, but external plugin compatibility still needs a tighter bar than "it is exported, therefore it is frozen."
| Plugin situation | Guidance |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Existing external plugins | Keep hook-based integrations working; this is the compatibility baseline. |
| New bundled/native plugins | Prefer explicit capability registration over vendor-specific reach-ins or new hook-only designs. |
| External plugins adopting capability registration | Allowed, but treat capability-specific helper surfaces as evolving unless docs mark them stable. |
Capability registration is the intended direction. Legacy hooks remain the safest no-breakage path for external plugins during the transition. Exported helper subpaths are not all equal — prefer narrow documented contracts over incidental helper exports.
### Plugin shapes
OpenClaw classifies every loaded plugin into a shape based on its actual registration behavior (not just static metadata):
<AccordionGroup>
<Accordion title="plain-capability">
Registers exactly one capability type (for example a provider-only plugin like `arcee` or `chutes`).
</Accordion>
<Accordion title="hybrid-capability">
Registers multiple capability types (for example `openai` owns text inference, speech, media understanding, and image generation).
</Accordion>
<Accordion title="hook-only">
Registers only hooks (typed or custom), no capabilities, tools, commands, or services.
</Accordion>
<Accordion title="non-capability">
Registers tools, commands, services, or routes but no capabilities.
</Accordion>
</AccordionGroup>
Use `openclaw plugins inspect <id>` to see a plugin's shape and capability breakdown. See [CLI reference](/cli/plugins#inspect) for details.
### Legacy hooks
The `before_agent_start` hook remains supported as a compatibility path for hook-only plugins. Legacy real-world plugins still depend on it.
Direction:
- keep it working
- document it as legacy
- prefer `before_model_resolve` for model/provider override work
- prefer `before_prompt_build` for prompt mutation work
- remove only after real usage drops and fixture coverage proves migration safety
### Compatibility signals
`openclaw doctor`, `openclaw plugins inspect <id>`, `openclaw status --all`, and `openclaw plugins doctor` surface these compatibility notices:
| Signal | Meaning |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| **config valid** | Config parses fine and plugins resolve |
| **hook-only** (info) | Plugin registers only hooks; a supported path, but not migrated to capability registration yet |
| **legacy `before_agent_start`** (warn) | Plugin uses the deprecated `before_agent_start` hook instead of `before_model_resolve`/`before_prompt_build` |
| **deprecated memory-embedding API** (warn) | Non-bundled plugin uses the old memory-specific embedding provider API instead of `registerEmbeddingProvider` |
| **hard error** | Config is invalid or plugin failed to load |
None of the advisory/warn signals break your plugin today. These signals also appear in `openclaw status --all` and `openclaw plugins doctor`.
## Architecture overview
OpenClaw's plugin system has four layers:
<Steps>
<Step title="Manifest + discovery">
OpenClaw finds candidate plugins from configured paths, workspace roots, global plugin roots, and bundled plugins. Discovery reads native `openclaw.plugin.json` manifests plus supported bundle manifests first.
</Step>
<Step title="Enablement + validation">
Core decides whether a discovered plugin is enabled, disabled, blocked, or selected for an exclusive slot such as memory.
</Step>
<Step title="Runtime loading">
Native OpenClaw plugins are loaded in-process and register capabilities into a central registry. Packaged JavaScript loads through native `require`; third-party local source TypeScript is the emergency Jiti fallback. Compatible bundles are normalized into registry records without importing runtime code.
</Step>
<Step title="Surface consumption">
The rest of OpenClaw reads the registry to expose tools, channels, provider setup, hooks, HTTP routes, CLI commands, and services.
</Step>
</Steps>
For plugin CLI specifically, root command discovery is split in two phases:
- parse-time metadata comes from `registerCli(..., { descriptors: [...] })`
- the real plugin CLI module can stay lazy and register on first invocation
That keeps plugin-owned CLI code inside the plugin while still letting OpenClaw reserve root command names before parsing.
The important design boundary:
- manifest/config validation should work from **manifest/schema metadata** without executing plugin code
- native capability discovery may load trusted plugin entry code to build a non-activating registry snapshot
- native runtime behavior comes from the plugin module's `register(api)` path with `api.registrationMode === "full"`
That split lets OpenClaw validate config, explain missing/disabled plugins, and build UI/schema hints before the full runtime is active.
### Plugin metadata snapshot and lookup table
Gateway startup builds one `PluginMetadataSnapshot` for the current config snapshot. The snapshot is metadata-only: it stores the installed plugin index, manifest registry, manifest diagnostics, owner maps, a plugin id normalizer, and manifest records. It does not hold loaded plugin modules, provider SDKs, package contents, or runtime exports.
Plugin-aware config validation, startup auto-enable, and Gateway plugin bootstrap consume that snapshot instead of rebuilding manifest/index metadata independently. `PluginLookUpTable` is derived from the same snapshot and adds the startup plugin plan for the current runtime config.
After startup, Gateway keeps the current metadata snapshot as a replaceable runtime product. Repeated runtime provider discovery can borrow that snapshot instead of reconstructing the installed index and manifest registry for each provider-catalog pass. The snapshot is cleared or replaced on Gateway shutdown, config/plugin inventory changes, and installed index writes; callers fall back to the cold manifest/index path when no compatible current snapshot exists. Compatibility checks must include plugin discovery roots such as `plugins.load.paths` and the default agent workspace, because workspace plugins are part of the metadata scope.
The snapshot and lookup table keep repeated startup decisions on the fast path:
- channel ownership
- deferred channel startup
- startup plugin ids
- provider and CLI backend ownership
- setup provider, command alias, model catalog provider, and manifest contract ownership
- plugin config schema and channel config schema validation
- startup auto-enable decisions
The safety boundary is snapshot replacement, not mutation. Rebuild the snapshot when config, plugin inventory, install records, or persisted index policy changes. Do not treat it as a broad mutable global registry, and do not keep unbounded historical snapshots. Runtime plugin loading remains separate from metadata snapshots so stale runtime state cannot be hidden behind a metadata cache.
The cache rule is documented in [Plugin architecture internals](/plugins/architecture-internals#plugin-cache-boundary): manifest and discovery metadata are fresh unless a caller holds an explicit snapshot, lookup table, or manifest registry for the current flow. Hidden metadata caches and wall-clock TTLs are not part of plugin loading. Only runtime loader, module, and dependency-artifact caches may persist after code or installed artifacts are actually loaded.
Some cold-path callers still reconstruct manifest registries directly from the persisted installed plugin index instead of receiving a Gateway `PluginLookUpTable`. That path now reconstructs the registry on demand; prefer passing the current lookup table or an explicit manifest registry through runtime flows when a caller already has one.
### Activation planning
Activation planning is part of the control plane. Callers can ask which plugins are relevant to a concrete command, provider, channel, route, agent harness, or capability before loading broader runtime registries.
The planner keeps current manifest behavior compatible:
- `activation.*` fields are explicit planner hints
- `providers`, `channels`, `commandAliases`, `setup.providers`, `contracts.tools`, and hooks remain manifest ownership fallback
- the ids-only planner API stays available for existing callers
- the plan API reports reason labels so diagnostics can distinguish explicit hints from ownership fallback
<Warning>
Do not treat `activation` as a lifecycle hook or a replacement for `register(...)`. It is metadata used to narrow loading. Prefer ownership fields when they already describe the relationship; use `activation` only for extra planner hints.
</Warning>
### Channel plugins and the shared message tool
Channel plugins do not need to register a separate send/edit/react tool for normal chat actions. OpenClaw keeps one shared `message` tool in core, and channel plugins own the channel-specific discovery and execution behind it.
The current boundary is:
- core owns the shared `message` tool host, prompt wiring, session/thread bookkeeping, and execution dispatch
- channel plugins own scoped action discovery, capability discovery, and any channel-specific schema fragments
- channel plugins own provider-specific session conversation grammar, such as how conversation ids encode thread ids or inherit from parent conversations
- channel plugins execute the final action through their action adapter
For channel plugins, the SDK surface is `ChannelMessageActionAdapter.describeMessageTool(...)`. That unified discovery call lets a plugin return its visible actions, capabilities, and schema contributions together so those pieces do not drift apart.
When a channel-specific message-tool param carries a media source such as a local path or remote media URL, the plugin should also return `mediaSourceParams` from `describeMessageTool(...)`. Core uses that explicit list to apply sandbox path normalization and outbound media-access hints without hardcoding plugin-owned param names. Prefer action-scoped maps there, not one channel-wide flat list, so a profile-only media param does not get normalized on unrelated actions like `send`.
Core passes runtime scope into that discovery step. Important fields include:
- `accountId`
- `currentChannelId`
- `currentThreadTs`
- `currentMessageId`
- `sessionKey`
- `sessionId`
- `agentId`
- trusted inbound `requesterSenderId`
That matters for context-sensitive plugins. A channel can hide or expose message actions based on the active account, current room/thread/message, or trusted requester identity without hardcoding channel-specific branches in the core `message` tool.
This is why embedded-runner routing changes are still plugin work: the runner is responsible for forwarding the current chat/session identity into the plugin discovery boundary so the shared `message` tool exposes the right channel-owned surface for the current turn.
For channel-owned execution helpers, bundled plugins should keep the execution runtime inside their own plugin modules. Core no longer owns the Discord, Slack, Telegram, or WhatsApp message-action runtimes under `src/agents/tools`. We do not publish separate `plugin-sdk/*-action-runtime` subpaths, and bundled plugins should import their own local runtime code directly from their plugin-owned modules.
The same boundary applies to provider-named SDK seams in general: core should not import channel-specific convenience barrels for Discord, Signal, Slack, WhatsApp, or similar plugins. If core needs a behavior, either consume the bundled plugin's own `api.ts` / `runtime-api.ts` barrel or promote the need into a narrow generic capability in the shared SDK.
Bundled plugins follow the same rule. A bundled plugin's `runtime-api.ts` should not re-export its own branded `openclaw/plugin-sdk/<plugin-id>` facade. Those branded facades remain compatibility shims for external plugins and older consumers, but bundled plugins should use local exports plus narrow generic SDK subpaths such as `openclaw/plugin-sdk/channel-policy`, `openclaw/plugin-sdk/runtime-store`, or `openclaw/plugin-sdk/webhook-ingress`. New code should not add plugin-id-specific SDK facades unless the compatibility boundary for an existing external ecosystem requires it.
For polls specifically, there are two execution paths:
- `outbound.sendPoll` is the shared baseline for channels that fit the common poll model
- `actions.handleAction("poll")` is the preferred path for channel-specific poll semantics or extra poll parameters
Core now defers shared poll parsing until after plugin poll dispatch declines the action, so plugin-owned poll handlers can accept channel-specific poll fields without being blocked by the generic poll parser first.
See [Plugin architecture internals](/plugins/architecture-internals) for the full startup sequence.
## Capability ownership model
OpenClaw treats a native plugin as the ownership boundary for a **company** or a **feature**, not as a grab bag of unrelated integrations.
That means:
- a company plugin should usually own all of that company's OpenClaw-facing surfaces
- a feature plugin should usually own the full feature surface it introduces
- channels should consume shared core capabilities instead of re-implementing provider behavior ad hoc
<AccordionGroup>
<Accordion title="Vendor multi-capability">
`google` owns text inference, CLI backend, embeddings, speech, realtime voice, media understanding, image/music/video generation, and web search. `openai` owns text inference, embeddings, speech, realtime transcription, realtime voice, media understanding, image/video generation. `minimax` owns text inference plus media understanding, speech, image/music/video generation, and web search.
</Accordion>
<Accordion title="Vendor single-capability">
`arcee` and `chutes` own text inference only; `microsoft` owns speech only. A vendor plugin can stay this narrow until it needs to cover more of that vendor's surface.
</Accordion>
<Accordion title="Feature plugin">
`voice-call` owns call transport, tools, CLI, routes, and Twilio media-stream bridging, but consumes shared speech, realtime transcription, and realtime voice capabilities instead of importing vendor plugins directly.
</Accordion>
</AccordionGroup>
The intended end state is:
- a vendor's OpenClaw-facing surface lives in one plugin even if it spans text models, speech, images, and video
- other vendors can do the same for their own surface area
- channels do not care which vendor plugin owns the provider; they consume the shared capability contract exposed by core
This is the key distinction:
- **plugin** = ownership boundary
- **capability** = core contract that multiple plugins can implement or consume
So if OpenClaw adds a new domain such as video, the first question is not "which provider should hardcode video handling?" The first question is "what is the core video capability contract?" Once that contract exists, vendor plugins can register against it and channel/feature plugins can consume it.
If the capability does not exist yet, the right move is usually:
<Steps>
<Step title="Define the capability">
Define the missing capability in core.
</Step>
<Step title="Expose through the SDK">
Expose it through the plugin API/runtime in a typed way.
</Step>
<Step title="Wire consumers">
Wire channels/features against that capability.
</Step>
<Step title="Vendor implementations">
Let vendor plugins register implementations.
</Step>
</Steps>
This keeps ownership explicit while avoiding core behavior that depends on a single vendor or a one-off plugin-specific code path.
### Capability layering
Use this mental model when deciding where code belongs:
<Tabs>
<Tab title="Core capability layer">
Shared orchestration, policy, fallback, config merge rules, delivery semantics, and typed contracts.
</Tab>
<Tab title="Vendor plugin layer">
Vendor-specific APIs, auth, model catalogs, speech synthesis, image generation, video backends, usage endpoints.
</Tab>
<Tab title="Channel/feature plugin layer">
Discord/Slack/voice-call/etc. integration that consumes core capabilities and presents them on a surface.
</Tab>
</Tabs>
For example, TTS follows this shape:
- core owns reply-time TTS policy, fallback order, prefs, and channel delivery
- `elevenlabs`, `google`, `microsoft`, and `openai` own synthesis implementations
- `voice-call` consumes the telephony TTS runtime helper
That same pattern should be preferred for future capabilities.
### Multi-capability company plugin example
A company plugin should feel cohesive from the outside. If OpenClaw has shared contracts for models, speech, realtime transcription, realtime voice, media understanding, image generation, video generation, web fetch, and web search, a vendor can own all of its surfaces in one place:
```ts
import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry";
import {
describeImageWithModel,
transcribeOpenAiCompatibleAudio,
} from "openclaw/plugin-sdk/media-understanding";
import { createPluginBackedWebSearchProvider } from "openclaw/plugin-sdk/provider-web-search";
const plugin: OpenClawPluginDefinition = {
id: "exampleai",
name: "ExampleAI",
register(api) {
api.registerProvider({
id: "exampleai",
// auth/model catalog/runtime hooks
});
api.registerSpeechProvider({
id: "exampleai",
// vendor speech config — implement the SpeechProviderPlugin interface directly
});
api.registerMediaUnderstandingProvider({
id: "exampleai",
capabilities: ["image", "audio", "video"],
async describeImage(req) {
return describeImageWithModel({
...req,
provider: "exampleai",
});
},
async transcribeAudio(req) {
return transcribeOpenAiCompatibleAudio({
...req,
provider: "exampleai",
});
},
});
api.registerWebSearchProvider(
createPluginBackedWebSearchProvider({
id: "exampleai-search",
// credential + fetch logic
}),
);
},
};
export default plugin;
```
What matters is not the exact helper names. The shape matters:
- one plugin owns the vendor surface
- core still owns the capability contracts
- channels and feature plugins consume `api.runtime.*` helpers, not vendor code
- contract tests can assert that the plugin registered the capabilities it claims to own
### Capability example: video understanding
OpenClaw already treats image/audio/video understanding as one shared capability. The same ownership model applies there:
<Steps>
<Step title="Core defines the contract">
Core defines the media-understanding contract.
</Step>
<Step title="Vendor plugins register">
Vendor plugins register `describeImage`, `transcribeAudio`, and `describeVideo` as applicable.
</Step>
<Step title="Consumers use the shared behavior">
Channels and feature plugins consume the shared core behavior instead of wiring directly to vendor code.
</Step>
</Steps>
That avoids baking one provider's video assumptions into core. The plugin owns the vendor surface; core owns the capability contract and fallback behavior.
Video generation already uses that same sequence: core owns the typed capability contract and runtime helper, and vendor plugins register `api.registerVideoGenerationProvider(...)` implementations against it.
Need a concrete rollout checklist? See [Capability Cookbook](/tools/capability-cookbook).
## Contracts and enforcement
The plugin API surface is intentionally typed and centralized in `OpenClawPluginApi`. That contract defines the supported registration points and the runtime helpers a plugin may rely on.
Why this matters:
- plugin authors get one stable internal standard
- core can reject duplicate ownership such as two plugins registering the same provider id
- startup can surface actionable diagnostics for malformed registration
- contract tests can enforce bundled-plugin ownership and prevent silent drift
There are two layers of enforcement:
<AccordionGroup>
<Accordion title="Runtime registration enforcement">
The plugin registry validates registrations as plugins load. Examples: duplicate provider ids, duplicate speech provider ids, and malformed registrations produce plugin diagnostics instead of undefined behavior.
</Accordion>
<Accordion title="Contract tests">
Bundled plugins are captured in contract registries during test runs so OpenClaw can assert ownership explicitly. Today this is used for model providers, speech providers, web search providers, and bundled registration ownership.
</Accordion>
</AccordionGroup>
The practical effect is that OpenClaw knows, up front, which plugin owns which surface. That lets core and channels compose seamlessly because ownership is declared, typed, and testable rather than implicit.
### What belongs in a contract
<Tabs>
<Tab title="Good contracts">
- typed
- small
- capability-specific
- owned by core
- reusable by multiple plugins
- consumable by channels/features without vendor knowledge
</Tab>
<Tab title="Bad contracts">
- vendor-specific policy hidden in core
- one-off plugin escape hatches that bypass the registry
- channel code reaching straight into a vendor implementation
- ad hoc runtime objects that are not part of `OpenClawPluginApi` or `api.runtime`
</Tab>
</Tabs>
When in doubt, raise the abstraction level: define the capability first, then let plugins plug into it.
## Execution model
Native OpenClaw plugins run **in-process** with the Gateway. They are not sandboxed. A loaded native plugin has the same process-level trust boundary as core code.
<Warning>
Native plugin implications: a plugin can register tools, network handlers, hooks, and services; a plugin bug can crash or destabilize the gateway; and a malicious native plugin is equivalent to arbitrary code execution inside the OpenClaw process.
</Warning>
Compatible bundles are safer by default because OpenClaw currently treats them as metadata/content packs. In current releases, that mostly means bundled skills.
Use allowlists and explicit install/load paths for non-bundled plugins. Treat workspace plugins as development-time code, not production defaults.
For bundled workspace package names, keep the plugin id anchored in the npm name: `@openclaw/<id>` by default, or an approved typed suffix such as `-provider`, `-plugin`, `-speech`, `-sandbox`, or `-media-understanding` when the package intentionally exposes a narrower plugin role.
<Note>
**Trust note:** `plugins.allow` trusts **plugin ids**, not source provenance. A workspace plugin with the same id as a bundled plugin intentionally shadows the bundled copy when that workspace plugin is enabled/allowlisted. This is normal and useful for local development, patch testing, and hotfixes. Bundled-plugin trust is resolved from the source snapshot — the manifest and code on disk at load time — rather than from install metadata. A corrupted or substituted install record cannot silently widen a bundled plugin's trust surface beyond what the actual source claims.
</Note>
## Export boundary
OpenClaw exports capabilities, not implementation convenience.
Keep capability registration public. Trim non-contract helper exports:
- bundled-plugin-specific helper subpaths
- runtime plumbing subpaths not intended as public API
- vendor-specific convenience helpers
- setup/onboarding helpers that are implementation details
Reserved bundled-plugin helper subpaths have been retired from the generated SDK export map. Keep owner-specific helpers inside the owning plugin package; promote only reusable host behavior to generic SDK contracts such as `plugin-sdk/gateway-runtime`, `plugin-sdk/security-runtime`, and `plugin-sdk/plugin-config-runtime`.
## Internals and reference
For the load pipeline, registry model, provider runtime hooks, Gateway HTTP routes, message tool schemas, channel target resolution, provider catalogs, context engine plugins, and the guide to adding a new capability, see [Plugin architecture internals](/plugins/architecture-internals).
## Related
- [Building plugins](/plugins/building-plugins)
- [Plugin manifest](/plugins/manifest)
- [Plugin SDK setup](/plugins/sdk-setup)

View File

@@ -0,0 +1,13 @@
---
summary: "Redirects to the current Building Plugins guide"
title: "Building plugins (redirect)"
read_when:
- Legacy link to building-extensions
---
This page has moved. See [Building Plugins](/plugins/building-plugins).
## Related
- [Building plugins](/plugins/building-plugins)
- [Plugin architecture](/plugins/architecture)

View File

@@ -0,0 +1,381 @@
---
summary: "Create your first OpenClaw plugin in minutes"
title: "Building plugins"
sidebarTitle: "Getting Started"
doc-schema-version: 1
read_when:
- You want to create a new OpenClaw plugin
- You need a quick-start for plugin development
- You are choosing between channel, provider, CLI backend, tool, or hook docs
---
Plugins extend OpenClaw without changing core. A plugin can add a messaging
channel, model provider, local CLI backend, agent tool, hook, media provider,
or another plugin-owned capability.
You do not need to add an external plugin to the OpenClaw repository. Publish
the package to [ClawHub](/clawhub) and users install it with:
```bash
openclaw plugins install clawhub:<package-name>
```
Bare package specs still install from npm during the launch cutover. Use the
`clawhub:` prefix when you want ClawHub resolution.
## Requirements
- Node 22.19+, Node 23.11+, or Node 24+, and `npm` or `pnpm`.
- TypeScript ESM modules.
- For in-repo bundled plugin work, clone the repository and run `pnpm install`.
Source-checkout plugin development is pnpm-only because OpenClaw discovers
bundled plugins from `extensions/*` workspace packages.
## Choose the plugin shape
<CardGroup cols={2}>
<Card title="Channel plugin" icon="messages-square" href="/plugins/sdk-channel-plugins">
Connect OpenClaw to a messaging platform.
</Card>
<Card title="Provider plugin" icon="cpu" href="/plugins/sdk-provider-plugins">
Add a model, media, search, fetch, speech, or realtime provider.
</Card>
<Card title="CLI backend plugin" icon="terminal" href="/plugins/cli-backend-plugins">
Run a local AI CLI through OpenClaw model fallback.
</Card>
<Card title="Tool plugin" icon="wrench" href="/plugins/tool-plugins">
Register agent tools.
</Card>
</CardGroup>
## Quickstart
Build a minimal tool plugin by registering one required agent tool. This is the
shortest useful plugin shape and covers the package, manifest, entry point, and
local proof.
<Steps>
<Step title="Create package metadata">
<CodeGroup>
```json package.json
{
"name": "@myorg/openclaw-my-plugin",
"version": "1.0.0",
"type": "module",
"dependencies": {
"typebox": "1.1.39"
},
"peerDependencies": {
"openclaw": ">=2026.3.24-beta.2"
},
"openclaw": {
"extensions": ["./index.ts"],
"compat": {
"pluginApi": ">=2026.3.24-beta.2",
"minGatewayVersion": "2026.3.24-beta.2"
},
"build": {
"openclawVersion": "2026.3.24-beta.2",
"pluginSdkVersion": "2026.3.24-beta.2"
}
}
}
```
```json openclaw.plugin.json
{
"id": "my-plugin",
"name": "My Plugin",
"description": "Adds a custom tool to OpenClaw",
"contracts": {
"tools": ["my_tool"]
},
"activation": {
"onStartup": true
},
"configSchema": {
"type": "object",
"additionalProperties": false
}
}
```
</CodeGroup>
Published external plugins should point runtime entries at built JavaScript
files. See [SDK entry points](/plugins/sdk-entrypoints) for the full entry
point contract.
Every plugin needs a manifest, even with no config. Runtime tools must
appear in `contracts.tools` so OpenClaw can discover ownership without
eagerly loading every plugin runtime. Set `activation.onStartup`
intentionally; this example loads on Gateway startup.
Host-trusted plugin surfaces are manifest-gated too and require explicit
declaration for installed plugins: `api.registerAgentToolResultMiddleware(...)`
needs each target runtime listed in `contracts.agentToolResultMiddleware`,
and `api.registerTrustedToolPolicy(...)` needs each policy id in
`contracts.trustedToolPolicies`. These declarations keep install-time
inspection and runtime registration aligned.
For every manifest field, see [Plugin manifest](/plugins/manifest).
</Step>
<Step title="Register the tool">
```typescript index.ts
import { Type } from "typebox";
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Adds a custom tool to OpenClaw",
register(api) {
api.registerTool({
name: "my_tool",
description: "Echo one input value",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return {
content: [{ type: "text", text: `Got: ${params.input}` }],
};
},
});
},
});
```
Use `definePluginEntry` for non-channel plugins. Channel plugins use
`defineChannelPluginEntry` from `openclaw/plugin-sdk/core` instead.
</Step>
<Step title="Test the runtime">
For an installed or external plugin, inspect the loaded runtime:
```bash
openclaw plugins inspect my-plugin --runtime --json
```
If the plugin registers a CLI command, run that command too and confirm
output, for example `openclaw demo-plugin ping`.
For a bundled plugin in this repository, OpenClaw discovers source-checkout
plugin packages from the `extensions/*` workspace. Run the closest targeted
test:
```bash
pnpm test extensions/my-plugin/
pnpm check
```
</Step>
<Step title="Test the package install">
Before publishing a package-ready plugin, test the same install shape users
will get. First add a build step, point runtime entries such as
`openclaw.extensions` at built JavaScript like `./dist/index.js`, and make
sure `npm pack` includes that `dist/` output. TypeScript source entries are
only for source checkouts and local development paths.
Then pack the plugin and install the tarball with `npm-pack:`:
```bash
npm pack --pack-destination /tmp
openclaw plugins install npm-pack:/tmp/<plugin-package>.tgz --force
openclaw plugins inspect my-plugin --runtime --json
```
`npm-pack:` uses OpenClaw's managed per-plugin npm project, so it catches
runtime dependency mistakes that source checkout testing can hide. It proves
the package and dependency shape, not catalog-linked official trust.
Runtime imports must be in `dependencies` or `optionalDependencies`;
dependencies left only in `devDependencies` will not be installed for the
managed runtime project.
Do not use a raw archive/path install as the final proof for official or
privileged plugin behavior. Raw sources are useful for local debugging, but
they do not prove the same dependency path as npm or ClawHub installs. If
your plugin relies on trusted official plugin status, add a second proof
through a catalog-backed official install or a published package path that
records official trust. See
[Plugin dependency resolution](/plugins/dependency-resolution) for
install-root and dependency ownership details.
</Step>
<Step title="Publish">
Validate the package before publishing:
```bash
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
```
Canonical ClawHub package snippets live in `docs/snippets/plugin-publish/`.
</Step>
<Step title="Install">
Install the published package through ClawHub:
```bash
openclaw plugins install clawhub:your-org/your-plugin
```
</Step>
</Steps>
<a id="registering-agent-tools"></a>
## Registering tools
Tools can be required or optional. Required tools are always available when the
plugin is enabled. Optional tools need explicit user opt-in before OpenClaw
loads the owning plugin runtime.
```typescript
register(api) {
api.registerTool(
{
name: "workflow_tool",
description: "Run a workflow",
parameters: Type.Object({ pipeline: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.pipeline }] };
},
},
{ optional: true },
);
}
```
Every tool registered with `api.registerTool(...)` must also be declared in the
plugin manifest:
```json
{
"contracts": {
"tools": ["workflow_tool"]
},
"toolMetadata": {
"workflow_tool": {
"optional": true
}
}
}
```
Users opt in with `tools.allow`:
```json5
{
tools: { allow: ["workflow_tool"] }, // or ["my-plugin"] for every tool from one plugin
}
```
Optional tools control whether a tool is exposed to the model. Use
[plugin permission requests](/plugins/plugin-permission-requests) when a tool
or hook should ask for approval after the model selects it and before the
action runs.
Use optional tools for side effects, unusual binaries, or capabilities that
should not be exposed by default. Tool names must not conflict with core tool
names; conflicts are skipped and reported in plugin diagnostics. Malformed
registrations are skipped and reported the same way: a missing non-empty
`name`, a non-function `execute`, or a tool descriptor without a `parameters`
object.
Tool factories receive a runtime-supplied context object. Use `ctx.activeModel`
when a tool needs to log, display, or adapt to the active model for the current
turn; it can include `provider`, `modelId`, and `modelRef`. Treat it as
informational runtime metadata, not a security boundary against the local
operator, installed plugin code, or a modified OpenClaw runtime. Sensitive
local tools should still require an explicit plugin or operator opt-in and
fail closed when active-model metadata is missing or unsuitable.
The manifest declares ownership and discovery; execution still calls the live
registered tool implementation. Keep `toolMetadata.<tool>.optional: true`
aligned with `api.registerTool(..., { optional: true })` so OpenClaw can avoid
loading that plugin runtime until the tool is explicitly allowlisted.
## Import conventions
Import from focused SDK subpaths:
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
```
Do not import from the deprecated root barrel:
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk";
```
Within your plugin package, use local barrel files such as `api.ts` and
`runtime-api.ts` for internal imports. Do not import your own plugin through an
SDK path. Provider-specific helpers should stay in the provider package unless
the seam is truly generic.
Custom Gateway RPC methods are an advanced entry point. Keep them on a
plugin-specific prefix; core admin namespaces such as `config.*`,
`exec.approvals.*`, `operator.admin.*`, `wizard.*`, and `update.*` stay reserved
and resolve to `operator.admin`. The
`openclaw/plugin-sdk/gateway-method-runtime` bridge is reserved for plugin HTTP
routes that declare `contracts.gatewayMethodDispatch: ["authenticated-request"]`.
For the full import map, see [Plugin SDK overview](/plugins/sdk-overview).
## Pre-submission checklist
<Check>**package.json** has correct `openclaw` metadata</Check>
<Check>**openclaw.plugin.json** manifest is present and valid</Check>
<Check>Entry point uses `defineChannelPluginEntry` or `definePluginEntry`</Check>
<Check>All imports use focused `plugin-sdk/<subpath>` paths</Check>
<Check>Internal imports use local modules, not SDK self-imports</Check>
<Check>Tests pass (`pnpm test <bundled-plugin-root>/my-plugin/`)</Check>
<Check>`pnpm check` passes (in-repo plugins)</Check>
## Test against beta releases
1. Watch [openclaw/openclaw](https://github.com/openclaw/openclaw/releases) releases (`Watch` > `Releases`). Beta tags look like `v2026.3.N-beta.1`. You can also follow [@openclaw](https://x.com/openclaw) on X for release announcements.
2. Test your plugin against the beta tag as soon as it appears. The window before stable is typically only a few hours.
3. Post in your plugin's thread in the `plugin-forum` Discord channel ([discord.gg/clawd](https://discord.gg/clawd)) after testing, with either `all good` or what broke. Create a thread if you do not have one yet.
4. If something breaks, open or update an issue titled `Beta blocker: <plugin-name> - <summary>` and apply the `beta-blocker` label. Link the issue in your thread.
5. Open a PR to `main` titled `fix(<plugin-id>): beta blocker - <summary>` and link the issue in both the PR and your Discord thread. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation. Blockers with a PR get merged; blockers without one might ship anyway.
6. Silence means green. Missing the window usually means your fix lands in the next cycle.
## Next steps
<CardGroup cols={2}>
<Card title="Channel Plugins" icon="messages-square" href="/plugins/sdk-channel-plugins">
Build a messaging channel plugin
</Card>
<Card title="Provider Plugins" icon="cpu" href="/plugins/sdk-provider-plugins">
Build a model provider plugin
</Card>
<Card title="CLI Backend Plugins" icon="terminal" href="/plugins/cli-backend-plugins">
Register a local AI CLI backend
</Card>
<Card title="SDK Overview" icon="book-open" href="/plugins/sdk-overview">
Import map and registration API reference
</Card>
<Card title="Runtime Helpers" icon="settings" href="/plugins/sdk-runtime">
TTS, search, subagent via api.runtime
</Card>
<Card title="Testing" icon="test-tubes" href="/plugins/sdk-testing">
Test utilities and patterns
</Card>
<Card title="Plugin Manifest" icon="file-json" href="/plugins/manifest">
Full manifest schema reference
</Card>
</CardGroup>
## Related
- [Plugin hooks](/plugins/hooks)
- [Plugin architecture](/plugins/architecture)

313
docs/plugins/bundles.md Normal file
View File

@@ -0,0 +1,313 @@
---
summary: "Install and use Codex, Claude, and Cursor bundles as OpenClaw plugins"
read_when:
- You want to install a Codex, Claude, or Cursor-compatible bundle
- You need to understand how OpenClaw maps bundle content into native features
- You are debugging bundle detection or missing capabilities
title: "Plugin bundles"
---
OpenClaw can install plugins from three external ecosystems: **Codex**, **Claude**,
and **Cursor**. These are called **bundles** - content and metadata packs that
OpenClaw maps into native features like skills, hooks, and MCP tools.
<Info>
Bundles are **not** the same as native OpenClaw plugins. Native plugins run
in-process and can register any capability. Bundles are content packs with
selective feature mapping and a narrower trust boundary.
</Info>
## Why bundles exist
Many useful plugins are published in Codex, Claude, or Cursor format. Instead
of requiring authors to rewrite them as native OpenClaw plugins, OpenClaw
detects these formats and maps their supported content into the native feature
set. You can install a Claude command pack or a Codex skill bundle and use it
immediately.
## Install a bundle
<Steps>
<Step title="Install from a directory, archive, or marketplace">
```bash
# Local directory
openclaw plugins install ./my-bundle
# Archive
openclaw plugins install ./my-bundle.tgz
# Claude marketplace
openclaw plugins marketplace list <source>
openclaw plugins install <plugin> --marketplace <source>
```
`<source>` is a local marketplace path/repo or a git/GitHub source.
</Step>
<Step title="Verify detection">
```bash
openclaw plugins list
openclaw plugins inspect <id>
```
Bundles show `Format: bundle` plus a `Bundle format:` value of `codex`,
`claude`, or `cursor`.
</Step>
<Step title="Restart and use">
```bash
openclaw gateway restart
```
Mapped features (skills, hooks, MCP tools, LSP defaults) are available in the next session.
</Step>
</Steps>
## What OpenClaw maps from bundles
Not every bundle feature runs in OpenClaw today. Here is what works and what
is detected but not yet wired.
### Supported now
| Feature | How it maps | Applies to |
| ------------- | ------------------------------------------------------------------------------------------------- | -------------- |
| Skill content | Bundle skill roots load as normal OpenClaw skills | All formats |
| Commands | `commands/` and `.cursor/commands/` treated as skill roots | Claude, Cursor |
| Hook packs | OpenClaw-style `HOOK.md` + `handler.ts` layouts | Codex |
| MCP tools | Bundle MCP config merged into embedded OpenClaw settings; supported stdio and HTTP servers loaded | All formats |
| LSP servers | Claude `.lsp.json` and manifest-declared `lspServers` merged into embedded OpenClaw LSP defaults | Claude |
| Settings | Claude `settings.json` imported as embedded OpenClaw defaults | Claude |
#### Skill content
- Bundle skill roots load as normal OpenClaw skill roots.
- Claude `commands/` roots are treated as additional skill roots.
- Cursor `.cursor/commands/` roots are treated as additional skill roots.
Claude markdown command files and Cursor command markdown both work through the
normal OpenClaw skill loader.
#### Hook packs
Bundle hook roots work **only** when they use the normal OpenClaw hook-pack
layout: `HOOK.md` plus `handler.ts` or `handler.js`. Today this is primarily
the Codex-compatible case.
#### MCP for embedded OpenClaw
- Enabled bundles can contribute MCP server config.
- OpenClaw merges bundle MCP config into the effective embedded OpenClaw
settings as `mcpServers`.
- OpenClaw exposes supported bundle MCP tools during embedded OpenClaw agent
turns by launching stdio servers or connecting to HTTP servers.
- The `coding` and `messaging` tool profiles include bundle MCP tools by
default; use `tools.deny: ["bundle-mcp"]` to opt out for an agent or gateway.
- Project-local embedded agent settings still apply after bundle defaults, so
workspace settings can override bundle MCP entries when needed.
- Bundle MCP tool catalogs are sorted deterministically before registration, so
upstream `listTools()` order changes do not thrash prompt-cache tool blocks.
##### Transports
MCP servers can use stdio or HTTP transport.
**Stdio** launches a child process:
```json
{
"mcp": {
"servers": {
"my-server": {
"command": "node",
"args": ["server.js"],
"env": { "PORT": "3000" }
}
}
}
}
```
**HTTP** connects to a running MCP server, defaulting to `sse` unless
`streamable-http` is requested:
```json
{
"mcp": {
"servers": {
"my-server": {
"url": "http://localhost:3100/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer ${MY_SECRET_TOKEN}"
},
"connectionTimeoutMs": 30000
}
}
}
}
```
- `transport` accepts `"streamable-http"` or `"sse"`; omitted defaults to `sse`.
- `type: "http"` is a CLI-native downstream shape; use `transport: "streamable-http"` in OpenClaw config. `openclaw mcp set` and `openclaw doctor --fix` normalize the common alias.
- Only `http:` and `https:` URL schemes are allowed.
- `headers` values support `${ENV_VAR}` interpolation.
- A server entry with both `command` and `url` is rejected.
- URL credentials (userinfo and query params) are redacted from tool
descriptions and logs.
- `connectionTimeoutMs` overrides the default 30-second connection timeout for
both stdio and HTTP transports. Request timeout defaults to 60 seconds and
can be overridden with `requestTimeoutMs`.
##### Tool naming
OpenClaw registers bundle MCP tools with provider-safe names in the form
`serverName__toolName`. For example, a server keyed `"vigil-harbor"` exposing a
`memory_search` tool registers as `vigil-harbor__memory_search`.
- Characters outside `A-Za-z0-9_-` are replaced with `-`.
- Fragments that would start with a non-letter get a letter prefix, so numeric
server keys such as `12306` become provider-safe tool prefixes.
- Server prefixes are capped at 30 characters.
- Full tool names are capped at 64 characters.
- Empty server names fall back to `mcp`.
- Colliding sanitized names are disambiguated with numeric suffixes.
- Final exposed tool order is deterministic by safe name, keeping repeated
embedded-agent turns cache-stable.
- Profile filtering treats every tool from one bundle MCP server as
plugin-owned by `bundle-mcp`, so profile allow/deny lists can reference
either individual exposed tool names or the `bundle-mcp` plugin key.
#### Embedded OpenClaw settings
Claude `settings.json` is imported as default embedded OpenClaw settings when
the bundle is enabled. OpenClaw sanitizes shell override keys before applying
them:
- `shellPath`
- `shellCommandPrefix`
#### Embedded OpenClaw LSP
- Enabled Claude bundles can contribute LSP server config.
- OpenClaw loads `.lsp.json` plus any manifest-declared `lspServers` paths.
- Bundle LSP config is merged into the effective embedded OpenClaw LSP
defaults.
- Only supported stdio-backed LSP servers are runnable today; unsupported
transports still show up in `openclaw plugins inspect <id>`.
### Detected but not executed
These are recognized and shown in diagnostics, but OpenClaw does not run them:
- Claude `agents`, `hooks/hooks.json` automation, `outputStyles`
- Cursor `.cursor/agents`, `.cursor/hooks.json`, `.cursor/rules`
- Codex `.app.json` metadata beyond capability reporting
## Bundle formats
<AccordionGroup>
<Accordion title="Codex bundles">
Markers: `.codex-plugin/plugin.json`
Optional content: `skills/`, `hooks/`, `.mcp.json`, `.app.json`
Codex bundles fit OpenClaw best when they use skill roots and OpenClaw-style
hook-pack directories (`HOOK.md` + `handler.ts`).
</Accordion>
<Accordion title="Claude bundles">
Two detection modes:
- **Manifest-based:** `.claude-plugin/plugin.json`
- **Manifestless:** default Claude layout (`skills/`, `commands/`, `agents/`, `hooks/`, `.mcp.json`, `.lsp.json`, `settings.json`)
Claude-specific behavior:
- `commands/` is treated as skill content
- `settings.json` is imported into embedded OpenClaw settings (shell override keys are sanitized)
- `.mcp.json` exposes supported stdio tools to embedded OpenClaw
- `.lsp.json` plus manifest-declared `lspServers` paths load into embedded OpenClaw LSP defaults
- `hooks/hooks.json` is detected but not executed
- Custom component paths in the manifest are additive; they extend defaults, not replace them
</Accordion>
<Accordion title="Cursor bundles">
Markers: `.cursor-plugin/plugin.json`
Optional content: `skills/`, `.cursor/commands/`, `.cursor/agents/`, `.cursor/rules/`, `.cursor/hooks.json`, `.mcp.json`
- `.cursor/commands/` is treated as skill content
- `.cursor/rules/`, `.cursor/agents/`, and `.cursor/hooks.json` are detect-only
</Accordion>
</AccordionGroup>
## Detection precedence
OpenClaw checks for native plugin format first:
1. `openclaw.plugin.json` or a valid `package.json` with `openclaw.extensions` - treated as a **native plugin**
2. Bundle markers (`.codex-plugin/`, `.claude-plugin/`, or default Claude/Cursor layout) - treated as a **bundle**
If a directory contains both, OpenClaw uses the native path. This prevents
dual-format packages from being partially installed as bundles.
## Runtime dependencies and cleanup
- Third-party compatible bundles do not get startup `npm install` repair. They
should be installed through `openclaw plugins install` and ship everything
they need in the installed plugin directory.
- OpenClaw-owned bundled plugins are either shipped lightweight in core or
downloadable through the plugin installer. Gateway startup never runs a
package manager for them.
- `openclaw doctor --fix` removes stale local bundled-plugin install records
and can recover downloadable plugins that are missing from the local plugin
index when config still references them.
## Security
Bundles have a narrower trust boundary than native plugins:
- OpenClaw does **not** load arbitrary bundle runtime modules in-process.
- Skills and hook-pack paths must stay inside the plugin root (boundary-checked).
- Settings files are read with the same boundary checks.
- Supported stdio MCP servers may be launched as subprocesses.
This makes bundles safer by default, but you should still treat third-party
bundles as trusted content for the features they do expose.
## Troubleshooting
<AccordionGroup>
<Accordion title="Bundle is detected but capabilities do not run">
Run `openclaw plugins inspect <id>`. If a capability is listed but marked as
not wired, that is a product limit, not a broken install.
</Accordion>
<Accordion title="Claude command files do not appear">
Make sure the bundle is enabled and the markdown files are inside a detected
`commands/` or `skills/` root.
</Accordion>
<Accordion title="Claude settings do not apply">
Only embedded OpenClaw settings from `settings.json` are supported. OpenClaw does
not treat bundle settings as raw config patches.
</Accordion>
<Accordion title="Claude hooks do not execute">
`hooks/hooks.json` is detect-only. If you need runnable hooks, use the
OpenClaw hook-pack layout or ship a native plugin.
</Accordion>
</AccordionGroup>
## Related
- [Install and Configure Plugins](/tools/plugin)
- [Building Plugins](/plugins/building-plugins) - create a native plugin
- [Plugin Manifest](/plugins/manifest) - native manifest schema

View File

@@ -0,0 +1,350 @@
---
summary: "Build a plugin that registers a local AI CLI backend"
title: "Building CLI backend plugins"
sidebarTitle: "CLI backend plugins"
read_when:
- You are building a local AI CLI backend plugin
- You want to register a backend for model refs such as acme-cli/model
- You need to map a third-party CLI into OpenClaw's text fallback runner
---
CLI backend plugins let OpenClaw call a local AI CLI as a text inference
backend. The backend appears as a provider prefix in model refs:
```text
acme-cli/acme-large
```
Use a CLI backend when the upstream integration is already exposed as a local
command, when the CLI owns local login state, or as a fallback when API
providers are unavailable.
<Info>
If the upstream service exposes a normal HTTP model API, write a
[provider plugin](/plugins/sdk-provider-plugins) instead. If the upstream
runtime owns complete agent sessions, tool events, compaction, or background
task state, use an [agent harness](/plugins/sdk-agent-harness).
</Info>
## What the plugin owns
A CLI backend plugin has three contracts:
| Contract | File | Purpose |
| -------------------- | ---------------------- | --------------------------------------------------------- |
| Package entry | `package.json` | Points OpenClaw at the plugin runtime module |
| Manifest ownership | `openclaw.plugin.json` | Declares the backend id before runtime loads |
| Runtime registration | `index.ts` | Calls `api.registerCliBackend(...)` with command defaults |
The manifest is discovery metadata: it does not execute the CLI or register
runtime behavior. Runtime behavior starts when the plugin entry calls
`api.registerCliBackend(...)`.
## Minimal backend plugin
<Steps>
<Step title="Create package metadata">
```json package.json
{
"name": "@acme/openclaw-acme-cli",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./index.ts"],
"compat": {
"pluginApi": ">=2026.3.24-beta.2",
"minGatewayVersion": "2026.3.24-beta.2"
},
"build": {
"openclawVersion": "2026.3.24-beta.2",
"pluginSdkVersion": "2026.3.24-beta.2"
}
},
"dependencies": {
"openclaw": "^2026.3.24"
},
"devDependencies": {
"typescript": "^5.9.0"
}
}
```
Published packages must ship built JavaScript runtime files. If your source
entry is `./src/index.ts`, add `openclaw.runtimeExtensions` pointing at the
built JavaScript peer. See [Entry points](/plugins/sdk-entrypoints).
</Step>
<Step title="Declare backend ownership">
```json openclaw.plugin.json
{
"id": "acme-cli",
"name": "Acme CLI",
"description": "Run Acme's local AI CLI through OpenClaw",
"cliBackends": ["acme-cli"],
"setup": {
"cliBackends": ["acme-cli"],
"requiresRuntime": false
},
"activation": {
"onStartup": false
},
"configSchema": {
"type": "object",
"additionalProperties": false
}
}
```
`cliBackends` is the runtime ownership list; it lets OpenClaw auto-load the
plugin when config or model selection mentions `acme-cli/...`.
`setup.cliBackends` is the descriptor-first setup surface. Add it when
model discovery, onboarding, or status should recognize the backend
without loading plugin runtime. Use `requiresRuntime: false` only when
those static descriptors are enough for setup.
</Step>
<Step title="Register the backend">
```typescript index.ts
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import {
CLI_FRESH_WATCHDOG_DEFAULTS,
CLI_RESUME_WATCHDOG_DEFAULTS,
type CliBackendPlugin,
} from "openclaw/plugin-sdk/cli-backend";
function buildAcmeCliBackend(): CliBackendPlugin {
return {
id: "acme-cli",
liveTest: {
defaultModelRef: "acme-cli/acme-large",
defaultImageProbe: false,
defaultMcpProbe: false,
docker: {
npmPackage: "@acme/acme-cli",
binaryName: "acme",
},
},
config: {
command: "acme",
args: ["chat", "--json"],
output: "json",
input: "stdin",
modelArg: "--model",
sessionArg: "--session",
sessionMode: "existing",
sessionIdFields: ["session_id", "conversation_id"],
systemPromptFileArg: "--system-file",
systemPromptWhen: "first",
imageArg: "--image",
imageMode: "repeat",
reliability: {
watchdog: {
fresh: { ...CLI_FRESH_WATCHDOG_DEFAULTS },
resume: { ...CLI_RESUME_WATCHDOG_DEFAULTS },
},
},
serialize: true,
},
};
}
export default definePluginEntry({
id: "acme-cli",
name: "Acme CLI",
description: "Run Acme's local AI CLI through OpenClaw",
register(api) {
api.registerCliBackend(buildAcmeCliBackend());
},
});
```
The backend id must match the manifest `cliBackends` entry. The
registered `config` is only the default; user config under
`agents.defaults.cliBackends.acme-cli` merges over it at runtime.
</Step>
</Steps>
## Config shape
`CliBackendConfig` describes how OpenClaw should launch and parse the CLI:
| Field | Use |
| --------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `command` | Binary name or absolute command path |
| `args` | Base argv for fresh runs |
| `resumeArgs` | Alternate argv for resumed sessions; supports `{sessionId}` |
| `output` / `resumeOutput` | Parser: `json`, `jsonl`, or `text` |
| `jsonlDialect` | JSONL event dialect: `claude-stream-json` or `gemini-stream-json` |
| `liveSession` | Long-lived CLI process mode (`claude-stdio`) |
| `input` | Prompt transport: `arg` or `stdin` |
| `maxPromptArgChars` | Max prompt length for `arg` mode before falling back to stdin |
| `env` / `clearEnv` | Extra env vars to inject, or names to strip before launch |
| `modelArg` | Flag used before the model id |
| `modelAliases` | Map OpenClaw model ids to CLI-native ids |
| `sessionArg` / `sessionArgs` | How to pass a session id |
| `sessionMode` | `always`, `existing`, or `none` |
| `sessionIdFields` | JSON fields OpenClaw reads from CLI output |
| `systemPromptArg` / `systemPromptFileArg` | System prompt transport |
| `systemPromptFileConfigArg` / `systemPromptFileConfigKey` | Config-override transport for a system prompt file (for example `-c`) |
| `systemPromptMode` | `append` or `replace` |
| `systemPromptWhen` | `first`, `always`, or `never` |
| `imageArg` / `imageMode` | Image path flag and how to pass multiple images (`repeat` or `list`) |
| `imagePathScope` | Where staged image files live before handoff: `temp` or `workspace` |
| `serialize` | Keep same-backend runs ordered |
| `reseedFromRawTranscriptWhenUncompacted` | Opt in to bounded raw-transcript reseed before compaction for safe session resets |
| `reliability.outputLimits` | Max raw JSONL chars/lines retained for one live CLI turn (live-session backends) |
| `reliability.watchdog` | No-output timeout tuning, separate for fresh vs resumed runs |
Prefer the smallest static config that matches the CLI. Add plugin callbacks
only for behavior that really belongs to the backend.
## Advanced backend hooks
`CliBackendPlugin` can also define:
| Hook | Use |
| ---------------------------------- | --------------------------------------------------------------------------- |
| `normalizeConfig(config, context)` | Rewrite legacy user config after merge |
| `resolveExecutionArgs(ctx)` | Add request-scoped flags such as thinking effort or side-question isolation |
| `prepareExecution(ctx)` | Create temporary auth or config bridges before launch |
| `transformSystemPrompt(ctx)` | Apply a final CLI-specific system prompt transform |
| `textTransforms` | Bidirectional prompt/output replacements |
| `defaultAuthProfileId` | Prefer a specific OpenClaw auth profile |
| `authEpochMode` | Decide how auth changes invalidate stored CLI sessions |
| `nativeToolMode` | Declare whether the CLI has always-on native tools |
| `sideQuestionToolMode` | Declare disabled native tools for `/btw` side questions |
| `bundleMcp` / `bundleMcpMode` | Opt into OpenClaw's loopback MCP tool bridge |
| `ownsNativeCompaction` | Backend owns its own compaction - OpenClaw defers |
Keep these hooks provider-owned. Do not add CLI-specific branches to core when
a backend hook can express the behavior.
`ctx.executionMode` is `"agent"` for normal turns and `"side-question"` for
ephemeral `/btw` calls. Use it when the CLI needs different one-shot flags,
such as disabling native tools, session persistence, or resume behavior for
BTW. If a backend normally has `nativeToolMode: "always-on"` but its
side-question argv reliably disables those tools, also set
`sideQuestionToolMode: "disabled"`; otherwise OpenClaw fails closed when BTW
requires a no-tools CLI run.
### `ownsNativeCompaction`: opting out of OpenClaw compaction
If your backend runs an agent that compacts its **own** transcript, set
`ownsNativeCompaction: true` so OpenClaw's safeguard summarizer never runs
against its sessions - the CLI compaction lifecycle returns a no-op and the
turn proceeds. `claude-cli` declares it because Claude Code compacts
internally with no harness endpoint. Native-harness sessions such as Codex
keep routing to their harness compaction endpoint instead.
**Only declare it when all of the following hold**, or a deferred
over-budget session can stay over budget or go stale (OpenClaw no longer
rescues it):
- the backend reliably compacts or bounds its own transcript as it nears its
window;
- it persists a resumable session so the compacted state survives turns
(for example `--resume` / `--session-id`);
- it is not a native-harness compaction session - matching `agentHarnessId`
sessions route to the harness endpoint instead.
## MCP tool bridge
CLI backends do not receive OpenClaw tools by default. If the CLI can consume
an MCP configuration, opt in explicitly:
```typescript
return {
id: "acme-cli",
bundleMcp: true,
bundleMcpMode: "codex-config-overrides",
config: {
command: "acme",
args: ["chat", "--json"],
output: "json",
},
};
```
Supported bridge modes:
| Mode | Use |
| ------------------------ | ---------------------------------------------------------------- |
| `claude-config-file` | CLIs that accept an MCP config file |
| `codex-config-overrides` | CLIs that accept config overrides on argv |
| `gemini-system-settings` | CLIs that read MCP settings from their system settings directory |
Only enable the bridge when the CLI can actually consume it. If the CLI has
its own built-in tool layer that cannot be disabled, set `nativeToolMode:
"always-on"` so OpenClaw can fail closed when a caller requires no native
tools.
## User configuration
Users can override any backend default:
```json5
{
agents: {
defaults: {
cliBackends: {
"acme-cli": {
command: "/opt/acme/bin/acme",
args: ["chat", "--json", "--profile", "work"],
modelAliases: {
large: "acme-large-2026",
},
},
},
model: {
primary: "openai/gpt-5.5",
fallbacks: ["acme-cli/large"],
},
},
},
}
```
Document the minimum override users are likely to need - usually only
`command` when the binary is outside `PATH`.
## Verification
For bundled plugins, add a focused test around the builder and setup
registration, then run the plugin's targeted test lane:
```bash
pnpm test extensions/acme-cli
```
For local or installed plugins, verify discovery and one real model run:
```bash
openclaw plugins inspect acme-cli --runtime --json
openclaw agent --message "reply exactly: backend ok" --model acme-cli/acme-large
```
If the backend supports images or MCP, add a live smoke that proves those
paths with the real CLI. Do not rely on static inspection for prompt, image,
MCP, or session-resume behavior.
## Checklist
<Check>`package.json` has `openclaw.extensions` and built runtime entries for published packages</Check>
<Check>`openclaw.plugin.json` declares `cliBackends` and intentional `activation.onStartup`</Check>
<Check>`setup.cliBackends` is present when setup/model discovery should see the backend cold</Check>
<Check>`api.registerCliBackend(...)` uses the same backend id as the manifest</Check>
<Check>User overrides under `agents.defaults.cliBackends.<id>` still win</Check>
<Check>Session, system prompt, image, and output parser settings match the real CLI contract</Check>
<Check>Targeted tests and at least one live CLI smoke prove the backend path</Check>
## Related
- [CLI backends](/gateway/cli-backends) - user configuration and runtime behavior
- [Building plugins](/plugins/building-plugins) - package and manifest basics
- [Plugin SDK overview](/plugins/sdk-overview) - registration API reference
- [Plugin manifest](/plugins/manifest) - `cliBackends` and setup descriptors
- [Agent harness](/plugins/sdk-agent-harness) - full external agent runtimes

View File

@@ -0,0 +1,336 @@
---
summary: "Set up Codex Computer Use for Codex-mode OpenClaw agents"
title: "Codex Computer Use"
read_when:
- You want Codex-mode OpenClaw agents to use Codex Computer Use
- You are deciding between Codex Computer Use, PeekabooBridge, and direct cua-driver MCP
- You are deciding between Codex Computer Use and a direct cua-driver MCP setup
- You are configuring computerUse for the bundled Codex plugin
- You are troubleshooting /codex computer-use status or install
---
Computer Use is a Codex-native MCP plugin for local desktop control. OpenClaw
does not vendor the desktop app, execute desktop actions itself, or bypass
Codex permissions. The bundled `codex` plugin only prepares Codex app-server:
it enables Codex plugin support, finds or installs the configured Computer Use
plugin, checks that the `computer-use` MCP server is available, and then lets
Codex own the native MCP tool calls during Codex-mode turns.
Use this page when OpenClaw is already using the native Codex harness. For the
runtime setup itself, see [Codex harness](/plugins/codex-harness).
## OpenClaw.app and Peekaboo
OpenClaw.app's Peekaboo integration is separate from Codex Computer Use. The
macOS app can host a PeekabooBridge socket so the `peekaboo` CLI can reuse the
app's local Accessibility and Screen Recording grants for Peekaboo's own
automation tools. That bridge does not install or proxy Codex Computer Use, and
Codex Computer Use does not call through the PeekabooBridge socket.
Use [Peekaboo bridge](/platforms/mac/peekaboo) when you want OpenClaw.app to be
a permission-aware host for Peekaboo CLI automation. Use this page when a
Codex-mode OpenClaw agent should have Codex's native `computer-use` MCP plugin
available before the turn starts.
## iOS app
The iOS app is separate from Codex Computer Use. It does not install or proxy
the Codex `computer-use` MCP server and it is not a desktop-control backend.
Instead, the iOS app connects as an OpenClaw node and exposes mobile
capabilities through node commands such as `canvas.*`, `camera.*`, `screen.*`,
`location.*`, and `talk.*`.
Use [iOS](/platforms/ios) when you want an agent to drive an iPhone node
through the gateway. Use this page when a Codex-mode agent should control the
local macOS desktop through Codex's native Computer Use plugin.
## Direct cua-driver MCP
Codex Computer Use is not the only way to expose desktop control. If you want
OpenClaw-managed runtimes to call TryCua's driver directly, use the upstream
`cua-driver mcp` server through OpenClaw's MCP registry instead of the
Codex-specific marketplace flow.
After installing `cua-driver`, either ask it for the OpenClaw command:
```bash
cua-driver mcp-config --client openclaw
```
or register the stdio server directly:
```bash
openclaw mcp set cua-driver '{"command":"cua-driver","args":["mcp"]}'
```
That path keeps the upstream MCP tool surface intact, including the driver
schemas and structured MCP responses. Use it when you want the CUA driver
available as a normal OpenClaw MCP server. Use the Codex Computer Use setup on
this page when Codex app-server should own plugin installation, MCP reloads,
and native tool calls inside Codex-mode turns.
CUA's driver is macOS-specific and still requires the local macOS permissions
its app prompts for, such as Accessibility and Screen Recording. OpenClaw does
not install `cua-driver`, grant those permissions, or bypass the upstream
driver's safety model.
## Quick setup
Set `plugins.entries.codex.config.computerUse` when Codex-mode turns must have
Computer Use available before a thread starts. `autoInstall: true` opts
Computer Use in and lets OpenClaw install or re-enable it before the turn:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
computerUse: {
autoInstall: true,
},
},
},
},
},
agents: {
defaults: {
model: "openai/gpt-5.5",
},
},
}
```
With this config, OpenClaw checks Codex app-server before each Codex-mode
turn. If Computer Use is missing but Codex app-server has already discovered
an installable marketplace, OpenClaw asks Codex app-server to install or
re-enable the plugin and reload MCP servers. On macOS, when no matching
marketplace is registered and the standard Codex app bundle exists, OpenClaw
also tries to register the bundled Codex marketplace from
`/Applications/Codex.app/Contents/Resources/plugins/openai-bundled` before it
fails. If setup still cannot make the MCP server available, the turn fails
before the thread starts.
After changing Computer Use config, use `/new` or `/reset` in the affected
chat before testing if an existing Codex thread has already started.
On macOS managed stdio startup, OpenClaw prefers the signed desktop Codex app
bundle at `/Applications/Codex.app/Contents/Resources/codex` when it exists.
That keeps Computer Use under the app bundle that owns the local
desktop-control permissions. If the desktop app is not installed, OpenClaw
falls back to the managed Codex binary installed beside the plugin. If an
installed desktop app initializes with an unsupported app-server version,
OpenClaw closes that child and retries the next managed binary candidate
instead of letting a stale desktop app shadow the plugin-local fallback.
Explicit `appServer.command` config or `OPENCLAW_CODEX_APP_SERVER_BIN` still
overrides this managed selection.
## Commands
Use the `/codex computer-use` commands from any chat surface where the
`codex` plugin command surface is available. These are OpenClaw chat/runtime
commands, not `openclaw codex ...` CLI subcommands:
```text
/codex computer-use status
/codex computer-use install
/codex computer-use install --source <marketplace-source>
/codex computer-use install --marketplace-path <path>
/codex computer-use install --marketplace <name>
```
`status` is the default action and is read-only: it does not add marketplace
sources, install plugins, or enable Codex plugin support. If no config opts
Computer Use in, `status` can report disabled even after a one-off install
command.
`install` enables Codex app-server plugin support, optionally adds a
configured marketplace source, installs or re-enables the configured plugin
through Codex app-server, reloads MCP servers, and verifies that the MCP
server exposes tools. Because installation changes trusted host resources,
only an owner or an `operator.admin` Gateway client can run `install`. Other
authorized senders can continue to use the read-only `status` command,
including with overrides.
## Marketplace choices
OpenClaw uses the same app-server API that Codex itself exposes. The
marketplace fields choose where Codex should find `computer-use`.
| Field | Use when | Install support |
| -------------------- | --------------------------------------------------------------- | -------------------------------------------------------- |
| No marketplace field | You want Codex app-server to use marketplaces it already knows. | Yes, when app-server returns a local marketplace. |
| `marketplaceSource` | You have a Codex marketplace source app-server can add. | Yes, for explicit `/codex computer-use install`. |
| `marketplacePath` | You already know the local marketplace file path on the host. | Yes, for explicit install and turn-start auto-install. |
| `marketplaceName` | You want to select one already registered marketplace by name. | Yes only when the selected marketplace has a local path. |
Fresh Codex homes may need a short moment to seed their official
marketplaces. During install, OpenClaw polls `plugin/list` for up to
`marketplaceDiscoveryTimeoutMs` milliseconds (default 60 seconds).
If multiple known marketplaces contain Computer Use, OpenClaw prefers
`openai-bundled`, then `openai-curated`, then `local`. Unknown ambiguous
matches fail closed and ask you to set `marketplaceName` or
`marketplacePath`.
## Bundled macOS marketplace
Recent Codex desktop builds bundle Computer Use here:
```text
/Applications/Codex.app/Contents/Resources/plugins/openai-bundled/plugins/computer-use
```
When `computerUse.autoInstall` is true and no marketplace containing
`computer-use` is registered, OpenClaw tries to add the standard bundled
marketplace root automatically:
```text
/Applications/Codex.app/Contents/Resources/plugins/openai-bundled
```
You can also register it explicitly from a shell with Codex:
```bash
codex plugin marketplace add /Applications/Codex.app/Contents/Resources/plugins/openai-bundled
```
If you use a nonstandard Codex app path, run `/codex computer-use install
--source <marketplace-root>` once, or set `computerUse.marketplacePath` to a
local marketplace file path. Use `--marketplace-path` only when you have the
marketplace JSON file path, not the bundled marketplace root.
## Remote catalog limit
Codex app-server can list and read remote-only catalog entries, but it does
not currently support remote `plugin/install`. That means `marketplaceName`
can select a remote-only marketplace for status checks, but installs and
re-enables still need a local marketplace via `marketplaceSource` or
`marketplacePath`.
If status says the plugin is available in a remote Codex marketplace but
remote install is unsupported, run install with a local source or path:
```text
/codex computer-use install --source <marketplace-source>
/codex computer-use install --marketplace-path <path>
```
## Configuration reference
| Field | Default | Meaning |
| ------------------------------- | -------------- | ------------------------------------------------------------------------------ |
| `enabled` | inferred | Require Computer Use. Defaults to true when another Computer Use field is set. |
| `autoInstall` | false | Install or re-enable from already discovered marketplaces at turn start. |
| `marketplaceDiscoveryTimeoutMs` | 60000 | How long install waits for Codex app-server marketplace discovery. |
| `marketplaceSource` | unset | Source string passed to Codex app-server `marketplace/add`. |
| `marketplacePath` | unset | Local Codex marketplace file path containing the plugin. |
| `marketplaceName` | unset | Registered Codex marketplace name to select. |
| `pluginName` | `computer-use` | Codex marketplace plugin name. |
| `mcpServerName` | `computer-use` | MCP server name exposed by the installed plugin. |
Turn-start auto-install intentionally refuses configured `marketplaceSource`
values. Adding a new source is an explicit setup operation, so use
`/codex computer-use install --source <marketplace-source>` once, then let
`autoInstall` handle future re-enables from discovered local marketplaces.
Turn-start auto-install can use a configured `marketplacePath`, because that
is already a local path on the host.
Each field also accepts an environment variable override, checked when the
matching config key is unset:
| Field | Env var |
| ------------------------------- | -------------------------------------------------------------- |
| `enabled` | `OPENCLAW_CODEX_COMPUTER_USE` |
| `autoInstall` | `OPENCLAW_CODEX_COMPUTER_USE_AUTO_INSTALL` |
| `marketplaceDiscoveryTimeoutMs` | `OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS` |
| `marketplaceSource` | `OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_SOURCE` |
| `marketplacePath` | `OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_PATH` |
| `marketplaceName` | `OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_NAME` |
| `pluginName` | `OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_NAME` |
| `mcpServerName` | `OPENCLAW_CODEX_COMPUTER_USE_MCP_SERVER_NAME` |
## What OpenClaw checks
OpenClaw reports a stable setup reason internally and formats the
user-facing status for chat:
| Reason | Meaning | Next step |
| ---------------------------- | ------------------------------------------------------ | --------------------------------------------- |
| `disabled` | `computerUse.enabled` resolved to false. | Set `enabled` or another Computer Use field. |
| `marketplace_missing` | No matching marketplace was available. | Configure source, path, or marketplace name. |
| `plugin_not_installed` | Marketplace exists, but the plugin is not installed. | Run install or enable `autoInstall`. |
| `plugin_disabled` | Plugin is installed but disabled in Codex config. | Run install to re-enable it. |
| `remote_install_unsupported` | Selected marketplace is remote-only. | Use `marketplaceSource` or `marketplacePath`. |
| `mcp_missing` | Plugin is enabled, but the MCP server is unavailable. | Check Codex Computer Use and OS permissions. |
| `ready` | Plugin and MCP tools are available. | Start the Codex-mode turn. |
| `check_failed` | A Codex app-server request failed during status check. | Check app-server connectivity and logs. |
| `auto_install_blocked` | Turn-start setup would need to add a new source. | Run explicit install first. |
The chat output includes the plugin state, MCP server state, marketplace,
tools when available, and the specific message for the failing setup step.
## macOS permissions
Computer Use is macOS-specific. The Codex-owned MCP server may need local OS
permissions before it can inspect or control apps. If OpenClaw says Computer
Use is installed but the MCP server is unavailable, verify the Codex-side
Computer Use setup first:
- Codex app-server is running on the same host where desktop control should
happen.
- The Computer Use plugin is enabled in Codex config.
- The `computer-use` MCP server appears in Codex app-server MCP status.
- macOS has granted the required permissions for the desktop-control app.
- The current host session can access the desktop being controlled.
OpenClaw intentionally fails closed when `computerUse.enabled` is true. A
Codex-mode turn should not silently proceed without the native desktop tools
that the config required.
## Troubleshooting
**Status says not installed.** Run `/codex computer-use install`. If the
marketplace is not discovered, pass `--source` or `--marketplace-path`.
**Status says installed but disabled.** Run `/codex computer-use install`
again. Codex app-server install writes the plugin config back to enabled.
**Status says remote install is unsupported.** Use a local marketplace
source or path. Remote-only catalog entries can be inspected but not
installed through the current app-server API.
**Status says the MCP server is unavailable.** Re-run install once so MCP
servers reload. If it remains unavailable, fix the Codex Computer Use app,
Codex app-server MCP status, or macOS permissions.
**Status or a probe times out on `computer-use.list_apps`.** The plugin and
MCP server are present, but the local Computer Use bridge did not answer.
Quit or restart Codex Computer Use, relaunch Codex Desktop if needed, then
retry in a fresh OpenClaw session. If the host previously ran Computer Use
through an older managed Codex app-server, refresh the installed plugin from
the desktop bundled marketplace:
```text
/codex computer-use install --source /Applications/Codex.app/Contents/Resources/plugins/openai-bundled
```
**A Computer Use tool says `Native hook relay unavailable`.** The
Codex-native tool hook could not reach an active OpenClaw relay through the
local bridge or Gateway fallback. Start a fresh OpenClaw session with `/new`
or `/reset`. If it works once and then fails again on a later tool call,
`/new` is only clearing the current attempt; restart the Codex app-server or
OpenClaw Gateway so old threads and hook registrations are dropped, then
retry in a fresh session.
**Turn-start auto-install refuses a source.** This is intentional. Add the
source with explicit `/codex computer-use install --source
<marketplace-source>` first, then future turn-start auto-install can use the
discovered local marketplace.
## Related
- [Codex harness](/plugins/codex-harness)
- [Peekaboo bridge](/platforms/mac/peekaboo)
- [iOS app](/platforms/ios)

View File

@@ -0,0 +1,582 @@
---
summary: "Configuration, auth, discovery, and app-server reference for the Codex harness"
title: "Codex harness reference"
read_when:
- You need every Codex harness config field
- You are changing app-server transport, auth, discovery, or timeout behavior
- You are debugging Codex harness startup, model discovery, or environment isolation
---
This reference covers detailed configuration for the bundled `codex` plugin.
For setup and routing decisions, start with
[Codex harness](/plugins/codex-harness).
## Plugin config surface
All Codex harness settings live under `plugins.entries.codex.config`.
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
discovery: {
enabled: true,
timeoutMs: 2500,
},
appServer: {
mode: "guardian",
},
},
},
},
},
}
```
Top-level fields:
| Field | Default | Meaning |
| -------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `discovery` | enabled | Model discovery settings for Codex app-server `model/list`. |
| `appServer` | managed stdio app-server | Transport, command, auth, approval, sandbox, and timeout settings. |
| `codexDynamicToolsLoading` | `"searchable"` | Use `"direct"` to put OpenClaw dynamic tools directly in the initial Codex tool context. |
| `codexDynamicToolsExclude` | `[]` | Additional OpenClaw dynamic tool names to omit from Codex app-server turns. |
| `codexPlugins` | disabled | Native Codex plugin/app support for migrated source-installed curated plugins. See [Native Codex plugins](/plugins/codex-native-plugins). |
| `computerUse` | disabled | Codex Computer Use setup. See [Codex Computer Use](/plugins/codex-computer-use). |
## App-server transport
By default OpenClaw starts the managed Codex binary shipped with the bundled
plugin (currently `@openai/codex` `0.142.5`):
```bash
codex app-server --listen stdio://
```
This keeps the app-server version tied to the bundled `codex` plugin instead of
whichever separate Codex CLI happens to be installed locally. Set
`appServer.command` only when you intentionally want a different executable.
For an already-running app-server, use WebSocket transport:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
transport: "websocket",
url: "ws://gateway-host:39175",
authToken: "${CODEX_APP_SERVER_TOKEN}",
requestTimeoutMs: 60000,
},
},
},
},
},
}
```
`appServer` fields:
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `homeScope` | `"agent"` | `"agent"` isolates Codex state per OpenClaw agent. `"user"` shares the native `$CODEX_HOME` or `~/.codex`, uses native auth, and enables owner-only thread management. User scope requires stdio. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. Accepts a literal string or SecretInput such as `${CODEX_APP_SERVER_TOKEN}`. |
| `headers` | `{}` | Extra WebSocket headers. Header values accept literal strings or SecretInput values, for example `x-codex-client-session-token: "${CODEX_CLIENT_SESSION_TOKEN}"`. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. |
| `remoteWorkspaceRoot` | unset | Remote Codex app-server workspace root. When set, OpenClaw infers the local workspace root from the resolved OpenClaw workspace, preserves the current cwd suffix under this remote root, and sends only the final app-server cwd to Codex. If the cwd is outside the resolved OpenClaw workspace root, OpenClaw fails closed instead of sending a gateway-local path to the remote app-server. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle and progress guard used after a tool handoff, native tool completion, post-tool raw assistant progress, raw reasoning completion, or reasoning progress while OpenClaw waits for `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start, resume, and turn. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start and resume. Active OpenClaw sandboxes narrow `danger-full-access` turns to Codex `workspace-write`; the turn network flag follows OpenClaw sandbox egress. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed. |
| `defaultWorkspaceDir` | current process directory | Workspace used by `/codex bind` when `--cwd` is omitted. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, and `null` clears the override. Legacy `"fast"` is accepted as `"priority"`. |
| `networkProxy` | disabled | Opt into Codex permissions-profile networking for app-server commands. OpenClaw defines the selected `permissions.<profile>.network` config and selects it with `default_permissions` instead of sending `sandbox`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
`appServer.networkProxy` is explicit because it changes the Codex sandbox
contract. When enabled, OpenClaw also sets `features.network_proxy.enabled` and
`default_permissions` in the Codex thread config so the generated permission
profile can start Codex-managed networking. OpenClaw generates a
collision-resistant `openclaw-network-<fingerprint>` profile name from the
profile body by default; use `profileName` only when a stable local name is
required.
```js
export default {
plugins: {
entries: {
codex: {
config: {
appServer: {
sandbox: "workspace-write",
networkProxy: {
enabled: true,
domains: {
"api.openai.com": "allow",
"blocked.example.com": "deny",
},
allowUpstreamProxy: true,
proxyUrl: "http://127.0.0.1:3128",
},
},
},
},
},
},
};
```
If the normal app-server runtime would be `danger-full-access`, enabling
`networkProxy` uses workspace-style filesystem access for the generated
permission profile instead. Codex-managed network enforcement is sandboxed
networking, so a full-access profile would not protect outbound traffic.
The plugin blocks older or unversioned app-server handshakes: Codex app-server
must report stable version `0.125.0` or newer.
OpenClaw treats non-loopback WebSocket app-server URLs as remote and requires
identity-bearing WebSocket auth through `appServer.authToken` or an
`Authorization` header. `appServer.authToken` and each `appServer.headers.*`
value can be a SecretInput; the secrets runtime resolves SecretRefs and env
shorthand before OpenClaw builds app-server start options, and unresolved
structured SecretRefs fail before any token or header is sent. When native
Codex plugins are configured, OpenClaw uses the connected app-server's plugin
control plane to install or refresh those plugins and then refreshes app
inventory so plugin-owned apps are visible to the Codex thread. `app/list` is
still the authoritative inventory and metadata source, but OpenClaw policy
decides whether `thread/start` sends `config.apps[appId].enabled = true` for a
listed accessible app even if Codex currently marks it disabled. Unknown or
missing app ids remain fail-closed; this path only activates marketplace
plugins via `plugin/install` and refreshes inventory. Only connect OpenClaw to
remote app-servers that are trusted to accept OpenClaw-managed plugin installs
and app inventory refreshes.
## Approval and sandbox modes
Local stdio app-server sessions default to YOLO mode:
`approvalPolicy: "never"`, `approvalsReviewer: "user"`, and
`sandbox: "danger-full-access"`. This trusted local operator posture lets
unattended OpenClaw turns and heartbeats make progress without native approval
prompts that nobody is around to answer.
If Codex's local system requirements file disallows implicit YOLO approval,
reviewer, or sandbox values, OpenClaw treats the implicit default as guardian
instead and selects allowed guardian permissions. `tools.exec.mode: "auto"`
also forces guardian-reviewed Codex approvals and does not preserve unsafe
legacy `approvalPolicy: "never"` or `sandbox: "danger-full-access"` overrides;
set `tools.exec.mode: "full"` for an intentional no-approval posture.
Hostname-matching `[[remote_sandbox_config]]` entries in the same requirements
file are honored for the sandbox default decision.
Set `appServer.mode: "guardian"` for Codex guardian-reviewed approvals:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
mode: "guardian",
serviceTier: "priority",
},
},
},
},
},
}
```
The `guardian` preset expands to `approvalPolicy: "on-request"`,
`approvalsReviewer: "auto_review"`, and `sandbox: "workspace-write"` when those
values are allowed. Individual policy fields override `mode`. The older
`guardian_subagent` reviewer value is still accepted as a compatibility alias,
but new configs should use `auto_review`.
When an OpenClaw sandbox is active, the local Codex app-server process still
runs on the Gateway host. OpenClaw therefore disables Codex native Code Mode,
user MCP servers, and app-backed plugin execution for that turn instead of
treating Codex host-side sandboxing as equivalent to the OpenClaw sandbox
backend. Shell access is exposed through OpenClaw sandbox-backed dynamic tools
such as `sandbox_exec` and `sandbox_process` when the normal exec/process tools
are available.
<Note>
On Docker-backed OpenClaw sandbox hosts (`agents.defaults.sandbox.mode` set to
a Docker backend), `openclaw doctor` probes whether the host allows the
unprivileged user (and, when Docker sandbox network egress is disabled,
network) namespaces that nested Codex `bwrap` needs for `workspace-write`
shell execution inside the sandbox container. A failed probe usually surfaces
as `bwrap: setting up uid map: Permission denied` or
`bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted` on
Ubuntu/AppArmor hosts. Fix the reported host namespace policy for the OpenClaw
service user and restart the gateway; prefer a scoped AppArmor profile for the
service process over the host-wide
`kernel.apparmor_restrict_unprivileged_userns=0` fallback, and do not grant
broader Docker container privileges just to satisfy nested `bwrap`.
</Note>
## Sandboxed native execution
The stable default is fail-closed: active OpenClaw sandboxing disables native
Codex execution surfaces that would otherwise run from the Codex app-server
host. Use `appServer.experimental.sandboxExecServer: true` only when you want
to try Codex's remote environment support with OpenClaw's sandbox backend.
This preview path requires Codex app-server 0.132.0 or newer.
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
experimental: {
sandboxExecServer: true,
},
},
},
},
},
},
}
```
When the flag is on and the current OpenClaw session is sandboxed, OpenClaw
starts a local loopback exec-server backed by the active sandbox, registers it
with Codex app-server, and starts the Codex thread and turn with that
OpenClaw-owned environment. If the app-server cannot register the environment,
the run fails closed instead of silently falling back to host execution.
This preview path is local-only. A remote WebSocket app-server cannot reach
the loopback exec-server unless it is running on the same host, so OpenClaw
rejects that combination.
## Auth and environment isolation
In the default per-agent home, auth is selected in this order:
1. An explicit OpenClaw Codex auth profile for the agent.
2. The app-server's existing account in that agent's Codex home.
3. For local stdio app-server launches only, `CODEX_API_KEY`, then
`OPENAI_API_KEY`, when no app-server account is present and OpenAI auth is
still required.
When OpenClaw sees a ChatGPT subscription-style Codex auth profile (OAuth or
token credential type), it removes `CODEX_API_KEY` and `OPENAI_API_KEY` from
the spawned Codex child process. That keeps Gateway-level API keys available
for embeddings or direct OpenAI models without making native Codex app-server
turns bill through the API by accident.
Explicit Codex API-key profiles and local stdio env-key fallback use
app-server login instead of inherited child-process env. WebSocket app-server
connections do not receive Gateway env API-key fallback; use an explicit auth
profile or the remote app-server's own account.
Stdio app-server launches inherit OpenClaw's process environment by default.
OpenClaw owns the Codex app-server account bridge and sets `CODEX_HOME` to a
per-agent directory under that agent's OpenClaw state. That keeps Codex
config, accounts, plugin cache/data, and thread state scoped to the OpenClaw
agent instead of leaking in from the operator's personal `~/.codex` home.
Set `appServer.homeScope: "user"` to share native Codex state with Codex
Desktop and the CLI. This local-stdio-only mode uses `$CODEX_HOME` when set
and `~/.codex` otherwise, including native auth, config, plugins, and threads.
OpenClaw skips its auth-profile bridge for the app-server. Verified owner
turns can use `codex_threads` to list (with an optional `search` filter),
read, fork, rename, archive, and unarchive those threads. Fork a thread before
continuing it in OpenClaw; independent Codex processes do not coordinate
concurrent writers for the same thread.
OpenClaw does not rewrite `HOME` for normal local app-server launches.
Codex-run subprocesses such as `openclaw`, `gh`, `git`, cloud CLIs, and shell
commands see the normal process home and can find user-home config and
tokens. Codex may also discover `$HOME/.agents/skills` and
`$HOME/.agents/plugins/marketplace.json`; that `.agents` discovery is
intentionally shared with the operator home and is separate from isolated
`~/.codex` state.
In the default agent scope, OpenClaw plugins and OpenClaw skill snapshots
still flow through OpenClaw's own plugin registry and skill loader; personal
Codex `~/.codex` assets do not. If you have useful Codex CLI skills or
plugins from a Codex home that should become part of an isolated OpenClaw
agent, inventory them explicitly:
```bash
openclaw migrate codex --dry-run
openclaw migrate apply codex --yes
```
If a deployment needs additional environment isolation, add those variables
to `appServer.clearEnv`:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
clearEnv: ["CODEX_API_KEY", "OPENAI_API_KEY"],
},
},
},
},
},
}
```
`appServer.clearEnv` only affects the spawned Codex app-server child process.
OpenClaw removes `CODEX_HOME` and `HOME` from this list during local launch
normalization: `CODEX_HOME` stays pointed at the selected agent or user scope,
and `HOME` stays inherited so subprocesses can use normal user-home state.
## Dynamic tools
Codex dynamic tools default to `searchable` loading, exposed under the
`openclaw` namespace with `deferLoading: true`. OpenClaw does not expose
dynamic tools that duplicate Codex-native workspace operations or Codex's own
tool-search surface:
- `read`
- `write`
- `edit`
- `apply_patch`
- `exec`
- `process`
- `update_plan`
- `tool_call`
- `tool_describe`
- `tool_search`
- `tool_search_code`
Most remaining OpenClaw integration tools, such as messaging, media, cron,
browser, nodes, gateway, `heartbeat_respond`, and `web_search`, are available
through Codex tool search under that namespace. This keeps the initial model
context smaller. A small set of tools stay directly callable regardless of
`codexDynamicToolsLoading`, because Codex tool search can be unavailable or
resolve a connector-only universe: `agents_list`, `sessions_spawn`, and
`sessions_yield`. Developer instructions still steer normal Codex subagents
toward native `spawn_agent` for Codex-native subagent work, while
`sessions_spawn` remains available for explicit OpenClaw or ACP delegation.
Message-tool-only source replies also stay direct, since that is a
turn-control contract.
Set `codexDynamicToolsLoading: "direct"` only when connecting to a custom
Codex app-server that cannot search deferred dynamic tools or when debugging
the full tool payload.
## Timeouts
OpenClaw-owned dynamic tool calls are bounded independently from
`appServer.requestTimeoutMs`. Each Codex `item/tool/call` request uses the
first available timeout in this order:
- A positive per-call `timeoutMs` argument.
- For `image_generate`, `agents.defaults.imageGenerationModel.timeoutMs`.
- For `image_generate` without a configured timeout, the 120 second
image-generation default.
- For the media-understanding `image` tool, `tools.media.image.timeoutSeconds`
converted to milliseconds, or the 60 second media default. For image
understanding, this applies to the request itself and is not reduced by
earlier preparation work.
- For the `message` tool, a fixed 120 second default.
- The 90 second dynamic-tool default.
This watchdog is the outer dynamic `item/tool/call` budget. Provider-specific
request timeouts run inside that call and keep their own timeout semantics.
Dynamic tool budgets are capped at 600000 ms. On timeout, OpenClaw aborts the
tool signal where supported and returns a failed dynamic-tool response to
Codex so the turn can continue instead of leaving the session in
`processing`.
After Codex accepts a turn, and after OpenClaw responds to a turn-scoped
app-server request, the harness expects Codex to make current-turn progress
and eventually finish the native turn with `turn/completed`. If the
app-server goes quiet for `appServer.turnCompletionIdleTimeoutMs`, OpenClaw
best-effort interrupts the Codex turn, records a diagnostic timeout, and
releases the OpenClaw session lane so follow-up chat messages are not queued
behind a stale native turn.
Most non-terminal notifications for the same turn disarm that short watchdog
because Codex has proven the turn is still alive. Tool handoffs use a longer
post-tool idle budget: after OpenClaw returns an `item/tool/call` response,
after native tool items such as `commandExecution` complete, after raw
`custom_tool_call_output` completions, and after post-tool raw assistant
progress, raw reasoning completions, or reasoning progress. The guard uses
`appServer.postToolRawAssistantCompletionIdleTimeoutMs` when configured and
defaults to five minutes otherwise. That same post-tool budget also extends
the progress watchdog for the silent synthesis window before Codex emits the
next current-turn event. Reasoning completions, commentary `agentMessage`
completions, and pre-tool raw reasoning or assistant progress can be followed
by an automatic final reply, so they use the post-progress reply guard
instead of releasing the session lane immediately. Only final/non-commentary
completed `agentMessage` items and pre-tool raw assistant completions arm the
assistant-output release: if Codex then goes quiet without `turn/completed`,
OpenClaw best-effort interrupts the native turn and releases the session
lane. Replay-safe stdio app-server failures, including turn-completion idle
timeouts without assistant, tool, active-item, or side-effect evidence, are
retried once on a fresh app-server attempt. Unsafe timeouts still retire the
stuck app-server client and release the OpenClaw session lane. They also
clear the stale native thread binding instead of being replayed
automatically. Completion-watch timeouts surface Codex-specific timeout text:
replay-safe cases say the response may be incomplete, while unsafe cases tell
the user to verify current state before retrying. Public timeout diagnostics
include structural fields such as the last app-server notification method,
raw assistant response item id/type/role, active request/item counts, and
armed watch state. When the last notification is a raw assistant response
item, they also include a bounded assistant text preview. They do not
include raw prompt or tool content.
## Model discovery
By default, the Codex plugin asks the app-server for available models. Model
availability is owned by Codex app-server, so the list can change when
OpenClaw upgrades the bundled `@openai/codex` version or when a deployment
points `appServer.command` at a different Codex binary. Availability can also
be account-scoped. Use `/codex models` on a running gateway to see the live
catalog for that harness and account.
If discovery fails or times out, OpenClaw uses a bundled fallback catalog:
| Model id | Display name | Reasoning efforts |
| -------------- | ------------ | ------------------------ |
| `gpt-5.5` | gpt-5.5 | low, medium, high, xhigh |
| `gpt-5.4-mini` | GPT-5.4-Mini | low, medium, high, xhigh |
<Note>
The current bundled harness is `@openai/codex` `0.142.5`. A `model/list` probe
against that bundled app-server returned these public picker rows beyond the
fallback catalog:
| Model id | Input modalities | Reasoning efforts |
| --------------------- | ---------------- | ------------------------ |
| `gpt-5.5` | text, image | low, medium, high, xhigh |
| `gpt-5.4` | text, image | low, medium, high, xhigh |
| `gpt-5.4-mini` | text, image | low, medium, high, xhigh |
| `gpt-5.3-codex-spark` | text | low, medium, high, xhigh |
Live picker rows are account-scoped and can change with the account, Codex
catalog, or bundled version; run `/codex models` for the current list rather
than relying on any point-in-time table. Hidden models can also appear in the
app-server catalog for internal or specialized flows without being normal
model-picker choices.
</Note>
Tune discovery under `plugins.entries.codex.config.discovery`:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
discovery: {
enabled: true,
timeoutMs: 2500,
},
},
},
},
},
}
```
Disable discovery when you want startup to avoid probing Codex and use only
the fallback catalog:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
discovery: {
enabled: false,
},
},
},
},
},
}
```
## Workspace bootstrap files
Codex handles `AGENTS.md` itself through native project-doc discovery.
OpenClaw does not write synthetic Codex project-doc files or depend on Codex
fallback filenames for persona files, because Codex fallbacks only apply when
`AGENTS.md` is missing.
For OpenClaw workspace parity, the Codex harness forwards the other
bootstrap files as developer instructions, but not identically:
- `TOOLS.md` is forwarded as **inherited** Codex developer instructions, so
native Codex subagents spawned during the turn also see it.
- `SOUL.md`, `IDENTITY.md`, and `USER.md` are forwarded as **turn-scoped**
collaboration instructions. Native Codex subagents do not inherit them,
which keeps subagent turns from picking up the parent agent's persona and
user profile.
- The compact loaded OpenClaw skills list is also forwarded as turn-scoped
collaboration developer instructions, so native Codex subagents do not
inherit it either.
- `HEARTBEAT.md` content is not injected; heartbeat turns get a
collaboration-mode pointer to read the file when it exists and is
non-empty.
- `MEMORY.md` content from the configured agent workspace is not pasted into
native Codex turn input when memory tools are available for that
workspace; when it exists, the harness adds a small workspace-memory
pointer to turn-scoped collaboration developer instructions and Codex
should use `memory_search` or `memory_get` when durable memory is relevant.
If tools are disabled, memory search is unavailable, or the active
workspace differs from the agent memory workspace, `MEMORY.md` uses the
normal bounded turn-context path instead.
- `BOOTSTRAP.md`, when present, is forwarded as OpenClaw turn input reference
context.
## Environment overrides
Environment overrides remain available for local testing:
- `OPENCLAW_CODEX_APP_SERVER_BIN`
- `OPENCLAW_CODEX_APP_SERVER_ARGS`
- `OPENCLAW_CODEX_APP_SERVER_MODE=yolo|guardian`
- `OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY`
- `OPENCLAW_CODEX_APP_SERVER_SANDBOX`
`OPENCLAW_CODEX_APP_SERVER_BIN` bypasses the managed binary when
`appServer.command` is unset.
`OPENCLAW_CODEX_APP_SERVER_GUARDIAN=1` was removed. Use
`plugins.entries.codex.config.appServer.mode: "guardian"` instead, or
`OPENCLAW_CODEX_APP_SERVER_MODE=guardian` for one-off local testing. Config is
preferred for repeatable deployments because it keeps the plugin behavior in
the same reviewed file as the rest of the Codex harness setup.
## Related
- [Codex harness](/plugins/codex-harness)
- [Codex harness runtime](/plugins/codex-harness-runtime)
- [Native Codex plugins](/plugins/codex-native-plugins)
- [Codex Computer Use](/plugins/codex-computer-use)
- [OpenAI provider](/providers/openai)
- [Configuration reference](/gateway/configuration-reference)

View File

@@ -0,0 +1,264 @@
---
summary: "Runtime boundaries, hooks, tools, permissions, and diagnostics for the Codex harness"
title: "Codex harness runtime"
read_when:
- You need the Codex harness runtime support contract
- You are debugging native Codex tools, hooks, compaction, or feedback upload
- You are changing plugin behavior across OpenClaw and Codex harness turns
---
Runtime contract for Codex harness turns. For setup and routing, see
[Codex harness](/plugins/codex-harness). For config fields, see
[Codex harness reference](/plugins/codex-harness-reference).
## Overview
Codex owns the native model loop, native thread resume, native tool
continuation, and native compaction. OpenClaw owns channel routing, session
files, visible message delivery, OpenClaw dynamic tools, approvals, media
delivery, and a transcript mirror around that boundary.
Prompt routing follows the selected runtime, not just the provider string. A
native Codex turn gets Codex app-server developer instructions; an explicit
OpenClaw compatibility route keeps the normal OpenClaw system prompt even when
it uses Codex-flavored OpenAI auth or transport.
OpenClaw starts and resumes native Codex threads with Codex's built-in
personality disabled (`personality: "none"`) so workspace personality files
and OpenClaw agent identity stay authoritative. Native Codex keeps Codex-owned
base/model instructions and project-doc loading otherwise. Lightweight
OpenClaw runs (for example cron) still suppress project-doc loading.
OpenClaw developer instructions cover OpenClaw runtime concerns: source-channel
delivery, OpenClaw dynamic tools, ACP delegation, adapter context, and the
active agent workspace profile files. Skill catalogs and tool-routed
`MEMORY.md` pointers are projected as turn-scoped collaboration developer
instructions. When memory tools are unavailable, active `BOOTSTRAP.md` content
and full `MEMORY.md` fall back to plain turn input context instead.
## Thread bindings and model changes
When an OpenClaw session is attached to an existing Codex thread, the next
turn resends the currently selected model, approval policy, sandbox,
approvals reviewer, and service tier to app-server. Switching from
`openai/gpt-5.5` to `openai/gpt-5.2` keeps the thread binding but asks Codex to
continue with the newly selected model.
## Visible replies and heartbeats
Direct/source chat turns through the Codex harness default to automatic final
assistant delivery for internal WebChat surfaces, matching the Pi harness
contract: the agent replies normally and OpenClaw posts the final text to the
source conversation. Set `messages.visibleReplies: "message_tool"` to keep
final assistant text private unless the agent calls `message(action="send")`.
Codex heartbeat turns get `heartbeat_respond` in the searchable OpenClaw tool
catalog by default so the agent can record whether the wake should stay quiet
or notify. Heartbeat initiative guidance is sent as a Codex collaboration-mode
developer instruction scoped to the heartbeat turn; ordinary chat turns stay
in Codex Default mode. When `HEARTBEAT.md` is non-empty, the heartbeat
instructions point Codex at the file instead of inlining its contents.
## Hook boundaries
| Layer | Owner | Purpose |
| ------------------------------------- | ------------------------ | ------------------------------------------------------------------- |
| OpenClaw plugin hooks | OpenClaw | Product/plugin compatibility across OpenClaw and Codex harnesses. |
| Codex app-server extension middleware | OpenClaw bundled plugins | Per-turn adapter behavior around OpenClaw dynamic tools. |
| Codex native hooks | Codex | Low-level Codex lifecycle and native tool policy from Codex config. |
OpenClaw does not use project or global Codex `hooks.json` files to route
plugin behavior. For the native tool and permission bridge, OpenClaw injects
per-thread Codex config for `PreToolUse`, `PostToolUse`, `PermissionRequest`,
and `Stop`.
When Codex app-server approvals are enabled (`approvalPolicy` is not
`"never"`), the default injected native hook config omits `PermissionRequest`
so Codex's app-server reviewer and OpenClaw's approval bridge handle real
escalations after review. Add `permission_request` to
`nativeHookRelay.events` to force the compatibility relay anyway. Other Codex
hooks such as `SessionStart` and `UserPromptSubmit` remain Codex-level
controls; they are not exposed as OpenClaw plugin hooks in the v1 contract.
For OpenClaw dynamic tools, OpenClaw executes the tool after Codex asks for
the call, so plugin and middleware behavior runs in the harness adapter. For
Codex-native tools, Codex owns the canonical tool record; OpenClaw can mirror
selected events but cannot rewrite the native thread unless Codex exposes that
through app-server or native hook callbacks.
Codex app-server report-mode `PreToolUse` events defer plugin approval to the
matching app-server approval. If an OpenClaw `before_tool_call` hook returns
`requireApproval` while the native payload sets `openclaw_approval_mode:
"report"`, the native hook relay records the plugin approval requirement and
returns no native decision. When Codex later sends the app-server approval
request for the same tool use, OpenClaw opens the plugin approval prompt and
maps the decision back to Codex. Codex `PermissionRequest` events are a
separate approval path and can still route through OpenClaw approvals when
configured for that bridge.
Codex app-server item notifications also provide async `after_tool_call`
observations for native tool completions not already covered by the native
`PostToolUse` relay. These are telemetry/compatibility only; they cannot
block, delay, or mutate the native tool call.
Compaction and LLM lifecycle projections come from Codex app-server
notifications and OpenClaw adapter state, not native Codex hook commands.
`before_compaction`, `after_compaction`, `llm_input`, and `llm_output` are
adapter-level observations, not byte-for-byte captures of Codex's internal
request or compaction payloads.
Codex native `hook/started` and `hook/completed` app-server notifications are
projected as `codex_app_server.hook` agent events for trajectory and
debugging. They do not invoke OpenClaw plugin hooks.
## V1 support contract
Supported in Codex runtime v1:
| Surface | Support | Why |
| --------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| OpenAI model loop through Codex | Supported | Codex app-server owns the OpenAI turn, native thread resume, and native tool continuation. |
| OpenClaw channel routing and delivery | Supported | Telegram, Discord, Slack, WhatsApp, iMessage, and other channels stay outside the model runtime. |
| OpenClaw dynamic tools | Supported | Codex asks OpenClaw to execute these tools, so OpenClaw stays in the execution path. |
| Prompt and context plugins | Supported | OpenClaw projects OpenClaw-specific prompt/context into the Codex turn while leaving Codex-owned base, model, and configured project-doc prompts in the native Codex lane. OpenClaw disables Codex's built-in personality for native threads so agent workspace personality files remain authoritative. Native Codex developer instructions accept only command guidance explicitly scoped to `codex_app_server`; legacy global command hints remain for non-Codex prompt surfaces. |
| Context engine lifecycle | Supported | Assemble, ingest, and after-turn maintenance run around Codex turns. Context engines do not replace native Codex compaction. |
| Dynamic tool hooks | Supported | `before_tool_call`, `after_tool_call`, and tool-result middleware run around OpenClaw-owned dynamic tools. |
| Lifecycle hooks | Supported as adapter observations | `llm_input`, `llm_output`, `agent_end`, `before_compaction`, and `after_compaction` fire with honest Codex-mode payloads. |
| Final-answer revision gate | Supported through native hook relay | Codex `Stop` is relayed to `before_agent_finalize`; `revise` asks Codex for one more model pass before finalization. |
| Native shell, patch, and MCP block or observe | Supported through native hook relay | Codex `PreToolUse` and `PostToolUse` are relayed for committed native tool surfaces, including MCP payloads on Codex app-server `0.125.0` or newer. Blocking is supported; argument rewriting is not. |
| Native permission policy | Supported through Codex app-server approvals and compatibility native hook relay | Codex app-server approval requests route through OpenClaw after Codex review. The `PermissionRequest` native hook relay is opt-in for native approval modes because Codex emits it before guardian review. |
| App-server trajectory capture | Supported | OpenClaw records the request it sent to app-server and the app-server notifications it receives. |
Not supported in Codex runtime v1:
| Surface | V1 boundary | Future path |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Native tool argument mutation | Codex native pre-tool hooks can block, but OpenClaw does not rewrite Codex-native tool arguments. | Requires Codex hook/schema support for replacement tool input. |
| Editable Codex-native transcript history | Codex owns canonical native thread history. OpenClaw owns a mirror and can project future context, but should not mutate unsupported internals. | Add explicit Codex app-server APIs if native thread surgery is needed. |
| `tool_result_persist` for Codex-native tool records | That hook transforms OpenClaw-owned transcript writes, not Codex-native tool records. | Could mirror transformed records, but canonical rewrite needs Codex support. |
| Rich native compaction metadata | OpenClaw can request native compaction, but does not receive a stable kept/dropped list, token delta, completion summary, or summary payload. | Needs richer Codex compaction events. |
| Compaction intervention | OpenClaw does not let plugins or context engines veto, rewrite, or replace native Codex compaction. | Add Codex pre/post compaction hooks if plugins need to veto or rewrite native compaction. |
| Byte-for-byte model API request capture | OpenClaw can capture app-server requests and notifications, but Codex core builds the final OpenAI API request internally. | Needs a Codex model-request tracing event or debug API. |
## Native permissions and MCP elicitations
For `PermissionRequest`, OpenClaw only returns explicit allow or deny
decisions when policy decides. A no-decision result is not an allow: Codex
treats it as no hook decision and falls through to its own guardian or user
approval path.
Codex app-server approval modes omit this native hook by default. This
applies unless `permission_request` is explicitly included in
`nativeHookRelay.events` or a compatibility runtime installs it.
When an operator chooses `allow-always` for a Codex native permission
request, OpenClaw remembers that exact provider/session/tool input/cwd
fingerprint for a bounded session window. The remembered decision is
intentionally exact-match only: a changed command, arguments, tool payload, or
cwd creates a fresh approval.
Codex MCP tool approval elicitations route through OpenClaw's plugin approval
flow when Codex marks `_meta.codex_approval_kind` as `"mcp_tool_call"`. Codex
`request_user_input` prompts are sent back to the originating chat, and the
next queued follow-up message answers that native server request instead of
being steered as extra context. Other MCP elicitation requests fail closed.
For the general plugin approval flow that carries these prompts, see
[Plugin permission requests](/plugins/plugin-permission-requests).
## Queue steering
Active-run queue steering maps onto Codex app-server `turn/steer`. With the
default `messages.queue.mode: "steer"`, OpenClaw batches steer-mode chat
messages for the configured quiet window and sends them as one `turn/steer`
request in arrival order.
Codex review and manual compaction turns can reject same-turn steering. In
that case, OpenClaw waits for the active run to finish before starting the
prompt. Use `/queue followup` or `/queue collect` when messages should queue
by default instead of steering. See [Steering queue](/concepts/queue-steering).
## Codex feedback upload
When `/diagnostics [note]` is approved for a session on the native Codex
harness, OpenClaw also calls Codex app-server `feedback/upload` for relevant
Codex threads, including logs for each listed thread and spawned Codex
subthreads when available.
The upload goes through Codex's normal feedback path to OpenAI servers. If
Codex feedback is disabled in that app-server, the command returns the
app-server error. The completed diagnostics reply lists the channels,
OpenClaw session ids, Codex thread ids, and local `codex resume <thread-id>`
commands for the threads that were sent.
If you deny or ignore the approval, OpenClaw does not print those Codex ids
and does not send Codex feedback. The upload does not replace the local
Gateway diagnostics export. See [Diagnostics export](/gateway/diagnostics) for
the approval, privacy, local bundle, and group-chat behavior.
Use `/codex diagnostics [note]` only when you want the Codex feedback upload
for the currently attached thread without the full Gateway diagnostics
bundle.
## Compaction and transcript mirror
When the selected model uses the Codex harness, native thread compaction
belongs to Codex app-server. OpenClaw does not run preflight compaction for
Codex turns, replace Codex compaction with context-engine compaction, or fall
back to OpenClaw or public OpenAI summarization when native compaction cannot
be started. OpenClaw keeps a transcript mirror for channel history, search,
`/new`, `/reset`, and future model or harness switching.
Explicit compaction requests, such as `/compact` or a plugin-requested manual
compact operation, start native Codex compaction with `thread/compact/start`.
OpenClaw keeps the request and shared-client lease open until Codex emits the
matching `contextCompaction` completion item and then reports the compaction
turn as completed. If that terminal turn exceeds the configured compaction
timeout, OpenClaw requests a native turn interrupt. The lease and per-thread
compaction fence remain held until Codex reports terminal state or confirms
the interrupt RPC. If Codex does not confirm within the interrupt grace
period, OpenClaw retires the connection before releasing the fence. Remote
connections also detach the matching thread binding so later work cannot
overlap an unconfirmed remote turn. Other turns on a retired connection fail
and can retry on a fresh client. Client closure, request cancellation, or a
failed compaction turn returns a failed operation. Automatic context-pressure
compaction is Codex's job; OpenClaw only starts native compaction for manually
requested triggers.
When a context engine requests Codex thread-bootstrap projection, OpenClaw
projects tool-call names and ids, input shapes, and redacted tool-result
content into the fresh Codex thread. It does not copy raw tool-call argument
values into that projection.
The mirror includes the user prompt, final assistant text, and lightweight
Codex reasoning or plan records when the app-server emits them. OpenClaw
records the native compaction start and terminal status, but it does not
expose a human-readable compaction summary or an auditable list of which
entries Codex kept after compaction.
Because Codex owns the canonical native thread, `tool_result_persist` does
not rewrite Codex-native tool result records. It only applies when OpenClaw
writes an OpenClaw-owned session transcript tool result.
## Media and delivery
OpenClaw continues to own media delivery and media provider selection. Image,
video, music, PDF, TTS, and media understanding use matching provider/model
settings such as `agents.defaults.imageGenerationModel`,
`videoGenerationModel`, `pdfModel`, and `messages.tts`.
Text, images, video, music, TTS, approvals, and messaging-tool output continue
through the normal OpenClaw delivery path; media generation does not require
the legacy runtime. When Codex emits a native image-generation item with a
`savedPath`, OpenClaw forwards that exact file through the normal reply-media
path even if the Codex turn has no assistant text.
## Related
- [Codex harness](/plugins/codex-harness)
- [Codex harness reference](/plugins/codex-harness-reference)
- [Native Codex plugins](/plugins/codex-native-plugins)
- [Plugin hooks](/plugins/hooks)
- [Agent harness plugins](/plugins/sdk-agent-harness)
- [Diagnostics export](/gateway/diagnostics)
- [Trajectory export](/tools/trajectory)

View File

@@ -0,0 +1,955 @@
---
summary: "Run OpenClaw embedded agent turns through the bundled Codex app-server harness"
title: "Codex harness"
read_when:
- You want to use the bundled Codex app-server harness
- You need Codex harness config examples
- You want Codex-only deployments to fail instead of falling back to OpenClaw
---
The bundled `codex` plugin runs embedded OpenAI agent turns through Codex
app-server instead of the built-in OpenClaw harness. Codex owns the
low-level agent session: native thread resume, native tool continuation,
native compaction, and app-server execution. OpenClaw still owns chat
channels, session files, model selection, OpenClaw dynamic tools, approvals,
media delivery, and the visible transcript mirror.
Use canonical OpenAI model refs such as `openai/gpt-5.5`. Do not configure
legacy Codex GPT refs; put OpenAI agent auth order under `auth.order.openai`.
Legacy Codex auth profile ids and legacy Codex auth order entries are
repaired by `openclaw doctor --fix`.
When no OpenClaw sandbox is active, OpenClaw starts Codex app-server threads
with Codex native code mode enabled (code-mode-only stays off by default), so
native workspace/code capabilities remain available alongside OpenClaw
dynamic tools routed through the app-server `item/tool/call` bridge. An
active OpenClaw sandbox or restricted tool policy disables native code mode
entirely unless you opt into the experimental sandbox exec-server path.
This Codex-native feature is separate from
[OpenClaw code mode](/reference/code-mode), an opt-in QuickJS-WASI runtime
for generic OpenClaw runs with a different `exec` input shape. For the
broader model/provider/runtime split, start with
[Agent runtimes](/concepts/agent-runtimes): `openai/gpt-5.5` is the model
ref, `codex` is the runtime, and Telegram, Discord, Slack, or another
channel is the communication surface.
## Requirements
- OpenClaw with the bundled `codex` plugin available. Include `codex` in
`plugins.allow` if your config uses an allowlist.
- Codex app-server `0.125.0` or newer. The plugin manages a compatible
binary by default, so a `codex` command on `PATH` does not affect normal
startup.
- Codex auth through `openclaw models auth login --provider openai`, an
app-server account already present in the agent's Codex home, or an
explicit Codex API-key auth profile.
For auth precedence, environment isolation, custom app-server commands,
model discovery, and the full config field list, see
[Codex harness reference](/plugins/codex-harness-reference).
## Quickstart
Sign in with Codex OAuth:
```bash
openclaw models auth login --provider openai
```
Enable the bundled `codex` plugin and select an OpenAI agent model:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
},
},
},
agents: {
defaults: {
model: "openai/gpt-5.5",
},
},
}
```
If your config uses `plugins.allow`, add `codex` there too:
```json5
{
plugins: {
allow: ["codex"],
entries: {
codex: {
enabled: true,
},
},
},
}
```
Restart the gateway after changing plugin config. If a chat already has a
session, run `/new` or `/reset` first so the next turn resolves the harness
from current config.
## Share threads with Codex Desktop and CLI
The default `appServer.homeScope: "agent"` isolates each OpenClaw agent from
the operator's native Codex state. To let an owner inspect and manage the
same native threads shown by Codex Desktop and the Codex CLI, opt into the
user Codex home:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
homeScope: "user",
},
},
},
},
},
}
```
User-home mode requires local stdio transport. It uses `$CODEX_HOME` when
set and `~/.codex` otherwise, including that home's native Codex auth,
config, plugins, and thread store. OpenClaw does not inject an OpenClaw auth
profile into this app-server.
Owner turns gain the `codex_threads` tool: list, search, read, fork, rename,
archive, and restore native threads. Fork a thread to continue it in
OpenClaw; the fork attaches to the current OpenClaw session and stays
visible to other native Codex clients. Archiving requires explicit
confirmation that the thread is closed elsewhere.
Do not resume or write the same thread concurrently from OpenClaw and
another Codex client. Codex coordinates live writers inside one app-server
process, not across independent Desktop, CLI, and OpenClaw processes.
Forking is the safe coexistence path.
## Configuration
| Need | Set | Where |
| -------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------- |
| Enable the harness | `plugins.entries.codex.enabled: true` | OpenClaw config |
| Keep an allowlisted plugin install | Include `codex` in `plugins.allow` | OpenClaw config |
| Route OpenAI agent turns through Codex | `agents.defaults.model` or `agents.list[].model` as `openai/gpt-*` | OpenClaw agent config |
| Sign in with ChatGPT/Codex OAuth | `openclaw models auth login --provider openai` | CLI auth profile |
| Add API-key backup for Codex runs | `openai:*` API-key profile listed after subscription auth in `auth.order.openai` | CLI auth profile + OpenClaw config |
| Fail closed when Codex is unavailable | Provider or model `agentRuntime.id: "codex"` | OpenClaw model/provider config |
| Use direct OpenAI API traffic | Provider or model `agentRuntime.id: "openclaw"` with normal OpenAI auth | OpenClaw model/provider config |
| Tune app-server behavior | `plugins.entries.codex.config.appServer.*` | Codex plugin config |
| Enable native Codex plugin apps | `plugins.entries.codex.config.codexPlugins.*` | Codex plugin config |
| Enable Codex Computer Use | `plugins.entries.codex.config.computerUse.*` | Codex plugin config |
Prefer `auth.order.openai` for subscription-first/API-key-backup ordering.
Existing legacy Codex auth profile ids and legacy Codex auth order are
doctor-only legacy state; do not write new legacy Codex GPT refs.
```json5
{
auth: {
order: {
openai: ["openai:user@example.com", "openai:api-key-backup"],
},
},
}
```
Both profiles above still run through Codex for `openai/gpt-*` agent turns.
The API key is only an auth fallback, not a request to switch to OpenClaw or
plain OpenAI Responses.
### Compaction
Do not set `compaction.model` or `compaction.provider` on Codex-backed
agents. Codex compacts through its native app-server thread state, so
OpenClaw ignores those local summarizer overrides at runtime, and
`openclaw doctor --fix` removes them when the agent uses Codex.
Lossless remains supported as a context engine for assembly, ingestion, and
maintenance around Codex turns, configured through
`plugins.slots.contextEngine: "lossless-claw"` and
`plugins.entries.lossless-claw.config.summaryModel`, not through
`agents.defaults.compaction.provider`. `openclaw doctor --fix` migrates the
old `compaction.provider: "lossless-claw"` shape to the Lossless
context-engine slot when Codex is the active runtime, but native Codex still
owns compaction. The native app-server harness supports context engines
that need pre-prompt assembly; generic CLI backends, including `codex-cli`,
do not provide that host capability.
For Codex-backed agents, `/compact` starts native Codex app-server
compaction on the bound thread. OpenClaw does not wait for completion,
impose an OpenClaw timeout, restart the shared app-server, or fall back to a
context-engine or public OpenAI summarizer. If the native Codex thread
binding is missing or stale, the command fails closed instead of silently
switching compaction backends.
The rest of this page covers deployment shape, fail-closed routing, guardian
approval policy, native Codex plugins, and Computer Use. For full option
lists, defaults, enums, discovery, environment isolation, timeouts, and
app-server transport fields, see
[Codex harness reference](/plugins/codex-harness-reference).
## Verify Codex runtime
Use `/status` in the chat where you expect Codex. A Codex-backed OpenAI
agent turn shows:
```text
Runtime: OpenAI Codex
```
Then check Codex app-server state:
```text
/codex status
/codex models
```
`/codex status` reports app-server connectivity, account, rate limits, MCP
servers, and skills. `/codex models` lists the live Codex app-server catalog
for the harness and account. If `/status` is surprising, see
[Troubleshooting](#troubleshooting).
## Routing and model selection
Keep provider refs and runtime policy separate:
- Use `openai/gpt-*` for OpenAI agent turns through Codex.
- Do not use legacy Codex GPT refs in config; run `openclaw doctor --fix` to
repair legacy refs and stale session route pins.
- `agentRuntime.id: "codex"` is optional for normal OpenAI auto mode, but
useful when a deployment should fail closed if Codex is unavailable.
- `agentRuntime.id: "openclaw"` opts a provider or model into the embedded
OpenClaw runtime when that is intentional.
- `/codex ...` controls native Codex app-server conversations from chat.
- ACP/acpx is a separate external harness path. Use it only when the user
asks for ACP/acpx or an external harness adapter.
| User intent | Use |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Attach the current chat | `/codex bind [thread-id] [--cwd <path>] [--model <model>] [--provider <provider>]` |
| Resume an existing Codex thread | `/codex resume <thread-id>` |
| List or filter Codex threads | `/codex threads [filter]` |
| List native Codex plugins | `/codex plugins list` |
| Enable or disable a configured native Codex plugin | `/codex plugins enable <name>`, `/codex plugins disable <name>` |
| Attach an existing Codex CLI session on a paired node | `/codex sessions --host <node> [filter]`, then `/codex resume <session-id> --host <node> --bind here` |
| Change the bound thread's model, fast-mode, or permissions | `/codex model <model>`, `/codex fast [on\|off\|status]`, `/codex permissions [default\|yolo\|status]` |
| Stop or steer the active turn | `/codex stop`, `/codex steer <text>` |
| Detach the current binding | `/codex detach` (alias `/codex unbind`) |
| Send Codex feedback only | `/codex diagnostics [note]` |
| Start an ACP/acpx task | ACP/acpx session commands, not `/codex` |
| Use case | Configure | Verify | Notes |
| ---------------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------- | ------------------------------------- |
| ChatGPT/Codex subscription with native Codex runtime | `openai/gpt-*` plus enabled `codex` plugin | `/status` shows `Runtime: OpenAI Codex` | Recommended path |
| Fail closed if Codex is unavailable | Provider or model `agentRuntime.id: "codex"` | Turn fails instead of embedded fallback | Use for Codex-only deployments |
| Direct OpenAI API-key traffic through OpenClaw | Provider or model `agentRuntime.id: "openclaw"` and normal OpenAI auth | `/status` shows OpenClaw runtime | Use only when OpenClaw is intentional |
| Legacy config | legacy Codex GPT refs | `openclaw doctor --fix` rewrites it | Do not write new config this way |
| ACP/acpx Codex adapter | ACP `sessions_spawn({ runtime: "acp" })` | ACP task/session status | Separate from native Codex harness |
`agents.defaults.imageModel` follows the same prefix split. Use `openai/gpt-*`
for the normal OpenAI route and `codex/gpt-*` only when image understanding
should run through a bounded Codex app-server turn. Doctor rewrites legacy
Codex GPT refs to `openai/gpt-*`.
## Deployment patterns
### Basic Codex deployment
Use the quickstart config when all OpenAI agent turns should use Codex by
default:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
},
},
},
agents: {
defaults: {
model: "openai/gpt-5.5",
},
},
}
```
### Mixed provider deployment
Keep Claude as the default agent and add a named Codex agent:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
},
},
},
agents: {
defaults: {
model: "anthropic/claude-opus-4-6",
},
list: [
{
id: "main",
default: true,
model: "anthropic/claude-opus-4-6",
},
{
id: "codex",
name: "Codex",
model: "openai/gpt-5.5",
},
],
},
}
```
The `main` agent uses its normal provider path; the `codex` agent uses Codex
app-server.
### Fail-closed Codex deployment
`openai/gpt-*` already resolves to Codex when the bundled plugin is
available. Add explicit runtime policy for a written fail-closed rule:
```json5
{
models: {
providers: {
openai: {
agentRuntime: {
id: "codex",
},
},
},
},
agents: {
defaults: {
model: "openai/gpt-5.5",
},
},
plugins: {
entries: {
codex: {
enabled: true,
},
},
},
}
```
With Codex forced, OpenClaw fails early if the Codex plugin is disabled, the
app-server is too old, or the app-server cannot start.
## App-server policy
By default, the plugin starts OpenClaw's managed Codex binary locally with
stdio transport. Set `appServer.command` only to intentionally run a
different executable. Use WebSocket transport only when an app-server is
already running elsewhere:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
transport: "websocket",
url: "ws://gateway-host:39175",
authToken: "${CODEX_APP_SERVER_TOKEN}",
},
},
},
},
},
}
```
Local stdio app-server sessions default to the trusted local operator
posture: `approvalPolicy: "never"`, `approvalsReviewer: "user"`, and
`sandbox: "danger-full-access"`. If local Codex requirements disallow that
implicit YOLO posture, OpenClaw selects allowed guardian permissions
instead. When an OpenClaw sandbox is active for the session, OpenClaw
disables Codex native Code Mode, user MCP servers, and app-backed plugin
execution for that turn instead of relying on Codex host-side sandboxing.
Shell access instead goes through OpenClaw sandbox-backed dynamic tools such
as `sandbox_exec` and `sandbox_process` when the normal exec/process tools
are available.
Use normalized OpenClaw exec mode for Codex native auto-review before
sandbox escapes or extra permissions:
```json5
{
tools: {
exec: {
mode: "auto",
},
},
plugins: {
entries: {
codex: {
enabled: true,
},
},
},
}
```
For Codex app-server sessions, `tools.exec.mode: "auto"` maps to Codex
Guardian-reviewed approvals: usually `approvalPolicy: "on-request"`,
`approvalsReviewer: "auto_review"`, and `sandbox: "workspace-write"` when
local requirements allow those values. In `tools.exec.mode: "auto"`,
OpenClaw does not preserve legacy unsafe Codex `approvalPolicy: "never"` or
`sandbox: "danger-full-access"` overrides; use `tools.exec.mode: "full"` for
an intentional no-approval Codex posture. The legacy
`plugins.entries.codex.config.appServer.mode: "guardian"` preset still
works, but `tools.exec.mode: "auto"` is the normalized OpenClaw surface.
For the mode-level comparison with host exec approvals and ACPX
permissions, see [Permission modes](/tools/permission-modes). For every
app-server field, auth order, environment isolation, and timeout behavior,
see [Codex harness reference](/plugins/codex-harness-reference).
## Commands and diagnostics
The bundled plugin registers `/codex` as a slash command on any channel that
supports OpenClaw text commands.
Native execution and control require an owner or an `operator.admin`
Gateway client: binding or resuming threads, sending or stopping turns,
changing model, fast-mode, or permission state, compacting or reviewing, and
detaching a binding. Other authorized senders keep read-only status, help,
account, model, thread, MCP server, skill, and binding inspection commands.
Common forms:
- `/codex status` checks app-server connectivity, models, account, rate
limits, MCP servers, and skills.
- `/codex models` lists live Codex app-server models.
- `/codex threads [filter]` lists recent Codex app-server threads.
- `/codex resume <thread-id>` attaches the current OpenClaw session to an
existing Codex thread.
- `/codex bind [thread-id] [--cwd <path>] [--model <model>] [--provider <provider>]`
attaches the current chat.
- `/codex detach` (or `/codex unbind`) detaches the current binding.
- `/codex binding` describes the current binding.
- `/codex stop` stops the active turn; `/codex steer <text>` steers it.
- `/codex model <model>`, `/codex fast [on|off|status]`, and
`/codex permissions [default|yolo|status]` change per-conversation state.
- `/codex compact` asks Codex app-server to compact the attached thread.
- `/codex review` starts Codex native review for the attached thread.
- `/codex diagnostics [note]` asks before sending Codex feedback for the
attached thread.
- `/codex account` shows account and rate-limit status.
- `/codex mcp` lists Codex app-server MCP server status.
- `/codex skills` lists Codex app-server skills.
- `/codex plugins list`, `/codex plugins enable <name>`, and
`/codex plugins disable <name>` manage configured native Codex plugins.
- `/codex computer-use [status|install]` manages Codex Computer Use.
- `/codex help` lists the full command tree.
For most support reports, start with `/diagnostics [note]` in the
conversation where the bug happened. It creates one Gateway diagnostics
report and, for Codex harness sessions, asks for approval to send the
relevant Codex feedback bundle. See
[Diagnostics export](/gateway/diagnostics) for the privacy model and group
chat behavior. Use `/codex diagnostics [note]` only when you specifically
want the Codex feedback upload for the currently attached thread without
the full Gateway diagnostics bundle.
### Inspect Codex threads locally
The fastest way to inspect a bad Codex run is often to open the native
Codex thread directly:
```bash
codex resume <thread-id>
```
Get the thread id from the completed `/diagnostics` reply, `/codex binding`,
or `/codex threads [filter]`.
For upload mechanics and runtime-level diagnostics boundaries, see
[Codex harness runtime](/plugins/codex-harness-runtime#codex-feedback-upload).
### Auth order
In the default per-agent home, auth is selected in this order:
1. Ordered OpenAI auth profiles for the agent, preferably under
`auth.order.openai`. Run `openclaw doctor --fix` to migrate older legacy
Codex auth profile ids and legacy Codex auth order.
2. The app-server's existing account in that agent's Codex home.
3. For local stdio app-server launches only, `CODEX_API_KEY`, then
`OPENAI_API_KEY`, when no app-server account is present and OpenAI auth
is still required.
When OpenClaw sees a ChatGPT subscription-style Codex auth profile, it
removes `CODEX_API_KEY` and `OPENAI_API_KEY` from the spawned Codex child
process. That keeps Gateway-level API keys available for embeddings or
direct OpenAI models without making native Codex app-server turns bill
through the API by accident. Explicit Codex API-key profiles and local
stdio env-key fallback use app-server login instead of inherited
child-process env. WebSocket app-server connections do not receive Gateway
env API-key fallback; use an explicit auth profile or the remote
app-server's own account.
If a subscription profile hits a Codex usage limit, OpenClaw records the
reset time when Codex reports one and tries the next ordered auth profile
for the same Codex run. When the reset time passes, the subscription
profile becomes eligible again without changing the selected `openai/gpt-*`
model or Codex runtime.
When native Codex plugins are configured, OpenClaw installs or refreshes
those plugins through the connected app-server before exposing plugin-owned
apps to the Codex thread. `app/list` remains the source of truth for app
ids, accessibility, and metadata, but OpenClaw owns the per-thread
enablement decision: if policy allows a listed accessible app, OpenClaw
sends `thread/start.config.apps[appId].enabled = true` even when `app/list`
currently reports that app disabled. This path does not invent app
installation for unknown ids; OpenClaw only activates marketplace plugins
with `plugin/install` and then refreshes inventory.
### Environment isolation
For local stdio app-server launches, OpenClaw sets `CODEX_HOME` to a
per-agent directory so Codex config, auth/account files, plugin cache/data,
and native thread state do not read or write the operator's personal
`~/.codex` by default. OpenClaw preserves the normal process `HOME`;
Codex-run subprocesses can still find user-home config and tokens, and
Codex may discover shared `$HOME/.agents/skills` and
`$HOME/.agents/plugins/marketplace.json` entries. With
`appServer.homeScope: "user"`, OpenClaw instead uses the native user Codex
home and its existing account without injecting an OpenClaw auth profile.
If a deployment needs additional environment isolation, add those
variables to `appServer.clearEnv`:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
clearEnv: ["CODEX_API_KEY", "OPENAI_API_KEY"],
},
},
},
},
},
}
```
`appServer.clearEnv` only affects the spawned Codex app-server child
process. OpenClaw removes `CODEX_HOME` and `HOME` from this list during
local launch normalization: `CODEX_HOME` stays pointed at the selected
agent or user scope, and `HOME` stays inherited so subprocesses can use
normal user-home state.
### Dynamic tools and web search
Codex dynamic tools default to `searchable` loading. OpenClaw does not
expose dynamic tools that duplicate Codex-native workspace operations:
`read`, `write`, `edit`, `apply_patch`, `exec`, `process`, `update_plan`,
`tool_call`, `tool_describe`, `tool_search`, and `tool_search_code`. Most
remaining OpenClaw integration tools, such as messaging, media, cron,
browser, nodes, gateway, and `heartbeat_respond`, are available through
Codex tool search under the `openclaw` namespace, keeping the initial model
context smaller.
Web search uses Codex's hosted `web_search` tool by default when search is
enabled and no managed provider is selected. Native hosted search and
OpenClaw's managed `web_search` dynamic tool are mutually exclusive so
managed search cannot bypass native domain restrictions. OpenClaw uses the
managed tool when hosted search is unavailable, explicitly disabled, or
replaced by a selected managed provider. OpenClaw keeps Codex's standalone
`web.run` extension disabled because production app-server traffic rejects
its user-defined `web` namespace. `tools.web.search.enabled: false`
disables both paths, as do tool-disabled LLM-only runs. Codex treats
`"cached"` as a preference and resolves it to live external access for
unrestricted app-server turns. Automatic managed fallback fails closed when
native `allowedDomains` are set so the allowlist cannot be bypassed.
Persistent effective search-policy changes rotate the bound Codex thread
before the next turn; transient per-turn restrictions use a temporary
restricted thread and preserve the existing binding for later resume.
`sessions_yield` and message-tool-only source replies stay direct because
those are turn-control contracts. `sessions_spawn` stays searchable so
Codex's native `spawn_agent` remains the primary Codex subagent surface,
while explicit OpenClaw or ACP delegation is still available through the
`openclaw` dynamic tool namespace. Heartbeat collaboration instructions
tell Codex to search for `heartbeat_respond` before ending a heartbeat turn
when the tool is not already loaded.
Set `codexDynamicToolsLoading: "direct"` only when connecting to a custom
Codex app-server that cannot search deferred dynamic tools or when
debugging the full tool payload.
### Config fields
Supported top-level Codex plugin fields:
| Field | Default | Meaning |
| -------------------------- | -------------- | ---------------------------------------------------------------------------------------- |
| `codexDynamicToolsLoading` | `"searchable"` | Use `"direct"` to put OpenClaw dynamic tools directly in the initial Codex tool context. |
| `codexDynamicToolsExclude` | `[]` | Additional OpenClaw dynamic tool names to omit from Codex app-server turns. |
| `codexPlugins` | disabled | Native Codex plugin/app support for migrated source-installed curated plugins. |
Supported `appServer` fields:
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `homeScope` | `"agent"` | `"agent"` isolates Codex state per OpenClaw agent. `"user"` shares the native `$CODEX_HOME` or `~/.codex`, uses native auth, and enables owner-only thread management. User scope requires stdio. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary; set it only for an explicit override. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. Accepts a literal string or SecretInput such as `${CODEX_APP_SERVER_TOKEN}`. |
| `headers` | `{}` | Extra WebSocket headers. Header values accept literal strings or SecretInput values, for example `x-codex-client-session-token: "${CODEX_CLIENT_SESSION_TOKEN}"`. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. OpenClaw keeps the selected `CODEX_HOME` and inherited `HOME` for local launches. |
| `codeModeOnly` | `false` | Opt into Codex's code-mode-only tool surface. OpenClaw dynamic tools remain registered with Codex so nested `tools.*` calls return through the app-server `item/tool/call` bridge. |
| `remoteWorkspaceRoot` | unset | Remote Codex app-server workspace root. When set, OpenClaw infers the local workspace root from the resolved OpenClaw workspace, preserves the current cwd suffix under this remote root, and sends only the final app-server cwd to Codex. If the cwd is outside the resolved OpenClaw workspace root, OpenClaw fails closed instead of sending a gateway-local path to the remote app-server. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle and progress guard used after a tool handoff, native tool completion, post-tool raw assistant progress, raw reasoning completion, or reasoning progress while OpenClaw waits for `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. Local stdio requirements that omit `danger-full-access`, `never` approval, or the `user` reviewer make the implicit default guardian. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start/resume/turn. Guardian defaults prefer `"on-request"` when allowed. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start/resume. Guardian defaults prefer `"workspace-write"` when allowed, otherwise `"read-only"`. When an OpenClaw sandbox is active, `danger-full-access` turns use Codex `workspace-write` with network access derived from the OpenClaw sandbox egress setting. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed, otherwise `guardian_subagent` or `user`. `guardian_subagent` remains a legacy alias. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
| `networkProxy` | disabled | Opt into Codex permissions-profile networking for app-server commands. OpenClaw defines the selected `permissions.<profile>.network` config and selects it with `default_permissions` instead of sending `sandbox`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
`appServer.networkProxy` is explicit because it changes the Codex sandbox
contract. When enabled, OpenClaw also sets `features.network_proxy.enabled`
and `default_permissions` in the Codex thread config so the generated
permission profile can start Codex managed networking. By default, OpenClaw
generates a collision-resistant `openclaw-network-<fingerprint>` profile
name from the profile body; use `profileName` only when a stable local name
is required.
```json5
{
plugins: {
entries: {
codex: {
config: {
appServer: {
sandbox: "workspace-write",
networkProxy: {
enabled: true,
domains: {
"api.openai.com": "allow",
"blocked.example.com": "deny",
},
unixSockets: {
"/tmp/proxy.sock": "allow",
"/tmp/blocked.sock": "none",
},
allowUpstreamProxy: true,
proxyUrl: "http://127.0.0.1:3128",
},
},
},
},
},
},
}
```
If the normal app-server runtime would be `danger-full-access`, enabling
`networkProxy` uses workspace-style filesystem access for the generated
permission profile: Codex managed network enforcement is sandboxed
networking, so a full-access profile would not protect outbound traffic.
Domain entries use `allow` or `deny`; Unix socket entries use Codex's
`allow` or `none` values.
### Dynamic tool call timeouts
OpenClaw-owned dynamic tool calls are bounded independently from
`appServer.requestTimeoutMs`: Codex `item/tool/call` requests use a 90
second OpenClaw watchdog by default. A positive per-call `timeoutMs`
argument extends or shortens that specific tool budget, capped at 600000 ms.
The `image_generate` tool uses `agents.defaults.imageGenerationModel.timeoutMs`
when the tool call does not provide its own timeout, or a 120 second
image-generation default otherwise. The media-understanding `image` tool
uses `tools.media.image.timeoutSeconds` or its 60 second media default; for
image understanding, that timeout applies to the request itself and is not
reduced by earlier preparation work. On timeout, OpenClaw aborts the tool
signal where supported and returns a failed dynamic-tool response to Codex
so the turn can continue instead of leaving the session in `processing`.
This watchdog is the outer dynamic `item/tool/call` budget; provider-specific
request timeouts run inside that call and keep their own timeout semantics.
After Codex accepts a turn, and after OpenClaw responds to a turn-scoped
app-server request, the harness expects Codex to make current-turn progress
and eventually finish the native turn with `turn/completed`. If the
app-server goes quiet for `appServer.turnCompletionIdleTimeoutMs`, OpenClaw
best-effort interrupts the Codex turn, records a diagnostic timeout, and
releases the OpenClaw session lane so follow-up chat messages are not
queued behind a stale native turn. Most non-terminal notifications for the
same turn disarm that short watchdog because Codex has proven the turn is
still alive.
Tool handoffs use a longer post-tool idle budget: after OpenClaw returns an
`item/tool/call` response, after native tool items such as
`commandExecution` complete, after raw `custom_tool_call_output`
completions, and after post-tool raw assistant progress, raw reasoning
completions, or reasoning progress. The guard uses
`appServer.postToolRawAssistantCompletionIdleTimeoutMs` when configured and
defaults to five minutes otherwise; that same budget also extends the
progress watchdog for the silent synthesis window before Codex emits the
next current-turn event. Global app-server notifications, such as
rate-limit updates, do not reset turn-idle progress. Reasoning completions,
commentary `agentMessage` completions, and pre-tool raw reasoning or
assistant progress can be followed by an automatic final reply, so they use
the post-progress reply guard instead of releasing the session lane
immediately.
Only final/non-commentary completed `agentMessage` items and pre-tool raw
assistant completions arm the assistant-output release: if Codex then goes
quiet without `turn/completed`, OpenClaw best-effort interrupts the native
turn and releases the session lane. If another turn watch wins that release
race, OpenClaw still accepts the completed final assistant item once no
native request, item, or dynamic tool completion remains active and the
assistant-output release still belongs to the latest completed item, with
no later item completion. This can preserve the final answer after
completed tool work without replaying the turn. Partial assistant deltas,
stale earlier replies, and empty later completions do not qualify.
Replay-safe stdio app-server failures, including turn-completion idle
timeouts without assistant, tool, active-item, or side-effect evidence, are
retried once on a fresh app-server attempt. Unsafe timeouts still retire the
stuck app-server client and release the OpenClaw session lane; they also
clear the stale native thread binding instead of being replayed
automatically. Completion-watch timeouts surface Codex-specific timeout
text: replay-safe cases say the response may be incomplete, while unsafe
cases tell the user to verify current state before retrying. Public timeout
diagnostics include structural fields such as the last app-server
notification method, raw assistant response item id/type/role, active
request/item counts, and armed watch state; when the last notification is a
raw assistant response item, they also include a bounded assistant text
preview. They do not include raw prompt or tool content.
### Local testing env overrides
- `OPENCLAW_CODEX_APP_SERVER_BIN` bypasses the managed binary when
`appServer.command` is unset.
- `OPENCLAW_CODEX_APP_SERVER_ARGS`
- `OPENCLAW_CODEX_APP_SERVER_MODE=yolo|guardian`
- `OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY`
- `OPENCLAW_CODEX_APP_SERVER_SANDBOX`
`OPENCLAW_CODEX_APP_SERVER_GUARDIAN=1` was removed. Use
`plugins.entries.codex.config.appServer.mode: "guardian"` instead, or
`OPENCLAW_CODEX_APP_SERVER_MODE=guardian` for one-off local testing. Config
is preferred for repeatable deployments because it keeps the plugin
behavior in the same reviewed file as the rest of the Codex harness setup.
## Native Codex plugins
Native Codex plugin support uses Codex app-server's own app and plugin
capabilities in the same Codex thread as the OpenClaw harness turn. OpenClaw
does not translate Codex plugins into synthetic `codex_plugin_*` OpenClaw
dynamic tools.
`codexPlugins` affects only sessions that select the native Codex harness.
It has no effect on built-in harness runs, normal OpenAI provider runs, ACP
conversation bindings, or other harnesses.
Minimal migrated config:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
codexPlugins: {
enabled: true,
allow_destructive_actions: true,
plugins: {
"google-calendar": {
enabled: true,
marketplaceName: "openai-curated",
pluginName: "google-calendar",
},
},
},
},
},
},
},
}
```
Thread app config is computed when OpenClaw establishes a Codex harness
session or replaces a stale Codex thread binding; it is not recomputed on
every turn. After changing `codexPlugins`, use `/new`, `/reset`, or restart
the gateway so future Codex harness sessions start with the updated app
set.
For migration eligibility, app inventory, destructive action policy,
elicitations, and native plugin diagnostics, see
[Native Codex plugins](/plugins/codex-native-plugins).
OpenAI-side app and plugin access is controlled by the signed-in Codex
account and, for Business and Enterprise/Edu workspaces, workspace app
controls. See
[Using Codex with your ChatGPT plan](https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan)
for OpenAI's account and workspace-control overview.
## Computer Use
Computer Use has its own setup guide:
[Codex Computer Use](/plugins/codex-computer-use).
Short version: OpenClaw does not vendor the desktop-control app or execute
desktop actions itself. It prepares Codex app-server, verifies that the
`computer-use` MCP server is available, and then lets Codex own the native
MCP tool calls during Codex-mode turns.
## Runtime boundaries
The Codex harness changes the low-level embedded agent executor only.
- OpenClaw dynamic tools are supported. Codex asks OpenClaw to execute
those tools, so OpenClaw remains in the execution path.
- Codex-native shell, patch, MCP, and native app tools are owned by Codex.
OpenClaw can observe or block selected native events through the
supported relay, but it does not rewrite native tool arguments.
- Codex owns native compaction. OpenClaw keeps a transcript mirror for
channel history, search, `/new`, `/reset`, and future model or harness
switching, but does not replace Codex compaction with an OpenClaw or
context-engine summarizer.
- Media generation, media understanding, TTS, approvals, and messaging-tool
output continue through the matching OpenClaw provider/model settings.
- `tool_result_persist` applies to OpenClaw-owned transcript tool results,
not Codex-native tool result records.
For hook layers, supported V1 surfaces, native permission handling, queue
steering, Codex feedback upload mechanics, and compaction details, see
[Codex harness runtime](/plugins/codex-harness-runtime).
## Troubleshooting
**Codex does not appear as a normal `/model` provider:** expected for new
configs. Select an `openai/gpt-*` model, enable
`plugins.entries.codex.enabled`, and check whether `plugins.allow` excludes
`codex`.
**OpenClaw uses the built-in harness instead of Codex:** confirm the model
ref is `openai/gpt-*` on the official OpenAI provider and that the Codex
plugin is installed and enabled. For strict proof while testing, set
provider or model `agentRuntime.id: "codex"` — a forced Codex runtime fails
instead of falling back to OpenClaw.
**OpenAI Codex runtime falls back to the API-key path:** collect a redacted
gateway excerpt that shows the model, runtime, selected provider, and
failure. Ask affected collaborators to run this read-only command on their
OpenClaw host:
```bash
(
pattern='openai/gpt-5\.[45]|openai[-]codex|agentRuntime(\.id)?|harnessRuntime|Runtime: OpenAI Codex|legacy OpenAI Codex prefix|resolveSelectedOpenAIRuntimeProvider|candidateProvider[": ]+openai|status[": ]+401|Incorrect API key|No API key|api-key path|API-key path|OAuth'
if ls /tmp/openclaw/openclaw-*.log >/dev/null 2>&1; then
grep -E -i -n "$pattern" /tmp/openclaw/openclaw-*.log 2>/dev/null || true
else
journalctl --user -u openclaw-gateway --since today --no-pager 2>/dev/null \
| grep -E -i "$pattern" || true
fi
) | sed -E \
-e 's/(Authorization: Bearer )[A-Za-z0-9._~+\/-]+/\1[REDACTED]/Ig' \
-e 's/(Bearer )[A-Za-z0-9._~+\/-]+/\1[REDACTED]/Ig' \
-e 's/(api[_ -]?key[=: ]+)[^ ,}"]+/\1[REDACTED]/Ig' \
-e 's/(OPENAI_API_KEY[=: ]+)[^ ,}"]+/\1[REDACTED]/Ig' \
-e 's/sk-[A-Za-z0-9_-]{12,}/sk-[REDACTED]/g' \
-e 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/[EMAIL-REDACTED]/g' \
| tail -200
```
Useful excerpts usually include `openai/gpt-5.5` or `openai/gpt-5.4`,
`Runtime: OpenAI Codex`, `agentRuntime.id` or `harnessRuntime`,
`candidateProvider: "openai"`, and a `401`, `Incorrect API key`, or
`No API key` result. A corrected run should show the OpenAI OAuth path
instead of a plain OpenAI API-key failure.
**Legacy Codex model refs config remains:** run `openclaw doctor --fix`.
Doctor rewrites legacy model refs to `openai/*`, removes stale session and
whole-agent runtime pins, and preserves existing auth-profile overrides.
**The app-server is rejected:** use Codex app-server `0.125.0` or newer.
Same-version prereleases or build-suffixed versions such as
`0.125.0-alpha.2` or `0.125.0+custom` are rejected because OpenClaw tests
the stable `0.125.0` protocol floor.
**`/codex status` cannot connect:** check that the bundled `codex` plugin
is enabled, that `plugins.allow` includes it when an allowlist is
configured, and that any custom `appServer.command`, `url`, `authToken`, or
headers are valid.
**Model discovery is slow:** lower
`plugins.entries.codex.config.discovery.timeoutMs` or disable discovery.
See [Codex harness reference](/plugins/codex-harness-reference#model-discovery).
**WebSocket transport fails immediately:** check `appServer.url`,
`authToken`, headers, and that the remote app-server speaks the same Codex
app-server protocol version.
**Native shell or patch tools are blocked with `Native hook relay
unavailable`:** the Codex thread is still trying to use a native hook relay
id that OpenClaw no longer has registered. This is a native Codex hook
transport problem, not an ACP backend, provider, GitHub, or shell-command
failure. Start a fresh session in the affected chat with `/new` or `/reset`,
then retry a harmless command. If that works once but the next native tool
call fails again, treat `/new` as a temporary workaround only: copy the
prompt into a fresh session after restarting the Codex app-server or
OpenClaw Gateway so old threads are dropped and native hook registrations
are recreated.
**A non-Codex model uses the built-in harness:** expected unless provider
or model runtime policy routes it to another harness. Plain non-OpenAI
provider refs stay on their normal provider path in `auto` mode.
**Computer Use is installed but tools do not run:** check
`/codex computer-use status` from a fresh session. If a tool reports
`Native hook relay unavailable`, use the native hook relay recovery above.
See [Codex Computer Use](/plugins/codex-computer-use#troubleshooting).
## Related
- [Codex harness reference](/plugins/codex-harness-reference)
- [Codex harness runtime](/plugins/codex-harness-runtime)
- [Native Codex plugins](/plugins/codex-native-plugins)
- [Codex Computer Use](/plugins/codex-computer-use)
- [Agent runtimes](/concepts/agent-runtimes)
- [Model providers](/concepts/model-providers)
- [OpenAI provider](/providers/openai)
- [OpenAI Codex help](https://help.openai.com/en/collections/14937394-codex)
- [Agent harness plugins](/plugins/sdk-agent-harness)
- [Plugin hooks](/plugins/hooks)
- [Diagnostics export](/gateway/diagnostics)
- [Status](/cli/status)
- [Testing](/help/testing-live#live-codex-app-server-harness-smoke)

View File

@@ -0,0 +1,263 @@
---
summary: "Configure migrated native Codex plugins for Codex-mode OpenClaw agents"
title: "Native Codex plugins"
read_when:
- You want Codex-mode OpenClaw agents to use native Codex plugins
- You are migrating source-installed openai-curated Codex plugins
- You are troubleshooting codexPlugins, app inventory, destructive actions, or plugin app diagnostics
---
Native Codex plugin support lets a Codex-mode OpenClaw agent use Codex
app-server's own app and plugin capabilities inside the same Codex thread that
handles the OpenClaw turn. Plugin calls stay in the native Codex transcript;
Codex app-server owns app-backed MCP execution. OpenClaw does not translate
Codex plugins into synthetic `codex_plugin_*` OpenClaw dynamic tools.
Use this page after the base [Codex harness](/plugins/codex-harness) is
working.
## Requirements
- The agent runtime must be the native Codex harness.
- `plugins.entries.codex.enabled` is `true`.
- `plugins.entries.codex.config.codexPlugins.enabled` is `true`.
- The target Codex app-server can see the expected marketplace, plugin, and
app inventory.
- V1 supports only `openai-curated` plugins that migration observed as
source-installed in the source Codex home.
`codexPlugins` has no effect on OpenClaw-provider runs, ACP conversation
bindings, or other harnesses, because those paths never create Codex
app-server threads with native `apps` config.
OpenAI-side Codex account, app availability, and workspace app/plugin controls
come from the signed-in Codex account. See
[Using Codex with your ChatGPT plan](https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan)
for the OpenAI account and admin model.
## Quickstart
Preview migration from the source Codex home:
```bash
openclaw migrate codex --dry-run
```
Add `--verify-plugin-apps` to make migration call source `app/list` and
require every owned app to be present, enabled, and accessible before
planning native activation:
```bash
openclaw migrate codex --dry-run --verify-plugin-apps
```
Apply the migration when the plan looks right:
```bash
openclaw migrate apply codex --yes
```
Migration writes explicit `codexPlugins` entries for eligible plugins and
calls Codex app-server `plugin/install` for selected plugins. A migrated
config looks like this:
```json5
{
plugins: {
entries: {
codex: {
enabled: true,
config: {
codexPlugins: {
enabled: true,
allow_destructive_actions: true,
plugins: {
"google-calendar": {
enabled: true,
marketplaceName: "openai-curated",
pluginName: "google-calendar",
},
},
},
},
},
},
},
}
```
After a `codexPlugins` change, new Codex conversations pick up the updated
app set automatically. Run `/new` or `/reset` to refresh the current
conversation. A gateway restart is not required for plugin enable/disable
changes.
## Manage plugins from chat
`/codex plugins` inspects or changes configured native Codex plugins from the
same chat where you operate the Codex harness:
```text
/codex plugins
/codex plugins list
/codex plugins disable google-calendar
/codex plugins enable google-calendar
```
`/codex plugins` is an alias for `/codex plugins list`. The list shows each
configured plugin's key, on/off state, Codex plugin name, and marketplace
from `plugins.entries.codex.config.codexPlugins.plugins`.
`enable`/`disable` write only to `~/.openclaw/openclaw.json`; they never edit
`~/.codex/config.toml` or install new Codex plugins. Only the owner or a
gateway client with the `operator.admin` scope can run them.
Enabling a configured plugin also turns on the global `codexPlugins.enabled`
switch. If the plugin was written disabled because migration returned
`auth_required`, reauthorize the app in Codex before enabling it in OpenClaw.
## How native plugin setup works
The integration tracks three states:
| State | Meaning |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Installed | Codex has the local plugin bundle in the target app-server runtime. |
| Enabled | OpenClaw config allows the plugin for Codex harness turns. |
| Accessible | Codex app-server confirms the plugin's app entries are available for the active account and map to the migrated plugin identity. |
Migration is the durable install/eligibility step:
- During planning, OpenClaw reads source Codex `plugin/read` details and
checks that the source Codex app-server account is a ChatGPT subscription
account. A non-ChatGPT or missing account response skips app-backed
plugins with `codex_subscription_required`.
- By default, migration skips the source `app/list` call: app-backed source
plugins that pass the account gate are planned without source app
accessibility verification, and account-lookup transport failures skip
with `codex_account_unavailable`.
- With `--verify-plugin-apps`, migration takes a fresh source `app/list`
snapshot and requires every owned app to be present, enabled, and
accessible before planning native activation. Account-lookup transport
failures then fall through to the source app-inventory gate instead of
skipping outright.
Runtime app inventory is the target-session accessibility check that runs
after migration. Codex harness session setup computes a restrictive thread
app config from the enabled and accessible plugin apps; it is not
recomputed on every turn, so `/codex plugins enable`/`disable` only affect
new Codex conversations. Use `/new` or `/reset` to pick up the change in the
current conversation.
## V1 support boundary
- Only `openai-curated` plugins already installed in the source Codex
app-server inventory are migration-eligible.
- App-backed source plugins must pass the migration-time subscription gate.
`--verify-plugin-apps` adds the source app-inventory gate. Subscription-gated
accounts, and in verification mode inaccessible/disabled/missing source
apps or app-inventory refresh failures, are reported as skipped manual
items instead of enabled config entries. Unreadable plugin details are
skipped before the app-inventory gate.
- Migration writes explicit plugin identities (`marketplaceName` and
`pluginName`); it does not write local `marketplacePath` cache paths.
- `codexPlugins.enabled` is the only global enablement switch; there is no
`plugins["*"]` wildcard or config key that grants arbitrary install
authority.
- Unsupported marketplaces, cached plugin bundles, hooks, and Codex config
files are preserved in the migration report for manual review, not
activated automatically.
## App inventory and ownership
OpenClaw reads Codex app inventory through app-server `app/list`, caches it
in memory for one hour, and refreshes stale or missing entries
asynchronously. The cache is process-local; restarting the CLI or gateway
drops it, and OpenClaw rebuilds it from the next `app/list` read.
Migration and runtime use separate cache keys:
- Source migration verification uses the source Codex home and start
options. It runs only with `--verify-plugin-apps` and forces a fresh
source `app/list` traversal for that planning run.
- Target runtime setup uses the target agent's Codex app-server identity
when building the thread app config. Plugin activation invalidates that
target cache key, then force-refreshes it after `plugin/install`.
A plugin app is exposed only when OpenClaw can map it back to the migrated
plugin through stable ownership: an exact app id from plugin detail, a known
MCP server name, or unique stable metadata. Display-name-only or ambiguous
ownership is excluded until the next inventory refresh proves ownership.
## Thread app config
OpenClaw injects a restrictive `config.apps` patch for the Codex thread:
`_default` is disabled, and only apps owned by enabled migrated plugins are
enabled.
`destructive_enabled` on each app comes from the effective global or
per-plugin `allow_destructive_actions` policy; `true`, `"auto"`, and `"ask"`
all set `destructive_enabled: true`, and `false` sets it `false`. Codex still
enforces destructive tool metadata from its native app tool annotations.
`_default` is disabled with `open_world_enabled: false`; enabled plugin apps
get `open_world_enabled: true`. OpenClaw does not expose a separate
plugin-level open-world policy knob and does not maintain per-plugin
destructive tool-name deny lists.
Tool approval mode defaults to automatic for plugin apps, so non-destructive
read tools run without a same-thread approval prompt. Destructive tools stay
controlled by each app's `destructive_enabled` policy.
## Destructive action policy
Destructive plugin elicitations are allowed by default for migrated Codex
plugins, while unsafe schemas and ambiguous ownership fail closed:
- Global `allow_destructive_actions` defaults to `true`.
- Per-plugin `allow_destructive_actions` overrides the global policy for
that plugin.
- `false`: OpenClaw returns a deterministic decline.
- `true`: OpenClaw auto-accepts only safe schemas it can map to an approval
response, such as a boolean approve field.
- `"auto"`: OpenClaw exposes destructive plugin actions to Codex, then
turns ownership-proven MCP approval elicitations into OpenClaw plugin
approvals before returning the Codex approval response.
- `"ask"`: OpenClaw uses the same Codex write/destructive gating as
`"auto"`, clears durable Codex per-tool approval overrides for the app
before the thread starts, and offers only one-shot approval or denial so
durable approvals cannot suppress later write-action prompts. For each
admitted app using `"ask"`, OpenClaw selects Codex's human approvals
reviewer for that app so Codex sends its approval elicitations to
OpenClaw; other apps and non-app thread approvals keep their configured
reviewer and policy.
- Missing plugin identity, ambiguous ownership, a missing or mismatched
turn id, or an unsafe elicitation schema declines instead of prompting.
## Troubleshooting
| Code | Meaning | Fix |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `auth_required` | Migration installed the plugin, but one of its apps still needs authentication. The entry is written disabled until you reauthorize. | Reauthorize the app in Codex, then enable the plugin in OpenClaw. |
| `app_inaccessible`, `app_disabled`, `app_missing` | With `--verify-plugin-apps`, the source Codex app inventory did not show all owned apps as present, enabled, and accessible. | Reauthorize or enable the app in Codex, then rerun migration with `--verify-plugin-apps`. |
| `app_inventory_unavailable` | Strict source app verification was requested but the source Codex app inventory refresh failed. | Fix source Codex app-server access, or retry without `--verify-plugin-apps` to accept the faster account-gated plan. |
| `codex_subscription_required` | The source Codex app-server account was not a ChatGPT subscription account. | Log in to the Codex app with subscription auth, then rerun migration. |
| `codex_account_unavailable` | The source Codex app-server account could not be read. | Fix source Codex app-server auth, or rerun with `--verify-plugin-apps` to let source app inventory decide eligibility. |
| `marketplace_missing`, `plugin_missing` | The target Codex app-server cannot see the expected `openai-curated` marketplace or plugin. | Rerun migration against the target runtime, or inspect Codex app-server plugin status. |
| `app_inventory_missing`, `app_inventory_stale` | App readiness came from an empty or stale cache. | OpenClaw schedules an async refresh automatically; plugin apps stay excluded until ownership and readiness are known. |
| `app_ownership_ambiguous` | App inventory only matched by display name. | The app stays hidden from the Codex thread until a later refresh proves ownership. |
**Config changed but the agent cannot see the plugin:** run `/codex plugins
list` to confirm the configured state, then `/new` or `/reset`. Existing
Codex thread bindings keep the app config they started with until OpenClaw
establishes a new harness session or replaces a stale binding.
**Destructive action is declined:** check the global and per-plugin
`allow_destructive_actions` values. Even with `true`, `"auto"`, or `"ask"`,
unsafe elicitation schemas and ambiguous plugin identity still fail closed.
## Related
- [Codex harness](/plugins/codex-harness)
- [Codex harness reference](/plugins/codex-harness-reference)
- [Codex harness runtime](/plugins/codex-harness-runtime)
- [Configuration reference](/gateway/configuration-reference#codex-harness-plugin-config)
- [Migrate CLI](/cli/migrate)

78
docs/plugins/community.md Normal file
View File

@@ -0,0 +1,78 @@
---
summary: "Find and publish community-maintained OpenClaw plugins"
read_when:
- You want to find third-party OpenClaw plugins
- You want to publish or list your own plugin on ClawHub
title: "Community plugins"
doc-schema-version: 1
---
Community plugins are third-party packages that extend OpenClaw with
channels, tools, providers, hooks, or other capabilities. Use
[ClawHub](/clawhub) as the primary discovery surface for public community
plugins.
## Find plugins
Search ClawHub from the CLI:
```bash
openclaw plugins search "calendar"
```
Install a ClawHub plugin with an explicit source prefix:
```bash
openclaw plugins install clawhub:<package-name>
```
npm remains a supported direct-install path during the launch cutover:
```bash
openclaw plugins install npm:<package-name>
```
Use [Manage plugins](/plugins/manage-plugins) for common install, update,
inspect, and uninstall examples. Use [`openclaw plugins`](/cli/plugins) for
the full command reference and source-selection rules.
## Publish plugins
Publish public community plugins on ClawHub so OpenClaw users can discover
and install them. ClawHub owns the live package listing, release history,
scan status, and install hints; the docs do not maintain a static
third-party plugin catalog.
```bash
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
```
Before publishing, make sure the plugin has package metadata, a plugin
manifest, setup docs, and a clear maintenance owner. ClawHub validates owner
scope, package name, version, file limits, and source metadata before
creating a release, then keeps new releases hidden from normal install and
download surfaces until review and verification finish.
Checklist before you publish:
| Requirement | Why |
| -------------------- | --------------------------------------------------- |
| Published on ClawHub | Users need `openclaw plugins install` hints to work |
| Public GitHub repo | Source review, issue tracking, transparency |
| Setup and usage docs | Users need to know how to configure it |
| Active maintenance | Recent updates or responsive issue handling |
Full publishing contract:
- [ClawHub publishing](/clawhub/publishing) - owners, scopes, releases,
review, package validation, and package transfer
- [Building plugins](/plugins/building-plugins) - the plugin package shape
and first publish workflow
- [Plugin manifest](/plugins/manifest) - native plugin manifest fields
## Related
- [Plugins](/tools/plugin) - install, configure, restart, and troubleshoot
- [Manage plugins](/plugins/manage-plugins) - command examples
- [ClawHub publishing](/clawhub/publishing) - publish and release rules

View File

@@ -0,0 +1,203 @@
---
summary: "Plugin compatibility contracts, deprecation metadata, and migration expectations"
title: "Plugin compatibility"
read_when:
- You maintain an OpenClaw plugin
- You see a plugin compatibility warning
- You are planning a plugin SDK or manifest migration
---
OpenClaw keeps older plugin contracts wired through named compatibility
adapters before removing them. This protects existing bundled and external
plugins while the SDK, manifest, setup, config, and agent runtime contracts
evolve.
## Compatibility registry
Plugin compatibility contracts are tracked in the core registry at
`src/plugins/compat/registry.ts`. Each record has:
- a stable compatibility code
- status: `active`, `deprecated`, `removal-pending`, or `removed`
- owner: `sdk`, `config`, `setup`, `channel`, `provider`, `plugin-execution`,
`agent-runtime`, or `core`
- introduction and deprecation dates when applicable
- replacement guidance
- docs, diagnostics, and tests that cover the old and new behavior
The registry is the source for maintainer planning and future plugin
inspector checks. If a plugin-facing behavior changes, add or update the
compatibility record in the same change that adds the adapter.
Doctor repair and migration compatibility is tracked separately at
`src/commands/doctor/shared/deprecation-compat.ts`. Those records cover old
config shapes, install-ledger layouts, and repair shims that may need to
stay available after the runtime compatibility path is removed.
Release sweeps should check both registries. Do not delete a doctor
migration just because the matching runtime or config compatibility record
expired; first verify there is no supported upgrade path that still needs
the repair. Revalidate each replacement annotation during release planning
too, since plugin ownership and config footprint can change as providers
and channels move out of core.
## Deprecation policy
OpenClaw should not remove a documented plugin contract in the same release
that introduces its replacement. Migration sequence:
1. Add the new contract.
2. Keep the old behavior wired through a named compatibility adapter.
3. Emit diagnostics or warnings when plugin authors can act.
4. Document the replacement and timeline.
5. Test both old and new paths.
6. Wait through the announced migration window.
7. Remove only with explicit breaking-release approval.
Deprecated records must include a warning start date, replacement, docs
link, and a final removal date no more than three months after the warning
starts. Do not add a deprecated compatibility path with an open-ended
removal window unless maintainers explicitly decide it is permanent
compatibility and mark it `active` instead.
## Current compatibility areas
The registry currently tracks around 70 compatibility codes across these
areas. New plugin code should use the replacement in each area and in the
specific migration guide; existing plugins can keep using a compatibility
path until docs, diagnostics, and release notes announce a removal window.
- legacy broad SDK imports such as `openclaw/plugin-sdk/compat`
- legacy hook-only plugin shapes and `before_agent_start`
- legacy `api.on("deactivate", ...)` cleanup hook names while plugins
migrate to `gateway_stop`
- legacy `activate(api)` plugin entrypoints while plugins migrate to
`register(api)`
- legacy SDK aliases such as `openclaw/extension-api`,
`openclaw/plugin-sdk/channel-runtime`, `openclaw/plugin-sdk/command-auth`
status builders, `openclaw/plugin-sdk/test-utils` (replaced by focused
`openclaw/plugin-sdk/*` test subpaths), and the `ClawdbotConfig` /
`OpenClawSchemaType` type aliases
- bundled plugin allowlist and enablement behavior
- legacy provider/channel env-var manifest metadata
- legacy provider plugin hooks and type aliases while providers move to
explicit catalog, auth, thinking, replay, and transport hooks
- legacy runtime aliases such as `api.runtime.taskFlow`,
`api.runtime.subagent.getSession`, `api.runtime.stt`, and deprecated
`api.runtime.config.loadConfig()` / `api.runtime.config.writeConfigFile(...)`
- WhatsApp `WebInboundMessage` flat callback fields (see below)
- WhatsApp `WebInboundMessage` top-level admission fields (see below)
- legacy memory-plugin split registration while memory plugins move to
`registerMemoryCapability`
- legacy memory-specific embedding provider registration while embedding
providers move to `api.registerEmbeddingProvider(...)` and
`contracts.embeddingProviders`
- legacy channel SDK helpers for native message schemas, mention gating,
inbound envelope formatting, and approval capability nesting
- legacy channel route key and comparable-target helper aliases while
plugins move to `openclaw/plugin-sdk/channel-route`
- activation hints being replaced by manifest contribution ownership
- `setup-api` runtime fallback while setup descriptors move to cold
`setup.requiresRuntime: false` metadata
- provider `discovery` hooks while provider catalog hooks move to
`catalog.run(...)`
- channel `showConfigured` / `showInSetup` metadata while channel packages
move to `openclaw.channel.exposure`
- legacy runtime-policy config keys while doctor migrates operators to
`agentRuntime`
- generated bundled channel config metadata fallback while registry-first
`channelConfigs` metadata lands
- persisted plugin registry disable and install-migration env flags while
repair flows migrate operators to `openclaw plugins registry --refresh`
and `openclaw doctor --fix`
- legacy plugin-owned web search, web fetch, and x_search config paths
while doctor migrates them to `plugins.entries.<plugin>.config`
- legacy `plugins.installs` authored config and bundled plugin load-path
aliases while install metadata moves into the state-managed plugin ledger
### WhatsApp inbound callback flat aliases
WhatsApp runtime callbacks deliver `WebInboundMessage`: the canonical
nested `event`, `payload`, `quote`, `group`, and `platform` contexts plus
deprecated flat aliases for the shipped callback fields. New callback code
should read the nested contexts. Code that constructs clean nested callback
messages can use `WebInboundCallbackMessage`; compatibility listeners that
still inject old flat test or plugin messages should use
`LegacyFlatWebInboundMessage` or `WebInboundMessageInput`.
The flat aliases remain available until **2026-08-30**; that window applies
only to flat alias access, not to the nested shape, which is the canonical
runtime contract. Each flat alias's TypeScript `@deprecated` annotation
names its exact nested replacement. Common examples:
- `id`, `timestamp`, and `isBatched` move under `event`.
- `body`, `mediaPath`, `mediaType`, `mediaFileName`, `mediaUrl`, `location`,
and `untrustedStructuredContext` move under `payload`.
- `to`, `chatId`, sender/self fields, `sendComposing`, `reply(...)`, and
`sendMedia(...)` move under `platform`.
- `replyTo*` fields move under `quote`; group subject/participant/mention
fields move under `group`.
`payload.untrustedStructuredContext` is extracted from inbound provider
payloads. Plugins should inspect `label`, `source`, and `type` before
treating its `payload` as authoritative.
### WhatsApp inbound admission fields
Accepted WhatsApp callback messages carry `admission`, a public-safe
envelope for the access-control decision that admitted the message. New
callback code should read admission facts from `msg.admission` instead of
the older top-level admission fields.
The top-level fields remain available until **2026-08-30**. Each field's
TypeScript `@deprecated` annotation names its replacement:
- `from` and `conversationId` move to `admission.conversation.id`.
- `accountId` moves to `admission.accountId`.
- `accessControlPassed` is a derived compatibility view of
`admission.ingress.decision === "allow"`; on messages that already carry
`admission`, writing the legacy boolean does not rewrite the ingress
graph.
- `chatType` moves to `admission.conversation.kind`.
## Plugin inspector package
The plugin inspector should live outside the core OpenClaw repo as a
separate package/repository backed by the versioned compatibility and
manifest contracts. The day-one CLI should be:
```sh
openclaw-plugin-inspector ./my-plugin
```
It should emit manifest/schema validation, the contract compatibility
version being checked, install/source metadata checks, cold-path import
checks, and deprecation/compatibility warnings. Use `--json` for stable
machine-readable output in CI annotations. OpenClaw core should expose
contracts and fixtures the inspector can consume, but should not publish the
inspector binary from the main `openclaw` package.
### Maintainer acceptance lane
Use Crabbox-backed Blacksmith Testbox for the installable-package acceptance
lane when validating the external inspector against OpenClaw plugin
packages. Run it from a clean OpenClaw checkout after the package is built:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox --timing-json --shell -- "pnpm install && pnpm build && npm exec --yes @openclaw/plugin-inspector@0.1.0 -- ./extensions/telegram --json"
pnpm crabbox:run -- --provider blacksmith-testbox --timing-json --shell -- "npm exec --yes @openclaw/plugin-inspector@0.1.0 -- ./extensions/discord --json"
pnpm crabbox:run -- --provider blacksmith-testbox --timing-json --shell -- "npm exec --yes @openclaw/plugin-inspector@0.1.0 -- <clawhub-plugin-dir> --json"
```
Keep this lane opt-in for maintainers, since it installs an external npm
package and may inspect plugin packages cloned outside the repo. The local
repo guards cover the SDK export map, compatibility registry metadata,
deprecated SDK-import burn-down, and bundled extension import boundaries;
Testbox inspector proof covers the package as external plugin authors
consume it.
## Release notes
Release notes should include upcoming plugin deprecations with target dates
and links to migration docs, before a compatibility path moves to
`removal-pending` or `removed`.

373
docs/plugins/copilot.md Executable file
View File

@@ -0,0 +1,373 @@
---
summary: "Run OpenClaw embedded agent turns through the external GitHub Copilot SDK harness"
title: "Copilot SDK harness"
read_when:
- You want to use the GitHub Copilot SDK harness for an agent
- You need configuration examples for the `copilot` runtime
- You are wiring an agent to subscription Copilot (github / openclaw / copilot) and want it to run through the Copilot CLI
---
The external `@openclaw/copilot` plugin runs embedded subscription Copilot
agent turns through the GitHub Copilot CLI (`@github/copilot-sdk`) instead of
OpenClaw's built-in PI harness. The Copilot CLI session owns the low-level
agent loop: native tool execution, native compaction (`infiniteSessions`), and
CLI-managed thread state under `copilotHome`. OpenClaw still owns chat
channels, session files, model selection, dynamic tools (bridged), approvals,
media delivery, the visible transcript mirror, `/btw` side questions (see
[Side questions (`/btw`)](#side-questions-btw)), and `openclaw doctor`.
For the broader model/provider/runtime split, start with
[Agent runtimes](/concepts/agent-runtimes).
## Requirements
- OpenClaw with the `@openclaw/copilot` plugin installed.
- If your config uses `plugins.allow`, include `copilot` (the manifest id the
plugin declares). An allowlist entry for the npm package name
`@openclaw/copilot` will not match and leaves the plugin blocked, even with
`agentRuntime.id: "copilot"` set.
- A GitHub Copilot subscription that can drive the Copilot CLI, or a
`gitHubToken` env var / auth-profile entry for headless or cron runs.
- A writable `copilotHome` directory. Defaults to `<agentDir>/copilot` when
OpenClaw provides an agent directory, otherwise
`~/.openclaw/agents/<agentId>/copilot`.
`openclaw doctor` runs the plugin's [doctor contract](#doctor) for
session-state ownership and future config migrations. It does not probe the
Copilot CLI environment.
## Install
The Copilot runtime ships as an external plugin so the core `openclaw`
package does not carry `@github/copilot-sdk` or its platform-specific
`@github/copilot-<platform>-<arch>` CLI binary (roughly 260 MB together).
Install it only for agents that opt into this runtime:
```bash
openclaw plugins install @openclaw/copilot
```
The setup wizard installs the plugin automatically the first time you select
a `github-copilot/*` model **and** your config routes that model (or its
provider) to the Copilot runtime via `agentRuntime: { id: "copilot" }`; see
[Quickstart](#quickstart). Without that opt-in, OpenClaw uses its built-in
GitHub Copilot provider and never installs this plugin.
The runtime resolves the SDK in this order:
1. `import("@github/copilot-sdk")` from the installed `@openclaw/copilot`
package.
2. The fallback dir `~/.openclaw/npm-runtime/copilot/` (legacy on-demand
install target).
A missing SDK surfaces one error with code `COPILOT_SDK_MISSING` and the
reinstall command above.
## Quickstart
Pin one model (or one provider) to the harness:
```json5
{
agents: {
defaults: {
model: "github-copilot/auto",
models: {
"github-copilot/auto": {
agentRuntime: { id: "copilot" },
},
},
},
},
}
```
Set `agentRuntime.id` on a single model entry to route only that model through
the harness, or on a provider to route every model under that provider.
`github-copilot/auto` is the portable starting point. Named Copilot models are
account- and organization-policy-dependent; confirm your authenticated
Copilot CLI actually exposes a model before pinning it.
## Supported providers
The harness supports the canonical `github-copilot` provider (owned by
`extensions/github-copilot`), plus custom `models.providers` entries when the
model has a non-empty `baseUrl` and one of these `api` shapes:
- `anthropic-messages`
- `azure-openai-responses`
- `ollama` (OpenAI-compatible completions)
- `openai-completions`
- `openai-responses`
Native provider ids (`openai`, `anthropic`, `google`, `ollama`) stay owned by
their native runtimes. Use a distinct custom provider id to route an endpoint
through Copilot BYOK instead.
Copilot BYOK endpoints must be public HTTPS URLs. The harness gives the
Copilot SDK a per-attempt loopback proxy, then forwards provider traffic
through OpenClaw's guarded fetch path so DNS pinning and SSRF policy stay
owned by OpenClaw. Use the native OpenClaw runtime for local Ollama, LM
Studio, or LAN model servers.
## BYOK
Copilot BYOK uses the SDK's session-level custom provider contract. OpenClaw
passes the resolved model endpoint, API key, bearer-token mode, headers, model
id, and context/output limits; provider transport logic stays in the SDK, not
core.
```json5
{
agents: {
defaults: {
model: "custom-proxy/llama-3.1-8b",
models: {
"custom-proxy/llama-3.1-8b": {
agentRuntime: { id: "copilot" },
},
},
},
},
models: {
mode: "merge",
providers: {
"custom-proxy": {
baseUrl: "https://api.example.com/v1",
apiKey: "${CUSTOM_PROXY_API_KEY}",
api: "openai-responses",
authHeader: true,
models: [{ id: "llama-3.1-8b", name: "Llama 3.1 8B" }],
},
},
},
}
```
BYOK sessions are keyed separately from subscription sessions and from other
BYOK endpoints or credentials. Rotating the key, headers, model, or endpoint
starts a fresh Copilot SDK session instead of resuming incompatible state.
## Auth
Precedence, applied per agent during `runCopilotAttempt`:
1. **Explicit `useLoggedInUser: true`** on the attempt input — uses the
Copilot CLI's logged-in user under the agent's `copilotHome`.
2. **Explicit `gitHubToken`** on the attempt input (requires `profileId` +
`profileVersion`). For direct CLI invocations and tests that need to
bypass auth-profile resolution.
3. **Contract-resolved `resolvedApiKey` + `authProfileId`** — the production
main path. Core resolves the agent's configured `github-copilot` auth
profile (`src/infra/provider-usage.auth.ts:resolveProviderAuths`) before
invoking the harness, so a `github-copilot:<profile>` auth profile works
end-to-end for headless, cron, or multi-profile setups without env vars.
4. **Env-var fallback**, checked in this order (first non-empty value wins,
empty strings count as absent; mirrors the shipped `github-copilot`
provider precedence in `extensions/github-copilot/auth.ts`):
1. `OPENCLAW_GITHUB_TOKEN` — harness-specific override; lets you pin a
token for the OpenClaw harness without disturbing system-wide `gh` /
Copilot CLI config.
2. `COPILOT_GITHUB_TOKEN` — standard Copilot SDK / CLI env var.
3. `GH_TOKEN` — standard `gh` CLI env var.
4. `GITHUB_TOKEN` — generic GitHub token fallback.
The synthesized pool profile id is `env:<NAME>`; the profile version is a
non-reversible sha256 fingerprint of the token, so rotating the env value
busts the client pool cleanly.
5. **Default `useLoggedInUser`** when no token signal is available.
Each agent gets its own `copilotHome` so Copilot CLI tokens, sessions, and
config never leak between agents on the same machine. Default:
`<agentDir>/copilot` (keeps SDK state out of the same directory as
OpenClaw's `models.json` / `auth-profiles.json`), or
`~/.openclaw/agents/<agentId>/copilot` when no agent directory is supplied.
Override with `copilotHome: <path>` on the attempt input for a custom
location (for example, a shared mount for migration).
Live harness tests use `OPENCLAW_COPILOT_AGENT_LIVE_TOKEN` for a direct
token. The shared live-test setup scrubs `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`,
and `GITHUB_TOKEN` after staging real auth profiles into the isolated test
home, so a `gh auth token` value passed through the dedicated variable avoids
false skips without leaking into unrelated suites.
## Configuration surface
The harness reads config from per-attempt input (`runCopilotAttempt({...})`)
plus a small set of env defaults inside `extensions/copilot/src/`:
| Field | Purpose |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `copilotHome` | Per-agent CLI state directory (defaults above). |
| `model` | String or `{ provider, id, api?, baseUrl?, headers?, authHeader? }`. Omit to use the agent's normal model selection; the harness verifies the resolved provider is supported. |
| `reasoningEffort` | `"low" \| "medium" \| "high" \| "xhigh"`. Maps from OpenClaw's `ThinkLevel` / `ReasoningLevel` resolution in `auto-reply/thinking.ts`. |
| `infiniteSessionConfig` | Optional override for the SDK `infiniteSessions` block driven by `harness.compact`. Safe to leave as-is. |
| `hooksConfig` | Optional native Copilot SDK `SessionHooks` config for tool/MCP, user-prompt, session, and error callbacks. Separate from OpenClaw's portable lifecycle hooks. |
| `permissionPolicy` | Optional override for the SDK's `onPermissionRequest` handler for built-in SDK tool kinds (`shell`, `write`, `read`, `url`, `mcp`, `memory`, `hook`). Defaults to `rejectAllPolicy` as a safety net; see [Permissions and ask_user](#permissions-and-ask_user) for why it never actually fires. |
| `enableSessionTelemetry` | Optional SDK session telemetry flag. |
OpenClaw plugin hooks need no Copilot-specific attempt configuration. The
harness runs `before_prompt_build` (and the legacy `before_agent_start`
compatibility hook), `llm_input`, `llm_output`, and `agent_end` through the
standard harness helpers. Successful SDK compactions also run
`before_compaction` and `after_compaction`. Bridged OpenClaw tools run
`before_tool_call` and report `after_tool_call`; `hooksConfig` remains for
native SDK-only callbacks with no portable equivalent.
Nothing else in OpenClaw needs to know about these fields. Other plugins,
channels, and core code see only the standard `AgentHarnessAttemptParams` /
`AgentHarnessAttemptResult` shape.
## Compaction
When `harness.compact` runs, the Copilot SDK harness:
1. Resumes the tracked SDK session without continuing pending work.
2. Calls the SDK's session-scoped history compaction RPC.
3. Returns the SDK compaction outcome without writing compatibility marker
files under the workspace.
The OpenClaw-side transcript mirror (below) keeps receiving post-compaction
messages, so user-facing chat history stays consistent.
## Transcript mirroring
`runCopilotAttempt` dual-writes each turn's mirrorable messages into the
OpenClaw audit transcript via
`extensions/copilot/src/dual-write-transcripts.ts`. The mirror is scoped per
session (`copilot:${sessionId}`) and keyed per message
(`${role}:${sha256_16(role,content)}`), so re-emitted prior-turn entries
collide with existing on-disk keys instead of duplicating.
Two layers of failure containment wrap the mirror so a transcript write
failure never fails the attempt: an internal best-effort wrapper, plus a
defense-in-depth `.catch(...)` at the attempt level. Failures are logged, not
surfaced.
## Side questions (`/btw`)
`/btw` is **not** native on this harness. `createCopilotAgentHarness()`
deliberately leaves `harness.runSideQuestion` undefined
(asserted in `extensions/copilot/harness.test.ts`, `describe("runSideQuestion")`),
so OpenClaw's `/btw` dispatcher (`src/agents/btw.ts`) falls through to the
same path it uses for every non-Codex runtime: the configured model provider
is called directly with a short side-question prompt and streamed back via
`streamSimple` (no CLI session, no extra pool slot).
This keeps Copilot CLI sessions reserved for the agent's main turn loop, and
keeps `/btw` behavior identical to other non-Codex runtimes.
## Doctor
`extensions/copilot/doctor-contract-api.ts` is auto-loaded by
`src/plugins/doctor-contract-registry.ts`. It contributes:
- An empty `legacyConfigRules` (no retired fields yet).
- A no-op `normalizeCompatibilityConfig` (kept so future field retirements
have a stable in-tree home).
- One `sessionRouteStateOwners` entry: provider `github-copilot`, runtime
`copilot`, CLI session key `copilot`, auth profile prefix `github-copilot:`.
## Limitations
- The harness claims `github-copilot` plus unowned custom BYOK provider ids.
Manifest-owned native provider ids stay on their owning runtime even when
`agentRuntime.id` is forced to `copilot`.
- No TUI surface; PI's TUI remains the fallback for runtimes without a peer
surface.
- PI session state does not migrate when an agent switches to `copilot`.
Selection is per attempt; existing PI sessions remain valid.
- `ask_user` uses the same OpenClaw prompt-and-reply path as the Codex
harness: when the Copilot SDK asks for user input, OpenClaw posts a
blocking prompt to the active channel/TUI, and the next queued user
message resolves the SDK request.
## Permissions and ask_user
Permission enforcement for bridged OpenClaw tools happens **inside the tool
wrapper**, not via the SDK's `onPermissionRequest` callback. The same
`wrapToolWithBeforeToolCallHook` that PI uses
(`src/agents/agent-tools.before-tool-call.ts`) is applied by
`createOpenClawCodingTools` to every coding tool: loop detection, trusted
plugin policies, before-tool-call hooks, and two-phase plugin approvals via
the gateway (`plugin.approval.request`) all run through the exact same code
path as native PI attempts.
The SDK Tool returned by `convertOpenClawToolToSdkTool` is marked with:
- `overridesBuiltInTool: true` — replaces the Copilot CLI's built-in tool of
the same name (edit, read, write, bash, ...) so every tool call routes back
to OpenClaw.
- `skipPermission: true` — tells the SDK not to fire
`onPermissionRequest({kind: "custom-tool"})` before invoking the tool. The
wrapped `execute()` already performs the richer OpenClaw policy check; an
SDK-level prompt would either short-circuit OpenClaw's enforcement
(allow-all) or block every tool call (reject-all) — neither matches PI
parity.
The in-tree Codex harness uses the same split: bridged OpenClaw tools are
wrapped (`extensions/codex/src/app-server/dynamic-tools.ts`) and the
codex-app-server's own native approval kinds
(`item/commandExecution/requestApproval`, `item/fileChange/requestApproval`,
`item/permissions/requestApproval`) route through `plugin.approval.request`
(`extensions/codex/src/app-server/approval-bridge.ts`). The Copilot SDK
equivalent — fail-closed `rejectAllPolicy` for any non-`custom-tool` kind
that ever reaches `onPermissionRequest` — is the same safety net, and it
never fires in practice because `overridesBuiltInTool: true` displaces every
built-in.
For the wrapped-tool layer to make policy decisions equivalent to PI, the
harness forwards the full PI attempt-tool context to
`createOpenClawCodingTools`: identity (`senderIsOwner`, `memberRoleIds`,
`ownerOnlyToolAllowlist`, ...), channel/routing (`groupId`,
`currentChannelId`, `replyToMode`, message-tool toggles), auth
(`authProfileStore`), run identity (`sessionKey` / `runSessionKey` derived
from `sandboxSessionKey`, `runId`), model context (`modelApi`,
`modelContextWindowTokens`, `modelCompat`, `modelHasVision`), and run hooks
(`onToolOutcome`, `onYield`). Without those fields, owner-only allowlists
silently deny by default, plugin-trust policies cannot resolve to the right
scope, and `session_status: "current"` resolves to a stale sandbox key. The
bridge builder is `extensions/copilot/src/tool-bridge.ts`, mirroring the PI
authoritative call at `src/agents/embedded-agent-runner/run/attempt.ts:1262`.
`runAttempt` resolves sandbox context through the shared
`resolveSandboxContext` seam, passes the SDK an effective working directory,
and forwards `sandbox` plus the subagent-spawn workspace into the tool
bridge. The bridge also forwards the bounded tool-construction controls it
can enforce at the SDK boundary: `includeCoreTools`, the runtime tool
allowlist, and `toolConstructionPlan`.
The bridge also uses the shared harness tool-surface helper from
`openclaw/plugin-sdk/agent-harness-tool-runtime` for PI parity. When
tool-search is enabled, the SDK sees compact control tools plus a hidden
catalog executor instead of every OpenClaw tool schema. When code mode is
enabled, the helper builds the same code-mode control surface and catalog
lifecycle used by other agent harnesses. Local-model lean defaults,
runtime-compatible schema filtering, directory hydration, and catalog
cleanup all stay in the shared helper so Copilot and Codex-adjacent
harnesses do not drift.
### Session-level GitHub token
The Copilot SDK contract distinguishes the **client-level** GitHub token
(`CopilotClientOptions.gitHubToken`, authenticates the CLI process itself)
from the **session-level** token (`SessionConfig.gitHubToken`, determines
content exclusion, model routing, and quota for that session; honored on
both `createSession` and `resumeSession`). The harness resolves auth once via
`resolveCopilotAuth` and sets both fields when the auth mode is `gitHubToken`
(an explicit `auth.gitHubToken` or a contract-resolved `resolvedApiKey` from
a configured `github-copilot` auth profile). When the resolved mode is
`useLoggedInUser`, the session-level field is omitted so the SDK keeps
deriving identity from the logged-in identity.
`ask_user` uses `SessionConfig.onUserInputRequest`. The bridge accepts choice
indexes or labels for fixed-choice requests, accepts free-form answers when
the SDK request allows them, and cancels a pending request when the OpenClaw
attempt is aborted.
## Related
- [Agent runtimes](/concepts/agent-runtimes)
- [Codex harness](/plugins/codex-harness)
- [Agent harness plugins (SDK reference)](/plugins/sdk-agent-harness)

View File

@@ -0,0 +1,222 @@
---
summary: "How OpenClaw installs plugin packages and resolves plugin dependencies"
read_when:
- You are debugging plugin package installs
- You are changing plugin startup, doctor, or package-manager install behavior
- You are maintaining packaged OpenClaw installs or bundled plugin manifests
title: "Plugin dependency resolution"
sidebarTitle: "Dependencies"
---
OpenClaw handles plugin dependencies at install/update time only. Runtime
loading never runs a package manager, repairs a dependency tree, or mutates
the OpenClaw package directory.
## Responsibility split
Plugin packages own their dependency graph:
- Runtime dependencies live in the plugin package's `dependencies` or
`optionalDependencies`.
- SDK/core imports are peer or supplied OpenClaw imports.
- Local development plugins bring their own already-installed dependencies.
- npm and git plugins install into OpenClaw-owned package roots.
OpenClaw owns only the plugin lifecycle:
- Discover the plugin source.
- Install or update the package when explicitly requested.
- Record install metadata.
- Load the plugin entrypoint.
- Fail with an actionable error when dependencies are missing.
## Install roots
OpenClaw uses stable per-source roots:
- npm packages install into per-plugin projects under
`~/.openclaw/npm/projects/<encoded-package>`.
- git packages clone under `~/.openclaw/git`.
- Local/path/archive installs are copied or referenced without dependency
repair.
npm installs run in that per-plugin project root with:
```bash
cd ~/.openclaw/npm/projects/<encoded-package>
npm install --omit=dev --omit=peer --legacy-peer-deps --ignore-scripts --no-audit --no-fund
```
`openclaw plugins install npm-pack:<path.tgz>` uses the same per-plugin npm
project root for a local npm-pack tarball: OpenClaw reads the tarball's npm
metadata, adds it to the managed project as a copied `file:` dependency, runs
the normal npm install above, then verifies the installed lockfile metadata
before trusting the plugin. This path exists for package-acceptance and
release-candidate proof, where a local pack artifact should behave like the
registry artifact it simulates.
Use `npm-pack:` when testing official or external plugin packages before
publish. A raw archive or path install is useful for local debugging, but it
does not prove the same dependency path as an installed npm or ClawHub
package. `npm-pack:` proves the managed package install shape; it is not, by
itself, proof that the plugin is catalog-linked official content.
When behavior depends on bundled-plugin or trusted official plugin status,
pair the local package proof with a catalog-backed official install or a
published package path that records official trust. Privileged helper access
and trusted-official scope handling should be validated on that trusted
install path, not inferred from a local tarball install.
If a plugin fails at runtime with a missing import, fix the package manifest
instead of repairing the managed project by hand. Runtime imports belong in
the plugin package `dependencies` or `optionalDependencies`; `devDependencies`
are not installed for managed runtime projects. A local `npm install` inside
`~/.openclaw/npm/projects/<encoded-package>` can unblock a temporary
diagnostic, but it is not package-acceptance proof because the next install or
update recreates the project from package metadata.
npm may hoist transitive dependencies to the per-plugin project's
`node_modules` beside the plugin package. OpenClaw scans the managed project
root before trusting the install, and removes that project on uninstall, so
hoisted runtime dependencies stay inside that plugin's cleanup boundary.
Published npm plugin packages can ship `npm-shrinkwrap.json`; npm uses that
publishable lockfile during install, and OpenClaw's managed npm project root
supports it through the normal install path. OpenClaw-owned publishable
plugin packages must include a package-local shrinkwrap generated from that
package's published dependency graph:
```bash
pnpm deps:shrinkwrap:generate
pnpm deps:shrinkwrap:check
```
The generator strips plugin `devDependencies`, applies the workspace override
policy, and writes `extensions/<id>/npm-shrinkwrap.json` for each plugin with
`openclaw.release.publishToNpm: true`. Third-party plugin packages may also
ship a shrinkwrap; OpenClaw does not require one for community packages, but
npm respects it when present.
Before treating a local package as release-candidate proof, inspect the
tarball that will be installed:
```bash
npm pack --pack-destination /tmp
tar -xOf /tmp/<plugin-package>.tgz package/package.json
tar -tf /tmp/<plugin-package>.tgz | grep '^package/dist/'
```
For dependency changes, also verify a production install can resolve the
runtime packages without dev dependencies:
```bash
tmpdir=$(mktemp -d)
(
cd "$tmpdir"
npm init -y >/dev/null
npm install --package-lock-only --omit=dev --omit=peer --legacy-peer-deps --ignore-scripts /tmp/<plugin-package>.tgz
)
rm -rf "$tmpdir"
```
OpenClaw-owned npm plugin packages can also publish with explicit
`bundledDependencies`. The npm publish path overlays the runtime dependency
name list, strips dev-only workspace metadata from the published manifest,
runs a script-free npm install for the package-local runtime dependencies,
then packs or publishes the plugin tarball with those dependency files
included. Native-heavy packages (Codex, ACPX, Copilot, llama.cpp,
memory-lancedb, Tlon) opt out with
`openclaw.release.bundleRuntimeDependencies: false`; they still ship a
shrinkwrap, but npm resolves runtime dependencies during install instead of
embedding every platform binary in the plugin tarball. The root `openclaw`
package does not bundle its full dependency tree.
Plugins that import `openclaw/plugin-sdk/*` declare `openclaw` as a peer
dependency. OpenClaw does not let npm install a separate registry copy of the
host package into a managed project, because a stale host package can affect
npm's peer resolution inside that plugin. Managed npm installs skip npm peer
resolution/materialization, and OpenClaw reasserts plugin-local
`node_modules/openclaw` links for installed packages that declare the host
peer, after install or update.
git installs clone or refresh the repository, then run:
```bash
npm install --omit=dev --ignore-scripts --no-audit --no-fund
```
The installed plugin then loads from that package directory, so
package-local and parent `node_modules` resolution work the same way they do
for a normal Node package.
## Local plugins
Local plugins are developer-controlled directories. OpenClaw never runs
`npm install`, `pnpm install`, or dependency repair for them; if a local
plugin has dependencies, install them in that plugin before loading it.
Third-party TypeScript local plugins load through Jiti as an emergency path.
Packaged JavaScript plugins and bundled internal plugins load through native
import/require instead.
## Startup and reload
Gateway startup and config reload never install plugin dependencies. They
read the plugin install records, compute the entrypoint, and load it.
A missing dependency at runtime fails plugin load with an error that points
the operator to an explicit fix:
```bash
openclaw plugins update <id>
openclaw plugins install <source>
openclaw doctor --fix
```
`doctor --fix` cleans legacy OpenClaw-generated dependency state and can
recover downloadable plugins that are missing from local install records when
config still references them. Doctor does not repair dependencies for an
already-installed local plugin.
## Bundled plugins
Lightweight and core-critical bundled plugins ship as part of OpenClaw. They
should either carry no heavy runtime dependency tree, or move out to a
downloadable package on ClawHub/npm.
For the current generated list of plugins that ship in the core package,
install externally, or stay source-only, see
[Plugin inventory](/plugins/plugin-inventory).
Bundled plugin manifests must not request dependency staging. Large or
optional plugin functionality should be packaged as a normal plugin and
installed through the same npm/git/ClawHub path as third-party plugins.
In source checkouts, OpenClaw treats the repository as a pnpm monorepo.
After `pnpm install`, bundled plugins load from `extensions/<id>` so
package-local workspace dependencies are available and edits are picked up
directly. Source checkout development is pnpm-only; plain `npm install` at
the repository root does not prepare bundled plugin dependencies.
| Install shape | Bundled plugin location | Dependency owner |
| -------------------------------- | ------------------------------------- | -------------------------------------------------------------------- |
| `npm install -g openclaw` | Built runtime tree inside the package | OpenClaw package and explicit plugin install/update/doctor flows |
| Git checkout plus `pnpm install` | `extensions/<id>` workspace packages | The pnpm workspace, including each plugin package's own dependencies |
| `openclaw plugins install ...` | Managed npm project/git/ClawHub root | The plugin install/update flow |
## Legacy cleanup
Older OpenClaw versions generated bundled-plugin dependency roots at startup
or during doctor repair. Current doctor cleanup removes those stale
directories and symlinks with `--fix`, including old `plugin-runtime-deps`
roots, global Node-prefix package symlinks pointing at pruned
`plugin-runtime-deps` targets, `.openclaw-runtime-deps*` manifests, generated
plugin `node_modules`, install stage directories, and package-local pnpm
stores. Packaged postinstall also removes those global symlinks before
pruning the legacy target roots, so upgrades do not leave dangling ESM
package imports.
Older npm installs also used a shared `~/.openclaw/npm/node_modules` root.
Current install, update, uninstall, and doctor flows still recognize that
legacy flat root for recovery and cleanup only. New npm installs create
per-plugin project roots instead.

1203
docs/plugins/google-meet.md Normal file

File diff suppressed because it is too large Load Diff

605
docs/plugins/hooks.md Normal file
View File

@@ -0,0 +1,605 @@
---
summary: "Plugin hooks: intercept agent, tool, message, session, and Gateway lifecycle events"
title: "Plugin hooks"
read_when:
- You are building a plugin that needs before_tool_call, before_agent_reply, message hooks, or lifecycle hooks
- You need to block, rewrite, or require approval for tool calls from a plugin
- You are deciding between internal hooks and plugin hooks
---
Plugin hooks are in-process extension points for OpenClaw plugins: inspect or
change agent runs, tool calls, message flow, session lifecycle, subagent
routing, installs, or Gateway startup.
Use [internal hooks](/automation/hooks) instead for a small operator-installed
`HOOK.md` script reacting to command and Gateway events such as `/new`,
`/reset`, `/stop`, `agent:bootstrap`, or `gateway:startup`.
## Quick start
Register typed hooks with `api.on(...)` from the plugin entry:
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "tool-preflight",
name: "Tool Preflight",
register(api) {
api.on(
"before_tool_call",
async (event) => {
if (event.toolName !== "web_search") {
return;
}
return {
requireApproval: {
title: "Run web search",
description: `Allow search query: ${String(event.params.query ?? "")}`,
severity: "info",
timeoutMs: 60_000,
timeoutBehavior: "deny",
},
};
},
{ priority: 50 },
);
},
});
```
Handlers run sequentially in descending `priority`; same-priority handlers
keep registration order.
`api.on(name, handler, opts?)` accepts:
| Option | Effect |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `priority` | Ordering; higher runs first. |
| `timeoutMs` | Per-hook budget. When set, the runner aborts that handler after the budget and moves on instead of blocking on the configured model timeout. Omit to use the runner's default per-hook timeout. |
Operators can set hook budgets without patching plugin code:
```json
{
"plugins": {
"entries": {
"my-plugin": {
"hooks": {
"timeoutMs": 30000,
"timeouts": {
"before_prompt_build": 90000,
"agent_end": 60000
}
}
}
}
}
}
```
`hooks.timeouts.<hookName>` overrides `hooks.timeoutMs`, which overrides the
plugin-authored `api.on(..., { timeoutMs })` value. Each value must be a
positive integer up to 600000 ms. Prefer per-hook overrides for known-slow
hooks so one plugin does not get a longer budget everywhere.
Each hook receives `event.context.pluginConfig`, the resolved config for the
plugin that registered that handler. OpenClaw injects it per handler without
mutating the shared event object other plugins see.
## Hook catalog
Hooks are grouped by the surface they extend. **Bold** names accept a decision
result (block, cancel, override, or require approval); the rest are
observation-only.
**Agent turn**
| Hook | Purpose |
| ------------------------------- | ---------------------------------------------------------------------------------------- |
| `before_model_resolve` | Override provider or model before session messages load |
| `agent_turn_prepare` | Consume queued plugin turn injections and add same-turn context before prompt hooks |
| `before_prompt_build` | Add dynamic context or system-prompt text before the model call |
| `before_agent_start` | Compatibility-only combined phase; prefer the two hooks above |
| **`before_agent_run`** | Inspect the final prompt and session messages before model submission; can block the run |
| **`before_agent_reply`** | Short-circuit the model turn with a synthetic reply or silence |
| **`before_agent_finalize`** | Inspect the natural final answer and request one more model pass |
| `agent_end` | Observe final messages, success state, and run duration |
| `heartbeat_prompt_contribution` | Add heartbeat-only context for background monitor and lifecycle plugins |
**Conversation observation**
| Hook | Purpose |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `model_call_started` / `model_call_ended` | Sanitized provider/model call metadata: timing, outcome, bounded request-id hashes. No prompt or response content. |
| `llm_input` | Provider input: system prompt, prompt, history |
| `llm_output` | Provider output, usage, and the resolved `contextTokenBudget` when available |
**Tools**
| Hook | Purpose |
| -------------------------- | --------------------------------------------------------- |
| **`before_tool_call`** | Rewrite tool params, block execution, or require approval |
| `after_tool_call` | Observe tool results, errors, and duration |
| `resolve_exec_env` | Contribute plugin-owned environment variables to `exec` |
| **`tool_result_persist`** | Rewrite the assistant message produced from a tool result |
| **`before_message_write`** | Inspect or block an in-progress message write (rare) |
**Messages and delivery**
| Hook | Purpose |
| --------------------------- | ----------------------------------------------------------------- |
| **`inbound_claim`** | Claim an inbound message before agent routing (synthetic replies) |
| `message_received` | Observe inbound content, sender, thread, and metadata |
| **`message_sending`** | Rewrite outbound content or cancel delivery |
| **`reply_payload_sending`** | Mutate or cancel normalized reply payloads before delivery |
| `message_sent` | Observe outbound delivery success or failure |
| **`before_dispatch`** | Inspect or rewrite an outbound dispatch before channel handoff |
| **`reply_dispatch`** | Participate in the final reply-dispatch pipeline |
**Sessions and compaction**
| Hook | Purpose |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `session_start` / `session_end` | Track session lifecycle boundaries. `reason` is one of `new`, `reset`, `idle`, `daily`, `compaction`, `deleted`, `shutdown`, `restart`, or `unknown`. `shutdown`/`restart` fire from the Gateway shutdown finalizer when the process stops or restarts with active sessions, so plugins (memory, transcript stores) can finalize ghost rows instead of leaving them open across restarts. The finalizer is bounded so a slow plugin cannot block SIGTERM/SIGINT. |
| `before_compaction` / `after_compaction` | Observe or annotate compaction cycles |
| `before_reset` | Observe session-reset events (`/reset`, programmatic resets) |
**Subagents**
- `subagent_spawned` / `subagent_ended` - observe subagent launch and completion.
- `subagent_delivery_target` - compatibility hook for completion delivery when no core session binding can project a route.
- `subagent_spawning` - deprecated compatibility hook. Core now prepares `thread: true` subagent bindings through channel session-binding adapters before `subagent_spawned` fires.
- `subagent_spawned` includes `resolvedModel` and `resolvedProvider` when OpenClaw has resolved the child session's native model before launch.
- `subagent_ended` carries `targetSessionKey` (identity - matches `subagent_spawned.childSessionKey`), `targetKind` (`"subagent"` or `"acp"`), `reason`, optional `outcome` (`"ok"`, `"error"`, `"timeout"`, `"killed"`, `"reset"`, or `"deleted"`), optional `error`, `runId`, `endedAt`, `accountId`, and `sendFarewell`. It does **not** include `agentId` or `childSessionKey`; use `targetSessionKey` to correlate with the matching `subagent_spawned` event.
**Lifecycle**
| Hook | Purpose |
| -------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `gateway_start` / `gateway_stop` | Start or stop plugin-owned services with the Gateway |
| `deactivate` | Deprecated compatibility alias for `gateway_stop`; use `gateway_stop` in new plugins |
| `cron_changed` | Observe Gateway-owned cron lifecycle changes (added, updated, removed, started, finished, scheduled) |
| **`before_install`** | Inspect staged skill or plugin install material from a loaded plugin runtime |
## Debug runtime hooks
Use `before_model_resolve` to switch provider or model for an agent turn - it
runs before model resolution. `llm_output` only runs after a model attempt
produces assistant output.
For proof of the effective session model, inspect runtime registrations, then
use `openclaw sessions` or the Gateway session/status surfaces. To debug
provider payloads, start the Gateway with `--raw-stream` and
`--raw-stream-path <path>` to write raw model stream events to a jsonl file.
## Tool call policy
`before_tool_call` receives:
- `event.toolName`
- `event.params`
- optional `event.toolKind` and `event.toolInputKind`, host-authoritative
discriminators for tools that intentionally share names; for example, outer
code-mode `exec` calls use `toolKind: "code_mode_exec"` and include
`toolInputKind: "javascript" | "typescript"` when the input language is
known
- optional `event.derivedPaths`, best-effort host-derived target path hints
for well-known tool envelopes such as `apply_patch`; these paths may be
incomplete or over-approximate what the tool will actually touch (for
example, with malformed or partial inputs)
- optional `event.runId`
- optional `event.toolCallId`
- context fields such as `ctx.agentId`, `ctx.sessionKey`, `ctx.sessionId`,
`ctx.runId`, `ctx.toolKind`, `ctx.toolInputKind`, and diagnostic `ctx.trace`
It can return:
```typescript
type BeforeToolCallResult = {
params?: Record<string, unknown>;
block?: boolean;
blockReason?: string;
requireApproval?: {
title: string;
description: string;
severity?: "info" | "warning" | "critical";
timeoutMs?: number;
timeoutBehavior?: "allow" | "deny";
allowedDecisions?: Array<"allow-once" | "allow-always" | "deny">;
pluginId?: string;
onResolution?: (
decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled",
) => Promise<void> | void;
};
};
```
Guard behavior for typed lifecycle hooks:
- `block: true` is terminal and skips lower-priority handlers.
- `block: false` is treated as no decision.
- `params` rewrites the tool parameters for execution.
- `requireApproval` pauses the agent run and asks the user through plugin
approvals. `/approve` can approve both exec and plugin approvals. In Codex
app-server report-mode native `PreToolUse` relays, this defers to the
matching app-server approval request; see
[Codex harness runtime](/plugins/codex-harness-runtime#hook-boundaries).
- A lower-priority `block: true` can still block after a higher-priority hook
requested approval.
- `onResolution` receives the resolved decision: `allow-once`, `allow-always`,
`deny`, `timeout`, or `cancelled`.
See [Plugin permission requests](/plugins/plugin-permission-requests) for
approval routing, decision behavior, and when to use `requireApproval` instead
of optional tools or exec approvals.
Plugins that need host-level policy can register trusted tool policies with
`api.registerTrustedToolPolicy(...)`. These run before ordinary
`before_tool_call` hooks and before normal hook decisions. Bundled trusted
policies run first; installed-plugin trusted policies run next in plugin-load
order; ordinary `before_tool_call` hooks run after them. Bundled plugins keep
the existing trusted-policy path. Installed plugins must be explicitly enabled
and declare every policy id in `contracts.trustedToolPolicies`; undeclared ids
are rejected before registration. Policy ids are scoped to the registering
plugin, so different plugins may reuse the same local id. Use this tier only
for host-trusted gates such as workspace policy, budget enforcement, or
reserved workflow safety.
### Exec environment hook
`resolve_exec_env` lets plugins contribute environment variables to `exec`
tool invocations before the command runs. It receives:
- `event.sessionKey`
- `event.toolName`, currently always `"exec"`
- `event.host`, one of `"gateway"`, `"sandbox"`, or `"node"`
- context fields such as `ctx.agentId`, `ctx.sessionKey`,
`ctx.messageProvider`, and `ctx.channelId`
Return a `Record<string, string>` to merge into the exec environment. Handlers
run in priority order; later results override earlier results for the same
key.
Hook output is filtered through the host exec environment key policy before
merging. `PATH` is always dropped (command resolution and safe-bin checks
depend on it). Invalid keys and dangerous host override keys such as `LD_*`,
`DYLD_*`, `NODE_OPTIONS`, proxy variables (`HTTP_PROXY`, `HTTPS_PROXY`,
`ALL_PROXY`, `NO_PROXY`), and TLS override variables (`NODE_TLS_REJECT_UNAUTHORIZED`,
`SSL_CERT_FILE`, and similar) are dropped. The filtered plugin env is included
in Gateway approval/audit metadata and forwarded to node-host execution
requests.
### Tool result persistence
Tool results can include structured `details` for UI rendering, diagnostics,
media routing, or plugin-owned metadata. Treat `details` as runtime metadata,
not prompt content:
- OpenClaw strips `toolResult.details` before provider replay and compaction
input so metadata does not become model context.
- Persisted session entries keep only bounded `details`. Oversized details are
replaced with a compact summary and `persistedDetailsTruncated: true`.
- `tool_result_persist` and `before_message_write` run before the final
persistence cap. Keep returned `details` small and avoid placing
prompt-relevant text only in `details`; put model-visible tool output in
`content`.
## Prompt and model hooks
Use the phase-specific hooks for new plugins:
- `before_model_resolve`: receives only the current prompt and attachment
metadata. Return `providerOverride` or `modelOverride`.
- `agent_turn_prepare`: receives the current prompt, prepared session
messages, and any exactly-once queued injections drained for this session.
Return `prependContext` or `appendContext`.
- `before_prompt_build`: receives the current prompt and session messages.
Return `prependContext`, `appendContext`, `systemPrompt`,
`prependSystemContext`, or `appendSystemContext`.
- `heartbeat_prompt_contribution`: runs only for heartbeat turns and returns
`prependContext` or `appendContext`. Intended for background monitors that
need to summarize current state without changing user-initiated turns.
`before_agent_start` remains for compatibility. Prefer the explicit hooks
above so the plugin does not depend on a legacy combined phase.
`before_agent_run` runs after prompt construction and before any model input,
including prompt-local image loading and `llm_input` observation. It receives
the current user input as `prompt`, plus loaded session history in `messages`
and the active system prompt. Return `{ outcome: "block", reason, message? }`
to stop the run before the model reads the prompt. `reason` is internal;
`message` is the user-facing replacement. Only `pass` and `block` outcomes are
supported; unsupported decision shapes fail closed.
When a run is blocked, OpenClaw stores only the replacement text in
`message.content` plus non-sensitive block metadata such as the blocking
plugin id and timestamp. The original user text is not retained in transcript
or future context. Internal block reasons are treated as sensitive and
excluded from transcript, history, broadcast, log, and diagnostics payloads.
Observability should use sanitized fields such as blocker id, outcome,
timestamp, or a safe category.
`before_agent_start` and `agent_end` include `event.runId` when OpenClaw can
identify the active run; the same value is also on `ctx.runId`. Cron-driven
runs also expose `ctx.jobId` (the originating cron job id) on the agent-turn
context so hooks can scope metrics, side effects, or state to a specific
scheduled job. `ctx.jobId` is not part of the `before_tool_call` tool context.
For channel-originated runs, `ctx.channel` and `ctx.messageProvider` identify
the provider surface such as `discord` or `telegram`, while `ctx.channelId` is
the conversation target identifier when OpenClaw can derive one from the
session key or delivery metadata.
When sender identity is available, agent hook contexts also include:
- `ctx.senderId` - channel-scoped sender ID (e.g. Feishu `open_id`, Discord
user ID). Populated when the run originates from a user message with known
sender metadata.
- `ctx.chatId` - transport-native conversation identifier (e.g. Feishu
`chat_id`, Telegram `chat_id`). Populated when the originating channel
provides a native conversation ID.
- `ctx.channelContext.sender.id` - the same sender ID as `ctx.senderId`, under
a channel-owned object plugins can extend with channel-specific fields.
- `ctx.channelContext.chat.id` - the same conversation ID as `ctx.chatId`,
under a channel-owned object plugins can extend with channel-specific
fields.
Core only defines the nested `id` fields. Channel plugins that pass richer
sender or chat metadata through the inbound helper can augment
`PluginHookChannelSenderContext` or `PluginHookChannelChatContext` from
`openclaw/plugin-sdk/channel-inbound`:
```ts
declare module "openclaw/plugin-sdk/channel-inbound" {
interface PluginHookChannelSenderContext {
unionId?: string;
userId?: string;
}
}
```
Channel plugins pass those fields through the inbound SDK helper:
```ts
buildChannelInboundEventContext({
// ...
channelContext: {
sender: { id: senderOpenId, unionId, userId },
chat: { id: chatId },
},
});
```
These fields are optional and absent for system-originated runs (heartbeat,
cron, exec-event).
`ctx.senderExternalId` remains as a deprecated source-compatibility field for
older plugins. Core does not populate it; new channel-specific sender
identities should live under `ctx.channelContext.sender` through module
augmentation.
`agent_end` is an observation hook. Gateway and persistent harness paths run
it fire-and-forget after the turn, while short-lived one-shot CLI paths wait
for the hook promise before process cleanup so trusted plugins can flush
terminal observability or capture state. The hook runner applies a 30 second
timeout so a wedged plugin or embedding endpoint cannot leave the hook promise
pending forever. A timeout is logged and OpenClaw continues; it does not
cancel plugin-owned network work unless the plugin also uses its own abort
signal.
Use `model_call_started` and `model_call_ended` for provider-call telemetry
that should not receive raw prompts, history, responses, headers, request
bodies, or provider request IDs. These hooks include stable metadata such as
`runId`, `callId`, `provider`, `model`, optional `api`/`transport`, terminal
`durationMs`/`outcome`, and `upstreamRequestIdHash` when OpenClaw can derive a
bounded provider request-id hash. When the runtime has resolved
context-window metadata, the hook event and context also include
`contextTokenBudget`, the effective token budget after model/config/agent
caps, plus `contextWindowSource` and `contextWindowReferenceTokens` when a
lower cap was applied.
`before_agent_finalize` runs only when a harness is about to accept a natural
final assistant answer. It is not the `/stop` cancellation path and does not
run when the user aborts a turn. Return `{ action: "revise", reason }` to ask
the harness for one more model pass before finalization, `{ action:
"finalize", reason? }` to force finalization, or omit a result to continue.
Codex native `Stop` hooks are relayed into this hook as OpenClaw
`before_agent_finalize` decisions.
When returning `action: "revise"`, plugins can include `retry` metadata to
make the extra model pass bounded and replay-safe:
```typescript
type BeforeAgentFinalizeRetry = {
instruction: string;
idempotencyKey?: string;
maxAttempts?: number;
};
```
`instruction` is appended to the revision reason sent to the harness.
`idempotencyKey` lets the host count retries for the same plugin request
across equivalent finalize decisions, and `maxAttempts` caps how many extra
passes the host will allow before continuing with the natural final answer.
Non-bundled plugins that need raw conversation hooks (`before_model_resolve`,
`before_agent_reply`, `llm_input`, `llm_output`, `before_agent_finalize`,
`agent_end`, or `before_agent_run`) must set:
```json
{
"plugins": {
"entries": {
"my-plugin": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}
```
Prompt-mutating hooks and durable next-turn injections can be disabled per
plugin with `plugins.entries.<id>.hooks.allowPromptInjection=false`.
### Session extensions and next-turn injections
Workflow plugins can persist small JSON-compatible session state with
`api.session.state.registerSessionExtension(...)` and update it through the
Gateway `sessions.pluginPatch` method. Session rows project registered
extension state through `pluginExtensions`, letting Control UI and other
clients render plugin-owned status without learning plugin internals.
`api.registerSessionExtension(...)` still works but is deprecated in favor of
the `api.session.state` namespace.
Use `api.session.workflow.enqueueNextTurnInjection(...)` when a plugin needs
durable context to reach the next model turn exactly once (the top-level
`api.enqueueNextTurnInjection(...)` is a deprecated alias with the same
behavior). OpenClaw drains queued injections before prompt hooks, drops
expired injections, and deduplicates by `idempotencyKey` per plugin. This is
the right seam for approval resumes, policy summaries, background monitor
deltas, and command continuations that should be visible to the model on the
next turn but should not become permanent system prompt text.
Cleanup semantics are part of the contract. Session extension cleanup and
runtime lifecycle cleanup callbacks receive `reset`, `delete`, `disable`, or
`restart`. The host removes the owning plugin's persistent session extension
state and pending next-turn injections for reset/delete/disable; restart
keeps durable session state while cleanup callbacks let plugins release
scheduler jobs, run context, and other out-of-band resources for the old
runtime generation.
## Message hooks
Use message hooks for channel-level routing and delivery policy:
- `message_received`: observe inbound content, sender, `threadId`,
`messageId`, `senderId`, optional run/session correlation, and metadata.
- `message_sending`: rewrite `content` or return `{ cancel: true }`.
- `reply_payload_sending`: rewrite normalized `ReplyPayload` objects
(including `presentation`, `delivery`, media refs, and text) or return
`{ cancel: true }`.
- `message_sent`: observe final success or failure.
For audio-only TTS replies, `content` may contain the hidden spoken
transcript even when the channel payload has no visible text/caption.
Rewriting that `content` updates the hook-visible transcript only; it is not
rendered as a media caption.
`reply_payload_sending` events may include `usageState`, a best-effort live
per-turn model/usage/context snapshot. Durable delivery, recovered replay, and
replies without exact run correlation omit it.
Message hook contexts expose stable correlation fields when available:
`ctx.sessionKey`, `ctx.runId`, `ctx.messageId`, `ctx.senderId`, `ctx.trace`,
`ctx.traceId`, `ctx.spanId`, `ctx.parentSpanId`, and `ctx.callDepth`. Inbound
and `before_dispatch` contexts also expose reply metadata when the channel
has visibility-filtered quoted message data: `replyToId`, `replyToIdFull`,
`replyToBody`, `replyToSender`, and `replyToIsQuote`. Prefer these
first-class fields before reading legacy metadata.
Prefer typed `threadId` and `replyToId` fields before using channel-specific
metadata.
Decision rules:
- `message_sending` with `cancel: true` is terminal.
- `message_sending` with `cancel: false` is treated as no decision.
- Rewritten `content` continues to lower-priority hooks unless a later hook
cancels delivery.
- `reply_payload_sending` runs after payload normalization and before channel
delivery, including replies routed back to the originating channel.
Handlers run sequentially and each handler sees the latest payload produced
by higher-priority handlers.
- `reply_payload_sending` payloads do not expose runtime trust markers such as
`trustedLocalMedia`; plugins can edit payload shape but cannot grant local
media trust.
- `message_sending` can return `cancelReason` and bounded `metadata` with a
cancellation. New message lifecycle APIs expose this as a suppressed
delivery outcome with reason `cancelled_by_message_sending_hook`; legacy
direct delivery keeps returning an empty result array for compatibility.
- `message_sent` is observation-only. Handler failures are logged and do not
change the delivery result.
## Install hooks
Use `security.installPolicy` for operator-owned allow/block decisions. That
policy runs from OpenClaw config, covers CLI install and update paths, and
fails closed when enabled but unavailable.
`before_install` is a plugin-runtime lifecycle hook. It runs after
`security.installPolicy` only in the OpenClaw process where plugin hooks have
already been loaded, such as Gateway-backed install flows. It is useful for
plugin-owned observations, warnings, and compatibility checks, but it is not
the primary enterprise or host security boundary for installs. The
`builtinScan` field remains in the event payload for compatibility, but
OpenClaw no longer runs built-in install-time dangerous-code blocking, so it
is an empty `ok` result. Return additional findings or
`{ block: true, blockReason }` to stop the install in that process.
`block: true` is terminal. `block: false` is treated as no decision. Handler
failures block the install fail-closed.
## Gateway lifecycle
Use `gateway_start` for plugin services that need Gateway-owned state. The
context exposes `ctx.config`, `ctx.workspaceDir`, and `ctx.getCron?.()` for
cron inspection and updates. Use `gateway_stop` to clean up long-running
resources.
Do not rely on the internal `gateway:startup` hook for plugin-owned runtime
services.
`cron_changed` fires for Gateway-owned cron lifecycle events with a typed
event payload covering `added`, `updated`, `removed`, `started`, `finished`,
and `scheduled` reasons. The event carries a `PluginHookGatewayCronJob`
snapshot (including `state.nextRunAtMs`, `state.lastRunStatus`, and
`state.lastError` when present) plus a `PluginHookGatewayCronDeliveryStatus`
of `not-requested` | `delivered` | `not-delivered` | `unknown`. Removed events
still carry the deleted job snapshot so external schedulers can reconcile
state. Use `ctx.getCron?.()` and `ctx.config` from the runtime context when
syncing external wake schedulers, and keep OpenClaw as the source of truth
for due checks and execution.
## Upcoming deprecations
A few hook-adjacent surfaces are deprecated but still supported. Migrate
before the next major release:
- **Plaintext channel envelopes** in `inbound_claim` and `message_received`
handlers. Read `BodyForAgent` and the structured user-context blocks
instead of parsing flat envelope text. See
[Plaintext channel envelopes → BodyForAgent](/plugins/sdk-migration#active-deprecations).
- **`before_agent_start`** remains for compatibility. New plugins should use
`before_model_resolve` and `before_prompt_build` instead of the combined
phase.
- **`subagent_spawning`** remains for compatibility with older plugins, but
new plugins should not return thread routing from it. Core prepares
`thread: true` subagent bindings through channel session-binding adapters
before `subagent_spawned` fires.
- **`deactivate`** remains as a deprecated cleanup compatibility alias until
after 2026-08-16. New plugins should use `gateway_stop`.
- **`onResolution` in `before_tool_call`** now uses the typed
`PluginApprovalResolution` union (`allow-once` / `allow-always` / `deny` /
`timeout` / `cancelled`) instead of a free-form `string`.
- **`api.registerSessionExtension` / `api.enqueueNextTurnInjection`** remain
as top-level compatibility aliases. New plugins should use
`api.session.state.registerSessionExtension(...)` and
`api.session.workflow.enqueueNextTurnInjection(...)`.
For the full list - memory capability registration, provider thinking
profile, external auth providers, provider discovery types, task runtime
accessors, and the `command-auth``command-status` rename - see
[Plugin SDK migration → Active deprecations](/plugins/sdk-migration#active-deprecations).
## Related
- [Plugin SDK migration](/plugins/sdk-migration) - active deprecations and removal timeline
- [Building plugins](/plugins/building-plugins)
- [Plugin SDK overview](/plugins/sdk-overview)
- [Plugin entry points](/plugins/sdk-entrypoints)
- [Internal hooks](/automation/hooks)
- [Plugin architecture internals](/plugins/architecture-internals)

View File

@@ -0,0 +1,80 @@
---
summary: "Test packaged plugin overrides with setup-time install flows"
read_when:
- Testing onboarding or setup flows against a locally packed plugin
- Verifying a plugin package before publishing it
- Replacing an automatic plugin install with a test artifact
title: "Plugin install overrides"
sidebarTitle: "Install overrides"
---
Plugin install overrides let maintainers point setup-time plugin installs at
a specific npm package or local npm-pack tarball instead of the catalog,
bundled, or default npm source. They exist for E2E and package validation
only; normal users install plugins with
[`openclaw plugins install`](/cli/plugins).
<Warning>
Overrides execute plugin code from the source you provide. Use them only in an
isolated state directory or disposable test machine.
</Warning>
## Environment
Overrides are disabled unless both variables are set:
```bash
export OPENCLAW_ALLOW_PLUGIN_INSTALL_OVERRIDES=1
export OPENCLAW_PLUGIN_INSTALL_OVERRIDES='{
"codex": "npm-pack:/tmp/openclaw-codex-2026.5.8.tgz",
"openclaw-web-search": "npm:@openclaw/web-search@2026.5.8"
}'
```
The override map is JSON keyed by plugin id. Values support:
| Prefix | Source |
| --------------------- | ------------------------------------------------------------------------------------------------ |
| `npm:<registry-spec>` | Registry packages, exact versions, or tags |
| `npm-pack:<path.tgz>` | Local tarballs produced by `npm pack`; relative paths resolve from the current working directory |
## Behavior
When a setup-time flow installs a plugin whose id appears in the map, OpenClaw
uses the override source instead of the catalog, bundled, or default npm
source. This applies to onboarding and any other flow using the shared
setup-time plugin installer.
- Overrides still enforce the expected plugin id: a tarball mapped to `codex`
must install a plugin whose manifest id is `codex`.
- Overrides do not inherit official trusted-source status. Even when the
catalog entry normally represents an OpenClaw-owned package, an override is
treated as operator-supplied test input.
- Workspace `.env` files cannot enable install overrides; both env vars are on
the blocked workspace dotenv list. Set them in the trusted shell, CI job, or
remote test command that launches OpenClaw.
## Package E2E
Use an isolated state directory so package installs and install records do not
touch your normal OpenClaw state:
```bash
npm pack extensions/codex --pack-destination /tmp
OPENCLAW_STATE_DIR="$(mktemp -d)" \
OPENCLAW_ALLOW_PLUGIN_INSTALL_OVERRIDES=1 \
OPENCLAW_PLUGIN_INSTALL_OVERRIDES='{"codex":"npm-pack:/tmp/openclaw-codex-2026.5.8.tgz"}' \
pnpm openclaw onboard --mode local
```
Verify the installed package under the state directory:
```bash
find "$OPENCLAW_STATE_DIR/npm/projects" -path '*/node_modules/@openclaw/codex/package.json' -print
grep -R '"@openclaw/codex"' "$OPENCLAW_STATE_DIR/npm/projects"/*/package-lock.json
```
For live provider E2E, source the real API key from a trusted shell or CI
secret before launching the test command. Do not print keys; report only the
source and whether the key was present.

71
docs/plugins/llama-cpp.md Normal file
View File

@@ -0,0 +1,71 @@
---
summary: "Install the official llama.cpp provider for local GGUF memory embeddings"
read_when:
- You want memory search embeddings from a local GGUF model
- You are configuring memorySearch.provider = "local"
- You need the OpenClaw plugin that owns the node-llama-cpp runtime
title: "llama.cpp Provider"
sidebarTitle: "llama.cpp Provider"
---
`llama-cpp` is the official external provider plugin for local GGUF
embeddings. It registers embedding provider id `local` and owns the
`node-llama-cpp` runtime dependency used by `memorySearch.provider: "local"`.
Install it before using local memory embeddings:
```bash
openclaw plugins install @openclaw/llama-cpp-provider
```
The main `openclaw` npm package does not include `node-llama-cpp`. Keeping the
native dependency in this plugin prevents normal OpenClaw npm updates from
deleting a manually installed runtime inside the OpenClaw package directory.
## Configuration
Set `memorySearch.provider` to `local`:
```json5
{
agents: {
defaults: {
memorySearch: {
provider: "local",
local: {
modelPath: "hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf",
},
},
},
},
}
```
`local.modelPath` defaults to the `hf:` URI shown above (`embeddinggemma-300m-qat-Q8_0.gguf`).
Point it at a different `hf:` URI or a local `.gguf` file to use another
model. `local.modelCacheDir` overrides where downloaded models are cached
(default: `~/.node-llama-cpp/models`), and `local.contextSize` accepts an
integer or `"auto"`.
## Native Runtime
Use Node 24 for the smoothest native install path. Source checkouts using
pnpm may need to approve and rebuild the native dependency:
```bash
pnpm approve-builds
pnpm rebuild node-llama-cpp
```
## Troubleshooting
If `node-llama-cpp` is missing or fails to load, OpenClaw reports the failure
with:
1. Install the plugin: `openclaw plugins install @openclaw/llama-cpp-provider`.
2. Use Node 24 for native installs/updates.
3. From a pnpm source checkout: `pnpm approve-builds`, then `pnpm rebuild node-llama-cpp`.
For lower-friction local embeddings without the native build step, set
`memorySearch.provider` to a remote embedding provider such as `lmstudio`,
`ollama`, `openai`, or `voyage` instead.

View File

@@ -0,0 +1,231 @@
---
summary: "Quick examples for listing, installing, updating, inspecting, and uninstalling OpenClaw plugins"
read_when:
- You want quick plugin list, install, update, inspect, or uninstall examples
- You want to choose a plugin install source
- You want the right reference for publishing plugin packages
title: "Manage plugins"
sidebarTitle: "Manage plugins"
doc-schema-version: 1
---
Common plugin management commands. For the full command contract, flags,
source-selection rules, and edge cases, see [`openclaw plugins`](/cli/plugins).
Typical workflow: find a package, install it from ClawHub, npm, git, or a
local path, let the managed Gateway auto-restart (or restart it manually),
then verify the plugin's runtime registrations.
## List and search plugins
```bash
openclaw plugins list
openclaw plugins list --enabled
openclaw plugins list --verbose
openclaw plugins list --json
openclaw plugins search "calendar"
```
`--json` for scripts:
```bash
openclaw plugins list --json \
| jq '.plugins[] | {id, enabled, format, source, dependencyStatus}'
```
`plugins list` is a cold inventory check: what OpenClaw can discover from
config, manifests, and the persisted plugin registry. It does not prove an
already-running Gateway imported the plugin runtime. JSON output includes
registry diagnostics and each plugin's `dependencyStatus` (whether declared
`dependencies`/`optionalDependencies` resolve on disk).
`plugins search` queries ClawHub for installable plugin packages and prints
an install hint (`openclaw plugins install clawhub:<package>`) per result.
## Enable and disable plugins
```bash
openclaw plugins enable <plugin-id>
openclaw plugins disable <plugin-id>
```
Toggles a plugin's config entry without touching installed files. Some
bundled plugins (bundled model/speech providers, the bundled browser plugin)
are enabled by default; others require `enable` after install.
## Install plugins
```bash
# Search ClawHub for plugin packages.
openclaw plugins search "calendar"
# Install from ClawHub.
openclaw plugins install clawhub:<package>
openclaw plugins install clawhub:<package>@1.2.3
openclaw plugins install clawhub:<package>@beta
# Install from npm.
openclaw plugins install npm:<package>
openclaw plugins install npm:@scope/openclaw-plugin@1.2.3
openclaw plugins install npm:@openclaw/codex
# Install from a local npm-pack artifact.
openclaw plugins install npm-pack:<path.tgz>
# Install from git or a local development checkout.
openclaw plugins install git:github.com/acme/openclaw-plugin@v1.0.0
openclaw plugins install ./my-plugin
openclaw plugins install --link ./my-plugin
```
Bare package specs install from npm during the launch cutover, unless the
name matches a bundled or official plugin id, in which case OpenClaw uses
that local/official copy instead. Use `clawhub:`, `npm:`, `git:`, or
`npm-pack:` for deterministic source selection.
Use `--force` only to overwrite an existing install target from a different
source. For routine upgrades of a tracked npm, ClawHub, or hook-pack install,
use `openclaw plugins update` instead; `--force` is not supported with
`--link`.
## Restart and inspect
A running managed Gateway with config reload enabled restarts automatically
after installing, updating, or uninstalling plugin code. If the Gateway is
unmanaged or reload is disabled, restart it yourself before checking live
runtime surfaces:
```bash
openclaw gateway restart
openclaw plugins inspect <plugin-id> --runtime --json
```
`inspect --runtime` loads the plugin module and proves it registered runtime
surfaces (tools, hooks, services, Gateway methods, HTTP routes, plugin-owned
CLI commands). Plain `inspect` and `list` are cold manifest/config/registry
checks only.
## Update plugins
```bash
openclaw plugins update <plugin-id>
openclaw plugins update <npm-package-or-spec>
openclaw plugins update --all
openclaw plugins update <plugin-id> --dry-run
```
Passing a plugin id reuses its tracked install spec: stored dist-tags
(`@beta`) and exact pinned versions carry over to later `update <plugin-id>`
runs.
`openclaw plugins update --all` is the bulk maintenance path. It still
respects ordinary tracked install specs, but trusted official OpenClaw
plugin records sync to the current official catalog target instead of
staying pinned to a stale exact official package; when `update.channel` is
`beta`, that sync prefers the beta release line. Use a targeted
`update <plugin-id>` to keep an exact or tagged official spec untouched.
For npm installs, pass an explicit package spec to switch the tracked
record:
```bash
openclaw plugins update @scope/openclaw-plugin@beta
openclaw plugins update @scope/openclaw-plugin
```
The second command moves a plugin back to the registry's default release
line when it was previously pinned to an exact version or tag.
See [`openclaw plugins`](/cli/plugins#update) for the exact fallback and
pinning rules.
## Uninstall plugins
```bash
openclaw plugins uninstall <plugin-id> --dry-run
openclaw plugins uninstall <plugin-id>
openclaw plugins uninstall <plugin-id> --keep-files
```
Uninstall removes the plugin's config entry, persisted plugin index record,
allow/deny list entries, and linked `plugins.load.paths` entries when
applicable. The managed install directory is removed unless you pass
`--keep-files`. A running managed Gateway restarts automatically when the
uninstall changes plugin source.
In Nix mode (`OPENCLAW_NIX_MODE=1`), plugin install, update, uninstall,
enable, and disable are all disabled; manage those choices in the Nix source
for the install instead.
## Choose a source
| Source | Use when | Example |
| ----------- | --------------------------------------------------------------------------- | -------------------------------------------------------------- |
| ClawHub | You want OpenClaw-native discovery, scan summaries, versions, and hints | `openclaw plugins install clawhub:<package>` |
| git | You want a branch, tag, or commit from a repository | `openclaw plugins install git:github.com/<owner>/<repo>@<ref>` |
| local path | You are developing or testing a plugin on the same machine | `openclaw plugins install --link ./my-plugin` |
| marketplace | You are installing a Claude-compatible marketplace plugin | `openclaw plugins install <plugin> --marketplace <source>` |
| npm pack | You are proving a local package artifact through npm install semantics | `openclaw plugins install npm-pack:<path.tgz>` |
| npmjs.com | You already ship JavaScript packages or need npm dist-tags/private registry | `openclaw plugins install npm:@acme/openclaw-plugin` |
Managed local path installs must be plugin directories or archives. Put
standalone plugin files in `plugins.load.paths` instead of installing them
with `plugins install`.
## Publish plugins
ClawHub is the primary public discovery surface for OpenClaw plugins. Publish
there when you want users to find plugin metadata, version history, registry
scan results, and install hints before they install.
```bash
npm i -g clawhub
clawhub login
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
clawhub package publish your-org/your-plugin@v1.0.0
```
Native npm plugins must ship a plugin manifest (`openclaw.plugin.json`) plus
`package.json` metadata before publishing:
```json package.json
{
"name": "@acme/openclaw-plugin",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./dist/index.js"]
}
}
```
```bash
npm publish --access public
openclaw plugins install npm:@acme/openclaw-plugin
openclaw plugins install npm:@acme/openclaw-plugin@beta
openclaw plugins install npm:@acme/openclaw-plugin@1.0.0
```
Use these pages for the full publishing contract instead of treating this
page as the publishing reference:
- [ClawHub publishing](/clawhub/publishing) explains owners, scopes,
releases, review, package validation, and package transfer.
- [Building plugins](/plugins/building-plugins) shows the full plugin
package shape (including `openclaw.plugin.json`) and first publish
workflow.
- [Plugin manifest](/plugins/manifest) defines native plugin manifest
fields.
If the same package is available on both ClawHub and npm, use the explicit
`clawhub:` or `npm:` prefix to force one source.
## Related
- [Plugins](/tools/plugin) - install, configure, restart, and troubleshoot
- [`openclaw plugins`](/cli/plugins) - full CLI reference
- [Community plugins](/plugins/community) - public discovery and ClawHub publishing
- [ClawHub](/clawhub/cli) - registry CLI operations
- [Building plugins](/plugins/building-plugins) - create a plugin package
- [Plugin manifest](/plugins/manifest) - manifest and package metadata

1251
docs/plugins/manifest.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,364 @@
---
summary: "Configure the official external LanceDB memory plugin, including local Ollama-compatible embeddings"
read_when:
- You are configuring the memory-lancedb plugin
- You want LanceDB-backed long-term memory with auto-recall or auto-capture
- You are using local OpenAI-compatible embeddings such as Ollama
title: "Memory LanceDB"
sidebarTitle: "Memory LanceDB"
---
`memory-lancedb` is an official external plugin that stores long-term memory in
LanceDB with vector search. It can auto-recall relevant memories before a model
turn and auto-capture important facts after a response.
Use it for a local vector database, an OpenAI-compatible embedding endpoint, or
a memory store outside the default built-in memory backend.
## Installation
```bash
openclaw plugins install @openclaw/memory-lancedb
```
The plugin is published to npm; it is not bundled into the OpenClaw runtime
image. Installing it writes the plugin entry, enables it, and switches
`plugins.slots.memory` to `memory-lancedb`. If another plugin currently owns
the memory slot, that plugin is disabled with a warning.
<Note>
Companion plugins such as `memory-wiki` can run alongside `memory-lancedb`,
but only one plugin owns the active memory slot at a time.
</Note>
## Quick start
```json5
{
plugins: {
slots: {
memory: "memory-lancedb",
},
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
provider: "openai",
model: "text-embedding-3-small",
},
autoRecall: true,
autoCapture: false,
},
},
},
},
}
```
Restart the Gateway after changing plugin config, then verify it loaded:
```bash
openclaw gateway restart
openclaw plugins list
```
## Embedding config
`embedding` is required and must include at least one field. `provider`
defaults to `openai`; `model` defaults to `text-embedding-3-small`.
| Field | Type | Notes |
| ---------------------- | ------------- | ------------------------------------------------------------------------ |
| `embedding.provider` | string | Adapter id, e.g. `openai`, `github-copilot`, `ollama`. Default `openai`. |
| `embedding.model` | string | Default `text-embedding-3-small`. |
| `embedding.apiKey` | string | Optional; supports `${ENV_VAR}` expansion. |
| `embedding.baseUrl` | string | Optional; supports `${ENV_VAR}` expansion. |
| `embedding.dimensions` | integer (>=1) | Required for models not in the built-in table (see below). |
Two request paths exist:
- **Provider adapter path** (default): set `embedding.provider` and omit
`embedding.apiKey`/`embedding.baseUrl`. The plugin resolves the provider's
configured auth profile, environment variable, or
`models.providers.<provider>.apiKey` through the same memory embedding
adapters `memory-core` uses. This is the path for `github-copilot`, `ollama`,
and any other bundled provider with embedding support.
- **Direct OpenAI-compatible client path**: leave `embedding.provider` unset
(or `"openai"`) and set `embedding.apiKey` plus `embedding.baseUrl`. Use this
for a raw OpenAI-compatible embeddings endpoint that has no bundled provider
adapter.
OpenAI Codex / ChatGPT OAuth is not an OpenAI Platform embeddings credential.
For OpenAI embeddings use an OpenAI API key auth profile, `OPENAI_API_KEY`, or
`models.providers.openai.apiKey`. OAuth-only users should pick another
embedding-capable provider such as `github-copilot` or `ollama`.
```json5
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
provider: "github-copilot",
model: "text-embedding-3-small",
},
},
},
},
},
}
```
Some OpenAI-compatible embedding endpoints reject the `encoding_format`
parameter; others ignore it and always return `number[]`. `memory-lancedb`
omits `encoding_format` on requests and accepts either float-array or
base64-encoded float32 responses, so both response shapes work without config.
### Dimensions
OpenClaw has a built-in dimension for `text-embedding-3-small` (1536) and
`text-embedding-3-large` (3072) only. Any other model needs an explicit
`embedding.dimensions` so LanceDB can create the vector column, for example
ZhiPu `embedding-3` at 2048 dimensions:
```json5
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
apiKey: "${ZHIPU_API_KEY}",
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
model: "embedding-3",
dimensions: 2048,
},
},
},
},
},
}
```
## Ollama embeddings
Use the bundled Ollama provider adapter path (`embedding.provider: "ollama"`).
It calls Ollama's native `/api/embed` endpoint and follows the same auth/base
URL rules as the [Ollama](/providers/ollama) provider.
```json5
{
plugins: {
slots: {
memory: "memory-lancedb",
},
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
provider: "ollama",
baseUrl: "http://127.0.0.1:11434",
model: "mxbai-embed-large",
dimensions: 1024,
},
recallMaxChars: 400,
autoRecall: true,
autoCapture: false,
},
},
},
},
}
```
`mxbai-embed-large` is not in the built-in dimension table, so `dimensions` is
required. For small local embedding models, lower `recallMaxChars` if the
local server returns context-length errors.
## Recall and capture limits
| Setting | Default | Range | Applies to |
| ----------------- | ------- | ---------------------------- | ---------------------------------------------------------- |
| `recallMaxChars` | `1000` | 100-10000 | Text sent to the embedding API for recall. |
| `captureMaxChars` | `500` | 100-10000 | Message length eligible for auto-capture. |
| `customTriggers` | `[]` | 0-50 items, each <=100 chars | Literal phrases that make auto-capture consider a message. |
`recallMaxChars` bounds the `before_prompt_build` auto-recall query, the
`memory_recall` tool, the `memory_forget` query path, and `openclaw ltm
search`. Auto-recall embeds the latest user message from the turn and falls
back to the full prompt only when no user message is present, keeping channel
metadata and large prompt blocks out of the embedding request.
`captureMaxChars` gates whether a user message from the turn's `agent_end`
event is short enough to be considered for auto-capture; it does not affect
recall queries.
`customTriggers` adds literal auto-capture phrases without regex. Built-in
triggers cover common English, Czech, Chinese, Japanese, and Korean memory
phrases (`remember`, `prefer`, `记住`, `覚えて`, `기억해`, and similar).
Auto-capture also rejects text that looks like envelope/transport metadata,
prompt-injection payloads, or already-injected `<relevant-memories>` context,
and caps at 3 captured memories per agent turn.
## Commands
`memory-lancedb` registers the `ltm` CLI namespace whenever it is installed
(not only when it owns the active memory slot):
```bash
openclaw ltm list [--limit <n>] [--order-by-created-at]
openclaw ltm search <query> [--limit <n>]
openclaw ltm stats
```
`ltm query` runs a non-vector query directly against the LanceDB table:
```bash
openclaw ltm query --cols id,text,createdAt --limit 20
openclaw ltm query --filter "category = 'preference'" --order-by createdAt:desc
```
| Flag | Default | Notes |
| --------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `--cols <columns>` | `id,text,importance,category,createdAt` | Comma-separated column allowlist. |
| `--filter <condition>` | none | SQL-style WHERE clause. Max 200 chars; only alphanumerics, `_-`, whitespace, and `='"<>!.,()%*` are allowed. |
| `--limit <n>` | `10` | Positive integer. |
| `--order-by <column>:<asc\|desc>` | none | Sorted in memory after the filter runs; the sort column is auto-added to the projection and stripped from output if it was not requested. |
Agents get three tools from the active memory plugin:
- `memory_recall`: vector search over stored memories.
- `memory_store`: save a fact, preference, decision, or entity (rejects text
that looks like a prompt-injection payload; skips near-duplicate stores).
- `memory_forget`: delete by `memoryId`, or by `query` (auto-deletes a single
match above 90% score, otherwise lists candidate IDs to disambiguate).
## Storage
LanceDB data defaults to `~/.openclaw/memory/lancedb`. Override with `dbPath`:
```json5
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
dbPath: "~/.openclaw/memory/lancedb",
embedding: {
apiKey: "${OPENAI_API_KEY}",
model: "text-embedding-3-small",
},
},
},
},
},
}
```
`storageOptions` accepts string key/value pairs for LanceDB storage backends
(e.g. S3-compatible object storage) and supports `${ENV_VAR}` expansion:
```json5
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
dbPath: "s3://memory-bucket/openclaw",
storageOptions: {
access_key: "${AWS_ACCESS_KEY_ID}",
secret_key: "${AWS_SECRET_ACCESS_KEY}",
endpoint: "${AWS_ENDPOINT_URL}",
},
embedding: {
apiKey: "${OPENAI_API_KEY}",
model: "text-embedding-3-small",
},
},
},
},
},
}
```
## Runtime dependencies and platform support
`memory-lancedb` depends on the native `@lancedb/lancedb` package, owned by the
plugin package (not the OpenClaw core dist). Gateway startup does not repair
plugin dependencies; if the native dependency is missing or fails to load,
reinstall or update the plugin package and restart the Gateway.
`@lancedb/lancedb` does not publish a native build for `darwin-x64` (Intel
Mac). On that platform the plugin logs that LanceDB is unavailable at load
time; use the default memory backend, run the Gateway on a supported
platform/architecture, or disable `memory-lancedb`.
## Troubleshooting
### Input length exceeds the context length
The embedding model rejected the recall query:
```text
memory-lancedb: recall failed: Error: 400 the input length exceeds the context length
```
Lower `recallMaxChars`, then restart the Gateway:
```json5
{
plugins: {
entries: {
"memory-lancedb": {
config: {
recallMaxChars: 400,
},
},
},
},
}
```
For Ollama, also verify the embedding server is reachable from the Gateway
host using its native embed endpoint:
```bash
curl http://127.0.0.1:11434/api/embed \
-H "Content-Type: application/json" \
-d '{"model":"mxbai-embed-large","input":"hello"}'
```
### Unsupported embedding model
Without `embedding.dimensions`, only the built-in OpenAI embedding dimensions
are known (`text-embedding-3-small`, `text-embedding-3-large`). For any other
model, set `embedding.dimensions` to the vector size that model reports.
### Plugin loads but no memories appear
Confirm `plugins.slots.memory` points at `memory-lancedb`, then run:
```bash
openclaw ltm stats
openclaw ltm search "recent preference"
```
If `autoCapture` is disabled, the plugin still recalls existing memories but
does not store new ones automatically. Use the `memory_store` tool, or enable
`autoCapture`.
## Related
- [Memory overview](/concepts/memory)
- [Active memory](/concepts/active-memory)
- [Memory search](/concepts/memory-search)
- [Memory Wiki](/plugins/memory-wiki)
- [Ollama](/providers/ollama)

442
docs/plugins/memory-wiki.md Normal file
View File

@@ -0,0 +1,442 @@
---
summary: "memory-wiki: compiled knowledge vault with provenance, claims, dashboards, and bridge mode"
read_when:
- You want persistent knowledge beyond plain MEMORY.md notes
- You are configuring the bundled memory-wiki plugin
- You want to understand wiki_search, wiki_get, or bridge mode
title: "Memory wiki"
---
`memory-wiki` is a bundled plugin that compiles durable knowledge into a
navigable wiki: deterministic pages, structured claims with evidence,
provenance, dashboards, and machine-readable digests.
It does not replace the active memory plugin. Recall, promotion, indexing, and
dreaming stay owned by whichever memory backend is configured
(`memory-core`, QMD, Honcho, etc.). `memory-wiki` sits beside it and compiles
knowledge into a maintained wiki layer.
| Layer | Owns |
| -------------------- | --------------------------------------------------------------------------------- |
| Active memory plugin | Recall, semantic search, promotion, dreaming, memory runtime |
| `memory-wiki` | Compiled wiki pages, provenance-rich syntheses, dashboards, wiki search/get/apply |
Practical rule:
- `memory_search` for one broad recall pass across whatever corpora are configured
- `wiki_search` / `wiki_get` when you want wiki-specific ranking, provenance, or page-level belief structure
- `memory_search corpus=all` to span both layers in one call, when the active memory plugin supports corpus selection
A common local-first setup: QMD as the active memory backend for recall, and
`memory-wiki` in `bridge` mode for durable synthesized pages. See the
QMD + bridge mode example under [Configuration](#configuration).
If bridge mode reports zero exported artifacts, the active memory plugin is
not currently exposing public bridge inputs. Run `openclaw wiki doctor` first,
then confirm the active memory plugin supports public artifacts.
## Vault modes
- `isolated` (default): own vault, own sources, no dependency on the active memory plugin. Use this for a self-contained curated knowledge store.
- `bridge`: reads public memory artifacts and event logs from the active memory plugin through public plugin SDK seams. Use this to compile the memory plugin's exported artifacts without reaching into private plugin internals.
- `unsafe-local`: explicit same-machine escape hatch for local private paths. Intentionally experimental and non-portable; use only when you understand the trust boundary and specifically need local filesystem access bridge mode cannot provide.
Bridge mode can index, per `bridge.*` config toggle:
- exported memory artifacts (`indexMemoryRoot`)
- daily notes (`indexDailyNotes`)
- dream reports (`indexDreamReports`)
- memory event logs (`followMemoryEvents`)
When bridge mode is active and `bridge.readMemoryArtifacts` is enabled,
`openclaw wiki status`, `openclaw wiki doctor`, and `openclaw wiki bridge
import` route through the running Gateway so they see the same active memory
plugin context as agent/runtime memory. If bridge is disabled or artifact
reads are off, those commands keep local/offline behavior.
## Vault layout
```text
<vault>/
AGENTS.md
WIKI.md
index.md
inbox.md
entities/
concepts/
syntheses/
sources/
reports/
_attachments/
_views/
.openclaw-wiki/
```
Managed content stays inside generated blocks; human note blocks are
preserved across regeneration.
- `sources/`: imported raw material and bridge/unsafe-local-backed pages
- `entities/`: durable things, people, systems, projects, objects
- `concepts/`: ideas, abstractions, patterns, policies (also the landing spot for OKF imports)
- `syntheses/`: compiled summaries and maintained rollups
- `reports/`: generated dashboards
## Open Knowledge Format imports
```bash
openclaw wiki okf import ./bundles/ga4
```
Import an unpacked Open Knowledge Format bundle into wiki concept pages. Good
fit when a data catalog, documentation crawler, or enrichment agent already
produces OKF: keep OKF as the portable exchange artifact, let `memory-wiki`
turn it into OpenClaw-native concept pages and compiled digests.
- non-reserved `.md` files are concept documents
- each imported concept requires a non-empty `type` frontmatter field; missing `type` produces a `missing-type` warning and the file is skipped
- unknown `type` values are accepted as generic concepts
- `index.md` and `log.md` are reserved and never imported as concepts
- broken or external markdown links are left unchanged
Imported pages flatten under `concepts/` so existing compile, search, get, and
dashboard flows see them without a second wiki tree. Each page keeps the
original OKF concept ID, source path, `type`, `resource`, `tags`, timestamp,
and full producer frontmatter. Internal OKF links rewrite to the generated
wiki concept pages and also emit structured `relationships` entries with
`kind: okf-link`.
## Structured claims and evidence
Pages carry structured `claims` frontmatter, not just freeform text. Each
claim can include `id`, `text`, `status`, `confidence`, `evidence[]`, and
`updatedAt`. Each evidence entry can include `kind`, `sourceId`, `path`,
`lines`, `weight`, `confidence`, `privacyTier`, `note`, and `updatedAt`.
This makes the wiki behave like a belief layer, not a passive note dump.
Claims can be tracked, scored, contested, and resolved back to sources.
## Agent-facing entity metadata
Entity pages carry generic routing metadata usable for people, teams,
systems, projects, or any other entity type:
- `entityType`: for example `person`, `team`, `system`, `project`
- `canonicalId`: stable identity key across aliases and imports
- `aliases`: names, handles, or labels that resolve to the same page
- `privacyTier`: free-form string; `public` is treated as no-review, any other value (for example `local-private`, `sensitive`, `confirm-before-use`) is flagged in `reports/privacy-review.md`
- `bestUsedFor` / `notEnoughFor`: compact routing hints
- `lastRefreshedAt`: source-refresh timestamp, separate from page edit time
- `personCard`: optional person-specific routing card (handles, socials, emails, timezone, lane, ask-for, avoid-asking-for, confidence, privacy tier)
- `relationships`: typed edges to related pages (target, kind, weight, confidence, evidence kind, privacy tier, note)
For a people wiki, start with `reports/person-agent-directory.md`, then open
the person page with `wiki_get` before using contact details or inferred
facts.
<Accordion title="Entity page example">
```yaml
pageType: entity
entityType: person
id: entity.example-person
canonicalId: maintainer.example-person
aliases:
- Alex
- example-handle
privacyTier: local-private
bestUsedFor:
- Example ecosystem routing
notEnoughFor:
- legal approval
lastRefreshedAt: "2026-04-29T00:00:00.000Z"
personCard:
handles:
- "@example-handle"
socials:
- "https://x.example/example-handle"
emails:
- alex@example.com
timezone: America/Chicago
lane: Example ecosystem
askFor:
- Example rollout questions
avoidAskingFor:
- unrelated billing decisions
confidence: 0.8
privacyTier: confirm-before-use
relationships:
- targetId: entity.other-person
targetTitle: Other Person
kind: collaborates-with
confidence: 0.7
evidenceKind: discrawl-stat
claims:
- id: claim.example.routing
text: Alex is useful for example-ecosystem routing.
status: supported
confidence: 0.9
evidence:
- kind: maintainer-whois
sourceId: source.maintainers
privacyTier: local-private
```
</Accordion>
## Compile pipeline
Compile reads wiki pages, normalizes summaries, and emits stable
machine-facing artifacts under:
- `.openclaw-wiki/cache/agent-digest.json`
- `.openclaw-wiki/cache/claims.jsonl`
Agents and runtime code read these digests instead of scraping Markdown.
Compiled output also powers first-pass wiki indexing for search/get, claim-id
lookup back to owning pages, compact prompt supplements, and report
generation.
## Dashboards and health reports
When `render.createDashboards` is enabled, compile maintains dashboards under
`reports/`:
| Report | Tracks |
| ----------------------------------- | -------------------------------------------------- |
| `reports/open-questions.md` | pages with unresolved questions |
| `reports/contradictions.md` | contradiction note clusters |
| `reports/low-confidence.md` | low-confidence pages and claims |
| `reports/claim-health.md` | claims missing structured evidence |
| `reports/stale-pages.md` | stale or unknown freshness |
| `reports/person-agent-directory.md` | person/entity routing cards |
| `reports/relationship-graph.md` | structured relationship edges |
| `reports/provenance-coverage.md` | evidence class coverage |
| `reports/privacy-review.md` | non-public privacy tiers needing review before use |
## Search and retrieval
Two search backends:
- `shared`: use the shared memory search flow when available
- `local`: search the wiki locally
Three corpora: `wiki`, `memory`, `all`.
- `wiki_search` / `wiki_get` use compiled digests as a first pass when possible
- claim ids resolve back to the owning page
- contested/stale/fresh claims influence ranking
- provenance labels survive into results
Search modes (`--mode` / tool `mode` param):
| Mode | Boosts |
| ----------------- | -------------------------------------------------------------- |
| `auto` | balanced default |
| `find-person` | person-like entities, aliases, handles, socials, canonical IDs |
| `route-question` | agent cards, ask-for/best-used-for hints, relationship context |
| `source-evidence` | source pages and structured evidence metadata |
| `raw-claim` | matching structured claims; returns claim/evidence metadata |
When a result matches a structured claim, `wiki_search` returns
`matchedClaimId`, `matchedClaimStatus`, `matchedClaimConfidence`,
`evidenceKinds`, and `evidenceSourceIds` in its details payload. Text output
includes compact `Claim:` and `Evidence:` lines when available.
## Agent tools
| Tool | Purpose |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `wiki_status` | current vault mode, health, Obsidian CLI availability |
| `wiki_search` | search wiki pages and, when configured, the shared memory corpus; accepts `mode` for person lookup, question routing, source evidence, or raw claim drilldown |
| `wiki_get` | read a wiki page by id/path, falling back to the shared memory corpus when shared search is enabled and the lookup misses |
| `wiki_apply` | narrow synthesis/metadata mutations without freeform page surgery |
| `wiki_lint` | structural checks, provenance gaps, contradictions, open questions |
The plugin also registers a non-exclusive memory corpus supplement, so shared
`memory_search` and `memory_get` can reach the wiki when the active memory
plugin supports corpus selection.
## Prompt and context behavior
When `context.includeCompiledDigestPrompt` is enabled, memory prompt sections
append a compact compiled snapshot from `agent-digest.json`: top pages only,
top claims only, contradiction count, question count, confidence/freshness
qualifiers. This is opt-in because it changes prompt shape; it mainly matters
for context engines or prompt assembly that explicitly consume memory
supplements.
## Configuration
Put config under `plugins.entries.memory-wiki.config`:
```json5
{
plugins: {
entries: {
"memory-wiki": {
enabled: true,
config: {
vaultMode: "isolated",
vault: {
path: "~/.openclaw/wiki/main",
renderMode: "obsidian",
},
obsidian: {
enabled: true,
useOfficialCli: true,
vaultName: "OpenClaw Wiki",
openAfterWrites: false,
},
bridge: {
enabled: false,
readMemoryArtifacts: true,
indexDreamReports: true,
indexDailyNotes: true,
indexMemoryRoot: true,
followMemoryEvents: true,
},
unsafeLocal: {
allowPrivateMemoryCoreAccess: false,
paths: [],
},
ingest: {
autoCompile: true,
maxConcurrentJobs: 1,
allowUrlIngest: true,
},
search: {
backend: "shared",
corpus: "wiki",
},
context: {
includeCompiledDigestPrompt: false,
},
render: {
preserveHumanBlocks: true,
createBacklinks: true,
createDashboards: true,
},
},
},
},
},
}
```
Key toggles:
| Key | Values / default | Notes |
| ------------------------------------------ | ---------------------------------------------- | -------------------------------------------------------- |
| `vaultMode` | `isolated` (default), `bridge`, `unsafe-local` | |
| `vault.path` | default `~/.openclaw/wiki/main` | |
| `vault.renderMode` | `native` (default), `obsidian` | |
| `bridge.readMemoryArtifacts` | default `true` | import active memory plugin public artifacts |
| `bridge.followMemoryEvents` | default `true` | include event logs in bridge mode |
| `unsafeLocal.allowPrivateMemoryCoreAccess` | default `false` | required to run `unsafe-local` imports |
| `unsafeLocal.paths` | default `[]` | explicit local paths to import in `unsafe-local` mode |
| `search.backend` | `shared` (default), `local` | |
| `search.corpus` | `wiki` (default), `memory`, `all` | |
| `context.includeCompiledDigestPrompt` | default `false` | append compact digest snapshot to memory prompt sections |
| `render.createBacklinks` | default `true` | generate deterministic related blocks |
| `render.createDashboards` | default `true` | generate dashboard pages |
### Example: QMD + bridge mode
Use this when you want QMD for recall and `memory-wiki` for a maintained
knowledge layer. Each layer stays focused: QMD keeps raw notes, session
exports, and extra collections searchable, while `memory-wiki` compiles
stable entities, claims, dashboards, and source pages.
```json5
{
memory: {
backend: "qmd",
},
plugins: {
entries: {
"memory-wiki": {
enabled: true,
config: {
vaultMode: "bridge",
bridge: {
enabled: true,
readMemoryArtifacts: true,
indexDreamReports: true,
indexDailyNotes: true,
indexMemoryRoot: true,
followMemoryEvents: true,
},
search: {
backend: "shared",
corpus: "all",
},
context: {
includeCompiledDigestPrompt: false,
},
},
},
},
},
}
```
This keeps QMD in charge of active memory recall, `memory-wiki` focused on
compiled pages and dashboards, and prompt shape unchanged until you
intentionally enable compiled digest prompts.
## CLI
```bash
openclaw wiki status
openclaw wiki doctor
openclaw wiki init
openclaw wiki ingest ./notes/alpha.md
openclaw wiki compile
openclaw wiki lint
openclaw wiki search "alpha"
openclaw wiki get entity.alpha
openclaw wiki apply synthesis "Alpha Summary" --body "..." --source-id source.alpha
openclaw wiki bridge import
openclaw wiki obsidian status
```
See [CLI: wiki](/cli/wiki) for the full command reference, including
`wiki okf import`, `wiki apply metadata`, `wiki unsafe-local import`,
`wiki chatgpt import` / `wiki chatgpt rollback`, and the full `wiki obsidian`
subcommand set.
## Obsidian support
When `vault.renderMode` is `obsidian`, the plugin writes Obsidian-friendly
Markdown and can optionally use the official `obsidian` CLI for status
probing, vault search, opening a page, invoking a command, and jumping to the
daily note. This is optional; the wiki still works in native mode without
Obsidian.
## Recommended workflow
<Steps>
<Step title="Keep the active memory plugin for recall">
Recall, promotion, and dreaming stay owned by the configured memory backend.
</Step>
<Step title="Enable memory-wiki">
Start with `isolated` mode unless you explicitly want bridge mode.
</Step>
<Step title="Use wiki_search / wiki_get when provenance matters">
Prefer these over `memory_search` when you want wiki-specific ranking or page-level belief structure.
</Step>
<Step title="Use wiki_apply for narrow syntheses or metadata updates">
Avoid hand-editing managed generated blocks.
</Step>
<Step title="Run wiki_lint after meaningful changes">
Catches contradictions, open questions, and provenance gaps.
</Step>
<Step title="Turn on dashboards for stale/contradiction visibility">
Set `render.createDashboards: true` (default).
</Step>
</Steps>
## Related docs
- [Memory Overview](/concepts/memory)
- [CLI: memory](/cli/memory)
- [CLI: wiki](/cli/wiki)
- [Plugin SDK overview](/plugins/sdk-overview)

View File

@@ -0,0 +1,520 @@
---
summary: "Semantic message cards, buttons, selects, fallback text, and delivery hints for channel plugins"
title: "Message presentation"
read_when:
- Adding or modifying message card, button, or select rendering
- Building a channel plugin that supports rich outbound messages
- Changing message tool presentation or delivery capabilities
- Debugging provider-specific card/block/component rendering regressions
---
Message presentation is OpenClaw's shared contract for rich outbound chat UI.
It lets agents, CLI commands, approval flows, and plugins describe the message
intent once, while each channel plugin renders the best native shape it can.
Use presentation for portable message UI: text sections, small context/footer
text, dividers, buttons, select menus, and card title/tone.
Do not add new provider-native fields such as Discord `components`, Slack
`blocks`, Telegram `buttons`, Teams `card`, or Feishu `card` to the shared
message tool. Those are renderer outputs owned by the channel plugin.
## Contract
Plugin authors import the public contract from:
```ts
import type {
MessagePresentation,
ReplyPayloadDelivery,
} from "openclaw/plugin-sdk/interactive-runtime";
```
Shape:
```ts
type MessagePresentation = {
title?: string;
tone?: "neutral" | "info" | "success" | "warning" | "danger";
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };
type MessagePresentationAction =
| { type: "command"; command: string }
| { type: "callback"; value: string };
type MessagePresentationButton = {
label: string;
action?: MessagePresentationAction;
/** Legacy callback value. Prefer action for new controls. */
value?: string;
url?: string;
webApp?: { url: string };
/** @deprecated Use webApp. Accepted for legacy JSON payloads only. */
web_app?: { url: string };
priority?: number;
disabled?: boolean;
reusable?: boolean;
style?: "primary" | "secondary" | "success" | "danger";
};
type MessagePresentationOption = {
label: string;
action?: MessagePresentationAction;
/** Legacy callback value. Prefer action for new controls. */
value?: string;
};
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
```
Button semantics:
- `action.type: "command"` runs a native slash command through core's command
path. Use this for built-in command buttons and menus.
- `action.type: "callback"` carries opaque plugin data through the channel's
interaction path. Channel plugins must not reinterpret callback data as slash
commands.
- `value` is the legacy opaque callback value. New controls should use `action`
so channel plugins can map commands and callbacks without guessing from text.
- `url` is a link button. It can exist without `value`.
- `webApp` describes a channel-native web app button. Telegram renders this
as `web_app` and only supports it in private chats. `web_app` is still
accepted in loose JSON payloads for compatibility, but TypeScript producers
should use `webApp`.
- `label` is required and is also used in text fallback.
- `style` is advisory. Renderers should map unsupported styles to a safe
default, not fail the send.
- `priority` is optional. When a channel advertises action limits and controls
must be dropped, core keeps higher-priority buttons first and preserves
original order among equal priority buttons. When all controls fit, authored
order is preserved.
- `disabled` is optional. Channels must opt in with `supportsDisabled`; otherwise
core degrades the disabled control to non-interactive fallback text. A
disabled button always renders label-only in fallback text, even when it
carries a `command` action.
- `reusable` is optional. Channels that support reusable native callbacks may
keep the action available after a successful interaction. Use it for
repeatable or idempotent actions such as refresh, inspect, or more details;
leave it unset for normal one-shot approvals and destructive actions.
Select semantics:
- `options[].action` has the same command/callback meaning as button `action`.
- `options[].value` is the legacy selected application value.
- `placeholder` is advisory and may be ignored by channels without native
select support.
- If a channel does not support selects, fallback text lists the labels.
## Producer examples
Simple card:
```json
{
"title": "Deploy approval",
"tone": "warning",
"blocks": [
{ "type": "text", "text": "Canary is ready to promote." },
{ "type": "context", "text": "Build 1234, staging passed." },
{
"type": "buttons",
"buttons": [
{ "label": "Approve", "value": "deploy:approve", "style": "success" },
{ "label": "Decline", "value": "deploy:decline", "style": "danger" }
]
}
]
}
```
URL-only link button:
```json
{
"blocks": [
{ "type": "text", "text": "Release notes are ready." },
{
"type": "buttons",
"buttons": [{ "label": "Open notes", "url": "https://example.com/release" }]
}
]
}
```
Telegram Mini App button:
```json
{
"blocks": [
{
"type": "buttons",
"buttons": [{ "label": "Launch", "web_app": { "url": "https://example.com/app" } }]
}
]
}
```
Select menu:
```json
{
"title": "Choose environment",
"blocks": [
{
"type": "select",
"placeholder": "Environment",
"options": [
{ "label": "Canary", "value": "env:canary" },
{ "label": "Production", "value": "env:prod" }
]
}
]
}
```
CLI send:
```bash
openclaw message send --channel slack \
--target channel:C123 \
--message "Deploy approval" \
--presentation '{"title":"Deploy approval","tone":"warning","blocks":[{"type":"text","text":"Canary is ready."},{"type":"buttons","buttons":[{"label":"Approve","value":"deploy:approve","style":"success"},{"label":"Decline","value":"deploy:decline","style":"danger"}]}]}'
```
Pinned delivery:
```bash
openclaw message send --channel telegram \
--target -1001234567890 \
--message "Topic opened" \
--pin
```
Pinned delivery with explicit JSON:
```json
{
"pin": {
"enabled": true,
"notify": true,
"required": false
}
}
```
## Renderer contract
Channel plugins declare render support on their outbound adapter:
```ts
const adapter: ChannelOutboundAdapter = {
deliveryMode: "direct",
presentationCapabilities: {
supported: true,
buttons: true,
selects: true,
context: true,
divider: true,
limits: {
actions: {
maxActions: 25,
maxActionsPerRow: 5,
maxRows: 5,
maxLabelLength: 80,
maxValueBytes: 100,
supportsStyles: true,
supportsDisabled: false,
},
selects: {
maxOptions: 25,
maxLabelLength: 100,
maxValueBytes: 100,
},
text: {
maxLength: 2000,
encoding: "characters",
markdownDialect: "discord-markdown",
},
},
},
deliveryCapabilities: {
pin: true,
},
renderPresentation({ payload, presentation, ctx }) {
return renderNativePayload(payload, presentation, ctx);
},
async pinDeliveredMessage({ target, messageId, pin }) {
await pinNativeMessage(target, messageId, { notify: pin.notify === true });
},
};
```
Capability booleans describe what the renderer can make interactive. Optional
`limits` describe the generic envelope core can adapt before calling the
renderer:
```ts
type ChannelPresentationCapabilities = {
supported?: boolean;
buttons?: boolean;
selects?: boolean;
context?: boolean;
divider?: boolean;
limits?: {
actions?: {
maxActions?: number;
maxActionsPerRow?: number;
maxRows?: number;
maxLabelLength?: number;
maxValueBytes?: number;
supportsStyles?: boolean;
supportsDisabled?: boolean;
supportsLayoutHints?: boolean;
};
selects?: {
maxOptions?: number;
maxLabelLength?: number;
maxValueBytes?: number;
};
text?: {
maxLength?: number;
encoding?: "characters" | "utf8-bytes" | "utf16-units";
markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown";
supportsEdit?: boolean;
};
};
};
```
Core applies generic limits to semantic controls before rendering. Renderers
still own final provider-specific validation and clipping for native block
count, card size, URL limits, and provider quirks that cannot be expressed in
the generic contract. If limits remove every control from a block, core keeps
the labels as non-interactive context text so the delivered message still has a
visible fallback.
## Core render flow
When a `ReplyPayload` or message action includes `presentation`, core:
1. Normalizes the presentation payload.
2. Resolves the target channel's outbound adapter.
3. Reads `presentationCapabilities`.
4. Applies generic capability limits such as action count, label length, and
select option count when the adapter advertises them.
5. Calls `renderPresentation` when the adapter can render the payload.
6. Falls back to conservative text when the adapter is absent or cannot render.
7. Sends the resulting payload through the normal channel delivery path.
8. Applies delivery metadata such as `delivery.pin` after the first successful
sent message.
Core owns fallback behavior so producers can stay channel-agnostic. Channel
plugins own native rendering and interaction handling.
## Degradation rules
Presentation must be safe to send on limited channels.
Fallback text includes:
- `title` as the first line
- `text` blocks as normal paragraphs
- `context` blocks as compact context lines
- `divider` blocks as a visual separator
- button labels, including URLs for link buttons
- select option labels
### Button value fallback visibility
When a channel cannot render interactive controls, button and select values
fall back to plain text. The fallback behavior preserves usability while
keeping opaque callback data private:
- **`command`-typed actions** render as `label: \`command\`` so users can
copy the command and run it manually in the channel input.
- **`callback`-typed actions** and legacy **`value`** fields render as
label-only. The opaque callback value is not exposed in fallback text.
- **`url` / `webApp`** buttons render the URL text alongside the button
label, since the URL is user-facing.
- **Select options** render as label-only. The underlying option value is not
exposed in fallback text.
Channel adapters that add manual-command guidance in their fallback UI (e.g.
Feishu document-comment instructions) must derive the command-present check
from the same presentation blocks that the fallback renderer uses, so the
guidance text only appears when a manual command is actually shown.
Unsupported native controls should degrade rather than fail the whole send.
Examples:
- Telegram with inline buttons disabled sends text fallback.
- A channel without select support lists select options as text.
- A URL-only button becomes either a native link button or a fallback URL line.
- Optional pin failures do not fail the delivered message.
The main exception is `delivery.pin.required: true`; if pinning is requested as
required and the channel cannot pin the sent message, delivery reports failure.
## Provider mapping
Current bundled renderers:
| Channel | Native render target | Notes |
| --------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Discord | Components and component containers | Preserves legacy `channelData.discord.components` for existing provider-native payload producers, but new shared sends should use `presentation`. |
| Feishu | Interactive cards | Card header can use `title`; body avoids duplicating that title. |
| Matrix | Text fallback plus structured event field | Buttons/selects advertise as supported, but every block currently renders as `renderMessagePresentationFallbackText` output carried in a `com.openclaw.presentation` event field, not native interactive widgets. |
| Mattermost | Text plus interactive props | Selects and dividers are not supported; those blocks degrade to text. |
| Microsoft Teams | Adaptive Cards | Plain `message` text is included with the card when both are provided. Selects, styles, and disabled state are not supported. |
| Slack | Block Kit | Preserves legacy `channelData.slack.blocks` for existing provider-native payload producers, but new shared sends should use `presentation`. |
| Telegram | Text plus inline keyboards | Buttons/selects require inline button capability for the target surface; otherwise text fallback is used. |
| Plain channels | Text fallback | Channels without a renderer still get readable output. |
Provider-native payload compatibility is a transition affordance for existing
reply producers. It is not a reason to add new shared native fields.
## Presentation vs InteractiveReply
`InteractiveReply` is the older internal subset used by approval and interaction
helpers. It supports:
- text
- buttons
- selects
`MessagePresentation` is the canonical shared send contract. It adds:
- title
- tone
- context
- divider
- URL-only buttons
- generic delivery metadata through `ReplyPayload.delivery`
Use helpers from `openclaw/plugin-sdk/interactive-runtime` when bridging older
code:
```ts
import {
adaptMessagePresentationForChannel,
applyPresentationActionLimits,
hasMessagePresentationBlocks,
interactiveReplyToPresentation,
isMessagePresentationInteractiveBlock,
normalizeMessagePresentation,
presentationPageSize,
presentationToInteractiveControlsReply,
presentationToInteractiveReply,
renderMessagePresentationFallbackText,
resolveMessagePresentationActionValue,
resolveMessagePresentationControlValue,
} from "openclaw/plugin-sdk/interactive-runtime";
```
New code should accept or produce `MessagePresentation` directly. Existing
`interactive` payloads are a deprecated subset of `presentation`; runtime
support remains for older producers.
Non-deprecated helpers worth knowing:
- `normalizeMessagePresentation(raw)` / `hasMessagePresentationBlocks(value)`
validate and coerce an untyped payload (for example, JSON from the CLI
`--presentation` flag) into `MessagePresentation`.
- `isMessagePresentationInteractiveBlock(block)` narrows a block to the
`buttons` | `select` union.
- `resolveMessagePresentationActionValue(action)` /
`resolveMessagePresentationControlValue(control)` read the effective
command/callback value off an `action`, falling back to the legacy `value`
field for `resolveMessagePresentationControlValue`.
The legacy `InteractiveReply*` types and conversion helpers are marked
`@deprecated` in the SDK:
- `InteractiveReply`, `InteractiveReplyBlock`, `InteractiveReplyButton`,
`InteractiveReplyOption`, `InteractiveReplySelectBlock`, and
`InteractiveReplyTextBlock`
- `normalizeInteractiveReply(...)`
- `hasInteractiveReplyBlocks(...)`
- `interactiveReplyToPresentation(...)`
- `presentationToInteractiveReply(...)`
- `presentationToInteractiveControlsReply(...)`
- `resolveInteractiveTextFallback(...)`
- `reduceInteractiveReply(...)`
`presentationToInteractiveReply(...)` and
`presentationToInteractiveControlsReply(...)` remain available as renderer
bridges for legacy channel implementations. New producer code should not call
them; send `presentation` and let core/channel adaptation handle rendering.
Approval helpers also have presentation-first replacements:
- use `buildApprovalPresentationFromActionDescriptors(...)` instead of
`buildApprovalInteractiveReplyFromActionDescriptors(...)`
- use `buildApprovalPresentation(...)` instead of
`buildApprovalInteractiveReply(...)`
- use `buildExecApprovalPresentation(...)` instead of
`buildExecApprovalInteractiveReply(...)`
`renderMessagePresentationFallbackText(...)` returns an empty string for
presentation blocks that have no text fallback, such as a divider-only
presentation. Transports that require a non-empty send body can pass
`emptyFallback` to opt into a minimal body without changing the default fallback
contract.
## Delivery pin
Pinning is delivery behavior, not presentation. Use `delivery.pin` instead of
provider-native fields such as `channelData.telegram.pin`.
Semantics:
- `pin: true` pins the first successfully delivered message.
- `pin.notify` defaults to `false`.
- `pin.required` defaults to `false`.
- Optional pin failures degrade and leave the sent message intact.
- Required pin failures fail delivery.
- Chunked messages pin the first delivered chunk, not the tail chunk.
Manual `pin`, `unpin`, and `pins` message actions still exist for existing
messages where the provider supports those operations.
## Plugin author checklist
- Declare `presentation` from `describeMessageTool(...)` when the channel can
render or safely degrade semantic presentation.
- Add `presentationCapabilities` to the runtime outbound adapter.
- Implement `renderPresentation` in runtime code, not control-plane plugin
setup code.
- Keep native UI libraries out of hot setup/catalog paths.
- Declare generic capability limits on `presentationCapabilities.limits` when
they are known.
- Preserve final platform limits in the renderer and tests.
- Add fallback tests for unsupported buttons, selects, URL buttons, title/text
duplication, and mixed `message` plus `presentation` sends.
- Add delivery pin support through `deliveryCapabilities.pin` and
`pinDeliveredMessage` only when the provider can pin the sent message id.
- Do not expose new provider-native card/block/component/button fields through
the shared message action schema.
## Related docs
- [Message CLI](/cli/message)
- [Plugin SDK Overview](/plugins/sdk-overview)
- [Plugin Architecture](/plugins/architecture-internals#message-tool-schemas)
- [Channel Presentation Refactor Plan](/plan/ui-channels)

168
docs/plugins/oc-path.md Normal file
View File

@@ -0,0 +1,168 @@
---
summary: "Bundled `oc-path` plugin: ships the `openclaw path` CLI for the `oc://` workspace-file addressing scheme"
read_when:
- You want to inspect or edit a single leaf inside a workspace file from the terminal
- You are scripting against workspace state and need a stable, kind-agnostic addressing scheme
- You are deciding whether to enable the optional `oc-path` plugin on a self-hosted Gateway
title: "OC Path plugin"
---
The bundled `oc-path` plugin adds the [`openclaw path`](/cli/path) CLI for the
`oc://` workspace-file addressing scheme. It ships in the OpenClaw repo under
`extensions/oc-path/` but is opt-in: install/build leaves it dormant until you
enable it.
`oc://` addresses point at a single leaf (or a wildcard set of leaves) inside
a workspace file. The plugin understands four file kinds:
- **markdown** (`.md`): frontmatter, sections, items, fields
- **jsonc** (`.jsonc`, `.json`): comments and formatting preserved
- **jsonl** (`.jsonl`, `.ndjson`): line-oriented records
- **yaml** (`.yaml`, `.yml`, `.lobster`): map/sequence/scalar nodes through the
`yaml` package's `Document` API
Self-hosters and editor extensions use the CLI to read or write a single leaf
without scripting against the SDK directly; agents and hooks treat it as a
deterministic substrate so byte-fidelity round-trips and the redaction
sentinel guard apply uniformly across kinds. See the
[CLI reference](/cli/path) for the full grammar, verb-by-verb flag list, and
worked examples per file kind; this page covers why and how to enable the
plugin.
## Why enable it
Enable `oc-path` when scripts, hooks, or local agent tooling need to point at
a precise piece of workspace state without a bespoke parser per file shape. A
single `oc://` address can name a markdown frontmatter key, a section item, a
JSONC config leaf, a JSONL event field, or a YAML workflow step.
That matters for maintainer workflows where the change should stay small,
auditable, and repeatable: inspect one value, find matching records, dry-run
a write, then apply only that leaf while leaving comments, line endings, and
nearby formatting alone.
Common reasons to enable it:
- **Local automation**: shell scripts resolve or update one workspace value
with `openclaw path … --json` instead of carrying separate markdown, JSONC,
JSONL, and YAML parsing code.
- **Agent-visible edits**: an agent shows a dry-run diff for one addressed
leaf before writing, which is easier to review than a free-form file
rewrite.
- **Editor integrations**: an editor maps `oc://AGENTS.md/tools/gh` to the
exact markdown node and line number without guessing from heading text.
- **Diagnostics**: `emit` round-trips a file through the parser and emitter,
so you can check whether a file kind is byte-stable before relying on
automated edits.
```bash
# Is the GitHub plugin enabled in this config?
openclaw path resolve 'oc://config.jsonc/plugins/github/enabled' --json
# Which tool-call names appear in this session log?
openclaw path find 'oc://session.jsonl/[event=tool_call]/name' --json
# What bytes would this tiny config edit write?
openclaw path set 'oc://config.jsonc/plugins/github/enabled' 'true' --dry-run
```
`oc-path` is intentionally not the owner of higher-level semantics. Memory
plugins still own memory writes, config commands still own full config
management, and last-known-good (LKG) config recovery still owns
restore/promotion. `oc-path` is the narrow addressing and byte-preserving
file operation layer those higher-level tools can build around.
## Where it runs
The plugin runs **in-process inside the `openclaw` CLI** on the host where you
invoke the command. It does not need a running Gateway and does not open any
network sockets; every verb is a pure transform over a file you point it at.
Plugin metadata lives in `extensions/oc-path/openclaw.plugin.json`:
```json
{
"id": "oc-path",
"name": "OC Path",
"activation": {
"onStartup": false,
"onCommands": ["path"]
},
"commandAliases": [{ "name": "path", "kind": "cli" }]
}
```
`onStartup: false` keeps the plugin out of the Gateway startup path.
`commandAliases` and `activation.onCommands` tell the CLI to load the plugin
lazily the first time you run `openclaw path …`, so installs that never use
the verb pay no cost.
## Enable
```bash
openclaw plugins enable oc-path
```
Restart the Gateway (if you run one) so the manifest snapshot picks up the new
state. Bare `openclaw path` invocations work immediately on the same host;
the CLI loads the plugin on demand.
Disable with:
```bash
openclaw plugins disable oc-path
```
## Dependencies
All parser dependencies are plugin-local; enabling `oc-path` does not pull
new packages into the core runtime:
| Dependency | Purpose |
| -------------- | ---------------------------------------------------------------------- |
| `commander` | Subcommand wiring for `resolve`, `find`, `set`, `validate`, `emit`. |
| `jsonc-parser` | JSONC parse and leaf edits with comments and trailing commas kept. |
| `markdown-it` | Markdown tokenization for the section / item / field model. |
| `yaml` | YAML `Document` parse / emit / edit with comments and flow style kept. |
JSONL stays hand-rolled: line-oriented parsing is simpler than any
dependency, and the per-line parse already goes through `jsonc-parser`.
## What it provides
| Surface | Provided by |
| ------------------------------ | ------------------------------------------------------- |
| `openclaw path` CLI | `extensions/oc-path/cli-registration.ts` |
| `oc://` parser / formatter | `extensions/oc-path/src/oc-path/oc-path.ts` |
| Per-kind parse / emit / edit | `extensions/oc-path/src/oc-path/{md,jsonc,jsonl,yaml}` |
| Universal resolve / find / set | `extensions/oc-path/src/oc-path/{resolve,find,edit}.ts` |
| Redaction-sentinel guard | `extensions/oc-path/src/oc-path/sentinel.ts` |
The CLI is the only public surface today. The substrate verbs are private to
the plugin; consumers use the CLI (or build their own plugin against the
SDK).
## Relationship to other plugins
- **`memory-*`**: memory writes go through the memory plugins, not
`oc-path`. `oc-path` is a generic file substrate; memory plugins layer
their own semantics on top.
- **LKG**: `path` does not know about last-known-good config restore. If a
file you edit through `path` is also LKG-tracked, the next config observe
cycle decides whether to promote or recover it; treat a `path` edit the
same as any other direct write to that file.
## Safety
`set` writes raw bytes through the substrate's emit path, which applies the
redaction-sentinel guard automatically. A leaf carrying
`__OPENCLAW_REDACTED__` (verbatim or as a substring) is refused at write time
with `OC_EMIT_SENTINEL`. The CLI also scrubs the literal sentinel from any
human or JSON output it prints, replacing it with `[REDACTED]` so terminal
captures and pipelines never leak the marker.
## Related
- [`openclaw path` CLI reference](/cli/path)
- [Manage plugins](/plugins/manage-plugins)
- [Building plugins](/plugins/building-plugins)

View File

@@ -0,0 +1,324 @@
---
summary: "Generated inventory of OpenClaw plugins shipped in core, published externally, or kept source-only"
read_when:
- You are deciding whether a plugin ships in the core npm package or installs separately
- You are updating bundled plugin package metadata or release automation
- You need the canonical internal vs external plugin list
title: "Plugin inventory"
---
# Plugin inventory
This page is generated from `extensions/*/package.json`, `openclaw.plugin.json`,
and the root npm package `files` exclusions. Regenerate it with:
```bash
pnpm plugins:inventory:gen
```
## Definitions
- **Core npm package:** built into the `openclaw` npm package and available without a separate plugin install.
- **Official external package:** OpenClaw-maintained plugin omitted from the core npm package, kept in this official inventory, and installed on demand through ClawHub and/or npm.
- **Source checkout only:** repo-local plugin omitted from published npm artifacts and not advertised as an installable package.
Source checkouts are different from npm installs: after `pnpm install`, bundled
plugins load from `extensions/<id>` so local edits and package-local workspace
dependencies are available.
## Install a plugin
Use the install route in each entry to decide whether install is needed. Plugins
that say `included in OpenClaw` are already present in the core package.
Official external packages need one install, then a Gateway restart.
For example, Discord is an official external package:
```bash
openclaw plugins install @openclaw/discord
openclaw gateway restart
openclaw plugins inspect discord --runtime --json
```
During the launch cutover, ordinary bare package specs still install from npm.
Use `clawhub:@openclaw/discord` or `npm:@openclaw/discord` when you need an
explicit source. After install, follow the plugin's setup doc, such as
[Discord](/channels/discord), to add credentials and channel config. See
[Manage plugins](/plugins/manage-plugins) for update, uninstall, and publishing
commands.
Each entry lists the package, distribution route, and description.
## Core npm package
60 plugins
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
- **[alibaba](/plugins/reference/alibaba)** (`@openclaw/alibaba-provider`) - included in OpenClaw. Adds video generation provider support.
- **[anthropic](/plugins/reference/anthropic)** (`@openclaw/anthropic-provider`) - included in OpenClaw. Adds Anthropic model provider support to OpenClaw.
- **[azure-speech](/plugins/reference/azure-speech)** (`@openclaw/azure-speech`) - included in OpenClaw. Azure AI Speech text-to-speech (MP3, native Ogg/Opus voice notes, PCM telephony).
- **[bonjour](/plugins/reference/bonjour)** (`@openclaw/bonjour`) - included in OpenClaw. Advertise the local OpenClaw gateway over Bonjour/mDNS.
- **[browser](/plugins/reference/browser)** (`@openclaw/browser-plugin`) - included in OpenClaw. Adds agent-callable tools.
- **[byteplus](/plugins/reference/byteplus)** (`@openclaw/byteplus-provider`) - included in OpenClaw. Adds BytePlus, BytePlus Plan model provider support to OpenClaw.
- **[canvas](/plugins/reference/canvas)** (`@openclaw/canvas-plugin`) - included in OpenClaw. Experimental Canvas control and A2UI rendering surfaces for paired nodes.
- **[clawrouter](/plugins/reference/clawrouter)** (`@openclaw/clawrouter`) - included in OpenClaw. Adds ClawRouter model provider support to OpenClaw.
- **[codex-supervisor](/plugins/reference/codex-supervisor)** (`@openclaw/codex-supervisor`) - included in OpenClaw. Supervise Codex app-server sessions from OpenClaw.
- **[cohere](/plugins/reference/cohere)** (`@openclaw/cohere-provider`) - included in OpenClaw; npm; ClawHub: `clawhub:@openclaw/cohere-provider`. OpenClaw Cohere provider plugin.
- **[comfy](/plugins/reference/comfy)** (`@openclaw/comfy-provider`) - included in OpenClaw. Adds ComfyUI model provider support to OpenClaw.
- **[copilot-proxy](/plugins/reference/copilot-proxy)** (`@openclaw/copilot-proxy`) - included in OpenClaw. Adds Copilot Proxy model provider support to OpenClaw.
- **[deepgram](/plugins/reference/deepgram)** (`@openclaw/deepgram-provider`) - included in OpenClaw. Adds media understanding provider support. Adds realtime transcription provider support.
- **[document-extract](/plugins/reference/document-extract)** (`@openclaw/document-extract-plugin`) - included in OpenClaw. Extract text and fallback page images from local document attachments.
- **[duckduckgo](/plugins/reference/duckduckgo)** (`@openclaw/duckduckgo-plugin`) - included in OpenClaw. Adds web search provider support.
- **[elevenlabs](/plugins/reference/elevenlabs)** (`@openclaw/elevenlabs-speech`) - included in OpenClaw. Adds media understanding provider support. Adds realtime transcription provider support. Adds text-to-speech provider support.
- **[fal](/plugins/reference/fal)** (`@openclaw/fal-provider`) - included in OpenClaw. Adds fal model provider support to OpenClaw.
- **[file-transfer](/plugins/reference/file-transfer)** (`@openclaw/file-transfer`) - included in OpenClaw. Fetch, list, and write files on paired nodes via dedicated node commands. Bypasses bash stdout truncation by using base64 over node.invoke for binaries up to 16 MB.
- **[github-copilot](/plugins/reference/github-copilot)** (`@openclaw/github-copilot-provider`) - included in OpenClaw. Adds GitHub Copilot model provider support to OpenClaw.
- **[google](/plugins/reference/google)** (`@openclaw/google-plugin`) - included in OpenClaw. Adds Google, Google Gemini CLI, Google Vertex model provider support to OpenClaw.
- **[huggingface](/plugins/reference/huggingface)** (`@openclaw/huggingface-provider`) - included in OpenClaw. Adds Hugging Face model provider support to OpenClaw.
- **[imessage](/plugins/reference/imessage)** (`@openclaw/imessage`) - included in OpenClaw. Adds the iMessage channel surface for sending and receiving OpenClaw messages.
- **[litellm](/plugins/reference/litellm)** (`@openclaw/litellm-provider`) - included in OpenClaw. Adds LiteLLM model provider support to OpenClaw.
- **[llm-task](/plugins/reference/llm-task)** (`@openclaw/llm-task`) - included in OpenClaw. Generic JSON-only LLM tool for structured tasks callable from workflows.
- **[lmstudio](/plugins/reference/lmstudio)** (`@openclaw/lmstudio-provider`) - included in OpenClaw. Adds LM Studio model provider support to OpenClaw.
- **[memory-core](/plugins/reference/memory-core)** (`@openclaw/memory-core`) - included in OpenClaw. Adds agent-callable tools.
- **[memory-wiki](/plugins/reference/memory-wiki)** (`@openclaw/memory-wiki`) - included in OpenClaw. Persistent wiki compiler and Obsidian-friendly knowledge vault for OpenClaw.
- **[microsoft](/plugins/reference/microsoft)** (`@openclaw/microsoft-speech`) - included in OpenClaw. Adds text-to-speech provider support.
- **[microsoft-foundry](/plugins/reference/microsoft-foundry)** (`@openclaw/microsoft-foundry`) - included in OpenClaw. Adds Microsoft Foundry model provider support to OpenClaw.
- **[migrate-claude](/plugins/reference/migrate-claude)** (`@openclaw/migrate-claude`) - included in OpenClaw. Imports Claude Code and Claude Desktop instructions, MCP servers, skills, and safe configuration into OpenClaw.
- **[migrate-hermes](/plugins/reference/migrate-hermes)** (`@openclaw/migrate-hermes`) - included in OpenClaw. Imports Hermes configuration, memories, skills, and supported credentials into OpenClaw.
- **[minimax](/plugins/reference/minimax)** (`@openclaw/minimax-provider`) - included in OpenClaw. Adds MiniMax, MiniMax Portal model provider support to OpenClaw.
- **[mistral](/plugins/reference/mistral)** (`@openclaw/mistral-provider`) - included in OpenClaw. Adds Mistral model provider support to OpenClaw.
- **[novita](/plugins/reference/novita)** (`@openclaw/novita-provider`) - included in OpenClaw. Adds Novita, Novita AI, Novitaai model provider support to OpenClaw.
- **[nvidia](/plugins/reference/nvidia)** (`@openclaw/nvidia-provider`) - included in OpenClaw. Adds NVIDIA model provider support to OpenClaw.
- **[oc-path](/plugins/reference/oc-path)** (`@openclaw/oc-path`) - included in OpenClaw. Adds the openclaw path CLI for oc:// workspace file addressing.
- **[ollama](/plugins/reference/ollama)** (`@openclaw/ollama-provider`) - included in OpenClaw. Adds Ollama, Ollama Cloud model provider support to OpenClaw.
- **[open-prose](/plugins/reference/open-prose)** (`@openclaw/open-prose`) - included in OpenClaw. OpenProse VM skill pack with a /prose slash command.
- **[openai](/plugins/reference/openai)** (`@openclaw/openai-provider`) - included in OpenClaw. Adds OpenAI model provider support to OpenClaw.
- **[opencode](/plugins/reference/opencode)** (`@openclaw/opencode-provider`) - included in OpenClaw. Adds OpenCode model provider support to OpenClaw.
- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - included in OpenClaw. Adds OpenCode Go model provider support to OpenClaw.
- **[openrouter](/plugins/reference/openrouter)** (`@openclaw/openrouter-provider`) - included in OpenClaw. Adds OpenRouter model provider support to OpenClaw.
- **[policy](/plugins/reference/policy)** (`@openclaw/policy`) - included in OpenClaw. Adds policy-backed doctor checks for workspace conformance.
- **[runway](/plugins/reference/runway)** (`@openclaw/runway-provider`) - included in OpenClaw. Adds video generation provider support.
- **[senseaudio](/plugins/reference/senseaudio)** (`@openclaw/senseaudio-provider`) - included in OpenClaw. Adds media understanding provider support.
- **[sglang](/plugins/reference/sglang)** (`@openclaw/sglang-provider`) - included in OpenClaw. Adds SGLang model provider support to OpenClaw.
- **[synthetic](/plugins/reference/synthetic)** (`@openclaw/synthetic-provider`) - included in OpenClaw. Adds Synthetic model provider support to OpenClaw.
- **[telegram](/plugins/reference/telegram)** (`@openclaw/telegram`) - included in OpenClaw. Adds the Telegram channel surface for sending and receiving OpenClaw messages.
- **[together](/plugins/reference/together)** (`@openclaw/together-provider`) - included in OpenClaw. Adds Together model provider support to OpenClaw.
- **[tts-local-cli](/plugins/reference/tts-local-cli)** (`@openclaw/tts-local-cli`) - included in OpenClaw. Adds text-to-speech provider support.
- **[vllm](/plugins/reference/vllm)** (`@openclaw/vllm-provider`) - included in OpenClaw. Adds vLLM model provider support to OpenClaw.
- **[volcengine](/plugins/reference/volcengine)** (`@openclaw/volcengine-provider`) - included in OpenClaw. Adds Volcengine, Volcengine Plan model provider support to OpenClaw.
- **[voyage](/plugins/reference/voyage)** (`@openclaw/voyage-provider`) - included in OpenClaw. Adds memory embedding provider support.
- **[vydra](/plugins/reference/vydra)** (`@openclaw/vydra-provider`) - included in OpenClaw. Adds Vydra model provider support to OpenClaw.
- **[web-readability](/plugins/reference/web-readability)** (`@openclaw/web-readability-plugin`) - included in OpenClaw. Extract readable article content from local HTML web fetch responses.
- **[webhooks](/plugins/reference/webhooks)** (`@openclaw/webhooks`) - included in OpenClaw. Authenticated inbound webhooks that bind external automation to OpenClaw TaskFlows.
- **[workboard](/plugins/reference/workboard)** (`@openclaw/workboard`) - included in OpenClaw. Dashboard workboard for agent-owned issues and sessions.
- **[xai](/plugins/reference/xai)** (`@openclaw/xai-plugin`) - included in OpenClaw. Adds xAI model provider support to OpenClaw.
- **[xiaomi](/plugins/reference/xiaomi)** (`@openclaw/xiaomi-provider`) - included in OpenClaw. Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw.
## Official external packages
68 plugins
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
- **[amazon-bedrock](/plugins/reference/amazon-bedrock)** (`@openclaw/amazon-bedrock-provider`) - npm; ClawHub. OpenClaw Amazon Bedrock provider plugin with model discovery, embeddings, and guardrail support.
- **[amazon-bedrock-mantle](/plugins/reference/amazon-bedrock-mantle)** (`@openclaw/amazon-bedrock-mantle-provider`) - npm; ClawHub. OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing.
- **[anthropic-vertex](/plugins/reference/anthropic-vertex)** (`@openclaw/anthropic-vertex-provider`) - npm; ClawHub. OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI.
- **[arcee](/plugins/reference/arcee)** (`@openclaw/arcee-provider`) - npm; ClawHub: `clawhub:@openclaw/arcee-provider`. Adds Arcee model provider support to OpenClaw.
- **[brave](/plugins/reference/brave)** (`@openclaw/brave-plugin`) - npm; ClawHub. OpenClaw Brave Search provider plugin for web search.
- **[cerebras](/plugins/reference/cerebras)** (`@openclaw/cerebras-provider`) - npm; ClawHub: `clawhub:@openclaw/cerebras-provider`. Adds Cerebras model provider support to OpenClaw.
- **[chutes](/plugins/reference/chutes)** (`@openclaw/chutes-provider`) - npm; ClawHub: `clawhub:@openclaw/chutes-provider`. Adds Chutes model provider support to OpenClaw.
- **[clickclack](/plugins/reference/clickclack)** (`@openclaw/clickclack`) - npm; ClawHub: `clawhub:@openclaw/clickclack`. Adds the Clickclack channel surface for sending and receiving OpenClaw messages.
- **[cloudflare-ai-gateway](/plugins/reference/cloudflare-ai-gateway)** (`@openclaw/cloudflare-ai-gateway-provider`) - npm; ClawHub: `clawhub:@openclaw/cloudflare-ai-gateway-provider`. Adds Cloudflare AI Gateway model provider support to OpenClaw.
- **[codex](/plugins/reference/codex)** (`@openclaw/codex`) - npm; ClawHub. OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog.
- **[copilot](/plugins/reference/copilot)** (`@openclaw/copilot`) - npm; ClawHub: `clawhub:@openclaw/copilot`. Registers the GitHub Copilot agent runtime.
- **[deepinfra](/plugins/reference/deepinfra)** (`@openclaw/deepinfra-provider`) - npm; ClawHub: `clawhub:@openclaw/deepinfra-provider`. Adds DeepInfra model provider support to OpenClaw.
- **[deepseek](/plugins/reference/deepseek)** (`@openclaw/deepseek-provider`) - npm; ClawHub: `clawhub:@openclaw/deepseek-provider`. Adds DeepSeek model provider support to OpenClaw.
- **[diagnostics-otel](/plugins/reference/diagnostics-otel)** (`@openclaw/diagnostics-otel`) - npm; ClawHub: `clawhub:@openclaw/diagnostics-otel`. OpenClaw diagnostics OpenTelemetry exporter for metrics, traces, and logs.
- **[diagnostics-prometheus](/plugins/reference/diagnostics-prometheus)** (`@openclaw/diagnostics-prometheus`) - npm; ClawHub: `clawhub:@openclaw/diagnostics-prometheus`. OpenClaw diagnostics Prometheus exporter for runtime metrics.
- **[diffs](/plugins/reference/diffs)** (`@openclaw/diffs`) - npm; ClawHub. OpenClaw read-only diff viewer plugin and file renderer for agents.
- **[diffs-language-pack](/plugins/reference/diffs-language-pack)** (`@openclaw/diffs-language-pack`) - npm; ClawHub: `clawhub:@openclaw/diffs-language-pack`. Adds syntax highlighting for languages outside the default diffs viewer set.
- **[discord](/plugins/reference/discord)** (`@openclaw/discord`) - npm; ClawHub. OpenClaw Discord channel plugin for channels, DMs, commands, and app events.
- **[exa](/plugins/reference/exa)** (`@openclaw/exa-plugin`) - npm; ClawHub: `clawhub:@openclaw/exa-plugin`. Adds web search provider support.
- **[feishu](/plugins/reference/feishu)** (`@openclaw/feishu`) - npm; ClawHub. OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).
- **[firecrawl](/plugins/reference/firecrawl)** (`@openclaw/firecrawl-plugin`) - npm; ClawHub: `clawhub:@openclaw/firecrawl-plugin`. Adds agent-callable tools. Adds web fetch provider support. Adds web search provider support.
- **[fireworks](/plugins/reference/fireworks)** (`@openclaw/fireworks-provider`) - npm; ClawHub: `clawhub:@openclaw/fireworks-provider`. Adds Fireworks model provider support to OpenClaw.
- **[gmi](/plugins/reference/gmi)** (`@openclaw/gmi-provider`) - npm; ClawHub: `clawhub:@openclaw/gmi-provider`. OpenClaw GMI Cloud provider plugin.
- **[google-meet](/plugins/reference/google-meet)** (`@openclaw/google-meet`) - npm; ClawHub. OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.
- **[googlechat](/plugins/reference/googlechat)** (`@openclaw/googlechat`) - npm; ClawHub. OpenClaw Google Chat channel plugin for spaces and direct messages.
- **[gradium](/plugins/reference/gradium)** (`@openclaw/gradium-speech`) - npm; ClawHub: `clawhub:@openclaw/gradium-speech`. Adds text-to-speech provider support.
- **[groq](/plugins/reference/groq)** (`@openclaw/groq-provider`) - npm; ClawHub: `clawhub:@openclaw/groq-provider`. Adds Groq model provider support to OpenClaw.
- **[inworld](/plugins/reference/inworld)** (`@openclaw/inworld-speech`) - npm; ClawHub: `clawhub:@openclaw/inworld-speech`. Inworld streaming text-to-speech (MP3, OGG_OPUS, PCM telephony).
- **[irc](/plugins/reference/irc)** (`@openclaw/irc`) - npm; ClawHub: `clawhub:@openclaw/irc`. Adds the IRC channel surface for sending and receiving OpenClaw messages.
- **[kilocode](/plugins/reference/kilocode)** (`@openclaw/kilocode-provider`) - npm; ClawHub: `clawhub:@openclaw/kilocode-provider`. Adds Kilocode model provider support to OpenClaw.
- **[kimi](/plugins/reference/kimi)** (`@openclaw/kimi-provider`) - npm; ClawHub: `clawhub:@openclaw/kimi-provider`. Adds Kimi, Kimi Coding model provider support to OpenClaw.
- **[line](/plugins/reference/line)** (`@openclaw/line`) - npm; ClawHub. OpenClaw LINE channel plugin for LINE Bot API chats.
- **[llama-cpp](/plugins/reference/llama-cpp)** (`@openclaw/llama-cpp-provider`) - npm; ClawHub. Local GGUF embeddings through node-llama-cpp.
- **[lobster](/plugins/reference/lobster)** (`@openclaw/lobster`) - npm; ClawHub. Lobster workflow tool plugin for typed pipelines and resumable approvals.
- **[matrix](/plugins/reference/matrix)** (`@openclaw/matrix`) - ClawHub: `clawhub:@openclaw/matrix`; npm. OpenClaw Matrix channel plugin for rooms and direct messages.
- **[mattermost](/plugins/reference/mattermost)** (`@openclaw/mattermost`) - npm; ClawHub: `clawhub:@openclaw/mattermost`. Adds the Mattermost channel surface for sending and receiving OpenClaw messages.
- **[memory-lancedb](/plugins/reference/memory-lancedb)** (`@openclaw/memory-lancedb`) - npm; ClawHub. OpenClaw LanceDB-backed long-term memory plugin with auto-recall, auto-capture, and vector search.
- **[moonshot](/plugins/reference/moonshot)** (`@openclaw/moonshot-provider`) - npm; ClawHub: `clawhub:@openclaw/moonshot-provider`. Adds Moonshot model provider support to OpenClaw.
- **[msteams](/plugins/reference/msteams)** (`@openclaw/msteams`) - npm; ClawHub. OpenClaw Microsoft Teams channel plugin for bot conversations.
- **[nextcloud-talk](/plugins/reference/nextcloud-talk)** (`@openclaw/nextcloud-talk`) - npm; ClawHub. OpenClaw Nextcloud Talk channel plugin for conversations.
- **[nostr](/plugins/reference/nostr)** (`@openclaw/nostr`) - npm; ClawHub. OpenClaw Nostr channel plugin for NIP-04 encrypted direct messages.
- **[openshell](/plugins/reference/openshell)** (`@openclaw/openshell-sandbox`) - npm; ClawHub. OpenClaw sandbox backend for the NVIDIA OpenShell CLI with mirrored local workspaces and SSH command execution.
- **[parallel](/tools/parallel-search)** (`@openclaw/parallel-plugin`) - npm; ClawHub: `clawhub:@openclaw/parallel-plugin`. Adds web search provider support.
- **[perplexity](/plugins/reference/perplexity)** (`@openclaw/perplexity-plugin`) - npm; ClawHub: `clawhub:@openclaw/perplexity-plugin`. Adds web search provider support.
- **[pixverse](/plugins/reference/pixverse)** (`@openclaw/pixverse-provider`) - npm; ClawHub: `clawhub:@openclaw/pixverse-provider`. OpenClaw PixVerse video generation provider plugin.
- **[qianfan](/plugins/reference/qianfan)** (`@openclaw/qianfan-provider`) - npm; ClawHub: `clawhub:@openclaw/qianfan-provider`. Adds Qianfan model provider support to OpenClaw.
- **[qqbot](/plugins/reference/qqbot)** (`@openclaw/qqbot`) - npm; ClawHub. OpenClaw QQ Bot channel plugin for group and direct-message workflows.
- **[qwen](/plugins/reference/qwen)** (`@openclaw/qwen-provider`) - npm; ClawHub: `clawhub:@openclaw/qwen-provider`. Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CLI model provider support to OpenClaw.
- **[raft](/plugins/reference/raft)** (`@openclaw/raft`) - npm; ClawHub. OpenClaw Raft channel plugin for secure CLI wake bridges.
- **[searxng](/plugins/reference/searxng)** (`@openclaw/searxng-plugin`) - npm; ClawHub: `clawhub:@openclaw/searxng-plugin`. Adds web search provider support.
- **[signal](/plugins/reference/signal)** (`@openclaw/signal`) - npm; ClawHub: `clawhub:@openclaw/signal`. Adds the Signal channel surface for sending and receiving OpenClaw messages.
- **[slack](/plugins/reference/slack)** (`@openclaw/slack`) - npm; ClawHub. OpenClaw Slack channel plugin for channels, DMs, commands, and app events.
- **[sms](/plugins/reference/sms)** (`@openclaw/sms`) - npm; ClawHub: `clawhub:@openclaw/sms`. Twilio SMS channel plugin for OpenClaw text messages.
- **[stepfun](/plugins/reference/stepfun)** (`@openclaw/stepfun-provider`) - npm; ClawHub: `clawhub:@openclaw/stepfun-provider`. Adds StepFun, StepFun Plan model provider support to OpenClaw.
- **[synology-chat](/plugins/reference/synology-chat)** (`@openclaw/synology-chat`) - npm; ClawHub. Synology Chat channel plugin for OpenClaw channels and direct messages.
- **[tavily](/plugins/reference/tavily)** (`@openclaw/tavily-plugin`) - npm; ClawHub: `clawhub:@openclaw/tavily-plugin`. Adds agent-callable tools. Adds web search provider support.
- **[tencent](/plugins/reference/tencent)** (`@openclaw/tencent-provider`) - npm; ClawHub: `clawhub:@openclaw/tencent-provider`. Adds Tencent TokenHub model provider support to OpenClaw.
- **[tlon](/plugins/reference/tlon)** (`@openclaw/tlon`) - npm; ClawHub. OpenClaw Tlon/Urbit channel plugin for chat workflows.
- **[tokenjuice](/plugins/reference/tokenjuice)** (`@openclaw/tokenjuice`) - npm; ClawHub: `clawhub:@openclaw/tokenjuice`. Compacts exec and bash tool results with tokenjuice reducers.
- **[twitch](/plugins/reference/twitch)** (`@openclaw/twitch`) - npm; ClawHub. OpenClaw Twitch channel plugin for chat and moderation workflows.
- **[venice](/plugins/reference/venice)** (`@openclaw/venice-provider`) - npm; ClawHub: `clawhub:@openclaw/venice-provider`. Adds Venice model provider support to OpenClaw.
- **[vercel-ai-gateway](/plugins/reference/vercel-ai-gateway)** (`@openclaw/vercel-ai-gateway-provider`) - npm; ClawHub: `clawhub:@openclaw/vercel-ai-gateway-provider`. Adds Vercel AI Gateway model provider support to OpenClaw.
- **[voice-call](/plugins/reference/voice-call)** (`@openclaw/voice-call`) - npm; ClawHub. OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.
- **[whatsapp](/plugins/reference/whatsapp)** (`@openclaw/whatsapp`) - ClawHub: `clawhub:@openclaw/whatsapp`; npm. OpenClaw WhatsApp channel plugin for WhatsApp Web chats.
- **[zai](/plugins/reference/zai)** (`@openclaw/zai-provider`) - npm; ClawHub: `clawhub:@openclaw/zai-provider`. Adds Z.AI model provider support to OpenClaw.
- **[zalo](/plugins/reference/zalo)** (`@openclaw/zalo`) - npm; ClawHub. OpenClaw Zalo channel plugin for bot and webhook chats.
- **[zalouser](/plugins/reference/zalouser)** (`@openclaw/zalouser`) - npm; ClawHub. OpenClaw Zalo Personal Account plugin via native zca-js integration.
## Source checkout only
3 plugins
- **[qa-channel](/plugins/reference/qa-channel)** (`@openclaw/qa-channel`) - source checkout only. Adds the QA Channel surface for sending and receiving OpenClaw messages.
- **[qa-lab](/plugins/reference/qa-lab)** (`@openclaw/qa-lab`) - source checkout only. OpenClaw QA lab plugin with private debugger UI and scenario runner.
- **[qa-matrix](/plugins/reference/qa-matrix)** (`@openclaw/qa-matrix`) - source checkout only. Matrix QA transport runner and substrate.

View File

@@ -0,0 +1,195 @@
---
summary: "Ask users to approve plugin tool calls and plugin-owned permission prompts"
title: "Plugin permission requests"
sidebarTitle: "Permission requests"
read_when:
- You need a plugin hook or tool to ask before a side effect runs
- You need to configure where plugin approval prompts are delivered
- You are deciding between optional tools, exec approvals, and plugin approvals
---
Plugin permission requests let plugin code pause a tool call or plugin-owned
operation until a user approves or denies it. They use the Gateway
`plugin.approval.*` flow and the same approval UI surfaces that handle chat
approval buttons and `/approve` commands.
Use plugin permission requests for plugin/app permissions. They do not replace
host exec approvals, optional tool allowlists, or Codex's native permission
review.
## Choose the right gate
Pick the gate that matches the decision point you need:
| Gate | Use it when | What it controls |
| -------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| Optional tools | A tool should not be visible to the model until the user opts in. | Tool exposure through `tools.allow`. |
| Plugin permission requests | A plugin hook or plugin-owned operation must ask before one action runs. | Runtime approval through `plugin.approval.*`. |
| Exec approvals | A host command or shell-like tool needs operator approval. | Host exec policy and durable exec allowlists. |
| Codex native permission requests | Codex asks before native shell, file, MCP, or app-server actions. | Codex app-server or native hook approval handling, routed through plugin approvals when OpenClaw owns the prompt. |
| MCP approval elicitations | A Codex MCP server requests approval for a tool call. | MCP approval responses bridged through OpenClaw plugin approvals. |
Optional tools are a discovery-time gate. Plugin permission requests are a
per-call gate. Use both when a sensitive tool should require explicit opt-in
before the model can see it and approval before the action runs.
## Request approval before a tool call
Most plugin-authored prompts should start in a `before_tool_call` hook. The hook
runs after the model selects a tool and before OpenClaw executes it:
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "deploy-policy",
name: "Deploy Policy",
register(api) {
api.on("before_tool_call", async (event) => {
if (event.toolName !== "deploy_service") {
return;
}
const environment =
typeof event.params.environment === "string" ? event.params.environment : "unknown";
return {
requireApproval: {
title: "Deploy service",
description: `Deploy service to ${environment}.`,
severity: environment === "production" ? "critical" : "warning",
allowedDecisions:
environment === "production"
? ["allow-once", "deny"]
: ["allow-once", "allow-always", "deny"],
timeoutMs: 120_000,
timeoutBehavior: "deny",
onResolution(decision) {
console.log(`deploy approval resolved: ${decision}`);
},
},
};
});
},
});
```
Write prompt text for the person who will approve the action:
- Keep `title` short and action-focused; the Gateway caps it at 80 characters.
- Keep `description` specific and bounded; the Gateway caps it at 256
characters.
- Include the action, target, and risk. Do not include secrets, tokens, or
private payloads that should not appear in chat approval surfaces.
- `severity` defaults to `"warning"` when omitted. Use `"critical"` only for
actions where the wrong decision could cause production damage or data loss.
- `allowedDecisions` defaults to `["allow-once", "allow-always", "deny"]` when
omitted. Pass `["allow-once", "deny"]` when persistent trust is unsafe for
that action.
- `timeoutMs` defaults to 120000 (2 minutes) and is capped at 600000 (10
minutes) regardless of the requested value.
## Decision behavior
OpenClaw creates a pending approval with a `plugin:` ID, delivers it to the
available approval surfaces, and waits for a decision.
| Decision | Result |
| ----------------- | ------------------------------------------------------------------------- |
| `allow-once` | The current call continues. |
| `allow-always` | The current call continues and the decision is passed to the plugin. |
| `deny` | The call is blocked with a denied tool result. |
| Timeout | The call is blocked unless `timeoutBehavior` is `"allow"`. |
| Cancellation | The call is blocked when the run is aborted. |
| No approval route | The call is blocked because no connected approval surface can resolve it. |
`allow-always` is only durable when the requesting plugin or runtime implements
that persistence. For ordinary `before_tool_call.requireApproval` hooks,
OpenClaw treats `allow-once` and `allow-always` as approval decisions for the
current call and passes the resolved value to `onResolution`. If your plugin
offers `allow-always`, document and implement exactly what future calls it
trusts.
If the hook also returns `params`, OpenClaw applies those parameter changes only
after the approval succeeds. A lower-priority hook can still block after a
higher-priority hook requested approval.
`allowedDecisions` limits the buttons and commands shown to the user. The
Gateway rejects a resolve attempt for any decision the request did not offer.
## Route approval prompts
Approval prompts can resolve in local UI surfaces or in chat channels that
support approval handling. To forward plugin approval prompts to explicit chat
targets, configure `approvals.plugin`:
```json5
{
approvals: {
plugin: {
enabled: true,
mode: "targets",
agentFilter: ["main"],
targets: [{ channel: "slack", to: "U12345678" }],
},
},
}
```
`approvals.plugin` is independent from `approvals.exec`. Enabling exec approval
forwarding does not route plugin approval prompts, and enabling plugin approval
forwarding does not change host exec policy.
When a prompt includes manual approval text, resolve it with one of the offered
decisions:
```text
/approve <id> allow-once
/approve <id> allow-always
/approve <id> deny
```
See [Advanced exec approvals](/tools/exec-approvals-advanced#plugin-approval-forwarding)
for the full forwarding model, same-chat approval behavior, native channel
delivery, and channel-specific approver rules.
## Codex native permissions
Codex native permission prompts can also travel through plugin approvals, but
they have different ownership than plugin-authored hooks.
- Codex app-server approval requests route through OpenClaw after Codex review.
- The native hook `permission_request` relay can ask through
`plugin.approval.request` when that relay is enabled.
- MCP tool approval elicitations route through plugin approvals when Codex marks
`_meta.codex_approval_kind` as `"mcp_tool_call"`.
See [Codex harness runtime](/plugins/codex-harness-runtime#native-permissions-and-mcp-elicitations)
for the Codex-specific behavior and fallback rules.
## Troubleshooting
**The tool says plugin approvals are unavailable.** No approval UI or configured
approval route accepted the request. Connect an approval-capable client, use a
channel that supports same-chat `/approve`, or configure `approvals.plugin`.
**`allow-always` appears but the next call prompts again.** The generic plugin
approval flow does not automatically persist trust for arbitrary hooks. Persist
plugin-owned trust in your plugin after `onResolution("allow-always")`, or
offer only `allow-once` and `deny`.
**`/approve` rejects the decision.** The request restricted
`allowedDecisions`. Use one of the decisions printed in the prompt.
**A Discord, Matrix, Slack, or Telegram prompt routes differently from exec
approvals.** Plugin approvals and exec approvals use separate config and may use
different authorization checks. Verify `approvals.plugin` and the channel's
plugin approval support instead of only checking `approvals.exec`.
## Related
- [Plugin hooks](/plugins/hooks#tool-call-policy)
- [Building plugins](/plugins/building-plugins#registering-tools)
- [Advanced exec approvals](/tools/exec-approvals-advanced#plugin-approval-forwarding)
- [Gateway protocol](/gateway/protocol)
- [Codex harness runtime](/plugins/codex-harness-runtime#native-permissions-and-mcp-elicitations)

19
docs/plugins/reference.md Normal file
View File

@@ -0,0 +1,19 @@
---
summary: "Generated index of OpenClaw plugin reference pages"
read_when:
- You need a reference page for a specific OpenClaw plugin
- You are auditing plugin docs coverage
title: "Plugin reference"
---
# Plugin reference
This page is generated from `extensions/*/package.json` and
`openclaw.plugin.json`. Regenerate it with:
```bash
pnpm plugins:inventory:gen
```
Use [Plugin inventory](/plugins/plugin-inventory) to browse all 130
generated plugin reference pages by distribution, package, and description.

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw ACP runtime backend with plugin-owned session and transport management."
read_when:
- You are installing, configuring, or auditing the acpx plugin
title: "ACPx plugin"
---
# ACPx plugin
OpenClaw ACP runtime backend with plugin-owned session and transport management.
## Distribution
- Package: `@openclaw/acpx`
- Install route: npm; ClawHub
## Surface
skills
## Related docs
- [acpx](/tools/acp-agents-setup)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw admin HTTP RPC endpoint."
read_when:
- You are installing, configuring, or auditing the admin-http-rpc plugin
title: "Admin Http Rpc plugin"
---
# Admin Http Rpc plugin
OpenClaw admin HTTP RPC endpoint.
## Distribution
- Package: `@openclaw/admin-http-rpc`
- Install route: included in OpenClaw
## Surface
contracts: gatewayMethodDispatch
## Related docs
- [admin-http-rpc](/plugins/admin-http-rpc)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds video generation provider support."
read_when:
- You are installing, configuring, or auditing the alibaba plugin
title: "Alibaba plugin"
---
# Alibaba plugin
Adds video generation provider support.
## Distribution
- Package: `@openclaw/alibaba-provider`
- Install route: included in OpenClaw
## Surface
contracts: videoGenerationProviders
## Related docs
- [alibaba](/providers/alibaba)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing."
read_when:
- You are installing, configuring, or auditing the amazon-bedrock-mantle plugin
title: "Amazon Bedrock Mantle plugin"
---
# Amazon Bedrock Mantle plugin
OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing.
## Distribution
- Package: `@openclaw/amazon-bedrock-mantle-provider`
- Install route: npm; ClawHub
## Surface
providers: amazon-bedrock-mantle
## Related docs
- [amazon-bedrock-mantle](/providers/bedrock-mantle)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Amazon Bedrock provider plugin with model discovery, embeddings, and guardrail support."
read_when:
- You are installing, configuring, or auditing the amazon-bedrock plugin
title: "Amazon Bedrock plugin"
---
# Amazon Bedrock plugin
OpenClaw Amazon Bedrock provider plugin with model discovery, embeddings, and guardrail support.
## Distribution
- Package: `@openclaw/amazon-bedrock-provider`
- Install route: npm; ClawHub
## Surface
providers: amazon-bedrock; contracts: memoryEmbeddingProviders
## Related docs
- [amazon-bedrock](/providers/bedrock)

View File

@@ -0,0 +1,29 @@
---
summary: "OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI."
read_when:
- You are installing, configuring, or auditing the anthropic-vertex plugin
title: "Anthropic Vertex plugin"
---
# Anthropic Vertex plugin
OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI.
## Distribution
- Package: `@openclaw/anthropic-vertex-provider`
- Install route: npm; ClawHub
## Surface
providers: anthropic-vertex
<!-- openclaw-plugin-reference:manual-start -->
## Claude Fable 5
Use `anthropic-vertex/claude-fable-5` where the model is available in your Google Cloud region.
Fable 5 always uses adaptive thinking and defaults to `high` effort. `/think off` and
`/think minimal` use `low` effort because the model does not support disabling thinking.
<!-- openclaw-plugin-reference:manual-end -->

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Anthropic model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the anthropic plugin
title: "Anthropic plugin"
---
# Anthropic plugin
Adds Anthropic model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/anthropic-provider`
- Install route: included in OpenClaw
## Surface
providers: anthropic; contracts: mediaUnderstandingProviders
## Related docs
- [anthropic](/providers/anthropic)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Arcee model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the arcee plugin
title: "Arcee plugin"
---
# Arcee plugin
Adds Arcee model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/arcee-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/arcee-provider`
## Surface
providers: arcee
## Related docs
- [arcee](/providers/arcee)

View File

@@ -0,0 +1,23 @@
---
summary: "Azure AI Speech text-to-speech (MP3, native Ogg/Opus voice notes, PCM telephony)."
read_when:
- You are installing, configuring, or auditing the azure-speech plugin
title: "Azure Speech plugin"
---
# Azure Speech plugin
Azure AI Speech text-to-speech (MP3, native Ogg/Opus voice notes, PCM telephony).
## Distribution
- Package: `@openclaw/azure-speech`
- Install route: included in OpenClaw
## Surface
contracts: speechProviders
## Related docs
- [azure-speech](/providers/azure-speech)

View File

@@ -0,0 +1,19 @@
---
summary: "Advertise the local OpenClaw gateway over Bonjour/mDNS."
read_when:
- You are installing, configuring, or auditing the bonjour plugin
title: "Bonjour plugin"
---
# Bonjour plugin
Advertise the local OpenClaw gateway over Bonjour/mDNS.
## Distribution
- Package: `@openclaw/bonjour`
- Install route: included in OpenClaw
## Surface
plugin

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Brave Search provider plugin for web search."
read_when:
- You are installing, configuring, or auditing the brave plugin
title: "Brave plugin"
---
# Brave plugin
OpenClaw Brave Search provider plugin for web search.
## Distribution
- Package: `@openclaw/brave-plugin`
- Install route: npm; ClawHub
## Surface
contracts: webSearchProviders
## Related docs
- [brave](/tools/brave-search)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds agent-callable tools."
read_when:
- You are installing, configuring, or auditing the browser plugin
title: "Browser plugin"
---
# Browser plugin
Adds agent-callable tools.
## Distribution
- Package: `@openclaw/browser-plugin`
- Install route: included in OpenClaw
## Surface
contracts: tools; skills
## Related docs
- [browser](/tools/browser)

View File

@@ -0,0 +1,19 @@
---
summary: "Adds BytePlus, BytePlus Plan model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the byteplus plugin
title: "BytePlus plugin"
---
# BytePlus plugin
Adds BytePlus, BytePlus Plan model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/byteplus-provider`
- Install route: included in OpenClaw
## Surface
providers: byteplus, byteplus-plan; contracts: videoGenerationProviders

View File

@@ -0,0 +1,19 @@
---
summary: "Experimental Canvas control and A2UI rendering surfaces for paired nodes."
read_when:
- You are installing, configuring, or auditing the canvas plugin
title: "Canvas plugin"
---
# Canvas plugin
Experimental Canvas control and A2UI rendering surfaces for paired nodes.
## Distribution
- Package: `@openclaw/canvas-plugin`
- Install route: included in OpenClaw
## Surface
contracts: tools; skills

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Cerebras model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the cerebras plugin
title: "Cerebras plugin"
---
# Cerebras plugin
Adds Cerebras model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/cerebras-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/cerebras-provider`
## Surface
providers: cerebras
## Related docs
- [cerebras](/providers/cerebras)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Chutes model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the chutes plugin
title: "Chutes plugin"
---
# Chutes plugin
Adds Chutes model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/chutes-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/chutes-provider`
## Surface
providers: chutes
## Related docs
- [chutes](/providers/chutes)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds ClawRouter model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the clawrouter plugin
title: "ClawRouter plugin"
---
# ClawRouter plugin
Adds ClawRouter model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/clawrouter`
- Install route: included in OpenClaw
## Surface
providers: clawrouter
## Related docs
- [clawrouter](/providers/clawrouter)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds the Clickclack channel surface for sending and receiving OpenClaw messages."
read_when:
- You are installing, configuring, or auditing the clickclack plugin
title: "Clickclack plugin"
---
# Clickclack plugin
Adds the Clickclack channel surface for sending and receiving OpenClaw messages.
## Distribution
- Package: `@openclaw/clickclack`
- Install route: npm; ClawHub: `clawhub:@openclaw/clickclack`
## Surface
channels: clickclack
## Related docs
- [clickclack](/channels/clickclack)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Cloudflare AI Gateway model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the cloudflare-ai-gateway plugin
title: "Cloudflare AI Gateway plugin"
---
# Cloudflare AI Gateway plugin
Adds Cloudflare AI Gateway model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/cloudflare-ai-gateway-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/cloudflare-ai-gateway-provider`
## Surface
providers: cloudflare-ai-gateway
## Related docs
- [cloudflare-ai-gateway](/providers/cloudflare-ai-gateway)

View File

@@ -0,0 +1,27 @@
---
summary: "Supervise Codex app-server sessions from OpenClaw."
read_when:
- You are installing, configuring, or auditing the codex-supervisor plugin
title: "Codex Supervisor plugin"
---
# Codex Supervisor plugin
Supervise Codex app-server sessions from OpenClaw.
## Distribution
- Package: `@openclaw/codex-supervisor`
- Install route: included in OpenClaw
## Surface
contracts: tools
<!-- openclaw-plugin-reference:manual-start -->
## Session Listing
`codex_sessions_list` defaults to loaded Codex sessions only. Set `include_stored` to include stored history; the plugin uses Codex app-server's state-DB-only listing path and caps stored results at 200 by default. Pass `max_stored_sessions` to lower or raise that cap, up to 1000.
<!-- openclaw-plugin-reference:manual-end -->

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog."
read_when:
- You are installing, configuring, or auditing the codex plugin
title: "Codex plugin"
---
# Codex plugin
OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog.
## Distribution
- Package: `@openclaw/codex`
- Install route: npm; ClawHub
## Surface
providers: codex; contracts: mediaUnderstandingProviders, migrationProviders, tools, webSearchProviders
## Related docs
- [codex](/plugins/codex-harness)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Cohere provider plugin."
read_when:
- You are installing, configuring, or auditing the cohere plugin
title: "Cohere plugin"
---
# Cohere plugin
OpenClaw Cohere provider plugin.
## Distribution
- Package: `@openclaw/cohere-provider`
- Install route: included in OpenClaw; npm; ClawHub: `clawhub:@openclaw/cohere-provider`
## Surface
providers: cohere
## Related docs
- [cohere](/providers/cohere)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds ComfyUI model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the comfy plugin
title: "ComfyUI plugin"
---
# ComfyUI plugin
Adds ComfyUI model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/comfy-provider`
- Install route: included in OpenClaw
## Surface
providers: comfy; contracts: imageGenerationProviders, musicGenerationProviders, videoGenerationProviders
## Related docs
- [comfy](/providers/comfy)

View File

@@ -0,0 +1,19 @@
---
summary: "Adds Copilot Proxy model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the copilot-proxy plugin
title: "Copilot Proxy plugin"
---
# Copilot Proxy plugin
Adds Copilot Proxy model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/copilot-proxy`
- Install route: included in OpenClaw
## Surface
providers: copilot-proxy

View File

@@ -0,0 +1,23 @@
---
summary: "Registers the GitHub Copilot agent runtime."
read_when:
- You are installing, configuring, or auditing the copilot plugin
title: "Copilot plugin"
---
# Copilot plugin
Registers the GitHub Copilot agent runtime.
## Distribution
- Package: `@openclaw/copilot`
- Install route: npm; ClawHub: `clawhub:@openclaw/copilot`
## Surface
plugin
## Related docs
- [copilot](/plugins/copilot)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds media understanding provider support. Adds realtime transcription provider support."
read_when:
- You are installing, configuring, or auditing the deepgram plugin
title: "Deepgram plugin"
---
# Deepgram plugin
Adds media understanding provider support. Adds realtime transcription provider support.
## Distribution
- Package: `@openclaw/deepgram-provider`
- Install route: included in OpenClaw
## Surface
contracts: mediaUnderstandingProviders, realtimeTranscriptionProviders
## Related docs
- [deepgram](/providers/deepgram)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds DeepInfra model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the deepinfra plugin
title: "DeepInfra plugin"
---
# DeepInfra plugin
Adds DeepInfra model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/deepinfra-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/deepinfra-provider`
## Surface
providers: deepinfra; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, speechProviders, videoGenerationProviders
## Related docs
- [deepinfra](/providers/deepinfra)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds DeepSeek model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the deepseek plugin
title: "DeepSeek plugin"
---
# DeepSeek plugin
Adds DeepSeek model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/deepseek-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/deepseek-provider`
## Surface
providers: deepseek
## Related docs
- [deepseek](/providers/deepseek)

View File

@@ -0,0 +1,19 @@
---
summary: "OpenClaw diagnostics OpenTelemetry exporter for metrics, traces, and logs."
read_when:
- You are installing, configuring, or auditing the diagnostics-otel plugin
title: "Diagnostics OpenTelemetry plugin"
---
# Diagnostics OpenTelemetry plugin
OpenClaw diagnostics OpenTelemetry exporter for metrics, traces, and logs.
## Distribution
- Package: `@openclaw/diagnostics-otel`
- Install route: npm; ClawHub: `clawhub:@openclaw/diagnostics-otel`
## Surface
plugin

View File

@@ -0,0 +1,19 @@
---
summary: "OpenClaw diagnostics Prometheus exporter for runtime metrics."
read_when:
- You are installing, configuring, or auditing the diagnostics-prometheus plugin
title: "Diagnostics Prometheus plugin"
---
# Diagnostics Prometheus plugin
OpenClaw diagnostics Prometheus exporter for runtime metrics.
## Distribution
- Package: `@openclaw/diagnostics-prometheus`
- Install route: npm; ClawHub: `clawhub:@openclaw/diagnostics-prometheus`
## Surface
plugin

View File

@@ -0,0 +1,31 @@
---
summary: "Adds syntax highlighting for languages outside the default diffs viewer set."
read_when:
- You are installing, configuring, or auditing the diffs-language-pack plugin
title: "Diffs Language Pack plugin"
---
# Diffs Language Pack plugin
Adds syntax highlighting for languages outside the default diffs viewer set.
## Distribution
- Package: `@openclaw/diffs-language-pack`
- Install route: npm; ClawHub: `clawhub:@openclaw/diffs-language-pack`
## Surface
plugin
<!-- openclaw-plugin-reference:manual-start -->
## Added languages
The base `diffs` plugin already highlights the common languages documented in [Diffs](/tools/diffs). Install this language pack when you want syntax highlighting for a broader set of Shiki-supported languages. If the pack is not installed, those files still render as readable plain text.
Examples include Astro, Vue, Svelte, MDX, GraphQL, Terraform/HCL, Nix, Clojure, Elixir, Haskell, OCaml, Scala, Zig, Solidity, Verilog/VHDL, Fortran, MATLAB, LaTeX, Mermaid, Sass/Less/SCSS, Nginx, Apache, CSV, dotenv, INI, and diff files.
See [Shiki languages](https://shiki.style/languages) for Shiki's upstream language and alias catalog.
<!-- openclaw-plugin-reference:manual-end -->

View File

@@ -0,0 +1,19 @@
---
summary: "OpenClaw read-only diff viewer plugin and file renderer for agents."
read_when:
- You are installing, configuring, or auditing the diffs plugin
title: "Diffs plugin"
---
# Diffs plugin
OpenClaw read-only diff viewer plugin and file renderer for agents.
## Distribution
- Package: `@openclaw/diffs`
- Install route: npm; ClawHub
## Surface
contracts: tools; skills

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Discord channel plugin for channels, DMs, commands, and app events."
read_when:
- You are installing, configuring, or auditing the discord plugin
title: "Discord plugin"
---
# Discord plugin
OpenClaw Discord channel plugin for channels, DMs, commands, and app events.
## Distribution
- Package: `@openclaw/discord`
- Install route: npm; ClawHub
## Surface
channels: discord; contracts: transcriptSourceProviders; skills
## Related docs
- [discord](/channels/discord)

View File

@@ -0,0 +1,23 @@
---
summary: "Extract text and fallback page images from local document attachments."
read_when:
- You are installing, configuring, or auditing the document-extract plugin
title: "Document Extract plugin"
---
# Document Extract plugin
Extract text and fallback page images from local document attachments.
## Distribution
- Package: `@openclaw/document-extract-plugin`
- Install route: included in OpenClaw
## Surface
contracts: documentExtractors
## Related docs
- [document-extract](/tools/pdf)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds web search provider support."
read_when:
- You are installing, configuring, or auditing the duckduckgo plugin
title: "DuckDuckGo plugin"
---
# DuckDuckGo plugin
Adds web search provider support.
## Distribution
- Package: `@openclaw/duckduckgo-plugin`
- Install route: included in OpenClaw
## Surface
contracts: webSearchProviders
## Related docs
- [duckduckgo](/tools/duckduckgo-search)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds media understanding provider support. Adds realtime transcription provider support. Adds text-to-speech provider support."
read_when:
- You are installing, configuring, or auditing the elevenlabs plugin
title: "Elevenlabs plugin"
---
# Elevenlabs plugin
Adds media understanding provider support. Adds realtime transcription provider support. Adds text-to-speech provider support.
## Distribution
- Package: `@openclaw/elevenlabs-speech`
- Install route: included in OpenClaw
## Surface
contracts: mediaUnderstandingProviders, realtimeTranscriptionProviders, speechProviders
## Related docs
- [elevenlabs](/providers/elevenlabs)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds web search provider support."
read_when:
- You are installing, configuring, or auditing the exa plugin
title: "Exa plugin"
---
# Exa plugin
Adds web search provider support.
## Distribution
- Package: `@openclaw/exa-plugin`
- Install route: npm; ClawHub: `clawhub:@openclaw/exa-plugin`
## Surface
contracts: webSearchProviders
## Related docs
- [exa](/tools/exa-search)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds fal model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the fal plugin
title: "fal plugin"
---
# fal plugin
Adds fal model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/fal-provider`
- Install route: included in OpenClaw
## Surface
providers: fal; contracts: imageGenerationProviders, musicGenerationProviders, videoGenerationProviders
## Related docs
- [fal](/providers/fal)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng)."
read_when:
- You are installing, configuring, or auditing the feishu plugin
title: "Feishu plugin"
---
# Feishu plugin
OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).
## Distribution
- Package: `@openclaw/feishu`
- Install route: npm; ClawHub
## Surface
channels: feishu; contracts: tools; skills
## Related docs
- [feishu](/channels/feishu)

View File

@@ -0,0 +1,19 @@
---
summary: "Fetch, list, and write files on paired nodes via dedicated node commands. Bypasses bash stdout truncation by using base64 over node.invoke for binaries up to 16 MB."
read_when:
- You are installing, configuring, or auditing the file-transfer plugin
title: "File Transfer plugin"
---
# File Transfer plugin
Fetch, list, and write files on paired nodes via dedicated node commands. Bypasses bash stdout truncation by using base64 over node.invoke for binaries up to 16 MB.
## Distribution
- Package: `@openclaw/file-transfer`
- Install route: included in OpenClaw
## Surface
contracts: tools

View File

@@ -0,0 +1,23 @@
---
summary: "Adds agent-callable tools. Adds web fetch provider support. Adds web search provider support."
read_when:
- You are installing, configuring, or auditing the firecrawl plugin
title: "Firecrawl plugin"
---
# Firecrawl plugin
Adds agent-callable tools. Adds web fetch provider support. Adds web search provider support.
## Distribution
- Package: `@openclaw/firecrawl-plugin`
- Install route: npm; ClawHub: `clawhub:@openclaw/firecrawl-plugin`
## Surface
contracts: tools, webFetchProviders, webSearchProviders
## Related docs
- [firecrawl](/tools/firecrawl)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Fireworks model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the fireworks plugin
title: "Fireworks plugin"
---
# Fireworks plugin
Adds Fireworks model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/fireworks-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/fireworks-provider`
## Surface
providers: fireworks
## Related docs
- [fireworks](/providers/fireworks)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds GitHub Copilot model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the github-copilot plugin
title: "GitHub Copilot plugin"
---
# GitHub Copilot plugin
Adds GitHub Copilot model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/github-copilot-provider`
- Install route: included in OpenClaw
## Surface
providers: github-copilot; contracts: memoryEmbeddingProviders
## Related docs
- [github-copilot](/providers/github-copilot)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw GMI Cloud provider plugin."
read_when:
- You are installing, configuring, or auditing the gmi plugin
title: "Gmi plugin"
---
# Gmi plugin
OpenClaw GMI Cloud provider plugin.
## Distribution
- Package: `@openclaw/gmi-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/gmi-provider`
## Surface
providers: gmi, gmi-cloud, gmicloud
## Related docs
- [gmi](/providers/gmi)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports."
read_when:
- You are installing, configuring, or auditing the google-meet plugin
title: "Google Meet plugin"
---
# Google Meet plugin
OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.
## Distribution
- Package: `@openclaw/google-meet`
- Install route: npm; ClawHub
## Surface
contracts: tools
## Related docs
- [google-meet](/plugins/google-meet)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Google, Google Gemini CLI, Google Vertex model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the google plugin
title: "Google plugin"
---
# Google plugin
Adds Google, Google Gemini CLI, Google Vertex model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/google-plugin`
- Install route: included in OpenClaw
## Surface
providers: google, google-gemini-cli, google-vertex; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, musicGenerationProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders, webSearchProviders
## Related docs
- [google](/providers/google)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Google Chat channel plugin for spaces and direct messages."
read_when:
- You are installing, configuring, or auditing the googlechat plugin
title: "Google Chat plugin"
---
# Google Chat plugin
OpenClaw Google Chat channel plugin for spaces and direct messages.
## Distribution
- Package: `@openclaw/googlechat`
- Install route: npm; ClawHub
## Surface
channels: googlechat
## Related docs
- [googlechat](/channels/googlechat)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds text-to-speech provider support."
read_when:
- You are installing, configuring, or auditing the gradium plugin
title: "Gradium plugin"
---
# Gradium plugin
Adds text-to-speech provider support.
## Distribution
- Package: `@openclaw/gradium-speech`
- Install route: npm; ClawHub: `clawhub:@openclaw/gradium-speech`
## Surface
contracts: speechProviders
## Related docs
- [gradium](/providers/gradium)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Groq model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the groq plugin
title: "Groq plugin"
---
# Groq plugin
Adds Groq model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/groq-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/groq-provider`
## Surface
providers: groq; contracts: mediaUnderstandingProviders
## Related docs
- [groq](/providers/groq)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Hugging Face model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the huggingface plugin
title: "Hugging Face plugin"
---
# Hugging Face plugin
Adds Hugging Face model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/huggingface-provider`
- Install route: included in OpenClaw
## Surface
providers: huggingface
## Related docs
- [huggingface](/providers/huggingface)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds the iMessage channel surface for sending and receiving OpenClaw messages."
read_when:
- You are installing, configuring, or auditing the imessage plugin
title: "iMessage plugin"
---
# iMessage plugin
Adds the iMessage channel surface for sending and receiving OpenClaw messages.
## Distribution
- Package: `@openclaw/imessage`
- Install route: included in OpenClaw
## Surface
channels: imessage
## Related docs
- [imessage](/channels/imessage)

View File

@@ -0,0 +1,23 @@
---
summary: "Inworld streaming text-to-speech (MP3, OGG_OPUS, PCM telephony)."
read_when:
- You are installing, configuring, or auditing the inworld plugin
title: "Inworld plugin"
---
# Inworld plugin
Inworld streaming text-to-speech (MP3, OGG_OPUS, PCM telephony).
## Distribution
- Package: `@openclaw/inworld-speech`
- Install route: npm; ClawHub: `clawhub:@openclaw/inworld-speech`
## Surface
contracts: speechProviders
## Related docs
- [inworld](/providers/inworld)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds the IRC channel surface for sending and receiving OpenClaw messages."
read_when:
- You are installing, configuring, or auditing the irc plugin
title: "IRC plugin"
---
# IRC plugin
Adds the IRC channel surface for sending and receiving OpenClaw messages.
## Distribution
- Package: `@openclaw/irc`
- Install route: npm; ClawHub: `clawhub:@openclaw/irc`
## Surface
channels: irc
## Related docs
- [irc](/channels/irc)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Kilocode model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the kilocode plugin
title: "Kilocode plugin"
---
# Kilocode plugin
Adds Kilocode model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/kilocode-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/kilocode-provider`
## Surface
providers: kilocode
## Related docs
- [kilocode](/providers/kilocode)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds Kimi, Kimi Coding model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the kimi plugin
title: "Kimi plugin"
---
# Kimi plugin
Adds Kimi, Kimi Coding model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/kimi-provider`
- Install route: npm; ClawHub: `clawhub:@openclaw/kimi-provider`
## Surface
providers: kimi, kimi-coding
## Related docs
- [kimi](/providers/moonshot)

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw LINE channel plugin for LINE Bot API chats."
read_when:
- You are installing, configuring, or auditing the line plugin
title: "LINE plugin"
---
# LINE plugin
OpenClaw LINE channel plugin for LINE Bot API chats.
## Distribution
- Package: `@openclaw/line`
- Install route: npm; ClawHub
## Surface
channels: line
## Related docs
- [line](/channels/line)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds LiteLLM model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the litellm plugin
title: "LiteLLM plugin"
---
# LiteLLM plugin
Adds LiteLLM model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/litellm-provider`
- Install route: included in OpenClaw
## Surface
providers: litellm; contracts: imageGenerationProviders
## Related docs
- [litellm](/providers/litellm)

View File

@@ -0,0 +1,23 @@
---
summary: "Local GGUF embeddings through node-llama-cpp."
read_when:
- You are installing, configuring, or auditing the llama-cpp plugin
title: "Llama Cpp plugin"
---
# Llama Cpp plugin
Local GGUF embeddings through node-llama-cpp.
## Distribution
- Package: `@openclaw/llama-cpp-provider`
- Install route: npm; ClawHub
## Surface
contracts: embeddingProviders
## Related docs
- [llama-cpp](/plugins/llama-cpp)

View File

@@ -0,0 +1,19 @@
---
summary: "Generic JSON-only LLM tool for structured tasks callable from workflows."
read_when:
- You are installing, configuring, or auditing the llm-task plugin
title: "LLM Task plugin"
---
# LLM Task plugin
Generic JSON-only LLM tool for structured tasks callable from workflows.
## Distribution
- Package: `@openclaw/llm-task`
- Install route: included in OpenClaw
## Surface
contracts: tools

View File

@@ -0,0 +1,23 @@
---
summary: "Adds LM Studio model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the lmstudio plugin
title: "LM Studio plugin"
---
# LM Studio plugin
Adds LM Studio model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/lmstudio-provider`
- Install route: included in OpenClaw
## Surface
providers: lmstudio; contracts: memoryEmbeddingProviders
## Related docs
- [lmstudio](/providers/lmstudio)

View File

@@ -0,0 +1,19 @@
---
summary: "Lobster workflow tool plugin for typed pipelines and resumable approvals."
read_when:
- You are installing, configuring, or auditing the lobster plugin
title: "Lobster plugin"
---
# Lobster plugin
Lobster workflow tool plugin for typed pipelines and resumable approvals.
## Distribution
- Package: `@openclaw/lobster`
- Install route: npm; ClawHub
## Surface
contracts: tools

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw Matrix channel plugin for rooms and direct messages."
read_when:
- You are installing, configuring, or auditing the matrix plugin
title: "Matrix plugin"
---
# Matrix plugin
OpenClaw Matrix channel plugin for rooms and direct messages.
## Distribution
- Package: `@openclaw/matrix`
- Install route: ClawHub: `clawhub:@openclaw/matrix`; npm
## Surface
channels: matrix
## Related docs
- [matrix](/channels/matrix)

View File

@@ -0,0 +1,23 @@
---
summary: "Adds the Mattermost channel surface for sending and receiving OpenClaw messages."
read_when:
- You are installing, configuring, or auditing the mattermost plugin
title: "Mattermost plugin"
---
# Mattermost plugin
Adds the Mattermost channel surface for sending and receiving OpenClaw messages.
## Distribution
- Package: `@openclaw/mattermost`
- Install route: npm; ClawHub: `clawhub:@openclaw/mattermost`
## Surface
channels: mattermost
## Related docs
- [mattermost](/channels/mattermost)

View File

@@ -0,0 +1,19 @@
---
summary: "Adds agent-callable tools."
read_when:
- You are installing, configuring, or auditing the memory-core plugin
title: "Memory Core plugin"
---
# Memory Core plugin
Adds agent-callable tools.
## Distribution
- Package: `@openclaw/memory-core`
- Install route: included in OpenClaw
## Surface
contracts: tools

View File

@@ -0,0 +1,23 @@
---
summary: "OpenClaw LanceDB-backed long-term memory plugin with auto-recall, auto-capture, and vector search."
read_when:
- You are installing, configuring, or auditing the memory-lancedb plugin
title: "Memory Lancedb plugin"
---
# Memory Lancedb plugin
OpenClaw LanceDB-backed long-term memory plugin with auto-recall, auto-capture, and vector search.
## Distribution
- Package: `@openclaw/memory-lancedb`
- Install route: npm; ClawHub
## Surface
contracts: tools
## Related docs
- [memory-lancedb](/plugins/memory-lancedb)

View File

@@ -0,0 +1,23 @@
---
summary: "Persistent wiki compiler and Obsidian-friendly knowledge vault for OpenClaw."
read_when:
- You are installing, configuring, or auditing the memory-wiki plugin
title: "Memory Wiki plugin"
---
# Memory Wiki plugin
Persistent wiki compiler and Obsidian-friendly knowledge vault for OpenClaw.
## Distribution
- Package: `@openclaw/memory-wiki`
- Install route: included in OpenClaw
## Surface
contracts: tools; skills
## Related docs
- [memory-wiki](/plugins/memory-wiki)

View File

@@ -0,0 +1,113 @@
---
summary: "Adds Microsoft Foundry model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the microsoft-foundry plugin
title: "Microsoft Foundry plugin"
---
# Microsoft Foundry plugin
Adds Microsoft Foundry model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/microsoft-foundry`
- Install route: included in OpenClaw
## Surface
providers: microsoft-foundry; contracts: imageGenerationProviders
<!-- openclaw-plugin-reference:manual-start -->
- Image-generation provider: `microsoft-foundry`
## Requirements
- A Microsoft Foundry or Azure AI Foundry resource with deployments.
- API-key auth through `AZURE_OPENAI_API_KEY` or a configured provider API key.
- For Entra ID auth, install the Azure CLI and run `az login` before
onboarding. OpenClaw refreshes Microsoft Foundry runtime tokens through
`az account get-access-token`.
## Chat models
Microsoft Foundry chat deployments use the provider model ref
`microsoft-foundry/<deployment-name>`. Onboarding discovers Foundry resources
and deployments with the Azure CLI, then writes the selected deployment name to
the model config.
OpenClaw uses the Foundry `/openai/v1` endpoint for supported OpenAI-compatible
chat APIs:
- GPT, `o*`, `computer-use-preview`, and DeepSeek-V4 model families default to
`openai-responses`.
- MAI-DS-R1 and other chat-completion deployments use `openai-completions`
unless an explicit supported API is configured.
- MAI-DS-R1 is recorded as reasoning-capable through reasoning content, not
through `reasoning_effort`. Its context and output token metadata are
163,840 tokens.
Anthropic Claude deployments in Microsoft Foundry use the Anthropic Messages
API shape, not the OpenAI-compatible `/openai/v1` shape. Configure those as a
custom `anthropic-messages` provider until the Microsoft Foundry plugin grows a
native Anthropic runtime. When the Foundry deployment name differs from the
Claude model ID, set `params.canonicalModelId` on the model entry so OpenClaw
can apply model-specific wire contracts, map `/think off` correctly, and
preserve signed thinking safely.
## MAI image generation
The plugin registers `microsoft-foundry` for `image_generate` with the current
Microsoft AI image models:
- `MAI-Image-2.5-Flash`
- `MAI-Image-2.5`
- `MAI-Image-2e`
- `MAI-Image-2`
Use a deployed MAI image deployment name as the model ref. The provider does
not declare a default image model because the MAI API requires your deployment
name in the request `model` field:
```json5
{
agents: {
defaults: {
imageGenerationModel: {
primary: "microsoft-foundry/<deployment-name>",
timeoutMs: 600000,
},
},
},
}
```
Prompt-only generation calls Microsoft Foundry's MAI generations endpoint:
`/mai/v1/images/generations`. Reference-image edits call
`/mai/v1/images/edits` and are limited to `MAI-Image-2.5-Flash` and
`MAI-Image-2.5` deployments.
Prompt-only generation can use a custom deployment name with just the Foundry
endpoint configured. For image edits with a custom deployment name, select the
deployment through onboarding or include model metadata so OpenClaw can verify
that the deployment is backed by `MAI-Image-2.5-Flash` or `MAI-Image-2.5`.
MAI image constraints:
- Output: one PNG image per request.
- Size: default `1024x1024`; both width and height must be at least 768 px.
- Total pixels: width × height must be at most 1,048,576.
- Edits: one PNG or JPEG input image.
- Unsupported shared hints such as `aspectRatio`, `resolution`, `quality`,
`background`, and non-PNG `outputFormat` are not sent to Microsoft Foundry.
## Troubleshooting
- `az: command not found`: install the Azure CLI or use API-key auth.
- `Microsoft Foundry endpoint missing for MAI image generation`: select a
Foundry deployment through onboarding or add `models.providers.microsoft-foundry.baseUrl`.
- `supports MAI image deployments only`: the selected image model points at a
non-MAI deployment. Use a deployed MAI image model for `image_generate`.
<!-- openclaw-plugin-reference:manual-end -->

View File

@@ -0,0 +1,19 @@
---
summary: "Adds text-to-speech provider support."
read_when:
- You are installing, configuring, or auditing the microsoft plugin
title: "Microsoft plugin"
---
# Microsoft plugin
Adds text-to-speech provider support.
## Distribution
- Package: `@openclaw/microsoft-speech`
- Install route: included in OpenClaw
## Surface
contracts: speechProviders

View File

@@ -0,0 +1,19 @@
---
summary: "Imports Claude Code and Claude Desktop instructions, MCP servers, skills, and safe configuration into OpenClaw."
read_when:
- You are installing, configuring, or auditing the migrate-claude plugin
title: "Migrate Claude plugin"
---
# Migrate Claude plugin
Imports Claude Code and Claude Desktop instructions, MCP servers, skills, and safe configuration into OpenClaw.
## Distribution
- Package: `@openclaw/migrate-claude`
- Install route: included in OpenClaw
## Surface
contracts: migrationProviders

Some files were not shown because too many files have changed in this diff Show More