> ## Documentation Index
> Fetch the complete documentation index at: https://zju-a00451d9-feat-personal-agent-team.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI Backends

# CLI backends (fallback runtime)

Velaclaw can run **local AI CLIs** as a **text-only fallback** when API providers are down,
rate-limited, or temporarily misbehaving. This is intentionally conservative:

* **Velaclaw tools are not injected directly**, but backends with `bundleMcp: true`
  can receive gateway tools via a loopback MCP bridge.
* **JSONL streaming** for CLIs that support it.
* **Sessions are supported** (so follow-up turns stay coherent).
* **Images can be passed through** if the CLI accepts image paths.

This is designed as a **safety net** rather than a primary path. Use it when you
want “always works” text responses without relying on external APIs.

If you want a full harness runtime with ACP session controls, background tasks,
thread/conversation binding, and persistent external coding sessions, use
[ACP Agents](/tools/acp-agents) instead. CLI backends are not ACP.

## Beginner-friendly quick start

You can use Codex CLI **without any config** (the bundled OpenAI plugin
registers a default backend):

```bash theme={null}
velaclaw agent --message "hi" --model codex-cli/gpt-5.4
```

If your gateway runs under launchd/systemd and PATH is minimal, add just the
command path:

```json5 theme={null}
{
  agents: {
    defaults: {
      cliBackends: {
        "codex-cli": {
          command: "/opt/homebrew/bin/codex",
        },
      },
    },
  },
}
```

That’s it. No keys, no extra auth config needed beyond the CLI itself.

If you use a bundled CLI backend as the **primary message provider** on a
gateway host, Velaclaw now auto-loads the owning bundled plugin when your config
explicitly references that backend in a model ref or under
`agents.defaults.cliBackends`.

## Using it as a fallback

Add a CLI backend to your fallback list so it only runs when primary models fail:

```json5 theme={null}
{
  agents: {
    defaults: {
      model: {
        primary: "anthropic/claude-opus-4-6",
        fallbacks: ["codex-cli/gpt-5.4"],
      },
      models: {
        "anthropic/claude-opus-4-6": { alias: "Opus" },
        "codex-cli/gpt-5.4": {},
      },
    },
  },
}
```

Notes:

* If you use `agents.defaults.models` (allowlist), you must include your CLI backend models there too.
* If the primary provider fails (auth, rate limits, timeouts), Velaclaw will
  try the CLI backend next.

## Configuration overview

All CLI backends live under:

```
agents.defaults.cliBackends
```

Each entry is keyed by a **provider id** (e.g. `codex-cli`, `my-cli`).
The provider id becomes the left side of your model ref:

```
<provider>/<model>
```

### Example configuration

```json5 theme={null}
{
  agents: {
    defaults: {
      cliBackends: {
        "codex-cli": {
          command: "/opt/homebrew/bin/codex",
        },
        "my-cli": {
          command: "my-cli",
          args: ["--json"],
          output: "json",
          input: "arg",
          modelArg: "--model",
          modelAliases: {
            "claude-opus-4-6": "opus",
            "claude-sonnet-4-6": "sonnet",
          },
          sessionArg: "--session",
          sessionMode: "existing",
          sessionIdFields: ["session_id", "conversation_id"],
          systemPromptArg: "--system",
          // Codex-style CLIs can point at a prompt file instead:
          // systemPromptFileConfigArg: "-c",
          // systemPromptFileConfigKey: "model_instructions_file",
          systemPromptWhen: "first",
          imageArg: "--image",
          imageMode: "repeat",
          serialize: true,
        },
      },
    },
  },
}
```

## How it works

1. **Selects a backend** based on the provider prefix (`codex-cli/...`).
2. **Builds a system prompt** using the same Velaclaw prompt + workspace context.
3. **Executes the CLI** with a session id (if supported) so history stays consistent.
4. **Parses output** (JSON or plain text) and returns the final text.
5. **Persists session ids** per backend, so follow-ups reuse the same CLI session.

<Note>
  The bundled Anthropic `claude-cli` backend is supported again. Anthropic staff
  told us Velaclaw-style Claude CLI usage is allowed again, so Velaclaw treats
  `claude -p` usage as sanctioned for this integration unless Anthropic publishes
  a new policy.
</Note>

The bundled OpenAI `codex-cli` backend passes Velaclaw's system prompt through
Codex's `model_instructions_file` config override (`-c
model_instructions_file="..."`). Codex does not expose a Claude-style
`--append-system-prompt` flag, so Velaclaw writes the assembled prompt to a
temporary file for each fresh Codex CLI session.

The bundled Anthropic `claude-cli` backend receives the Velaclaw skills snapshot
two ways: the compact Velaclaw skills catalog in the appended system prompt, and
a temporary Claude Code plugin passed with `--plugin-dir`. The plugin contains
only the eligible skills for that agent/session, so Claude Code's native skill
resolver sees the same filtered set that Velaclaw would otherwise advertise in
the prompt. Skill env/API key overrides are still applied by Velaclaw to the
child process environment for the run.

## Sessions

* If the CLI supports sessions, set `sessionArg` (e.g. `--session-id`) or
  `sessionArgs` (placeholder `{sessionId}`) when the ID needs to be inserted
  into multiple flags.
* If the CLI uses a **resume subcommand** with different flags, set
  `resumeArgs` (replaces `args` when resuming) and optionally `resumeOutput`
  (for non-JSON resumes).
* `sessionMode`:
  * `always`: always send a session id (new UUID if none stored).
  * `existing`: only send a session id if one was stored before.
  * `none`: never send a session id.

Serialization notes:

* `serialize: true` keeps same-lane runs ordered.
* Most CLIs serialize on one provider lane.
* Velaclaw drops stored CLI session reuse when the backend auth state changes, including relogin, token rotation, or a changed auth profile credential.

## Images (pass-through)

If your CLI accepts image paths, set `imageArg`:

```json5 theme={null}
imageArg: "--image",
imageMode: "repeat"
```

Velaclaw will write base64 images to temp files. If `imageArg` is set, those
paths are passed as CLI args. If `imageArg` is missing, Velaclaw appends the
file paths to the prompt (path injection), which is enough for CLIs that auto-
load local files from plain paths.

## Inputs / outputs

* `output: "json"` (default) tries to parse JSON and extract text + session id.
* For Gemini CLI JSON output, Velaclaw reads reply text from `response` and
  usage from `stats` when `usage` is missing or empty.
* `output: "jsonl"` parses JSONL streams (for example Codex CLI `--json`) and extracts the final agent message plus session
  identifiers when present.
* `output: "text"` treats stdout as the final response.

Input modes:

* `input: "arg"` (default) passes the prompt as the last CLI arg.
* `input: "stdin"` sends the prompt via stdin.
* If the prompt is very long and `maxPromptArgChars` is set, stdin is used.

## Defaults (plugin-owned)

The bundled OpenAI plugin also registers a default for `codex-cli`:

* `command: "codex"`
* `args: ["exec","--json","--color","never","--sandbox","workspace-write","--skip-git-repo-check"]`
* `resumeArgs: ["exec","resume","{sessionId}","--color","never","--sandbox","workspace-write","--skip-git-repo-check"]`
* `output: "jsonl"`
* `resumeOutput: "text"`
* `modelArg: "--model"`
* `imageArg: "--image"`
* `sessionMode: "existing"`

The bundled Google plugin also registers a default for `google-gemini-cli`:

* `command: "gemini"`
* `args: ["--output-format", "json", "--prompt", "{prompt}"]`
* `resumeArgs: ["--resume", "{sessionId}", "--output-format", "json", "--prompt", "{prompt}"]`
* `imageArg: "@"`
* `imagePathScope: "workspace"`
* `modelArg: "--model"`
* `sessionMode: "existing"`
* `sessionIdFields: ["session_id", "sessionId"]`

Prerequisite: the local Gemini CLI must be installed and available as
`gemini` on `PATH` (`brew install gemini-cli` or
`npm install -g @google/gemini-cli`).

Gemini CLI JSON notes:

* Reply text is read from the JSON `response` field.
* Usage falls back to `stats` when `usage` is absent or empty.
* `stats.cached` is normalized into Velaclaw `cacheRead`.
* If `stats.input` is missing, Velaclaw derives input tokens from
  `stats.input_tokens - stats.cached`.

Override only if needed (common: absolute `command` path).

## Plugin-owned defaults

CLI backend defaults are now part of the plugin surface:

* Plugins register them with `api.registerCliBackend(...)`.
* The backend `id` becomes the provider prefix in model refs.
* User config in `agents.defaults.cliBackends.<id>` still overrides the plugin default.
* Backend-specific config cleanup stays plugin-owned through the optional
  `normalizeConfig` hook.

Plugins that need tiny prompt/message compatibility shims can declare
bidirectional text transforms without replacing a provider or CLI backend:

```typescript theme={null}
api.registerTextTransforms({
  input: [
    { from: /red basket/g, to: "blue basket" },
    { from: /paper ticket/g, to: "digital ticket" },
    { from: /left shelf/g, to: "right shelf" },
  ],
  output: [
    { from: /blue basket/g, to: "red basket" },
    { from: /digital ticket/g, to: "paper ticket" },
    { from: /right shelf/g, to: "left shelf" },
  ],
});
```

`input` rewrites the system prompt and user prompt passed to the CLI. `output`
rewrites streamed assistant deltas and parsed final text before Velaclaw handles
its own control markers and channel delivery.

For CLIs that emit Claude Code stream-json compatible JSONL, set
`jsonlDialect: "claude-stream-json"` on that backend's config.

## Bundle MCP overlays

CLI backends do **not** receive Velaclaw tool calls directly, but a backend can
opt into a generated MCP config overlay with `bundleMcp: true`.

Current bundled behavior:

* `claude-cli`: generated strict MCP config file
* `codex-cli`: inline config overrides for `mcp_servers`
* `google-gemini-cli`: generated Gemini system settings file

When bundle MCP is enabled, Velaclaw:

* spawns a loopback HTTP MCP server that exposes gateway tools to the CLI process
* authenticates the bridge with a per-session token (`VELACLAW_MCP_TOKEN`)
* scopes tool access to the current session, account, and channel context
* loads enabled bundle-MCP servers for the current workspace
* merges them with any existing backend MCP config/settings shape
* rewrites the launch config using the backend-owned integration mode from the owning extension

If no MCP servers are enabled, Velaclaw still injects a strict config when a
backend opts into bundle MCP so background runs stay isolated.

## Limitations

* **No direct Velaclaw tool calls.** Velaclaw does not inject tool calls into
  the CLI backend protocol. Backends only see gateway tools when they opt into
  `bundleMcp: true`.
* **Streaming is backend-specific.** Some backends stream JSONL; others buffer
  until exit.
* **Structured outputs** depend on the CLI’s JSON format.
* **Codex CLI sessions** resume via text output (no JSONL), which is less
  structured than the initial `--json` run. Velaclaw sessions still work
  normally.

## Troubleshooting

* **CLI not found**: set `command` to a full path.
* **Wrong model name**: use `modelAliases` to map `provider/model` → CLI model.
* **No session continuity**: ensure `sessionArg` is set and `sessionMode` is not
  `none` (Codex CLI currently cannot resume with JSON output).
* **Images ignored**: set `imageArg` (and verify CLI supports file paths).
