# crates/cli reference

> Reference for the code under `crates/cli`: what it exports, how it is invoked, its options and defaults, and its error cases.

- Repository: egoist/lorca
- GitHub: https://github.com/egoist/lorca
- Human docs: https://grok-wiki.com/public/docs/egoist-lorca-2cf67495e5e6
- Complete Markdown: https://grok-wiki.com/public/docs/egoist-lorca-2cf67495e5e6/llms-full.txt

## Source Files

- `web/content/docs/cli.mdx`
- `crates/cli/src/main.rs`
- `crates/cli/src/lib.rs`

---

---
title: "crates/cli reference"
description: "Reference for the code under `crates/cli`: what it exports, how it is invoked, its options and defaults, and its error cases."
---

Run `lorca serve` (or plain `lorca`) to bind `ws://127.0.0.1:<port>/ws`. The package under `crates/cli` is both the Device/Runner library (crate name `lorca`, entry `crates/cli/src/lib.rs`) and the `lorca` binary (`crates/cli/src/main.rs`, feature `cli`).

## Package and features

| Item | Value |
| --- | --- |
| Package | `lorca` (`crates/cli/Cargo.toml`) |
| Library | `crates/cli/src/lib.rs` → crate name `lorca` |
| Binary | `crates/cli/src/main.rs` → `lorca` (`required-features = ["cli"]`) |
| Default features | `cli` |
| Workspace version | from root `Cargo.toml` workspace package |

| Feature | Pulls in | Role |
| --- | --- | --- |
| `cli` | `runner`, `server`, `usage`, `tracing-subscriber` | Full command-line binary |
| `runner` | `provider-auth`, `lorca-agent`, MCP deps | Bots, tools, providers |
| `server` | `axum` | Local websocket for the app |
| `provider-auth` | `lorca-provider-auth` | Connect/disconnect providers without the agent loop |

Phone builds link the core through `lorca-mobile` with `default-features = false` and `provider-auth` only (no `cli` binary surface).

## Invoke the binary

Default command when none is given: `serve`.

```bash
lorca
lorca serve
lorca --home ~/.lorca --port 4862 status
```

Logging goes to **stderr**. Default filter when `RUST_LOG` is unset: `lorca=info,lorca_agent=info`.

### Global options

<ParamField body="home" type="path" optional>
Long flag `--home`. Env `LORCA_HOME`. Default `~/.lorca` (or `./.lorca` if no home directory). Data directory for keys, DB, credentials, plugins, workspaces.
</ParamField>

<ParamField body="port" type="u16" optional>
Long flag `--port`. Env `LORCA_PORT`. Default `4862`. Local websocket bind port (`127.0.0.1` only).
</ParamField>

Unknown flags error (`unknown_flags = "error"` on the CLI derive).

## Commands

| Command | Purpose |
| --- | --- |
| `serve` | Local API + sync + agent runtime (default) |
| `identity new\|restore\|show` | Create, restore, or print this Device’s identity |
| `pair [string]` | Start pairing or join with a pairing string |
| `provider set\|remove\|list` | Connect, disconnect, or list providers |
| `status` | Pretty-printed JSON snapshot |
| `doctor` | Local health checks (always exits successfully after printing) |

### `lorca serve`

```bash
lorca serve [--parent-pid <pid>] [--ready-stdout]
```

<ParamField body="parent_pid" type="u32" optional>
`--parent-pid`. When that process exits, the CLI shuts down shell sessions and exits `0`. Used by the desktop app so a killed UI does not leave a stale server on the port.
</ParamField>

<ParamField body="ready_stdout" type="bool" optional>
`--ready-stdout`. After bind succeeds, writes one JSON line to stdout and flushes: `{"event":"ready","port":<u16>}`. Logs stay on stderr.
</ParamField>

On start, `serve`:

1. Primes bot names and resumes sent jobs
2. Closes stale shell rows left by a previous quit
3. On Unix, installs SIGTERM/SIGINT/SIGHUP handlers that shut down shell sessions before re-raising the signal
4. Refreshes installed marketplace plugins against the bundled index
5. Spawns login-shell environment capture, relay sync, and routines
6. Binds `127.0.0.1:<port>` and serves `/` (`"lorca"`) and `/ws`

<RequestExample>
```bash
lorca serve --ready-stdout --port 0 --home /tmp/lorca-test
```
</RequestExample>

<ResponseExample>
```json
{"event":"ready","port":54321}
```
</ResponseExample>

Port `0` lets the OS assign a free port; the readiness line reports the actual port. A failed bind exits without writing readiness (stdout stays empty).

### `lorca identity`

```bash
lorca identity new [--name <device-name>]
lorca identity restore <phrase...> [--name <device-name>]
lorca identity show
```

| Subcommand | Success signal | Failure |
| --- | --- | --- |
| `new` | Prints backup phrase (base32 lowercase, no padding, groups of four → 13 groups for a 32-byte master). Creates lead bot `Chef` on this Runner. | Already has identity: remove `LORCA_HOME` first |
| `restore` | `Identity restored. Run lorca serve to sync.` | Needs relay URL; phrase must unwrap DEK from relay; fails if identity already present |
| `show` | Prints identity id, keys, device name/os, master-hold flag, registered flag | Prints guidance to run `identity new` when empty |

`new` without a relay prints a note to set `LORCA_RELAY_URL`. With a relay, it runs one outbox flush (8s timeout).

### `lorca pair`

```bash
lorca pair                          # host: print string, wait
lorca pair '<lorca://pair?…>' [--name <device-name>]
```

| Mode | Behavior |
| --- | --- |
| No argument | Prints a pairing string, polls until `completed` or `failed`, then flushes outbox once |
| With string | Joins as a Device; prints `Paired as …. Run lorca serve to sync.` |

Failed host wait bails with the status error string (or `pairing failed`).

### `lorca provider`

```bash
lorca provider set <kind> [api-key] [--base-url <url>]
lorca provider remove <kind>
lorca provider list
```

Kinds: `deepseek`, `anthropic`, `opencode`, `opencode-go`, `chatgpt`, `grok`.

| Kind group | Connect flow |
| --- | --- |
| API-key kinds | Key from argv or stdin; optional `--base-url` |
| `chatgpt`, `grok` | Browser sign-in only; API key / `--base-url` bail |

When `lorca serve` is listening on the configured port, provider mutations go over `ws://127.0.0.1:<port>/ws` so the live app updates immediately. Otherwise the CLI dispatches locally and flushes the outbox once.

### `lorca status` / `lorca doctor`

- `status` — pretty-printed JSON from `App::snapshot()`
- `doctor` — prints ✔/✘ lines for home, identity, port, relay, providers; always returns success after printing

## Local HTTP / websocket surface

Bound address: `127.0.0.1:<port>` only (`crates/cli/src/ws.rs`).

| Route | Behavior |
| --- | --- |
| `GET /` | Plain text `lorca` |
| `GET /ws` | JSON-RPC + push events |

Request shape: `{ "id", "method", "params" }` → `{ "id", "result" }` or `{ "id", "error": { "message" } }`. Push events: `{ "event", "data" }` (see `crates/cli/src/events.rs`).

## Environment variables

| Variable | Role |
| --- | --- |
| `LORCA_HOME` | Data directory (default `~/.lorca`) |
| `LORCA_PORT` | Local bind port (default `4862`) |
| `LORCA_RELAY_URL` | Relay URL; wins over `settings.json` |
| `LORCA_DEFAULT_RELAY_URL` | Fallback when nothing else names a relay |
| `LORCA_DEV` | Non-empty and not `0`: use LAN `http://<lan-ip>:8787` when no relay is set |
| `LORCA_SHELL` | Shell for bot commands (read in `lorca-agent` bash tool; default `/bin/bash` or Git for Windows bash) |
| `LORCA_*_MODEL` | Default model overrides (`DEEPSEEK`, `ANTHROPIC`, `OPENCODE`, `OPENCODE_GO`, `CHATGPT`, `GROK`) |
| `LORCA_*_BASE_URL` | Provider API roots when credential has none |
| `LORCA_GROK_ISSUER` | Grok OAuth issuer override |
| `LORCA_MARKETPLACE_URL` | Extra marketplace index beside the bundled one |
| `LORCA_COMPACTION` | `0` disables compaction |
| `LORCA_MEMORY_FLUSH` | `0` disables memory flush before compaction |
| `LORCA_OAUTH_NO_BROWSER` | `1` skips opening a browser for OAuth |
| `RUST_LOG` | Tracing filter (stderr) |

Relay resolution order: `LORCA_RELAY_URL` → `settings.json` `relay_url` → machine pairing URL → `LORCA_DEV` LAN relay → `LORCA_DEFAULT_RELAY_URL`.

## Home directory layout

Under `LORCA_HOME` (mode `0700` on Unix; private JSON files `0600`):

:::files
~/.lorca/
  identity.json      # master secret (identity device)
  machine.json       # this Device’s machine keys + metadata
  credentials.json   # account provider credentials
  settings.json      # relay_url, marketplace_url
  lorca.sqlite3      # local store
  files/             # attachments
  plugins/           # installed plugins + secrets
  workspaces/<bot>/  # per-bot workspace and memory
:::

Dev desktop builds often use `LORCA_HOME=~/.lorca-dev` and port `4863`.

## Library surface (`lorca`)

`crates/cli/src/lib.rs` exports modules used by the binary, mobile bindings, and tests.

| Module | Role |
| --- | --- |
| `api` | JSON-RPC method dispatch for `/ws` |
| `app` | Loaded Device state, snapshot, relay helpers |
| `config` | `Config`, `Settings`, paths, defaults |
| `credentials` | `PROVIDER_KINDS`, connect/merge/save |
| `identity`, `keys`, `pairing`, `crypto` | Identity and pairing |
| `ws` | Local axum server (`server` feature) |
| `sync`, `relay`, `runtime`, `routines` | Relay sync and Runner loops |
| `providers`, `shell`, `turns`, `local_review` | Runner-only (`runner` feature) |
| `provider_auth` | Optional connect flows (`provider-auth` feature) |

## Error cases

| Situation | Behavior |
| --- | --- |
| Port already bound | `serve` fails: `cannot bind 127.0.0.1:<port>: …. Is another lorca serve running?`; no readiness line |
| Unknown provider kind | Bail: `Unknown provider … Use one of: deepseek, anthropic, …` |
| API key on chatgpt/grok | Bail: `<kind> connects with a browser sign-in and takes no API key` |
| Identity already exists | `identity new` / `restore` bail |
| Restore without relay | Bail: set a relay URL first |
| Pairing failed | Bail with status error string |
| Live serve closed mid-RPC | Bail: `lorca serve closed the connection` |
| Serve RPC error | Mapped from websocket `error.message` |

Provider CLI changes against a running serve keep the app’s in-memory view in sync; offline changes sync on the next `serve` outbox flush.

## Related pages

<CardGroup>
  <Card title="CLI reference" href="/cli-reference">
    Product-facing commands, install scripts, and Runner setup.
  </Card>
  <Card title="Configuration reference" href="/configuration-reference">
    Config keys, env vars, and where each value is read.
  </Card>
  <Card title="crates/relay reference" href="/ref-crates-relay">
    Relay binary, storage backends, and HTTP routes.
  </Card>
  <Card title="crates/agent reference" href="/ref-crates-agent">
    Agent loop, tools, and provider adapters used by Runners.
  </Card>
  <Card title="Architecture" href="/architecture">
    App ↔ CLI ↔ relay process boundaries.
  </Card>
</CardGroup>

Next: run `lorca doctor` and confirm every line shows ✔ (or fix the ✘ lines it prints).
