> ## Documentation Index
> Fetch the complete documentation index at: https://www.plungeai.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless and server

> oceancode runs without a UI two ways: a one-shot run for scripts and CI, and a long-lived serve that exposes the engine's HTTP surface to clients. The terminal UI is Ocean pager, which embeds the engine in its own process (see 19 · Ocean pager); serve is the headless surface.


`oceancode` runs without a UI two ways: a one-shot `run` for scripts and CI, and a long-lived
`serve` that exposes the engine's HTTP surface to clients. The terminal UI is Ocean pager, which
embeds the engine in its own process (see [19 · Ocean pager](/oceancode/pager)); `serve` is the
headless surface.

## One-shot — `oceancode run`

Run a single non-interactive turn and exit.

```bash
oceancode run "explain what this repo does"
oceancode run --format json "fix the failing test"
oceancode run --continue "and now add a test for it"
```

Flags go before the prompt (a flag after it is sent to the model as text, with a warning). When
stdin is not a terminal, `run` reads it to EOF and appends it to the prompt — the piped body is
the instruction — so a script that passes the prompt as an argument must close stdin
(`oceancode run "hi" </dev/null`) or the run waits forever (observed 2026-10-05: four minutes of
nothing with stdin left open).

Useful flags:

| Flag | Meaning |
|---|---|
| `--output-format <fmt>` | `stream-json` (newline-delimited events, then the final `result` envelope), `json` (a single buffered `result` object), or `text` (human, default). Supersedes `--format`. |
| `--format json` | Deprecated alias of `--output-format stream-json` — output unchanged. Emits newline-delimited events, then one final `result` envelope (`ok`, `steps`, `durationMs`, `messages`, `tokens`, `cost`) — written on the failure path too. |
| `-r <title>` / `--resume-title <title>` | Resume the most recent session whose title matches `<title>`. |
| `--tools <a,b>` | Restrict the advertised tool set to these ids (an unknown id is an error). |
| `--disallowed-tools <a,b>` | Remove these ids from the advertised set. |
| `--allow <Tool(pat),…>` | Append `allow` permission rules for the run. |
| `--deny <Tool(pat),…>` | Append `deny` permission rules (last-match-wins; a `--deny` beats an overlapping `--allow`). |
| `--append-system-prompt <text>` | Append text to the run's system context. |
| `--json-schema <path\|json>` | Structured output: validate the model's final JSON against this JSON Schema (a file path or inline JSON). Threads the schema into the prompt, re-prompts with the validation errors up to a bounded retry cap. On success the validated object is the result — printed bare in text framing, or as `result.structured` on the `--format json` result envelope (exit 0). An unsatisfiable or uncompilable schema exits **6** with the typed error; a run cut short keeps its typed exit code (budget 3 / time 4 / no-progress 5 / permission 2 / interrupt 130). |
| `--continue` / `-c` | Continue the last session. |
| `--session <id>` / `-s` | Continue a specific session. |
| `--fork` | Fork the session before continuing (needs `--continue` or `--session`). |
| `--agent <name>` | Start in a specific agent. |
| `--model <provider/model>` / `-m` | Use a specific model. |
| `--directory <dir>` | Working directory (defaults to the current one). |
| `--db <path>` | Session database file. |
| `--atif <path>` | Write the session's ATIF-v1.8 trajectory (JSON) to `<path>` at the end of the run — the same document `oceancode export --atif` produces. Empty/unset = off. See [06 · Session ledger and export](/oceancode/session-ledger-and-export#exporting-a-session). |
| `--subagent <provider/model>` | `/subagent` for a headless run: the sub-agent model this session's children run (e.g. `openai/gpt-5-mini`). Written onto the session (survives `--continue`). A value that is not `provider/model` is refused with the same words `/subagent` uses. Empty/unset leaves whatever the session already carries. |

Bound flags (`--max-usd`, `--max-minutes`, `--max-steps`, `--tideline`, `--subagent`) must come **before** the
prompt — the parser stops at the first non-flag word, and a bound placed after the prompt is
ignored with a warning. `--tideline <pct>%` sets the tideline as a share of the model's
context (e.g. `--tideline 50%`); `--tideline <limit>` or `default` also work. The floor and the
presets were removed: a second number or a preset word is refused with the usage line.
The old `--window` name is refused with the hint `use --tideline`; `--shelve` still works as an alias. See
[08 · Bounding a long run](/oceancode/bounding-a-long-run).

The engine also serves `GET /session/{id}/subagent` → `{"model": <ModelRef> | null}` — the session's
effective sub-agent model (the `/subagent` override, else the fleet router's `CLAUDE_CODE_SUBAGENT_MODEL`
while the subscription slot is live, else the `subagent.model` config, else the session's own model). A client
reads it for the identity row's `sub-agents <name>` segment; an engine without the route answers as
"nothing to show".

## Host-run workflows — `oceancode workflow`

Launch and control a host-run Rhai workflow without a UI. `workflow run` boots the engine the
same way `oceancode run` does, launches the workflow, streams each `workflow_updated` body as
one JSON line on stdout, and exits by the run's outcome.

```bash
oceancode workflow run pipeline --args '{"steps":[{"prompt":"say A"},{"prompt":"say B"}]}'
oceancode workflow run ./research.rhai --budget 64 --model openai/gpt-5-mini
oceancode workflow run pipeline --validate-only --args '{"steps":[{"prompt":"x"}]}'
oceancode workflow runs --all
oceancode workflow stop wf-…
```

The workflow **name (or a path to a `.rhai` file) comes first**, before any flags. A registered
name (a built-in such as `pipeline`, or a discovered `.oceancode/workflows/<name>.rhai`) is
resolved by the launcher; a path you type is read and run as an inline script.

| Flag (of `workflow run`) | Meaning |
|---|---|
| `--args <json>` | A JSON object bound to the script's `args` global (e.g. a pipeline's `steps`). Empty = `{}`. |
| `--budget <n>` | Absolute cap on cumulative child-agent calls for this run, `1..=1024`. Unset uses the `workflows.agent_budget` config default. |
| `--validate-only` | Run a metadata + compile smoke check only — prints a `validated` body and launches no agent (no provider call). |
| `--model <provider/model>` / `-m` | Fill this model in for workflow steps that specify none (a pipeline's `args.steps[].model`, else top-level `args.model`). It never overrides a model a step already carries, and there is **no default provider** — a step left unset follows the session policy. |
| `--directory <dir>` | Working directory the run and its sub-agents use (defaults to the current one). |
| `--db <path>` | Session database file. |
| `--verbose` / `-v` | Trace outbound LLM provider calls to stderr. |

**Exit codes** (the run's outcome): **0** `complete`; **2** `failed`, `cancelled` or
`budget_limited`; **3** a pause (`user_paused`, `back_off_paused`, `no_progress_paused`,
`infra_paused`, `blocked`). The last streamed line always carries the terminating body, so a
script can read the outcome from stdout as well as from `$?`.

`workflow runs [--all]` lists the persisted runs (each `workflow_updated` body, one per line),
read from the run directories under the app data dir — scoped to the current project unless
`--all` lifts the filter. `workflow pause|resume|stop <run_id>` drive the launcher's control
seam; `resume` takes an optional `--budget <n>` to lift a budget-limited run. These control a
run **live in the engine this command boots** — a run launched by a separate `oceancode
workflow run` has already exited in its own process, so cross-process control is a shared-server
concern not wired here.

## Goal mode — `oceancode goal`

Prove an objective is done, not merely claim it — headless. `oceancode goal "<objective>"` boots
the engine like `oceancode run` does, launches the built-in `goal` workflow (**Plan → Work →
Verify**: plan the objective into verifiable deliverables, work in rounds with one resumed
worker, and converge only when a cold panel of adversarial skeptics fails to refute completion),
streams each `goal_updated` body as one JSON line on stdout, and exits by the run's outcome. It is
the headless twin of the pager's `orchestrate: always` goal mode (`19-pager.md`).

```bash
oceancode goal "add a --json flag to the status command and prove it works"
oceancode goal --budget 64 --model openai/gpt-5-mini "port the parser to the new API"
```

The **objective is the positional argument** — quote it, or let the words after the flags form
it. Go-style flag parsing stops at the first positional, so any flag must come **before** the
objective.

| Flag | Meaning |
|---|---|
| `--budget <n>` | Absolute cap on cumulative child-agent calls for the whole goal, `1..=1024`. Unset uses the `workflows.agent_budget` config default. |
| `--model <provider/model>` / `-m` | Run-level default model: pins every one of the goal's agents (planner, worker, skeptics) whose own step set no model. There is **no default provider** — unset, each agent follows the session policy. |
| `--directory <dir>` | Working directory the goal and its sub-agents use (defaults to the current one). |
| `--db <path>` | Session database file. |
| `--verbose` / `-v` | Trace outbound LLM provider calls to stderr. |

**Exit codes** (the run's outcome): **0** `complete`; **2** `failed`, `interrupted` (a stopped
run) or `budget_limited`; **3** a pause (`user_paused`, `back_off_paused`, `no_progress_paused`,
`infra_paused`, `blocked`) — a goal that stalls on identical gaps two rounds running, or spends
its budget, pauses rather than looping forever. The last streamed line always carries the
terminating body, so the outcome reads from stdout as well as from `$?`. A finished goal is also
listed by `oceancode workflow runs --all` (it shares the workflow run store).

## Long-lived server — `oceancode serve`

```bash
oceancode serve                 # loopback, port 4096
oceancode serve --port 8080
```

| Flag | Meaning | Default |
|---|---|---|
| `--port <n>` | TCP port to listen on. | `4096` |
| `--host <ip>` | Interface to bind. Loopback by default; a non-loopback host refuses to start without `OC_SERVER_PASSWORD`. | `127.0.0.1` |
| `--db <path>` | Session database file. | `oceancode.db` |
| `--directory <dir>` | Working directory. | current directory |
| `--verbose` / `-v` | Trace outbound LLM provider calls. | off |

The default shape (`oceancode`, the pager) passes `--listen <host:port>` through to the engine it
embeds; a non-loopback bind refuses to start without a server password (below). The guard is
enforced inside the server for both `oceancode --listen` and `oceancode serve --host`.

## Authentication

HTTP basic auth is off until you set a password.

| Variable | Meaning | Default |
|---|---|---|
| `OC_SERVER_PASSWORD` | The basic-auth password. Empty means auth is disabled; any value turns it on for every route, SSE included. | unset (off) |
| `OC_SERVER_USERNAME` | The basic-auth username. | `oceancode` |

A non-loopback bind (`--listen` on the default shape, or serving to a public interface) refuses
to start unless `OC_SERVER_PASSWORD` is set.

## Managing capabilities from the CLI

Besides `run` and `serve`, the binary answers a set of non-interactive management
subcommands that boot no session. Each is read-only or writes a single config file, and exits.

| Subcommand | What it does |
|---|---|
| `inspect [--json]` | Print the provenance of every config key, capability, MCP server and instruction file for the current directory. See [09 · Capabilities and plugins](/oceancode/capabilities). |
| `doctor` | Report crash-recovery state: orphaned sessions (registry entries whose process died without a clean exit) and captured panic reports found under the data dir; prints `no orphaned sessions` when clean. Read-only. See [12 · Permissions and sandbox](/oceancode/permissions-and-sandbox#managed-enterprise-config). |
| `plugin …` | Manage plugins and marketplaces: `marketplace add\|list\|update\|remove`, `install`, `list`, `enable`/`disable`, `trust [--off]`, `validate`, `update`/`uninstall`, and `import --from claude-code [--trust] [--no-repo-trust] [--dry-run]` (copy Claude Code's plugins, register its marketplaces, seed trust). See [09 · Capabilities and plugins](/oceancode/capabilities#importing-from-claude-code). |
| `mcp …` | Manage MCP servers: `add` (`--command`/`--url`), `list` (every discovered server with `name  kind  tier  trusted  enabled  source`), `enable`/`disable`, `remove`, `login`/`logout`, `doctor`. See [11 · MCP servers](/oceancode/mcp). |
| `skill …` | `skill create <name> [--description <text>]` scaffolds `.oceancode/skills/<name>/SKILL.md`; `skill list [--json]` prints every discovered skill with its tier, trust and enable state. See [09 · Capabilities and plugins](/oceancode/capabilities#skills--browse-and-run). |
| `hooks …` | `hooks list [--json]` prints every hook source file the boot loader reads (tier, trust, loaded or held and why) with its handlers and ends with `HOOKS_OK sources=<n> handlers=<m> loaded=<k>`; `hooks add <Event> --command <cmd> [--matcher <re>] [--timeout <s>] [--scope user\|project\|local]` and `hooks remove …` edit the same `settings.json` files Claude Code writes. See [10 · Hooks](/oceancode/hooks#hooks-and-oceancode-hooks-list). |
| `jev status [--json] \| probe [--record …] \| labels \| questions --json \| verdicts --in <file>` | The Jev decision layer: each of the nine decision points' mode and endpoint host (`JEV_STATUS_OK points=9`), a one-call live probe (`JEV_PROBE_OK`) and fixture recorder (`probe --record`, `JEV_RECORD_OK`), the export of every labelled decision from the per-session `jev-decisions.jsonl` files into `bench/jev/labels.json` (`JEV_LABELS_OK`), and the seams' question sets and policy verdicts for the bench. Reads the current directory and your environment (no `--dir`/`--home`); only `probe` calls Jev. See [13 · Jev decisions](/oceancode/jev-decisions#the-oceancode-jev-subcommand). |
| `trust …` | The persisted per-project trust record (`~/.oceancode/trust.json`): `show` (ends with `TRUST_OK`), `repo on\|off`, `mcp <name> on\|off\|clear`. See [11 · MCP servers](/oceancode/mcp#held-until-trusted). |
| `migrate [--db <path>]` | Open and migrate a session database, then exit — the standalone form of the boot-time schema upgrade (`--db` defaults to `oceancode.db`). |
| `update [--self-test]` | Self-update to the newest release for the configured channel: verify the release signatures, swap `oceancode` and `ocean-pager` atomically, roll both back on a failed health check. `--self-test` proves the pair swap+rollback offline and prints `UPDATE_OK from=<old> to=<new> rollback_tested=1` then `UPDATE_SELF_TEST_OK binaries=2`. Channel/opt-out via `update.*`, `OC_UPDATE_CHANNEL`, `OC_NO_UPDATE_CHECK`. See [17 · Distribution and updates](/oceancode/distribution). |
| `verify-release <artifact> [--pubkey <base64>] [--sha256sums <path>]` | Verify a release artifact's minisign `.minisig` signature (and, with `--sha256sums`, its `SHA256SUMS` entry) in-process — no external tool. Prints `VERIFY_RELEASE_OK file=<name>`. The portable trust check on macOS, Linux and Windows. See [17](/oceancode/distribution#verifying-a-download). |
| `uninstall [--purge] [--yes] [--dry-run]` | Remove the binary the installer placed; `--purge` also removes the app's config and data dirs. Requires a typed `oceancode` confirmation unless `--yes`; `--dry-run` reports the plan and removes nothing. Prints `UNINSTALL_OK removed=<n>`. See [17](/oceancode/distribution#uninstalling). |
| `login [--provider claude\|copilot\|codex] [--no-browser]` | Log in and store the credential in `auth.json`. `claude` (default) runs the Claude Pro/Max subscription OAuth; `copilot` and `codex` run the OAuth 2.0 device-code flow. See [01 · Getting started](/oceancode). |
| `logout [provider]` | Clear the stored credential for a provider (default `anthropic`) from `auth.json`; the counterpart to `oceancode login` / `oceancode auth`. See [01 · Getting started](/oceancode). |
| `claude` | Preflight the claude-code provider: report whether the Claude Code CLI is installed and logged in. Advisory only — it never blocks a boot. |

Every management subcommand takes `--dir <d>` (the project; default: the current directory) and
`--home <h>` (the home the user tier and `~/.oceancode` are read from; default: your home) so a
script — or a test — can point it at another tree.

## Permission mode

A client reads and switches the session's permission mode over HTTP — the boot
default is the `permission_mode` config key, and these two routes change it live
(the pager switches it from its own prompt):

| Route | Meaning |
|---|---|
| `GET /api/session/{id}/permission/mode` | Returns `{ mode, bypass_locked }` for the session. |
| `POST /api/session/{id}/permission/mode` | Set the mode; body `{ "mode": "acceptEdits" }`. An unknown mode is `400`; `bypassPermissions` while a managed requirements file has locked it is `409`. |

The four modes are `default`, `acceptEdits`, `dontAsk`, `bypassPermissions` — see
[12 · Permissions and sandbox](/oceancode/permissions-and-sandbox#permission-modes).

## Managed (enterprise) configuration

For a shared or locked-down deployment, an administrator layers a managed config
and a signed requirements file over every project:

- `OC_MANAGED_CONFIG` — path to the managed config file (default: the OS admin
  path). It is loaded last, so it overrides the project and global files.
- `OC_REQUIREMENTS_PUBKEY` — the trusted ed25519 public key (64 hex chars) that a
  `requirements.json` signature is checked against; an unsigned or tampered file
  is refused. With no key set, managed requirements are not enforced.

Both are described in [02 · Configuration](/oceancode/configuration); the requirements
file can disable `bypassPermissions`, allow-list MCP servers, and pin config keys.
See [12 · Permissions and sandbox](/oceancode/permissions-and-sandbox#managed-enterprise-config).

## See also

- [01 · Getting started](/oceancode) — the three boot shapes.
- [02 · Configuration](/oceancode/configuration) — the server variables in one table.
