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:Documentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
If the upstream service exposes a normal HTTP model API, write a
provider plugin instead. If the upstream
runtime owns complete agent sessions, tool events, compaction, or background
task state, use an agent harness.
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 |
api.registerCliBackend(...).
Minimal backend plugin
Create package metadata
package.json
./src/index.ts, add openclaw.runtimeExtensions that points at
the built JavaScript peer. See Entry points.Declare backend ownership
openclaw.plugin.json
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.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 |
input | Prompt transport: arg or stdin |
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 |
systemPromptWhen | first, always, or never |
imageArg / imageMode | Image path support |
serialize | Keep same-backend runs ordered |
reliability.watchdog | No-output timeout tuning |
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 |
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 |
bundleMcp / bundleMcpMode | Opt into OpenClaw’s loopback MCP tool bridge |
MCP tool bridge
CLI backends do not receive OpenClaw tools by default. If the CLI can consume an MCP configuration, opt in explicitly:| 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 |
nativeToolMode: "always-on" so OpenClaw can fail closed when a caller requires no native tools.
User configuration
Users can override any backend default: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:Checklist
package.json has openclaw.extensions and built runtime entries for published packagesopenclaw.plugin.json declares cliBackends and intentional activation.onStartupsetup.cliBackends is present when setup/model discovery should see the backend coldapi.registerCliBackend(...) uses the same backend id as the manifestUser overrides under
agents.defaults.cliBackends.<id> still winSession, system prompt, image, and output parser settings match the real CLI contract
Targeted tests and at least one live CLI smoke prove the backend path
Related
- CLI backends - user configuration and runtime behavior
- Building plugins - package and manifest basics
- Plugin SDK overview - registration API reference
- Plugin manifest -
cliBackendsand setup descriptors - Agent harness - full external agent runtimes