Skip to content
18.1k

CLI Agents, Routing, and Integrations

These commands control agent policy and routing, inspect the live proxy, and connect supported clients to opencodex.

ocx agent <status|injection|effort|subagents|fallback|roles|sidecar|memory-models|compaction-routing> ...

Section titled “ocx agent <status|injection|effort|subagents|fallback|roles|sidecar|memory-models|compaction-routing> ...”

Manage the headless multi-agent roster, effort caps, prompt injection, fallback, and sidecar settings. Use status for the current policy. See Sub-agent surfaces for how surface modes, delegation, effort, and fallback behavior fit together.

Terminal window
ocx agent subagents set ark/model-a,openai/gpt-5.5

ocx agent roles is for omo (Codex / LazyCodex). It lists each Codex agent role in $CODEX_HOME/agents with its model pin and whether ~/.omo/omo.jsonc can be updated, or says LazyCodex is not installed, in which case set is refused. ocx agent roles set <role> <model> [--effort <level>] rewrites only that role’s root model line, and its model_reasoning_effort line with --effort, and mirrors both into omo.jsonc at [codex].agents.<role> as model and reasoning. An effort LazyCodex has no level for, such as ultra, is written to the role file only. A missing omo.jsonc, or one containing comments, is left unchanged and the command says so. See omo (Codex / LazyCodex) role models.

Terminal window
ocx agent roles set explorer xai/grok-4.5 --effort medium

ocx agent roles suggest is omo (Codex / LazyCodex) only, refused like set when LazyCodex is not installed. It sizes every role with one call to the default Codex model (or --model) and prints a proposed model and effort per role without writing anything. --apply writes every proposal through the same write as set, skipping and naming the roles whose model and effort already match. See Auto-assign.

One --apply accepts at most 50 changed roles, so its recorded changes fit one complete history batch and can be restored together in the dashboard’s Change history. Already-set, unsized and unassigned roles do not count toward this limit. If more than 50 roles would change, the command exits 5 before sending any role update. Preview without --apply, then use ocx agent roles set <role> <model> [--effort <level>] for individual changes.

Updates run sequentially. If a request fails, earlier confirmed writes remain applied, later roles are not attempted, and the command keeps the original nonzero error exit. The receipt names confirmed writes, the role whose write was not confirmed, roles not attempted, and the server-issued history batch when known. A lost response can follow a saved write, including the first write before its batch id is received; inspect ocx agent roles --json and the dashboard history before retrying. No automatic retry or rollback occurs. History remains subject to its existing availability and retention limits; a batch id does not guarantee that every write was recorded or is still restorable. With --json, an interrupted apply adds complete: false, unconfirmedRole and unattemptedRoles beside the existing applied, skipped and omoJsoncNotWritten arrays. A preflight refusal instead adds refusal with code too_many_role_changes, the limit and the proposed change count.

Human-readable suggestion output displays terminal control characters as visible escapes. Use --json when you need the original suggestion values without presentation escaping.

ocx agent injection suggest <work> does the same for the delegation model: it sizes the described work, proposes the cheapest sufficient model and an effort from the delegation picker’s list, and writes nothing unless --apply is given, which saves through the same write as injection set. See Delegation model and effort.

ocx agent sidecar web --list and ocx agent sidecar vision --list print the models the server currently offers for each sidecar — the exact filtered set the dashboard picker shows (picker-visible rows plus the login-entitled Luna/Haiku auth slots, intersected with executor availability for web search, minus provably text-only models for vision). Human-readable lists show each model’s backend in brackets. A web-search --model write resolves that server-offered row and persists its backend and model together, so switching to an Anthropic option cannot keep an OpenAI backend (or vice versa). Writes go to the same management route as the GUI and are subject to the same per-sidecar gate: web search refuses a backend/model pair outside the listed set (closed membership), while vision refuses only a model provably unable to see (unknown ids stay writable).

Terminal window
ocx agent sidecar web --list
ocx agent sidecar web --model gpt-5.6-luna
ocx agent sidecar web --enabled off

--enabled off is the same switch as the Dashboard’s Off row: OpenCodex stops running the sidecar and the Codex integration writes web_search = "disabled" into ~/.codex/config.toml, which is what lets an MCP search server be the only search path. --enabled on removes that marker-owned line again. When the save actually moves the switch, the command reports the Codex-side write it triggered (codexWebSearch in --json, a trailing Codex config: line otherwise) and points at ocx sync when it could not happen; a save that leaves the switch where it was has nothing to report and prints no Codex config: line. The flag works for vision too.

Injection defaults and sidecar runtime settings

Section titled “Injection defaults and sidecar runtime settings”
Terminal window
ocx agent injection status --json
ocx agent injection set --sync-codex-defaults off --json
ocx agent injection status --json
ocx agent sidecar web --stream-routed-output on --json
ocx agent sidecar vision --timeout-ms 30000 --json
ocx agent sidecar status --json

Run writes only for the requested change. Injection --sync-codex-defaults on|off updates syncCodexSubagentDefaults; omitted model/effort/prompt/guidance stay intact, and - clears model/effort/prompt. The receipt has actual normalized model, effort, prompt, multiAgentGuidanceEnabled and syncCodexSubagentDefaults, not a fabricated catalog result.

Web --reasoning remains supported. --max-descriptions and --timeout-ms are vision-only; timeout accepts integers from 1 to 2147483647 milliseconds. --stream-routed-output is web-only. Partial writes preserve sibling settings. The new-option receipt exposes only the selected public webSearch or vision state and codexWebSearch apply report. {applied:false, reason, retryable} distinguishes native apply deferral/refusal from a saved setting; a missing or mismatched new setting is unverified and nonzero. Read status for full observed settings, including web reasoning. Do not retry blindly on ownership refusal.

Terminal window
ocx agent memory-models show --json
ocx agent memory-models set --extract-model <route> --extract-effort high --consolidation-model <route> --json
ocx agent memory-models show --json
ocx agent compaction-routing show --json
ocx agent compaction-routing set --model <route> --effort high --triggers manual,auto --sources '<exact-source>,<provider>/*' --json
ocx agent compaction-routing show --json

Each set replaces the entire block. Memory accepts extract/consolidation model and optional effort pairs; an effort without that phase’s model is refused. Omitted phases use their existing/default route, not a stopped pipeline. --file memory.json instead reads the block itself:

{"extract":{"model":"example/model","reasoningEffort":"high"}}

An explicit memory file {} is valid and remains an empty override block; ocx agent memory-models clear --json writes null. Both mean no custom override, not disabled memory processing. File mode is exclusive with scalar options. Regular UTF-8 files or piped --file - use the 4 MiB/30-second bounded-input contract, including a 4 MiB serialized request limit.

Compaction files contain required model, optional reasoningEffort, triggers and sourceModels. Triggers are unique manual/auto; source selectors must be exact and unique, or provider/* patterns. Omitted triggers use server defaults; omitted sources select all sources, not the previous custom scope. ocx agent compaction-routing clear --json writes null and restores ordinary compaction routing without disabling compaction. No synthetic model call verifies these saves.

Reads return only {memoryModels: blockOrNull} or {compactionRouting: blockOrNull}. Writes add catalogRefreshPending: false exits 0 without promising every client applied, true exits 1 after saving. Missing/malformed pending evidence is null with verification:"unverified" and exit 1. Read back before recovery.

Inspect or change main and subagent reasoning-effort caps through the live proxy, or the local configuration when no proxy is available. Cap values are low, medium, high, xhigh, max, and ultra; - clears the selected cap. none and minimal are not cap levels and are rejected before probing the proxy or submitting an update, including when another option in the same command is valid. They remain valid for --injection, which sets the separate injection effort rather than a cap.

Terminal window
ocx effort status --json
ocx effort set --main high --subagent low
ocx effort set --subagent -

Status preserves existing stored/runtime cap values and reports unsupported values in warnings (an empty array when none are unsupported). The same warnings appear in human output and name the field that is ignored with a correction command. Status never repairs or rewrites those values. An ignored subagent field does not remove a valid main cap. ocx effort clear clears both caps while retaining the separate injection-effort setting. See Sub-agent surfaces for the request surfaces where caps apply.

ocx v2 <status|on|off|mode <v1|default|v2>|keep-native-v1 <on|off>|threads <n>|mode-hint <text|--clear>>

Section titled “ocx v2 <status|on|off|mode <v1|default|v2>|keep-native-v1 <on|off>|threads <n>|mode-hint <text|--clear>>”

Manage the Codex multi_agent_v2 feature flag and the three-state multi-agent surface mode. These operate locally by default. --live uses the selected running proxy with no local fallback; both targets support --json. Re-read status on the same target after a change and distinguish stored settings from new-session behavior.

Subcommand Action
status (default) Report the current v2 flag, multi-agent mode, and thread concurrency.
on Enable the global multi_agent_v2 feature; local changes resync the catalog. Rejected while the v2 hybrid pin is active because the global override would defeat it.
off Disable the multi_agent_v2 feature and resync the catalog.
mode v1 Force all models to v1, disable native v2, and preserve the active thread limit.
mode default Respect upstream model surface pins.
mode v2 Force models to v2 and preserve the active thread limit. With keep-native-v1 off, enable global native v2; with it on, disable the global override and use catalog pins.
keep-native-v1 on|off Under mode v2, keep ChatGPT-native models on v1 and routed models on v2. Enabling it disables the global V2 override before catalog sync.
threads <n> Set the active v1/v2 thread limit to an integer of at least 1.
mode-hint <text> Set the Proactive delegation hint (Ultra mode) for every model and effort.
mode-hint --clear Remove the hint so the effort-derived policy (ultra = proactive) resumes.
Terminal window
ocx v2 status
ocx v2 mode v1
ocx v2 mode default
ocx v2 on
ocx v2 threads 16
ocx v2 mode-hint "Proactive multi-agent delegation is active."
ocx v2 mode-hint --clear

The mode subcommand writes multiAgentMode to the opencodex config and resyncs the Codex catalog. Mode and flag transitions move the current numeric thread limit between the valid v1/v2 Codex keys; a failed transition restores the original config.toml. Changes apply to new Codex sessions, while running sessions keep their pinned surface.

Codex resolves an enabled global multi_agent_v2 override before the selected model’s catalog pin. The hybrid keep-native-v1 contract therefore keeps that global override off; otherwise a native row stamped v1 would still start on V2 and produce backend-encrypted child tasks.

mode-hint writes features.multi_agent_v2.multi_agent_mode_hint_text in Codex’s $CODEX_HOME/config.toml even when multi_agent_v2 is currently disabled. The command only persists the override; it does not enable or disable the feature, so the hint takes effect when a matching Codex surface is active. The hint overrides codex-rs’s effort-derived multi-agent policy, so any model and any reasoning effort receives the Proactive delegation prompt. It does not change reasoning effort itself. A missing argument or a whitespace-only value is rejected; only --clear removes the hint. The Subagents dashboard’s Ultra mode on toggle has a stricter gate: it requires the native feature to be enabled with an explicit v2 surface (ocx v2 mode v2); ocx v2 on alone does not satisfy that dashboard gate.

Terminal window
ocx v2 status --json
ocx v2 status --live --json
ocx v2 mode v1 --live --json
ocx v2 status --live --json

The live write uses the existing management route. Only explicit live mode accepts --acknowledge-surface-advisory; add it only when acknowledging that advisory is requested. Local mode and status/on/off/keep-native/threads/hint reject it. There is no automatic acknowledgment.

For literal reserved hint text, pass one quoted operand after --:

Terminal window
ocx v2 mode-hint --live --json -- '--clear'

This stores literal --clear; without --, mode-hint --clear removes the hint. The suffix is not scanned for help, live, JSON or clear controls; controls belong before --. Extra operands and duplicate flags refuse before mutation.

Local JSON is {ok, target:"local", action, changed, state, sync} using actual post-write state. Mode/keep-native and changed on/off keep their real sync attempt even without a discovered port; threads/hints and unchanged on/off add no sync. An absent/malformed sync result becomes unverified with exit 1, not success. changed or state can be unknown after failure; do not claim rollback. Live status reports validated state/advisory/recommendation with target:"live"; writes add ok:true and catalogRefresh. Only committed, nondegraded refresh exits 0. HTTP 502 may mean partially applied native state: inspect before retrying. Local usage errors retain exit 1; new live usage errors use exit 2.

ocx combo <list|show|set|remove|stats> ... · ocx route combo ...

Section titled “ocx combo <list|show|set|remove|stats> ... · ocx route combo ...”

Manage combo failover and round-robin virtual models. ocx route combo is the hierarchical alias; combos and routing profiles are distinct resources. Combo targets use provider/model[:weight],provider/model[:weight].

Terminal window
ocx combo list
ocx route combo set reliable --targets ark/model-a:2,openai/gpt-5.5

set accepts --strategy, --sticky, --effort, --alias, --rename-from, --native-alias, and --display-name <label|-> (- clears the label). A native alias captures only one currently supported, unqualified bare OpenAI model id. Bare gpt-5.6-* native aliases use Codex Pool/Direct credentials. Account-qualified OpenAI routes remain distinct, while provider-qualified routes such as openai-apikey/gpt-5.6-* use their configured API key and never fall through to the native alias. Read the safety and visibility contract in the guide before enabling the compatibility pair. Only when the effective strategy is JEV (--strategy jev, or a stored JEV Combo when --strategy is omitted), the decision method is chosen by one of two mutually exclusive flags. --decision-provider <provider|-> names a configured jev-decision row (for example a self-hosted Ollama tev1) as a System One-compatible server. --decision-model <route|-> names an ordinary opencodex route (for example ollama/qwen3:4b) that answers the same choice as JSON; it cannot be this combo or any JEV combo. A new JEV Combo that omits both uses TypeSafe; an existing JEV Combo keeps its stored decision method until one of the flags changes it. --decision-timeout <ms|-> sets the decision deadline (1000–120000, default 4000); - clears any of the three.

ocx combo set <id> --decision-quota-signals on|off|- controls per-Combo advisory evidence. --decision-quota-tiers '{"limited":80}' sets partial threshold overrides; - clears them. Both are JEV-only. Omitted policy survives --targets-file or --targets replacement and rename. Without --strategy, replacing the targets of an existing Combo keeps its stored strategy, so a JEV Combo stays JEV with its decision method, quota settings and session pin; a new Combo defaults to failover. If the kept JEV policy rejects the new targets, the command fails, names that policy, and saves nothing. Off retains thresholds; switching away from JEV removes both settings. This adds quota data to the selected decision backend, not probes, new account selection or hard exclusions. See quota defaults, freshness and privacy.

ocx combo set <id> --session-pin <duration|-> (JEV only) keeps each client session on the target JEV chose for it while the session stays active, so the provider prompt cache stays warm. The duration is the idle window: 90s, 20m, 1h or milliseconds, from 1 minute to 24 hours; - turns it off. See Session pin for JEV.

ocx combo test [--combo <id>] [--decision-provider <provider|jev> | --decision-model <route>] [--decision-timeout <ms>] sends one synthetic decision probe through a saved combo’s method or an unsaved selection and reports the gate, backend, and latency; it may spend one decision call. ocx combo discover [--query <text>] lists configured System One rows and catalog models that look like decision models, with the derived endpoint.

For structured target metadata, inspect offline help and the current combo:

Terminal window
ocx combo set --help
ocx combo list --json
ocx combo show reliable --json

A --targets-file document is a nonempty ordered array, for example this shape with provider/model values replaced by actual configured candidates:

[{"provider":"example","model":"raw/model","weight":1,"reasoningEfforts":["high"],"modelProfile":"Reasoning tasks","lastResort":false}]

Optional fields are weight, reasoningEfforts, modelProfile and lastResort. Efforts are a unique nonempty list of low, medium, high, xhigh, max, ultra; empty/none/minimal custom-model semantics do not apply. Files or explicit piped - have a 4 MiB limit and 30-second read deadline; the serialized management body must also fit 4 MiB. Unknown fields refuse before the write.

Terminal window
ocx combo set reliable --targets-file targets.json --image-input auto --reasoning-effort-mode strict --json
ocx combo show reliable --json

--targets-file and --targets are mutually exclusive. Omitting both preserves complete target metadata for partial edits; replacement files preserve order and explicit lastResort: false. --image-input auto|disabled and --reasoning-effort-mode strict|adaptive preserve omission, while explicit auto and strict override saved disabled/adaptive values. Reasoning-effort mode is separate from --effort-mode fallback|force, which governs the default effort. --allow-metered-targets on|off grants or clears operator consent for marked combo targets on a loopback-only proxy; public and linked callers still need configured-key consent. --native-alias on|off preserves explicit false; the legacy bare flag means true. Turning it off may require the intended alias clear, --native-alias off --alias -, to avoid retaining an incompatible native alias. Set/rename is an upsert without CAS, so re-read after changes. The receipt is {success, id, model, combo, catalogRefresh}; skipped, failed or degraded catalog refresh returns nonzero after saving.

Terminal window
ocx combo stats reliable --range 30d --json

Use the exact stored combo ID from list/show, not its public model or alias. Ranges are 7d, 30d (default), and all. This reads recorded JEV observations without running a paid decision probe. Inspect decisions, model attempts, measured attempts, model tokens and decision tokens separately. Keep the measuredModelAttempts/modelAttempts and decisionUsageReported/decisions coverage ratios with the totals. Nullable averages are unavailable, not zero. Preserve usageIncomplete, historyTruncated, entriesTruncated, dropped-entry counts and snapshot-window boundaries. Zero observations do not prove success. There is no monetary cost or comparative savings field in this report.

See Combos for routing behavior and configuration guidance.

ocx fallback <status|off|on|clear|local> ...

Section titled “ocx fallback <status|off|on|clear|local> ...”
Terminal window
ocx fallback status --json
ocx fallback off --kind provider
ocx fallback on --route combo/coding
ocx fallback clear --provider anthropic --kind model
ocx fallback local on --device mac-studio

off, on and clear take --kind model|provider|all (default all) and at most one scope: --provider <name>, --route <selector> or --device <id|alias>; with none they set the global switch. A device set to off always refuses; otherwise route beats provider beats global. local records whether a device may use its own providers while the Home is unreachable, a permission GOAT reads; OpenCodex itself still answers home_unreachable there. The commands talk to the live proxy; on a Remote Link Child, status reads the Home and writes are refused. See Fallback off.

Existing profiles support inspection and evaluation through the live API:

Terminal window
ocx route policy list --json
ocx route policy show reliable --json
ocx route policy dry-run reliable --model-context 128000 --tools --image --structured-output --json

Only run this evaluation with authority to activate Lab on the target. The management POST can activate Lab and start automation that is already enabled there, including upstream probes. Use list/show for observation without that activation effect.

Replace reliable with a listed ID. evaluate is an alias for dry-run; both send requirements to the saved profile’s evaluator without an inference request. Creation, update and deletion use the explicit file/revision workflow below. Combo writes edit a separate resource. Missing profiles return exit 4 and missing operands return 2.

Edit a routing profile with its observed revision

Section titled “Edit a routing profile with its observed revision”

Create/update can activate Lab and already-enabled automation, including upstream probes. Only run them with that authority. List/show are observational; first read offline help and save the intended profile:

Terminal window
ocx route policy update --help
ocx route policy show reliable --json > profile.observed.json
jq 'del(.id, .model, .revision) | if .alias == null then del(.alias) else . end' profile.observed.json > profile.next.json

Edit and review the next file; keep the observed file unchanged. Input contains only editable alias, candidates, require, optimize, limits, unknownEvidence, and compatibility with supported nested fields. id, model, revision, unknown keys and null alias are not editable input. The server still validates provider, alias and policy semantics. --file - accepts piped stdin; regular UTF-8 files/stdin have the 4 MiB and 30-second bounded read contract.

Terminal window
ocx route policy update reliable --file profile.next.json --expected-revision '<exact-revision-from-observed-show>' --json
ocx route policy show reliable --json

Use the original opaque revision explicitly. HTTP 409 / exit 5 means read show again, review concurrent changes and rebuild the edit. Never silently fetch a replacement revision, retry or convert update into create. For an authorized new ID use ocx route policy create <new-id> --file profile.next.json --json without a revision. Authorized removal is ocx route policy remove <id> --yes --json and has no revision guard.

Create/update returns {success, id, model, profile, catalogRefresh} with the new profile.revision; remove returns {success, id, catalogRefresh}. Only committed, nondegraded refresh exits 0. A saved receipt with skipped/failed/degraded refresh exits 1: inspect before recovery instead of repeating the configuration write.

Lab is local inspection and explicit evidence/automation management. Reads use the local projection and do not require a running management API:

Terminal window
ocx lab status --json
ocx lab catalog --json
ocx lab subjects --limit 10 --json
ocx lab automation status --json
ocx lab automation runs --limit 10 --json
ocx lab public community --json

subject, observations, event, artifact, and production-signals follow local evidence lineage. The public family offers preview/export by repeated --event <id>, verification/import through --file <bundle.json>, and community context. Export and import write local evidence. Verification can print its result and still exit nonzero when the bundle is not cryptographically valid.

Automation enable/disable changes local policy; manual lab run selects a layer and scenario and may spend upstream quota. Read ocx help lab and the relevant leaf before these authorized operations. A saved local policy does not prove that a separately running proxy’s scheduler adopted it. Full automation policy editing and run cancellation are not exposed by these CLI controls.

ocx observe <logs|usage|storage|memory|debug|claude-inbound|injection> ...

Section titled “ocx observe <logs|usage|storage|memory|debug|claude-inbound|injection> ...”

Inspect proxy requests, usage, storage, memory, and debug data. The direct aliases are:

Alias Equivalent resource
`ocx logs [filters] [–follow] [–json –jsonl
`ocx usage [–range <today 1d
`ocx usage compare [–range <today 1d
ocx storage [--json] ocx observe storage
ocx memory [--json] ocx observe memory
Terminal window
ocx observe usage --range 30d --json
ocx usage --since 2026-09-01T09:00:00Z --until 2026-09-01T10:59:59.999Z --json

--since and --until must be supplied together. They accept integer epoch milliseconds or full ISO datetimes with an explicit timezone, include both endpoints, and override --range. Invalid or reversed bounds fail before the request. Human output prints the requested interval; --json includes customWindow, since, and until. Existing surface/provider/model filters still apply. These commands query the running proxy; they do not provide offline reports.

--range today (alias 1d) reports the current local day. --provider and --model narrow the report to one upstream target — distinct from --surface, which selects the calling client (Codex, Claude Code, Grok) rather than the provider serving the request.

The default view prints request, token and estimated-cost totals plus per-provider and per-model breakdowns. Costs are API list-price equivalents, not a billing receipt: subscription plans and provider credits are billed separately, and requests with no matching price row are counted as unpriced/unmetered rather than folded in as zero.

Terminal window
ocx usage --range today --provider xai

When some usage records cannot be included, human output warns, including when there are zero readable rows. Any displayed totals reflect readable records only. If a filter has no readable matches, the output shows the warning and guidance instead of total lines; skipped records may contain matches. --json preserves the response-level usageIncomplete diagnostic and reason.

Compare a range with the previous equal window

Section titled “Compare a range with the previous equal window”
Terminal window
ocx usage compare --range today --json
ocx usage compare --range 7d --provider xai

ocx observe usage compare is the equivalent family form. The command reads GET /api/usage twice: the named range ending now, then the same range evaluated one equal window earlier (one local day for today/1d, seven for 7d, thirty for 30d). Default range is 30d. --range all is refused because open history has no previous equal window. --since and --until are not accepted; the windows are derived. Surface, provider, model, and API-key filters apply to both reads. Human output prints current, previous, signed delta, and percent change. --json is {schemaVersion,range,current,previous,delta,change,incomplete}. The two reads are sequential, not an atomic snapshot. Custom since/until on each response must match the requested window. Both reads use the same connection and credential. If the connection, account, or credential changes during the command, it reports an owner mismatch and asks you to retry instead of printing a comparison.

Terminal window
ocx logs history --provider xai --status 200 --limit 50 --json
ocx logs history --cursor '<nextCursor>' --json
ocx logs get <request-id> --json

ocx observe logs history and ocx observe logs get are the equivalent family forms. These read the derived request-history index, not the recent ocx logs ring. --limit is 1–100 (default 50). --from and --to accept epoch milliseconds or full ISO datetimes with a timezone and are inclusive. --json returns {entries,hasMore,nextCursor,index}. --jsonl emits rows only; when more pages exist, nextCursor=… is printed on stderr so a caller can resume without mixing the token into the row stream. Empty matches succeed. get returns one canonical row by request ID; ocx logs explain remains the route-decision view for that same ID.

Terminal window
ocx logs filter --surface claude --status errors --time-window 1h --scan-limit 2000 --limit 50 --json

ocx observe logs filter is the equivalent family form. This reads one recent window, filters locally, then keeps the newest matches in their original order. --scan-limit controls fetched rows (1–2000, default 2000); --limit controls returned rows (1–2000, default 200). JSON reports {schemaVersion:1,logs,cursor,filters,window:{scanLimit,loaded,matched,returned,limit}}. Counts describe this observed window, not all history. JSONL emits rows only; empty matches succeed. Cursor metadata is not a resumable search token.

Selectors include --surface all|codex|claude|grok, --status all|success|errors, --time-window all|15m|1h|24h, --model, --provider, --conversation (alias --conversationId), --intercepted-only, --min-tok-per-sec, --max-tok-per-sec, and --protocol-mode all|native|translated|legacy-bridge|blocked|none. Model/provider equality is trimmed and case-insensitive, including resolved/served models and attempts. Claude includes Desktop; Codex means absent surface. Success is HTTP 200–299, errors 400–599. Time lower bounds are inclusive. Speed uses observed value-kind tok/s, with inclusive minimum and exclusive maximum; unavailable values fail active speed filters. Protocol none includes absent or invalid traces. Conversation matching uses the same hash-aware IDs as ordinary logs. Interception selects string-valued rewrite markers.

Unknown/repeated/conflicting flags, invalid bounds, and follow/events fail before discovery. Malformed, oversized or failed reads are nonzero, not empty results. To reduce response size, reduce the scan limit; reducing output limit does not change the fetch. For streaming use the separate follow forms below.

Terminal window
ocx usage --range 7d --search 'model-a' --json

--search matches a trimmed case-insensitive substring in model, provider or resolved model after reading the report. It sorts model rows by descending total tokens with stable ties and keeps up to 100 by default. JSON adds modelView:{query,matchedModelCount,returnedModelCount,limit:100,truncated}; human output labels the view and shows its selected model rows. Report totals, provider/day/account rows, exact filters and incomplete/window metadata remain unchanged. No model match does not mean no report usage.

An explicit blank query (--search=) selects the top-100 view; omitting search preserves the existing output. Exact --provider/--model still scope the underlying report. Search does not broaden selected-key or connected-client self scope and is never sent as a new Hub API query parameter.

ocx usage --top 25 (also ocx observe usage --top 25) sets the human model table limit to an integer from 1 to 1000. The default is 10, or 100 with --search; the limit applies after search filtering. It changes local display only: report totals, provider/account rows and API parameters stay unchanged. With --json, a valid --top is ignored; JSON retains its existing full report or 100-row search view. Invalid limits return exit 2 before fetching.

Terminal window
ocx companion show --json
ocx companion usage --json

The second command reads saved companion settings, then today and 30d usage sequentially on the same management runtime. It applies the saved models and hiddenProviders preferences and preserves unknown/unmeasured costs and tokens. Null model selection means all; an empty selection means none. It does not change settings, operate native windows or relay through a connected client.

JSON returns schemaVersion:1, filters, settingsUpdatedAt, settingsCorrupt, settingsFallback, ranges and partial. Each range has status:"available" with filtered data, or status:"unavailable". An unavailable range sets partial and exit 1 while retaining the other range. Available incomplete data retains its own metadata; it is not measured zero. Valid server defaults retain a null settings timestamp and set fallback; corrupt-file defaults additionally set corrupt and warn in human output. Malformed settings stop before usage reads. These reads are not an atomic snapshot. Each GET has a 10-second fetch/body deadline after discovery and a 32 MiB response cap; this is not a whole-command deadline. Signals exit 130/143 without late results.

Follow request windows or injection sequences

Section titled “Follow request windows or injection sequences”
Terminal window
ocx logs --help
ocx logs --limit 200 --json
ocx logs --follow --events --limit 200

--events requires follow and implies JSONL; redundant --jsonl is accepted. --json remains one-shot and conflicts with follow/events. Each events-v1 line is {schemaVersion:1,type:"snapshot"|"append",rows,cursor,limit}. Replace the consumer window on snapshot, append/trim on append, preserving order and repeated IDs. Initial empty and reset/removal snapshots are emitted; stable empty polls remain silent. Legacy arrays are snapshots with cursor null, not invented cursors. These are observed windows, not a lossless replay of traffic missed between polls or after ring eviction.

ocx logs --follow --jsonl --limit 200 retains row-shaped output. It re-emits changed occurrences, including same-ID status/token amendments and repeated IDs. Do not collapse everything by request ID. This legacy output cannot encode removals, resets or exact window order; choose events when those distinctions matter. Log follow limit is 1–2000, default 200.

Terminal window
ocx observe injection --limit 500 --json
ocx observe injection --follow --jsonl --limit 500

Injection emits ordered {seq,at,line} rows, where at is epoch milliseconds; internal after advances with seq. Follow limit is 1–2000, default 500. JSON is one-shot and JSONL requires follow. Observation does not enable capture. Empty polls do not identify disabled capture or prove absence of gaps. Detectable runtime drift stops; undetectable restart/latest-N gaps cannot be excluded without an API epoch/gap marker.

Both follow loops use serial one-second waits, 10-second fetch/body deadlines and 32 MiB response limits. Malformed/oversized/transport errors stop with stderr and exit 1, without automatic retry/reconnect. Reduce limit for oversized windows. SIGINT/Ctrl-C exits 130, SIGTERM 143, with no later polls/output. Inspect exit state and retained rows instead of treating cancellation as complete history.

Terminal window
ocx companion timeline --help
ocx companion timeline --hours 24 --bucket-minutes 60 --metric total --aggregation sum --grouping model --model example/model-a --hide-provider excluded-provider --json

Replace fictional IDs with the selected filters. Repeat --model for individual provider/model IDs (nested slashes allowed; not CSV); repeat --hide-provider to exclude providers. Positive --provider is unsupported. Hours are 6/24/72/168, bucket minutes 1–1440 with at most 2000 buckets, metric total/input/output/cached, aggregation sum/average/max, grouping model/modelAccount. The API limits filter inputs to 100 items. This reads usage without changing companion settings.

Check appliedFilters.models/hiddenProviders. Timeline bounds are epoch seconds, with exclusive end, unlike ordinary usage’s millisecond custom window. The end must match the request-time bucket, or its immediate successor if the request crosses a bucket boundary; an older aligned window is refused. Empty series retains bucket/filter metadata. missingMeasurements and truncated must remain visible: zero-filled points do not prove complete zero usage.

On a non-client management host:

Terminal window
ocx access key list --json
ocx usage --api-key-id key-example --range 7d --json

Use a non-secret actual key ID. The CLI requires exact response acknowledgment in filter.apiKeyId; ignored filters fail rather than showing unscoped totals. An unknown acknowledged ID can return matched:false and empty traffic, not 404. Keep incomplete/custom-window facts. Connected clients reject --api-key-id before enrolled-key access or transport; omit it for existing self-only Hub usage or perform the selected-key view on the Hub. No data key grants management authority.

ocx debug <provider|usage|injection|claude> <on|off|status|reset|logs [-f]>

Section titled “ocx debug <provider|usage|injection|claude> <on|off|status|reset|logs [-f]>”

Read or change runtime debug overrides through the running proxy’s management API.

Terminal window
ocx debug provider on|off|status|reset
ocx debug provider logs [-f|--follow]
ocx debug usage on|off|status|reset
ocx debug usage logs [-f|--follow]

With no scope, ocx debug prints usage and, when the proxy is stopped, the next-start environment defaults. Provider debug defaults from OCX_DEBUG=1 (legacy OCX_DEBUG_FRAMES=1 also works); usage debug defaults from OPENCODEX_USAGE_DEBUG=1.

ocx access <key|endpoints|models|test|audio> ...

Section titled “ocx access <key|endpoints|models|test|audio> ...”

Inspect admission keys, external endpoints and models with the access family. ocx api-key aliases the access-key family. Creation and rotation-start return a one-time plaintext credential in text and JSON output. Agents must leave those steps to a human-operated terminal outside the agent session; request only confirmation and non-secret key/rotation IDs, never the credential.

Terminal window
ocx access key list --json

After the human configures and verifies the replacement, committing its rotation or removing the old key requires separate explicit revocation authority. Safe non-secret follow-ups are ocx access key rotate commit <id> <rotation-id> --json and ocx access key rotate abort <id> <rotation-id> --json, with authority for the chosen action. Re-list afterward. Missing pending state alone does not prove commit: expiry or abort can also clear it. Do not route around consent by issuing the secret-returning management request directly.

Rename one key without changing its access policy

Section titled “Rename one key without changing its access policy”
Terminal window
ocx access key rename key-example 'Research client' --json
ocx access key list --json

Use an actual unique ID or unambiguous name. Rename sends only {id,name} and preserves provider/model scopes; it does not rotate/delete a key. The response contains id/name/createdAt and optional allowedProviders/allowedModels, never plaintext or a prefix. List remains masked. Names are control-free, trimmed, nonempty and at most 64 JavaScript string units. The read/rename sequence is not CAS; inspect the masked roster after an unknown outcome before retrying. The root api-key rename alias uses the same command.

Discover the installed syntax without contacting upstream:

Terminal window
ocx access test --help
ocx access audio transcribe --help
ocx access audio live-check --help

Model requests, audio uploads and live-session checks require explicit operator authorization for that particular upstream operation and possible quota/cost. The operator supplies the selected key from an approved private stdin source in a human-operated terminal outside the agent session. Agents must not capture it or ask for it in chat. Never put it in argv/environment. These are the ocx side of that private pipe, not direct interactive key prompts or an agent-run batch:

Terminal window
ocx access test example/model --protocol responses --api-key-stdin --json
ocx access audio transcribe sample.wav --model gpt-4o-mini-transcribe --api-key-stdin --json
ocx access audio live-check --model gpt-live-1-codex --api-key-stdin --json

Choose only the authorized task and real model/file. TTY input is refused. Input is bounded to 4096 bytes/30 seconds, valid UTF-8 printable ASCII, without outer whitespace, controls or extra lines; one final LF/CRLF is allowed. This deliberately covers currently issued keys, not every Unicode value the server configuration might accept. Exact supplied-key occurrences in permitted text become [redacted]; arbitrary encodings are not guaranteed detected. No encoded key carrier is printed.

Targets are the checked local serving origin or existing normalized enrolled Hub origin, with identity checked around asynchronous work. There is no custom-origin, admin or enrolled-key fallback, redirect following, credential cache or automatic retry. The operator reports only the non-secret result to the agent.

Protocols are chat (default), responses or messages. Selected-key mode first sends one credentialless malformed-JSON control to that endpoint. Only the native key-required 401 advances to one fixed 16-token model request using the supplied key. The control has a 5-second/4096-byte response budget; the request has a 60-second/2 MiB response budget including body reads. Authless/unrecognized controls stop before inference. Local logging/admission bookkeeping may still occur.

JSON is {schemaVersion:1,control:{outcome,status?},request:{outcome,status?},response?}. Safe response contains protocol, ordered text, complete/limited completion and optional measured token counts. A usable length-limited reply is limited; refusal/content-filter/tool-only or malformed responses are unsupported, even with HTTP 2xx. Error metadata, IDs, tools and reasoning are not printed. Operational failure retains one versioned report plus fixed stderr/exit 1; invalid grammar/key input exits 2 without a fabricated report.

Success says only: “Credentialless request was refused; the model request using the supplied key succeeded.” Listener/policy changes between calls remain possible; this does not certify key scope, atomic admission or billing identity. Without --api-key-stdin, legacy test JSON remains its original payload and says nothing about a newly selected key.

Transcription requires a nonempty regular file of at most 25,000,000 bytes with a 30-second local read limit, and a multipart body capped at 32 MiB. Models are gpt-4o-transcribe, gpt-4o-mini-transcribe or whisper-1, subject to target support. Upload/response share 130 seconds; response is capped at 2 MiB. Success returns only {text}, including empty text, with exact-key redaction. Failure leaves stdout empty and prints fixed stderr/nonzero; no JSON error envelope or raw body.

Audio uses explicit-key admission without the model control. Live-check sends fixed session.update and session.close only. Readiness requires session.started or session.updated with nonblank native session ID within 15 seconds; socket-open or session.created alone is insufficient. After readiness it waits at most 2 seconds for normal code-1000 closure. Each UTF-8 frame is capped at 64 KiB, aggregate 2 MiB; there is no retained frame history.

Live JSON is {schemaVersion:1,ready,close:"confirmed"|"unverified",check:"session-readiness",event?}. Operational failure preserves that observation without raw frames. Partial readiness with unverified close exits 1; a later normal close cannot erase an earlier error. Signals exit 130/143. This checks readiness/closure only, not microphone, upload, tool execution, full voice roundtrip or server lease release. Opening the upstream session is not guaranteed free. No reconnect or retry is automatic.

Inspect and set how requests travel between the client APIs and provider wires. See Protocol paths for the vocabulary.

Command Route Changes state
ocx api protocols [--provider <name>] [--json] GET /api/protocols No
ocx api explain --model <id> --inbound <responses|chat|messages> [--feature <key>]... [--json] POST /api/protocols/plan No
ocx api policy [--json] GET /api/protocols No
ocx api policy [--messages <on|off>] [--unrepresentable <legacy|reject>] [--rollout <switch>=<on|off>]... [--json] PATCH /api/protocols/settings Yes
  • protocols prints the contract version, whether each client API is served and why, the unrepresentable policy, every rollout switch, and the policy revision. --provider adds the upstream wire that provider receives, who decided it, and the models on another wire.
  • explain previews the path a model would take from one client API. --feature is repeatable and accepts a comma-separated list; ocx api protocols --json lists the known feature keys. The preview is computed from configuration: nothing is sent upstream, no combo rotation advances, and the input is not logged.
  • policy without a setting flag only reads. With one it sends a single change to the running proxy, which validates it, saves the configuration, and answers with the new policy. --messages off also turns the Claude integration off, as the dashboard toggle does. Switch names and combinations are validated by the proxy; for example --rollout managedMessagesNativeOAuth=on is refused unless managedMessagesNative is already on or turned on in the same command.
Terminal window
ocx api explain --model combo/main --inbound chat --feature request.seed,request.tools
ocx api policy --rollout shadowPlan=on

Usage errors exit 2 before any request is sent. --json prints the management API body as is.

Command Action
ocx integration client status [--client <id>] [--profile <id>] [--json] Read all managed file integrations, one client, or Aside profiles. show and list alias status.
ocx integration client history [--client <id>] [--profile <id>] [--json] Read rollback operations and snapshot availability. journal aliases history.
ocx integration client enable --client <id> [--profile <id>] [--overwrite-conflict] [--json] Apply the managed file integration. Overwriting a conflicting block requires the explicit flag.
ocx integration client disable --client <id> [--profile <id>] [--json] Remove the selected managed integration through its runtime owner.
ocx integration client restore --op <opId> [--client aside --profile <id>] [--confirm-drift] [--json] Restore a recorded operation; replacing later edits requires explicit drift confirmation.
ocx integration native [list] [--json] Read native integration state.
ocx integration native <claude|claude-desktop|codex|grok> <on|off> [--json] Write the selected native client’s configuration through its runtime owner.

These commands require a running proxy. --profile selects a nonnegative Aside account ID and requires --client aside; omitted profiles select the aggregate for reads and all profiles for unbound enable/disable. Native toggles change client configuration; Cursor has separate read-only inspection commands below. For preview and bound-write options, continue with the recipes below.

Preview and recover managed file integrations

Section titled “Preview and recover managed file integrations”
Terminal window
ocx integration client preview --client hermes --operation apply --json
ocx integration client restore --op op-example --preview --json

op-example is fictional; use an ID from history. Preview operations are apply, overwrite and disable; restore uses --preview on its existing command. Review structural changes and canApply/willChange; valid refusal/no-op exits 0 without applying. Enable/disable/restore accept optional --plan-fingerprint for an explicit bound commit. Direct legacy writes remain available. Aside preview or bound writes require --client aside --profile N. Drift confirmation and overwrite are never automatic; stale binding exits 5 with empty stdout and a re-preview instruction on stderr. Follow the complete preview/commit and drift recipes.

Droid apply/overwrite supports repeated --reasoning-default MODEL=EFFORT for full map replacement, or exclusive --clear-reasoning-defaults for {}. Omission preserves the map. Repeat the exact map in preview and commit; see Droid defaults.

History removal is irreversible and requires an exact opId plus --yes: ocx integration client history remove --op op-example --yes --json addresses the global journal. Only --client aside and optional --profile N provide narrower delete scopes. The newest row is protected. snapshotRemoved:false exits 1 after retirement with cleanup incomplete; do not retry deletion or claim rollback.

ocx integration client sync --client aside --json refreshes eligible profiles through the attested owner, with no profile selector or local fallback. Empty results is successful observation of no eligible profiles; a failed row makes the aggregate nonzero while preserving other successes. Read status and recovery facts before retrying; Aside controls explain profile intent versus file state.

Terminal window
ocx integration native cursor status --json
ocx integration native cursor local-installer --json

Status can gather model inventory; installer lookup may fetch a public manifest. They do not download/install or toggle Cursor. Status distinguishes credential from placeholder gateway mode; the placeholder is not an access credential. Installer {available:false,url:null,version:null,reason:null} is valid, including when Private Inference is already installed. A valid unavailable read exits 0.

Manage supported Claude and Grok integrations. The direct command families below expose their client-specific controls.

Ensure the proxy is running, then launch Claude Code with ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1, and model slots from config.claudeCode. Routed models appear in the native /model picker through stable slot aliases with Claude Code 2.1.129 or newer. On older versions, select with ANTHROPIC_MODEL or /model <id>. User-exported ANTHROPIC_* variables always take precedence.

Claude Desktop profile commands are:

ocx claude desktop [apply] Save and apply the four-family profile
ocx claude desktop show [--json] Show routes, families, and defaults
ocx claude desktop status [--json] Show applied state, drift, and health
ocx claude desktop move <route> <family> [--default]
ocx claude desktop default <family> <route|none>
ocx claude desktop export <path|-> Export versioned JSON (`-` = stdout)
ocx claude desktop import <path> [--apply] Validate and import JSON

The families are opus, fable, sonnet, and haiku; new routes start in opus. none is valid only when that family is empty. Legacy apply flags --static, --hybrid, and --discovery-only remain supported. Use ocx claude config <status|set> ... for Claude Code settings.

Read or save the selected runtime’s Desktop profile

Section titled “Read or save the selected runtime’s Desktop profile”

The existing show/import commands above are local. The profile family targets the running management runtime and can gather model inventory:

Terminal window
ocx claude desktop profile show --json > desktop-observed.json
jq '.profile' desktop-observed.json > desktop-profile.json

Edit/review the versioned profile, preserving server-owned applied markers. For an authorized save, then read-back:

Terminal window
ocx claude desktop profile import desktop-profile.json --json
ocx claude desktop profile show --json

Import accepts the profile itself, not the outer {profile,models,rendered,port} response, using bounded regular JSON files or explicit stdin - (4 MiB/30 seconds). It returns those observed fields plus ok:true, meaning saved only. --apply and native-mode flags are rejected; failed runtime save has no local fallback. Apply is a separate existing Desktop action on its machine, so verify host/context before choosing it. Rendered models are not proof of native application.

The key is supplied only when the configuration and its namespaces are protected from other principals; the current user and privileged OS authorities are trusted. Same-user processes are trusted: an actor with your write access can already read your OpenCodex key file. Same-user configuration replacement between verification and native startup is outside this threat model; the launcher does not freeze configuration at handoff.

On a normal Windows installation, default ProgramData permissions allow other users to create directories. Automatic credentials are therefore withheld even when ProgramData\OpenAI\Codex is absent. The system Codex configuration folder under ProgramData must exist and be writable only by Administrators/SYSTEM, and its ancestors must prevent replacement by other users. Ask an administrator to review the directory policy. opencodex never changes ACLs itself and provides no provisioning command.

Alternatively, supply the key yourself, for example by exporting OPENCODEX_API_AUTH_TOKEN; ocx codex leaves it untouched. Existing system configuration files still withhold automatic credentials and require separate review. Each withholding reason produces one short, specific stderr diagnostic without key values, key-file contents or key-file paths.

Use -- before a single-word prompt so it cannot select an unknown Codex subcommand.

The machine configuration namespace must also prevent other users from creating missing system files. An unprotected Windows ProgramData/OpenAI/Codex namespace withholds automatic credentials; the launcher does not create it. macOS accepts deny-only and read-only allow ACLs, but refuses any allow entry granting write, append, delete, attribute/security changes or ownership changes, even after a deny entry. Unknown tags and inspection errors refuse.

A fresh service token is loaded only when argv is within the allowlist below, the environment has no nonempty HTTP(S)/ALL proxy or CODEX_*/OPENAI_*/AZURE_OPENAI_* overrides (canonical CODEX_HOME is allowed), and the home/config/system namespaces pass ownership checks. The configuration must contain only audited keys and the exact managed loopback provider, with no additional credential consumers or configuration layers. Every unsupported argument, including -c/--config, -p/--profile, unknown flags and resume/fork, withholds the token with a value-free diagnostic; explicit user credentials and original arguments are preserved.

The canonical home directory and config.toml must belong to the current user. POSIX denies group/other writes; Windows checks owner SID and rejects DACL write grants outside the current user, SYSTEM and Administrators. Ancestor replacement permissions are checked too. macOS additionally requires no forced Codex configuration preferences. These checks exclude other-user writers; they do not isolate a malicious process running as the same user or an administrator.

Allowlist Flags
Switches --no-daemon, --json, --ephemeral, --skip-git-repo-check, --no-alt-screen, --full-auto, --dangerously-bypass-approvals-and-sandbox, --search
One value --model/-m, --sandbox/-s, --ask-for-approval/-a, --image/-i

Automatic credential delivery resolves CODEX_HOME as a literal path (including ~ and whitespace), verifies that home, and passes its canonical absolute path to the child. An unreadable home skips loading. Any nonempty HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY variable, in any letter case, also skips loading regardless of NO_PROXY; denied launches and user-exported credentials remain unchanged. With a newly loaded token, both child NO_PROXY and no_proxy include 127.0.0.1 and ::1, preserving existing bypass entries. Enabling features.respect_system_proxy or forwarding --enable/--disable skips automatic loading.

Ensure the proxy is running, then launch Codex with the original arguments. Routing remains in Codex configuration; the launcher never rewrites it. Native and foreign routes skip startup. Unknown routing warns and attempts startup; a failed startup warns and continues. Help/version and internal commands such as login, doctor, and help skip startup and automatic token loading.

A missing OPENCODEX_API_AUTH_TOKEN is read from this installation’s service-api-token only when the selected provider’s complete transport configuration matches the managed block for the configured loopback listener or persisted local client connection. Names and injection comments alone grant no credential access. Unknown or remote destinations, default profiles, project configuration, OPENAI_BASE_URL, and forwarded -c/--config, -p/--profile, -C/--cd, or --remote options skip automatic loading. User-exported credentials and arguments are preserved; token-file overrides cannot select a different credential, and management-token collisions are refused.

Only a matched autostart wrapper launches its backing Codex directly. Unknown state, including an inspection exception, requires a verified bypass; Windows CMD managed wrappers must match the complete current generated template before the selected absolute command runs with OCX_SHIM_BYPASS=1. Ordinary npm launchers remain supported. Unverifiable or obsolete wrappers refuse with exit 1 and start no Codex; run ocx codex-shim install to refresh them. This launch does not repair shims. The content check does not establish Windows backing-file provenance or prevent concurrent pathname replacement.

On macOS, every launch, including help/version, verifies the selected executable when its selected path or canonical location is inside any .app bundle. Renamed bundles and symlinks into bundles require the same safe ownership, permissions and OpenAI signatures for the bundle and executable. A selected bundle member must stay inside that bundle’s canonical Contents/, including through executable, directory or whole-bundle symlinks. Failed verification exits 1 without starting Codex. Ordinary non-bundle executables, including npm installations, retain their behavior.

Use ocx help codex for launcher help and ocx codex --help for Codex help. Launching plain codex later retains its existing behavior.

Ensure the proxy is running, then launch opencode with the generated provider.opencodex and providers.opencodex blocks in OpenCode’s inline runtime layer (OPENCODE_CONFIG_CONTENT). The legacy block keeps V1 clients working with variant maps; the V2 block carries native arrays for the same reasoning-effort choices and defaults. Existing inline config is preserved and only those two keys are replaced for this launch. Global or project opencode.json files may be read to warn about an existing override, but on-disk files are never modified. Routed models appear as opencodex/<provider>/<model>. Launching plain opencode later behaves exactly as before.

ocx grok <status|exclude|include|set|clear|apply> ...

Section titled “ocx grok <status|exclude|include|set|clear|apply> ...”

Manage and apply the Grok Build model fence.

Hermes and Command Code export and integration apply/overwrite accept --model-names alias|routed (JSON API field: modelNames). Omission on export means routed; omission on a later integration Apply preserves its stored mode. This is independent of preferModelAliasIds. Only a provider-qualified alias that routes to the same provider/model is emitted; unsafe, missing or colliding aliases fall back to routed names, and combos keep their existing keys.

ocx export --client hermes --model-names alias --json previews an existing current catalog without writing client files or managed state. A cold/stale catalog returns unavailable; load the catalog separately and retry. Explicit --out writes only the requested export artifact and retains its existing exclusive-create/--force behavior. For managed writes, pass the same mode to both integration client preview --operation apply|overwrite and enable when confirming a plan. The field is unsupported on disable/restore and other clients. An alias change during Apply or refresh can cause a conflict before any write; retry against the current catalog. Removed/renamed aliases migrate at the next successful refresh, with foreign-edit refusal. See the integration guide.

ocx export --client <opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|prime|aside|raycast|omo|cline|kilo|commandcode|droid>

Section titled “ocx export --client <opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|prime|aside|raycast|omo|cline|kilo|commandcode|droid>”

Print a client config wired to the running proxy. The command serializes the opencodex provider block — base URL, model list, and the client’s credential reference or loopback placeholder — in the selected client’s native format.

The proxy must be running; the command resolves its live port, uses the current catalog (/api/models or the server-side client export), and emits only models Codex can currently see.

OpenCode and Kilo exports preserve effective model limits, known capabilities, declared reasoning choices and defaults, including metadata inherited by custom rows. Explicit overrides still win; unknown capabilities and defaults are not invented. The OpenCode launcher uses the same metadata. See client integrations for managed refresh and upgrade behavior.

Flag Action
--client <opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|prime|aside|raycast|omo|cline|kilo|commandcode|droid> Required. Selects the client config dialect.
--json Print the generated document as JSON on stdout for scripts. This is JSON even when the selected client’s native format is YAML, TOML, or JSON5.
--out <path> Write the client’s native config format to <path>. Refuses to replace an existing file.
--force Allow --out to replace an existing file.
Terminal window
ocx export --client opencode # config plus destination, merge warning, and counts
ocx export --client pi --json > pi-models.json # JSON document for a pipe or a diff
ocx export --client omp --out ./omp-models.yml # native OMP YAML
ocx export --client opencode --out ~/opencodex-opencode.json

Without --json the generated config leads, then the canonical destination path, the merge warning, the env export line where the client has one, and a model count with how many rows omit context limits (the client applies its own defaults for those).

Client Canonical destination Download filename Env var
opencode ~/.config/opencode/opencode.json (XDG_CONFIG_HOME wins when set) opencode.json OPENCODEX_OPENCODE_API_KEY
pi ~/.pi/agent/models.json (PI_CODING_AGENT_DIR wins when set; a relative value is refused) pi-models.json none — the block carries the literal opencodex-loopback
omp ~/.omp/agent/models.yml (OMP_PROFILE wins over PI_PROFILE, even when empty; named profiles use the home-relative PI_CONFIG_DIR directory name and ignore PI_CODING_AGENT_DIR, while the default profile lets PI_CODING_AGENT_DIR win) omp-models.yaml none — loopback placeholder
hermes ~/.hermes/config.yaml hermes-config.yaml OPENCODEX_HERMES_API_KEY
openclaw ~/.openclaw/openclaw.json openclaw.json5 OPENCODEX_OPENCLAW_API_KEY
kimi ~/.kimi-code/config.toml kimi-config.toml none — loopback placeholder
gajae ~/.gjc/agent/models.yml gajae-models.yaml non-secret loopback placeholder
dsh $DSH_HOME/settings.yaml (default ~/.dsh/settings.yaml) settings.yaml none — non-secret loopback bearer placeholder
mcode ~/.minimax/config.yaml (MINIMAX_DATA_DIR, then the legacy MAVIS_DATA_DIR, win when set; a relative value is refused) mcode-config.yaml none — loopback placeholder
zcode ~/.zcode/v2/config.json (dataBaseDir in the default-home setting.json relocates the root; ZCODE_DATA_DIR wins when set; relative values are refused) config.json none — loopback placeholder
prime ~/.prime/agent/models.json (PRIME_AGENT_CODING_AGENT_DIR wins when set; a relative value is refused) prime-models.json none — loopback placeholder
aside ~/.aside/u/<account>/models.json for the account Aside’s own accounts.json names as current; an unreadable manifest is refused rather than defaulting to an account aside-models.json none — loopback placeholder
raycast ~/.config/raycast/ai/providers.yaml on macOS and Windows alike (Raycast does not honor XDG_CONFIG_HOME) raycast-providers.yaml none — loopback only, no api_keys entry is written
omo ~/.omo/agent/models.json (OMO_CODING_AGENT_DIR, then SENPI_CODING_AGENT_DIR, then PI_CODING_AGENT_DIR win in that order when set; a relative value is refused) omo-models.json none — loopback placeholder
kilo first existing kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, or config.json under ~/.config/kilo (XDG_CONFIG_HOME relocates that directory); uses kilo.jsonc when none exists kilo.jsonc OPENCODEX_KILO_API_KEY
commandcode ~/.commandcode/providers.json (on Windows with the default home: use HOME ?? USERPROFILE only if nonblank and Windows-absolute, otherwise homedir(); a separately supplied home is preserved; append .commandcode\providers.json) providers.json loopback only; apiKey: false; no environment variable
droid ~/.factory/settings.json (%USERPROFILE%\.factory\settings.json on Windows) factory-settings.json loopback only; no environment variable

The managed DSH export requires DSH 0.1.0-rc.6 or newer and owns only llm-pi-ai.providers.opencodex. DSH hot reloads that provider; the user’s default model and deepseek-official remain untouched. This export is loopback-only and carries no real credential. DSH 0.1.7 and newer import settings.yaml once into the first profile that boots and then rename it, so the dashboard integration writes the same provider into the llm-pi-ai row of the Desktop profile’s $DSH_HOME/profiles/desktop/cordis.patch.yml once that profile exists.

opencode interpolates {env:OPENCODEX_OPENCODE_API_KEY}. The generated Pi and OMP exports do not require an environment variable: each carries the literal opencodex-loopback placeholder. This is load-bearing because both clients resolve apiKey while building their model lists and hide the whole provider when an existing config contains an unset env reference. The proxy never checks the generated placeholder on loopback. OMP supports provider-level headers, but this initial integration deliberately remains loopback-only; remote x-opencodex-api-key wiring is deferred.

The Raycast export is a standalone providers.yaml document with one id: opencodex element in the providers sequence: name: OpenCodex, the proxy’s /v1 base URL, and every routed model with its abilities (tools and system_message always supported, vision from the catalog’s input modalities, reasoning_effort when the model has an effort ladder, temperature off for reasoning models). Custom Providers is a Raycast Pro feature, and Raycast watches the file, so a saved change takes effect without a restart. The format is documented at manual.raycast.com/ai/custom-providers. No api_keys entry is written, so this export is loopback-only and a non-loopback bind is refused.

The MCode, ZCode and Prime exports are loopback-only for the same reason and likewise carry the opencodex-loopback placeholder rather than a real credential. Prime Agent reads the same models.json contract Pi does, so the two exports produce the same document; only the destination differs. A relative path in any of those three environment overrides is refused, because the proxy and the client can have different working directories and would otherwise disagree about which file is meant.

ZCode 3.8.1 may save runtime-derived reasoning, limit.output, and default context metadata back into the generated provider.opencodex.models entries. Managed integration status treats only those documented additions as refreshable drift. Provider identity and connection settings, including options.baseURL, model membership, names, modalities, and any context limit OpenCodex emitted authoritatively remain protected; editing them reports conflict / foreign-edit instead of overwriting the file. An ownership record created by an older OpenCodex version can recover automatically when the generated catalog is otherwise unchanged. If both the catalog and the block changed, re-apply only after reviewing the file because the older record cannot prove which change was ZCode-derived.

No key is ever serialized. Configs carry either a documented environment reference or a non-secret loopback placeholder. A loopback address (127.0.0.1) alone does not establish keyless admission: check the target policy and endpoint. Selected-key model/audio commands still require explicit key input on loopback. Set a referenced variable only when the client schema supports it and the proxy binds beyond loopback; see Remote access for how admission keys are issued. Keys for the upstream providers themselves are a separate thing entirely, configured per Providers. The generated gjc integration uses a non-secret loopback placeholder and needs no environment variable. It remains loopback-only; it does not configure remote admission credentials.

The same payload is served by GET /api/client-config and rendered on the dashboard’s API tab, so the CLI, the API, and the GUI use the same bytes.

ocx system <status|settings|startup|diagnostics|sync|codex-app-server|codex-restart|update|codex-cli-update> ...

Section titled “ocx system <status|settings|startup|diagnostics|sync|codex-app-server|codex-restart|update|codex-cli-update> ...”

Manage headless runtime settings, startup, sync, diagnostics, and updates.

ocx system codex-restart --yes restarts Codex app-servers through the same module as ocx sync --restart-codex. It quits and relaunches the Codex desktop app when the app launched before the current model catalog was written or this request changed its model_catalog_json binding, because the model picker is built at launch. Otherwise the app stays open, respawns its own app-server, and keeps unsaved drafts and pending approvals. If the app or catalog state cannot be read, it takes the full restart. When the proxy itself is running inside the Codex app, the desktop restart refuses with an actionable message instead of promising a handoff it cannot complete.

A model_catalog_json binding changed by this request also forces the desktop restart, even when the shell started after the catalog file was written.

Terminal window
ocx system settings --stream-mode eager-relay

Additional system booleans take on/off: --show-codex-credits, --account-picker, --main-account-hard-lock, --ultra-fast-tier, and --fast-rows. They write only explicit fields and may combine with existing system options. Showing credits is a display preference, not paid-credit opt-in; system Ultra Fast is separate from provider Fast.

Ultra Fast is an opt-in setting, default off. With --ultra-fast-tier on, the generated catalog adds the Ultrafast speed choice to native gpt-6-astra and gpt-6.1-sol (including account-bound rows), so the Codex picker offers it next to Fast. Ultrafast requires an eligible ChatGPT plan; the catalog cannot check that, so turn the setting on only if your plan includes it. Other models and the default speed are unchanged.

For routed models, sync and catalog convergence retain an existing routed row’s operator-supplied ultrafast entries in service_tiers and additional_speed_tiers alongside its current Fast capability. Declarations belong to the exact provider/model slug; they are not copied to other models. The setting does not create missing declarations or restore removed models. Turning it off removes Ultra Fast from ordinary routed rows and the generated native choice on the next catalog regeneration.

The proxy’s Fast mode decides what reaches the backend: when it is unset, a selected Ultrafast request is forwarded as service_tier: "ultrafast"; fastMode: true replaces any tier with Fast (priority), and fastMode: false removes the tier. Leave Fast mode unset to use Ultrafast.

Terminal window
ocx system settings --json
ocx system settings --show-codex-credits on --json
ocx system settings --json

New-option writes report {ok:true, settings: observedFields, catalogRefreshPending}. Ultra Fast performs same-target GET read-back because PUT omits that value. A missing/mismatched/read-failed observation stays verification:"unverified" with unverifiedFields and a nonzero exit after acceptance; requested values are never substituted for observations. Combined desktop switches retain stored/effective and apply facts. Pending catalog or deferred/refused native apply is distinct from a saved setting. False pending is not proof that every client has reloaded.

ocx system update updates OpenCodex itself. The separate Codex CLI inspection surface is:

Terminal window
ocx system codex-cli-update check --json

check makes no package-registry request and inspects bounded configured-candidate provenance evidence, including a redacted executable location and ownership evidence. Trusted published-launcher context authenticates the candidate snapshot, not successful Codex execution. On POSIX, selection is attested only when the runtime resolver selects the same canonical environment candidate without executing it. A linked npm-global manifest can then establish managed: true when it proves ownership and, if a candidate version is reported, that version matches the manifest; persisted candidates remain unattested. The JSON report exposes candidateAvailable, candidateVersion, candidateSource, and selectionAttested. Inspecting the configured candidate requires a trusted published-launcher context; a direct Bun/source launch has no such proof, ignores ambient and persisted candidate state, and may report candidate_unavailable on POSIX. On Windows x64, a proof-captured absolute standard npm codex.cmd can be managed when held local handles bind its package, a prefix-local Node/npm pair or the captured PATH metadata pair tied to the launcher architecture, and the first in-prefix platform backing. This metadata pair does not attest the interpreter a later CMD invocation would select. Plan paths and configured version-manager roots must use their canonical long DOS names; aliases, unavailable roots and reparse points leave the installation unmanaged. Other Windows layouts remain deferred or unmanaged. Windows never consults persisted state, so a run with no captured environment candidate reports windows_inspection_deferred rather than candidate_unavailable: the command cannot observe whether a Codex CLI is installed, so it reports the deferral instead of asserting that no candidate exists. The command does not execute Codex or a package manager, repair a shim, write configuration or cache state, stop a process, or install anything. App-bundled, recognized version-manager, unverified standalone, and ambiguous shim states are reported as unmanaged or unknown and are never classified as managed.

On Windows, a captured bare command such as CODEX_CLI_PATH=codex, a remote path, or a device path reports candidate_path_unavailable instead. Those cases have a captured candidate; its path is not eligible for this inspection.

Terminal window
ocx system codex-cli-update plan --channel latest --json

Run through the published Node launcher with the intended CODEX_CLI_PATH in the shell environment. The plan requires an attested npm-global installation and a linked package manifest version. Windows supports only an explicit absolute standard npm codex.cmd with a held-bound Node/npm toolchain — prefix-local when present, otherwise the captured-PATH pair anchored to the launcher architecture; PATH-only selection, OpenCodex autostart wrappers and global/vendor fallback stay deferred. It queries the official npm registry for an exact version, SHA-512 integrity and same-origin tarball, using the launcher’s captured PATH and isolated temporary npm configuration, cache and logs. Proxy settings and NODE_EXTRA_CA_CERTS remain supported; cleanup is best-effort. No Codex command runs.

An applicable plan reports applicable: true and a deterministic planId binding platform, installation-root/content digests, installed version, channel and exact main/platform artifacts. The plan is never persisted. It refuses downgrades, already-current versions, active Codex sessions and incomplete process observation. Supported Windows metadata queries use the observed Node/npm under matching held handles. Windows x64 can be applicable only for a bounded npm prefix with verified write authority; other observed prefixes retain windows_apply_disabled. Active/unknown sessions still refuse earlier. Unsupported Windows layouts return windows_inspection_deferred before registry/process queries. A refusal exits 0: inspect applicable and refusal. The printed install argv is indicative; this command installs nothing, changes no application state and never signals a session. A plan ID alone is not installation authorization: apply requires separate explicit confirmation.

Terminal window
ocx system codex-cli-update apply --plan-id <32-hex> --yes --request-id <stable-key> --json
ocx system codex-cli-update status <job-id> --json

Apply supports the selected, managed, non-shim npm-global CLI on Linux/macOS and the restricted Windows x64 npm layout. It revalidates the approved plan under an installation lease, verifies the exact main/platform archives, installs them offline with lifecycle scripts disabled, and checks installed files and the selected CLI’s version. Existing Codex sessions are never stopped; active or unknown process observations refuse the update. Windows supports shared prefixes with verified ACLs and no reparse paths. Observation includes unrelated packages and shims, capped at 4,096 entries, 512 MiB total and 384 MiB per file. Their bytes and identities must be preserved. Larger or unsafe prefixes, ARM64, shim repair, native apps and other installation managers remain unsupported. Unknown child lifetime or incomplete handle cleanup retains staging and the installation lease; do not retry by deleting its lock. Readback includes auxiliary files, new/absent backing roots and npm’s hidden lockfile. not_applied means scoped installation state was observed unchanged, not that npm performed no I/O anywhere. Installation directories and staging require trusted POSIX ownership and permissions throughout their ancestry. Unsafe installation paths report installation_prefix_unsupported or installation_paths_untrusted; unsafe temporary roots report staging_path_untrusted. Use a private temporary directory below trusted ancestors (root-owned sticky temporary roots are supported). Owned session starts, desktop restarts and runtime/shim selection changes report busy while installation and readback run. An unconfirmed installer or verification child keeps admission closed. Admission recovers when the owned process group is proven gone, including a verification child that closes after its reap deadline. Worker loss before commit also restores admission; worker close after commit alone does not. Durable recovery records preserve this exclusion across proxy restarts. On Windows, recovery checks the exact installer/verifier Job and original process creation identity; all Job members must have exited. Access failures keep admission closed and never stop an installer. Missing child identity, partial records or inaccessible liveness evidence require inspection. A complete terminal write left before its publication rename can restore admission after restart when its exact owner and current parent/group absence are verified. On Windows, a complete pending child identity can also restore admission when it matches the armed owner and Job, the guardian’s terminal proof is valid, and the parent, exact child lifetime and every Job member are proven gone. Missing proof, incomplete or armed pending writes still require inspection; guardian death alone cannot reopen admission. Recovery does not change an ambiguous job result, retry installation or reclaim an abandoned installation lease. Without recovery history, a symlinked OPENCODEX_HOME (or home ancestor) permits these ordinary operations. With history, admission reads the protected canonical home target; unsafe recovery paths still report busy. This does not relax the updater’s installation or config-path eligibility. Shim repair, native apps and other installation managers remain unsupported.

Apply exits 0 only for an applied job; not_applied, refused, ambiguous and pending duplicate jobs exit 1, including with --json. Status reads the same private job record without a running proxy or GUI token. Reuse the same optional request ID after a lost response: the same key and plan return the original job; a changed plan with that key refuses. The private ledger retains up to 64 jobs, including finished jobs, without automatic pruning. At that limit, new request IDs are refused with store_full; existing matching retries still return their original job. Capacity and operator recovery remain a separate follow-up that must preserve this deduplication contract. A busy admission ledger reports job_store_busy (HTTP 503 with Retry-After: 1); permanent admission failures have no retry-delay header. Missing or unreadable CLI status returns job_unavailable and a nonzero exit. Completion persistence failures do not rerun the installer or turn an uncertain job into a confirmed success. An ambiguous result is never automatically retried or rolled back. After an owner restart, an unfinished job reports unknown ownership instead of claiming the old process stopped. Inspect the job’s outcome, child/lease state and cleanup errors; command exit status alone does not establish an installation result.

The management API provides authenticated plan/status reads and confirmed trusted-loopback GUI-session apply admission. A published Node ocx start supplies the required inspection snapshot; direct Bun or compiled sidecar startup does not provide that proof. The Dashboard update panel is a separate follow-up.

Explicit installation observation on Windows x64

Section titled “Explicit installation observation on Windows x64”
ocx system codex-cli-update attest [--json]
ocx system codex-cli-update attest --candidate <absolute-path> --npm-prefix <absolute-path> --npm-cli <absolute-path> --node <absolute-path> [--json]

attest is an opt-in, read-only observation of a Windows x64 npm installation. With no options it identifies the selected candidate from the proof-bound launcher snapshot — the configured CODEX_CLI_PATH or the first codex on the captured PATH, with an OpenCodex wrapper resolving to its renamed codex.opencodex-real.cmd npm backing. Supplying all four absolute paths overrides discovery; discovery only proposes paths and the held-handle observation remains the authority. --candidate must name the standard npm <prefix>/codex.cmd or <prefix>/node_modules/@openai/codex/bin/codex.js. --npm-cli must end in node_modules/npm/bin/npm-cli.js; --node names an explicit node.exe. App bundles, recognized version-manager layouts, opencodex-owned shims without their npm backing, and custom wrappers are refused.

Native handles hold the ancestor directories and files during bounded reads. Unsupported platforms, reparse points/junctions, conflicting writers, unsafe paths, and oversized files are refused. The fixed report contains no paths: status is observed or refused, with installationIdentityObserved; selectionAttested, managed, and applyAllowed remain false. Check status, not just the process exit code: a reported refusal can exit 0.

An observed identity or digest describes those files during this observation. It is not a durable update permit and does not prove the selected runtime, the past installer, effective npm configuration, or tool authenticity. The supplied Node is observed only, not proven to be the Node a launcher would select. No target is executed; no registry request, installation, configuration write, or process control occurs. The separate Windows check/plan predicate above can establish read-only planning evidence; attest remains observation-only.

ocx config [show|get|set|unset|validate|export|import] ...

Section titled “ocx config [show|get|set|unset|validate|export|import] ...”

ocx config [show] [--json] [--source] displays the local configuration without a running proxy. Omitting show also works with either flag or both, in either order. --source includes diagnostic source, error, and warning fields and is only accepted for display. --json may precede an explicit action; it does not change which action runs. Repeated --json or --source flags and unknown arguments are rejected.

Inspect and safely modify validated OpenCodex configuration. show and get mask secrets. Import validates before writing and requires --yes.

Display and mutation output strip credentials from proxy URLs while retaining the host and port. direct and credential-free proxy values stay readable. export preserves credentials so the backup can restore the configuration; store exported files as secrets.

ocx usage reads the connected hub with this client’s enrolled data key. Human output identifies the hub source and client-key scope; --json returns the same scoped data. Range, surface, provider/model filters and custom --since/--until bounds remain available. Account breakdowns and other clients’ records are not shared. An old or unavailable hub produces an explicit error instead of substituting local usage; upgrade the hub if it does not support this read.

The read-only data-plane endpoint is GET /v1/usage, using x-opencodex-api-key with a configured client key. Environment-wide and admin keys are refused. It accepts range, surface, provider, model, since, and until; unknown/repeated options and caller-selected key IDs are rejected. Oversized skipped rows retain the explicit incomplete-history warning.

Human ocx logs output includes id=<request-id>. Pass that value to ocx logs explain <request-id> to inspect routing decisions. Rows without an ID or with control characters in their ID omit the field instead of displaying a different lookup key. JSON and JSONL output retain their existing schema.

ocx route policy show <id> exits 4 when the profile does not exist. Missing or invalid command arguments exit 2. Scripts can distinguish a missing profile from incorrect usage.

When an upstream error envelope contains several message fields, OpenCodex uses the first nonblank string in its established priority order. Empty or malformed fields no longer hide a valid fallback diagnostic.

The Subagents page offers Force all subagents onto one model, off by default. Select an exposed roster-style id, such as combo/tev-auto, then enable the switch. The roster is offered first; unavailable saved roster entries cannot be force targets.

ocx agent subagents force combo/tev-auto sets claudeCode.subagentModelForce; ocx agent subagents force - clears it. ocx agent status reports the setting. GET /api/subagent-models returns force, forceAvailable, and forceStatus; PUT accepts { "force": "combo/tev-auto" } or { "force": null } without changing the roster. Omitting force leaves it unchanged. Invalid or unexposed targets are rejected on write; stale targets are reported and skipped at launch.

This takes effect on the next routed ocx claude launch, injecting CLAUDE_CODE_SUBAGENT_MODEL as an explicit proxy alias (with [1m] only for an authoritative million-token window; native Claude targets use a reversible native alias) and CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1. Each nonempty shell-exported variable independently wins. Native launches inject neither variable; plain claude is not affected. No plugin files or settings.json are modified by this setting.

Claude Code 2.1.257 or newer is required for FORCE. Plugin and built-in agents (including Explore/Plan) and per-call model arguments are overridden. Forks and subagent skills with model: inherit keep the main conversation model. The main loop and Haiku/small-fast sidecars are unaffected. Existing roster files remain available.

The dashboard warns about old or unknown CLI versions, unavailable targets, and either variable already present in settings.json → env (which overrides launch env). Detection is read-only and server-local: it cannot inspect another launch shell, another machine, or project-local settings. An unknown result is not proof of force support.