# cara CLI Guide

This page is command-reference-first: subcommands, key flags, and CLI-specific
behavior that is easy to miss from `--help`.

For first-run walkthroughs and channel onboarding:
- [First Run](site/first-run.md)
- [Getting Started](getting-started.md)
- [Channel Setup](channels.md)

## Command Reference

### `cara` / `cara start`
Starts the Carapace service (default when no subcommand is given).

### `cara config`
Manage configuration values.

- `cara config show` — print resolved config as JSON (secrets redacted)
- `cara config get <key>` — read value by dot path
- `cara config set <key> <value>` — set value (JSON interpreted, string fallback)
- `cara config path` — print the config file path

### `cara setup`
Interactive first-run wizard for provider/auth/network/channel setup.

Supported `--provider` values: Anthropic, OpenAI, Gemini (API key or OAuth),
Ollama, Bedrock, Vertex, Codex, NEAR AI Cloud, and Venice. The Claude CLI provider is
configured directly in `carapace.json5` via `claude-cli:<model>` in agent
`model` fields; it is not currently exposed through `cara setup --provider`.
`claude` is an Anthropic setup alias, and `gpt` is an OpenAI setup alias.

Wizard outcomes include `local-chat`, `discord`, `telegram`, `matrix`, and `hooks`.
Use `--force` to overwrite an existing config file.

Config and runtime require explicit `provider:model` routing (for example,
`anthropic:claude-sonnet-4-6`); bare model names are rejected by the schema
validator and the runtime router.

`cara setup` is the one input boundary that accepts a bare `<model-id>` without
`:` — both the interactive model prompt and `--model` auto-prefix it with the
canonical provider prefix before writing config (so
`--provider openai --model gpt-5.5` persists as `openai:gpt-5.5`). Provider-native
model IDs that contain `:` must use the full form, for example
`--provider ollama --model ollama:qwen3-coder:30b`. The supplied prefix (when
present) must match `--provider`. `--model` is required for non-interactive
setup and optional in interactive setup (skips the model prompt). Carapace
never picks a default model for you — `agents.defaults.model` is always
operator-set. The `<model-id>` portion is the provider-native name from that
provider's docs, console, or local endpoint; Carapace owns only the routing
prefix. Examples in these docs show the shape and may age as providers rename
or retire models.

`--auth-mode` is accepted for Anthropic and Gemini setup. Anthropic supports
`api-key` and `setup-token`; Gemini supports `api-key` and `oauth`. Non-
interactive Gemini OAuth setup is rejected because the Google sign-in flow is
interactive. Codex auth is fixed to OAuth-only — pass `--provider codex`
without `--auth-mode`; the wizard completes the sign-in via a loopback
callback and writes `codex.authProfile`.

For the full setup flow and decision guidance, use [First Run](site/first-run.md).

### `cara import`
Import configuration from another tool into Carapace.

```bash
cara import <source> [--force]
```

Supported sources:
- `openclaw` — imports from `~/.openclaw/openclaw.json`, `.env`, and
  `~/.clawdbot/`. Maps provider API keys, channel tokens, gateway auth, model
  selection, and env-block secrets. Supports JSON5 config and dotenv files.
- `opencode` — imports from `~/.opencode.json` (home, XDG, or local project).
  Maps provider API keys and the coder agent model.
- `aider` — imports from `~/.aider.conf.yml` (home or project) and `.env`.
  Maps API keys and model from YAML and dotenv with litellm model ID
  remapping.
- `nemoclaw` — imports from `~/.nemoclaw/config.json`. Resolves credentials
  from the env var named in `credentialEnv`. Maps Anthropic, OpenAI, Gemini,
  and Ollama endpoints.

The import flow:
1. Discovers the source config on disk
2. Shows a preview table of mapped fields (secrets redacted) and skipped
   surfaces with reasons
3. Asks for confirmation before writing
4. Writes Carapace config with restricted file permissions and secret
   encryption

Use `--force` to overwrite an existing Carapace config.

After import, run `cara verify` to validate the imported providers work.

### `cara verify`
Run first-run outcome checks with pass/fail output and next-step guidance.

```bash
cara verify --outcome auto --port 18789
```

Autonomy scenario:

```bash
cara verify --outcome autonomy --port 18789
```

Outcomes:
- `auto` — infer from current config
- `local-chat` — local reachability + one non-interactive `chat.send` roundtrip
- `hooks` — signed `POST /hooks/wake` with configured token
- `discord` / `telegram` — credential validity + outbound send-path verification
- `matrix` — Matrix config, encrypted-store prerequisite, daemon runtime, and
  verification API wiring
- `autonomy` — creates a durable objective task and verifies start proof
  (`attempts > 0`) plus terminal proof (`done` or `blocked`)

Options:
- `--port` / `-p` — local service port (default: config or `18789`)
- `--discord-to <channel_id>` — required for Discord send-path verification
- `--telegram-to <chat_id>` — required for Telegram send-path verification
- `--matrix-to <room_id>` — sends a real Matrix verification message to the
  room through the daemon-owned Matrix runtime.

Notes:
- `cara verify` currently targets local loopback only (`127.0.0.1`)
- Discord/Telegram/Matrix verification sends a real test message when a
  destination is provided
- Hooks verification may trigger a real agent run
- Autonomy verification submits a real task to the task queue

### `cara matrix`

Manage daemon-owned Matrix verification state. **`cara matrix verify`** here is
Matrix SAS device verification (interactive cryptographic key exchange with a
peer), distinct from `cara verify --outcome matrix` above (a daemon-wiring
health check). The two commands share the word "verify" but are unrelated
operations.

```bash
cara matrix devices
cara matrix verifications
cara matrix verify '@alice:example.org' DEVICEID
cara matrix accept <flow_id>
cara matrix confirm <flow_id> --match
cara matrix confirm <flow_id> --no-match
cara matrix cancel <flow_id>
cara matrix recovery-key show
cara matrix recovery-key restore --key-file ./matrix-recovery-key.txt
printf '%s\n' '<recovery-key>' | cara matrix recovery-key restore --stdin
cara matrix recovery-key rotate
cara matrix rekey-store --new
```

#### `cara matrix confirm <flow_id> --match` — security flags

`cara matrix confirm` displays the SAS emoji + decimal codes from the
homeserver and prompts for an interactive `yes` confirmation before submitting
the match. The prompt is the only MITM-resistance step in the SAS protocol:
without it, a homeserver-in-the-middle that injected a fake device fingerprint
would be confirmed silently.

- `--unsafe-skip-sas-prompt` — **SECURITY WARNING**: skips the interactive
  comparison prompt. Use only in automation that has already presented the
  SAS values to a human through a separate channel (e.g., a paired mobile app)
  and captured approval. Bypassing the prompt without out-of-band human
  comparison defeats the MITM resistance the SAS step provides.

#### `cara matrix rekey-store`

`cara matrix rekey-store --new` rewraps the Matrix SDK SQLite store cipher with
a fresh random passphrase and pins it in the local state directory. Stop the
daemon, run it before rotating `CARAPACE_CONFIG_PASSWORD` while the old password
is still available, then restart. Stores configured with explicit
`MATRIX_STORE_PASSPHRASE` / `matrix.storePassphrase` are rotated outside
Carapace — `rekey-store --new` refuses to operate on those.

**Recovering from an interrupted rekey.** If the daemon emits a
`Matrix store rekey interrupted` error at startup (or `cara verify --outcome
matrix` fails the encrypted-store check with the same message), the previous
`rekey-store --new` crashed mid-rotation and a `store_passphrase.pending` or
`store_passphrase.rekeying` marker remains on disk. The same command,
`cara matrix rekey-store --new`, is also the recovery path: it is idempotent
and will advance or roll back the in-flight rotation. Stop any running daemon
first. See [Channel Setup → Matrix store rekey lifecycle](channels.md#matrix-store-rekey-lifecycle)
for the full procedure.

#### `cara matrix recovery-key rotate`

`cara matrix recovery-key rotate` calls the Matrix SDK recovery reset flow and
atomically replaces the owner-only local recovery key. Stop the daemon first;
the command refuses to run while `.matrix-rekey.lock` is held by the daemon or
another Matrix secret-maintenance command.
The previous recovery key is abandoned after rotation, so capture the new key
from `cara matrix recovery-key show` before relying on encrypted Matrix backup.

If rotation is interrupted after the SDK returns a new key, the CLI preserves
`recovery_key.pending` plus a `recovery_key.rotating` marker. The next daemon
start promotes the pending key before Matrix recovery only when the
`pending_key_written` marker records the pending digest and the current
`recovery_key` still matches the recorded previous-key digest. If the current
key is missing, mismatched, or the marker is malformed, startup fails closed
and leaves `recovery_key.pending` / `recovery_key.rotating` untouched for
operator repair. Do not delete pending material unless you have confirmed the
current `recovery_key` is the one you intend to keep. `recovery-key restore`
can exit non-zero after writing the restored key if stale marker/pending cleanup
fails, so resolve that cleanup error before restarting the daemon.

### `cara status`
Health/status check via HTTP. `--json` emits a terminal-sanitized JSON object
with the lightweight `/health` payload under `health` and, when available, the
richer `/control/status` payload under `controlStatus`.

```bash
cara status --port 18789
cara status --port 18789 --json
```

### `cara logs`
Fetch log lines via WebSocket (`logs.tail`).

```bash
cara logs -n 50 --port 18789
```

`cara logs` is a snapshot tail request (not a persistent follow stream).

Remote hosts require TLS or explicit plaintext opt-in:
- `--tls` — use the WebSocket Secure scheme (recommended for remote)
- `--trust` — accept invalid TLS certs (only with `--tls`)
- `--allow-plaintext` — permit plaintext WebSocket on non-loopback hosts (unsafe; warns)

### `cara plugins`
Inspect runtime plugin status and manage installed plugins.

#### `cara plugins status`
Fetch plugin activation state via WebSocket (`plugins.status`).

```bash
cara plugins status --strict
```

Useful flags:
- `--json` — print JSON instead of human-readable output
- `--name <name>` — filter by configured plugin name
- `--plugin-id <id>` — filter by instantiated plugin ID
- `--source <managed|config>` — filter by activation source
- `--state <active|disabled|ignored|failed>` — filter by activation state
- `--only-failed` — show only failed plugin entries
- `--strict` — exit nonzero if activation errors exist, the filtered result is empty, or any returned plugin is not `active`

#### `cara plugins bins`
List managed plugin binary names tracked on disk (`plugins.bins`).

```bash
cara plugins bins
```

Use `--json` to print the raw response payload.

#### `cara plugins install`
Install a managed plugin (`plugins.install`).

```bash
cara plugins install demo-plugin --url https://example.com/demo-plugin.wasm
```

Local file workflow:

```bash
cara plugins install demo-plugin --file ./target/wasm32-wasip1/release/demo_plugin.wasm
```

Options:
- exactly one of `--url <url>` or `--file <path>` is required
- `--version <version>` — optional version string stored in the managed manifest
- `--publisher-key <key>` — optional publisher key to record with the managed artifact
- `--signature <signature>` — optional detached signature to record with the managed artifact
- `--json` — print the raw response payload

Notes:
- `--file` is local-only and stages the file into `state_dir/plugins/<name>.wasm` before calling `plugins.install`
- `--file` is intended for direct loopback targets; SSH port-forwarded remotes are not a supported workflow
- If the follow-up `plugins.install` request fails, the CLI restores the previous local managed artifact state when possible and reports the recovery action explicitly
- If `plugins.install` succeeds but the CLI cannot remove its local `.cli-backup` / `.cli-lock` staging files, the command exits nonzero and tells you to recover or remove those files before the next local `--file` mutation
- If a previous local `--file` install/update was interrupted and left `.cli-backup` or `.cli-lock` files under `state_dir/plugins`, the CLI fails closed instead of mutating plugin files again; verify that no other local file-based plugin mutation is still running, inspect the PID recorded in `.cli-lock` if needed, remember that PID values may have been recycled if the original process crashed, restore from the `.cli-backup` file if needed, remove stale `.cli-backup` / `.cli-lock` files, and then retry
- `--publisher-key` and `--signature` are validated against `plugins.signature` during install/update, and the same policy is enforced again at plugin load time
- managed plugin installs still require a Carapace restart before activation
- remote hosts use the same TLS/plaintext flags as `cara logs`

#### `cara plugins update`
Update a managed plugin (`plugins.update`).

```bash
cara plugins update demo-plugin --url https://example.com/demo-plugin.wasm
```

Local file workflow:

```bash
cara plugins update demo-plugin --file ./target/wasm32-wasip1/release/demo_plugin.wasm
```

`cara plugins update` accepts the same flags as `cara plugins install`.
If `--file` is used, the CLI stages the file into `state_dir/plugins/<name>.wasm`
and the server adopts that managed artifact on update. Managed plugin updates
still require restart before the new artifact becomes active. If the update
request fails after local staging, the CLI restores the previous local managed
artifact state when possible and reports the recovery action explicitly. If
`plugins.update` succeeds but the CLI cannot remove its local `.cli-backup` /
`.cli-lock` staging files, the command exits nonzero and tells you to recover
or remove those files before the next local `--file` mutation. If a
previous local `--file` install/update was interrupted and left `.cli-backup`
or `.cli-lock` files under `state_dir/plugins`, the CLI fails closed instead of
mutating plugin files again; verify that no other local file-based plugin
mutation is still running, inspect the PID recorded in `.cli-lock` if needed,
remember that PID values may have been recycled if the original process
crashed, restore from the `.cli-backup` file if needed, remove stale
`.cli-backup` / `.cli-lock` files, and then retry.

### `cara chat`
Start an interactive chat REPL (`chat.send` over WebSocket).

```bash
cara chat
```

Options:
- `--new` — start a new session key instead of resuming `cli-chat`
- `--port` / `-p` — connect to a specific local Carapace port

REPL commands:
- `/help` — show command help
- `/new` — start a fresh session
- `/exit` or `/quit` — exit chat

### `cara task`
Manage durable objective tasks through the control API.

```bash
cara task create --payload '{"kind":"agentTurn","message":"summarize recent logs"}'
cara task list --state queued --limit 20
cara task get <task_id>
cara task cancel <task_id> --reason "operator cancelled"
cara task retry <task_id> --delay-ms 60000 --reason "transient provider error"
cara task resume <task_id> --reason "operator approved continuation"
cara task update <task_id> --max-attempts 3 --reason "tighten retry budget"
```

Policy flags on `create` and `update` map to durable task budgets:
`--max-attempts`, `--max-total-runtime-ms`, `--max-turns`, and
`--max-run-timeout-seconds`.

### `cara pair`
Pair this CLI with a Carapace service.

```bash
cara pair https://gateway.local:3001 --name "My CLI" --trust
```

Notes:
- Requires service auth (token/password)
- Performs device-identity challenge/response during WS connect
- If pairing approval is required, the CLI prints a `requestId` for control UI approval

### `cara backup` / `cara restore`
Create or restore a backup archive of Carapace state.

`cara backup` writes a `.tar.gz` archive with a Carapace marker and the
operator state sections currently handled by the CLI: `sessions`, `config`,
`memory`, `cron`, `tasks`, and `usage` when those files/directories exist.
Restore validates the marker and rejects path traversal entries before writing.

The archive does not export secrets from the OS credential store,
`auth_profiles.json`, managed plugin binaries, node/device pairing registries,
or other state-dir files that are outside those sections. Keep provider
recovery material available or re-enroll credentials after moving to a new
machine.

### `cara reset`
Remove state data categories. Use `--all` or explicit flags plus `--force`.

### `cara update`
Check for or install updates from GitHub releases.

- `cara update --check` — check only (no install)
- `cara update --version <x.y.z>` — install a specific version

### `cara version`
Print version/build info.

### `cara tls`
Manage cluster CA and node certificates:
- `cara tls init-ca`
- `cara tls issue-cert`
- `cara tls revoke-cert`
- `cara tls show-ca`

## Authentication Inputs

The CLI resolves auth inputs in this order:

1. Environment: `CARAPACE_GATEWAY_TOKEN` / `CARAPACE_GATEWAY_PASSWORD`
2. Config file: `gateway.auth.token` / `gateway.auth.password`
3. OS credential store (Keychain / Secret Service / Credential Manager)

If none are found, local-direct access may still work when configured.

## Device Identity (CLI)

The CLI creates a device identity for WebSocket access:

- Stored in the OS credential store when available
- Falls back to `{state_dir}/device-identity.json` with owner-only file
  permissions when the credential store is unavailable, locked, or denied
- A service-issued `connect.challenge` nonce is signed and sent in `connect`

Set `CARAPACE_DEVICE_IDENTITY_STRICT=1` to fail instead of using the file-backed
device identity fallback.

## State Directory

Default: platform config directory (for example `~/.config/carapace/` on Linux).

Override with:
- `CARAPACE_STATE_DIR=/path/to/state`

## Common Snippets

Tail logs over TLS (self-signed service cert):

```bash
cara logs --host gateway.local --port 3001 --tls --trust -n 200
```

Allow plaintext logs (unsafe):

```bash
cara logs --host 10.0.0.12 --port 18789 --allow-plaintext
```

Pair with a remote Carapace service:

```bash
CARAPACE_GATEWAY_TOKEN=... cara pair https://gateway.local:3001 --name "Ops CLI" --trust
```

Start a fresh local chat session:

```bash
cara chat --new
```
