# Runtime environments

> Headless `orca serve`, runtime metadata/RPC transport, pairing codes, saved environments, and targeting a remote runtime from the CLI with `--environment` or `--pairing-code`.

- Repository: stablyai/orca
- GitHub: https://github.com/stablyai/orca
- Human docs: https://grok-wiki.com/public/docs/stablyai-orca-2036d532bf1c
- Complete Markdown: https://grok-wiki.com/public/docs/stablyai-orca-2036d532bf1c/llms-full.txt

## Source Files

- `src/cli/specs/core.ts`
- `src/cli/specs/environment.ts`
- `src/main/runtime/runtime-rpc.ts`
- `src/main/runtime/runtime-metadata.ts`
- `src/cli/runtime-client.ts`
- `src/shared/runtime-bootstrap.ts`
- `src/preload/runtime-environment-subscriptions.ts`

---

---
title: "Runtime environments"
description: "Headless `orca serve`, runtime metadata/RPC transport, pairing codes, saved environments, and targeting a remote runtime from the CLI with `--environment` or `--pairing-code`."
---

An Orca **runtime** is the main-process control plane that exposes JSON RPC over a local Unix socket or Windows named pipe, and optionally over WebSocket for remote clients. The bundled `orca` CLI discovers a **local** runtime through `orca-runtime.json` in user data; **remote** commands use a pairing offer (`orca://pair#…`) or a saved environment entry in `orca-environments.json`, then connect over WebSocket with per-device tokens and application-layer E2EE.

## Runtime roles

| Surface | Process | Local transport | Remote transport | Typical client |
| --- | --- | --- | --- | --- |
| Desktop app | Electron main + renderer | Unix socket / named pipe | WebSocket (optional, for pairing) | Renderer, in-app terminals |
| Headless `orca serve` | Electron main, no window | Same as desktop | WebSocket always enabled | CLI, mobile, web client |
| CLI against saved env | Any machine with `orca` | Reads store only for credentials | WebSocket to saved endpoint | `orca … --environment <name>` |

Headless serve skips the desktop PTY daemon and agent-hook loopback server; it registers a headless PTY runtime and publishes an empty window graph so `status.get` reports a ready server without a renderer.

## Bootstrap metadata (`orca-runtime.json`)

When `OrcaRuntimeRpcServer` starts, it writes a single metadata file under user data (default paths mirror Electron: macOS `~/Library/Application Support/orca`, Windows `%APPDATA%/orca`, Linux `$XDG_CONFIG_HOME/orca` or `~/.config/orca`). Override with `ORCA_USER_DATA_PATH` so CLI and app target the same instance (for example `orca-dev` during `pnpm dev`).

| Field | Type | Role |
| --- | --- | --- |
| `runtimeId` | string | Identity checked on in-flight local RPC responses |
| `pid` | number | Owning process; used for stale detection and socket sweep |
| `transports` | array | One or more of `unix`, `named-pipe`, `websocket` |
| `authToken` | string | Shared secret for **local** Unix/named-pipe RPC only |
| `startedAt` | number | Epoch ms at runtime start |

Local CLI RPCs read this file, pick the first `unix` or `named-pipe` transport, and send newline-delimited JSON:

```json
{"id":"<uuid>","authToken":"<from metadata>","method":"<rpc.method>","params":{...}}
```

<Note>
Metadata is written with mode `0o600` (via `writeSecureJsonFile`). On shutdown, metadata is **not** deleted by default so parallel restarts do not erase a sibling process’s bootstrap; `clearRuntimeMetadataIfOwned` only removes the file when `pid` and `runtimeId` still match the quitting process.
</Note>

### Local socket naming

| Platform | `kind` | Endpoint pattern |
| --- | --- | --- |
| macOS / Linux | `unix` | `{userData}/o-{pid}-{suffix}.sock` |
| Windows | `named-pipe` | `\\.\pipe\orca-{pid}-{suffix}` |

Orphan `o-*.sock` files whose PID no longer exists are swept at RPC server startup.

## RPC transports and security

```mermaid
flowchart TB
  subgraph clients [Clients]
    CLI_LOCAL[orca CLI local]
    CLI_REMOTE[orca CLI remote]
    DESKTOP[Desktop renderer]
    MOBILE[Mobile app]
  end

  subgraph runtime [Orca main process]
    RPC[OrcaRuntimeRpcServer]
    DISP[RpcDispatcher]
    META[(orca-runtime.json)]
    DEV[DeviceRegistry]
  end

  CLI_LOCAL -->|authToken + unix/pipe| RPC
  CLI_REMOTE -->|deviceToken + E2EE WS| RPC
  DESKTOP -->|authToken + unix/pipe| RPC
  MOBILE -->|deviceToken + E2EE WS allowlist| RPC
  RPC --> DISP
  RPC --> META
  RPC --> DEV
```

| Transport | Auth | Encryption | Connection model |
| --- | --- | --- | --- |
| Unix / named pipe | `authToken` in each request | None (same-user machine) | One-shot request/response per connection |
| WebSocket | Per-device `deviceToken` after E2EE handshake | Curve25519 ECDH + NaCl secretbox | Streaming dispatch; mobile methods restricted to allowlist |

WebSocket is supplementary: if bind fails (port in use), the runtime continues with Unix socket only and logs the failure. Default listen port is **6768**; the first dev instance pins **6769** when not in E2E mode.

Long-poll RPCs (`terminal.wait`, `orchestration.check` with `wait: true`) emit `{"_keepalive":true}` frames every 10s and are capped at 16 concurrent slots server-side (`runtime_busy` when full). The CLI extends socket timeouts for those methods using `params.timeoutMs + 10s` grace.

## Headless `orca serve`

`orca serve` spawns the Orca executable with `--serve` (foreground, Ctrl+C to stop). It does **not** use `--environment` or `--pairing-code`; those flags are ignored for `serve` and `environment` subcommands.

<ParamField body="--port" type="string">
Maps to `--serve-port` on the child. Integer 0–65535. Default WebSocket port is 6768 unless overridden or dev-pinned.
</ParamField>

<ParamField body="--pairing-address" type="string">
Advertised host for pairing URLs and web client links. Accepts a hostname/IP, `host:port`, bracketed IPv6, or full `ws://` / `wss://` URL. Without it, pairing endpoints use `127.0.0.1` on the bound port.
</ParamField>

<ParamField body="--mobile-pairing" type="boolean">
Creates a **mobile**-scoped device and prints a terminal QR when available. Mutually exclusive with `--no-pairing`.
</ParamField>

<ParamField body="--no-pairing" type="boolean">
Starts RPC without emitting a pairing offer.
</ParamField>

<ParamField body="--json" type="boolean">
Emits a single `orca_server_ready` JSON object instead of human-readable lines.
</ParamField>

### Readiness output

Human mode prints the WebSocket endpoint, optional web client URL (pairing data in URL **fragment** to avoid proxy logs), and `Pairing URL: orca://pair#…`.

JSON mode (`--json` or `--serve-json`):

```json
{
  "type": "orca_server_ready",
  "runtimeId": "<id>",
  "endpoint": "ws://0.0.0.0:6768",
  "pairing": {
    "url": "orca://pair#...",
    "endpoint": "ws://100.64.1.20:6768",
    "deviceId": "<uuid>",
    "webClientUrl": "http://.../web-index.html#pairing=...",
    "scope": "runtime",
    "qr": null
  }
}
```

`pairing` is `null` when `--no-pairing` is set or WebSocket/pairing prerequisites are unavailable.

<Steps>
<Step title="Start a headless runtime on a reachable address">

```bash
orca serve --pairing-address 100.64.1.20 --json
```

Copy `pairing.url` from the JSON payload (or the printed `Pairing URL` line).

</Step>
<Step title="Save the environment on your workstation">

```bash
orca environment add --name work-server --pairing-code 'orca://pair#...'
```

</Step>
<Step title="Run commands against the remote runtime">

```bash
orca worktree list --environment work-server --json
```

</Step>
</Steps>

<Warning>
`orca serve` requires `ORCA_APP_EXECUTABLE` (or running inside the packaged Electron CLI with `ELECTRON_RUN_AS_NODE=1`). Set the executable path when invoking serve from a plain Node install.
</Warning>

## Pairing codes

A pairing offer is version **2** (`PAIRING_OFFER_VERSION`) with:

| Field | Meaning |
| --- | --- |
| `endpoint` | WebSocket URL clients connect to |
| `deviceToken` | Pending device token registered in `DeviceRegistry` |
| `publicKeyB64` | Server Curve25519 public key for E2EE handshake |

Encoded form:

```
orca://pair#<base64url(JSON)>
```

`parsePairingCode` also accepts the bare base64url payload (paste-friendly). `orca environment add` and `--pairing-code` reject invalid codes with `invalid_argument`.

`createPairingOffer` on the server:

- Resolves the public WebSocket endpoint (honors `--pairing-address` / `--serve-pairing-address`).
- Creates or rotates a pending device (`scope`: `runtime` for CLI/desktop pairing, `mobile` for mobile QR flow).
- Optionally builds `webClientUrl` when the bundled web client exists (`out/web/web-index.html`).

## Saved environments

Persisted at `{userData}/orca-environments.json` (secure JSON, schema version `1`).

| Field | Notes |
| --- | --- |
| `id` | UUID; preferred selector when names collide |
| `name` | Unique display name at add time |
| `endpoints[]` | At least one `websocket` endpoint with `deviceToken` and `publicKeyB64` |
| `preferredEndpointId` | Used to rebuild a `PairingOffer` |
| `runtimeId` | Last seen remote runtime id (updated on successful RPC) |
| `lastUsedAt` | Updated when CLI or desktop marks usage |

CLI commands (always local store I/O — no remote RPC for the subcommand itself):

| Command | Purpose |
| --- | --- |
| `orca environment add --name <n> --pairing-code <code>` | Parse offer, append environment |
| `orca environment list` | List saved environments (secrets redacted in output) |
| `orca environment show --environment <selector>` | Show one (`id` or unique `name`) |
| `orca environment rm --environment <selector>` | Remove; desktop also closes cached WS connections |

`environment list` / `show` redact `deviceToken` and `publicKeyB64` from printed JSON; the on-disk file retains them for reconnect.

## Targeting a remote runtime from the CLI

Global flags on most command groups (from `GLOBAL_FLAGS`):

<ParamField body="--pairing-code" type="string" required={false}>
One-shot remote session using an `orca://pair#…` URL or bare payload. Mutually exclusive with `--environment`.
</ParamField>

<ParamField body="--environment" type="string" required={false}>
Selector for a saved environment (`id` or unique `name`). Resolves to the preferred endpoint’s pairing offer.
</ParamField>

Equivalent environment variables (used when flags omitted): `ORCA_PAIRING_CODE` or `ORCA_REMOTE_PAIRING`, and `ORCA_ENVIRONMENT`.

`RuntimeClient` behavior when remote:

1. Opens WebSocket to `offer.endpoint`, completes E2EE handshake, sends RPC with `deviceToken`.
2. Before non-`status.get` calls, runs protocol compatibility check (`RUNTIME_PROTOCOL_VERSION` 3, min compatible server 2).
3. On success with `--environment`, updates `lastUsedAt` and `runtimeId` in the store.

Commands that **ignore** remote selection (always local user data / local spawn): `environment *`, `serve`, and `agent` (per `shouldIgnoreRemoteSelection`).

<Tip>
For remote worktrees, use server-side selectors (`id:`, `branch:`, `issue:`, `path:<absolute-on-server>`). Local shortcuts such as `path:` for the current working directory are rejected against a remote runtime.
</Tip>

### Example invocations

```bash
# Ephemeral remote session
orca status --pairing-code 'orca://pair#eyJ2IjoyLCJl...' --json

# Named environment
orca terminal list --environment work-server --json

# Cannot combine
orca repo list --pairing-code '...' --environment work-server   # invalid_argument
```

## Protocol compatibility

Remote CLI calls require overlapping protocol versions reported by `status.get`:

| Constant | Value |
| --- | --- |
| `RUNTIME_PROTOCOL_VERSION` | 3 |
| `MIN_COMPATIBLE_RUNTIME_SERVER_VERSION` | 2 |

Mismatch surfaces as `incompatible_runtime` before other RPCs run. Capability `runtime.environments.v1` is advertised for environment-aware clients.

## Desktop and web clients

The renderer uses `runtimeEnvironments` IPC (`runtimeEnvironments:list`, `addFromPairingCode`, `call`, `subscribe`, …) to manage the same `orca-environments.json` store and proxy RPC to remote servers. Preload subscribes to `runtimeEnvironments:subscriptionEvent` **before** `invoke('runtimeEnvironments:subscribe')` so streaming frames are not missed.

Web and mobile clients consume pairing URLs from serve output or in-app pairing flows; mobile WebSocket RPCs are limited to `MOBILE_RPC_METHOD_ALLOWLIST` in `runtime-rpc.ts`.

## Operational notes

| Symptom | Likely cause | Mitigation |
| --- | --- | --- |
| `runtime_unavailable` / metadata read error | App not running, wrong `ORCA_USER_DATA_PATH`, or incomplete metadata | Start Orca or `orca serve`; align user data path |
| `stale_bootstrap` in `orca status` | Metadata exists but RPC dead | Restart runtime; check PID |
| `Invalid remote pairing code` | Malformed `--pairing-code` | Copy full `orca://pair#…` from serve output |
| `Use either --pairing-code or --environment` | Both flags set | Pick one targeting mode |
| `Environment name "…" is ambiguous` | Duplicate names in store | Use environment `id` from `environment list` |
| `incompatible_runtime` | CLI/runtime protocol skew | Upgrade client or server together |
| `runtime_busy` on long waits | Long-poll capacity (16) exhausted | Retry with backoff |
| WebSocket `endpoint: null` in serve JSON | WS failed to bind | Free port 6768/6769 or pass `--port` |

```text
userData/
  orca-runtime.json      # local discovery: socket + authToken
  orca-environments.json # saved remote targets (CLI + desktop)
  o-<pid>-<suffix>.sock  # Unix RPC (ephemeral per process)
```

## Related pages

<CardGroup>
<Card title="CLI core reference" href="/cli-core-reference">
`serve`, `status`, `open`, and global flags including `--environment` and `--pairing-code`.
</Card>
<Card title="Selectors and JSON output" href="/selectors-json-output">
Remote selector rules, `--json` envelopes, and error shapes.
</Card>
<Card title="SSH remote worktrees" href="/ssh-remote-worktrees">
SSH execution targets and CLI constraints on paired runtimes.
</Card>
<Card title="Quickstart" href="/quickstart">
Local install path: open Orca, worktree, and `orca status` without remote targeting.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Runtime reachability, selector ambiguity, and native dependency failures.
</Card>
</CardGroup>
