Skip to content

CLI Lifecycle

These commands install, run, inspect, repair, and update the local opencodex proxy and its Codex integration.

Interactive setup wizard (setup is an alias of init). Prompts for a provider (preset or custom), API key (literal or ${ENV}), default model, and proxy port; saves ~/.opencodex/config.json; optionally injects the proxy into $CODEX_HOME/config.toml (default ~/.codex/config.toml); and optionally installs the Codex autostart shim.

Start the proxy server (preferred port 10100). If that port is occupied, opencodex selects and records another available port. It writes PID/runtime-port state and refuses to start a second live instance. On start it syncs each provider’s models into Codex’s catalog. On shutdown it restores native Codex — unless it was launched as a managed service (OCX_SERVICE=1).

Terminal window
ocx start
ocx start --port 8080

Stop the running proxy (by PID), remove the PID file, and restore native Codex. If a managed background service is installed, ocx stop also stops it first so it cannot respawn the proxy. The web dashboard’s Stop button runs the same action (POST /api/stop) on every backend except Windows Task Scheduler. There the wrapper can respawn the proxy after the task ends, and only a stop running outside the proxy can verify that restart window before restoring your client config — so the dashboard refuses with respawnable_service, changes nothing, and asks you to run ocx stop.

The dashboard also refuses when the proxy is running as the installed launchd or systemd service. Stopping that manager from inside the proxy would terminate the process before native Codex is restored, leaving your client config pointed at a proxy that is gone, so the dashboard returns self_unload_service, changes nothing, and asks you to run ocx stop — which stops the service from outside and completes the restore.

A proxy exit alone does not confirm that shared Codex/Grok restoration succeeded. If the stop response reports failure, is unreadable, or does not confirm the assigned teardown mode, the CLI keeps restoration with the stopping parent after the existing ownership and respawn checks. It does not enter the forced-stop fallback for a process already observed to have exited. A receipt-backed deferral still leaves final restoration and receipt cleanup with the parent; failure to restore shared client configuration keeps the stop failed and its receipt outstanding.

When a proxy is running, ask that exact attested PID and port to restart in place, wait for its normal drain, and verify a different runtime PID on the same port. Managed routing and service supervision stay installed throughout; an uncertain request is observed rather than replayed as a separate stop/start. If no proxy is running, the command falls back to the normal ensure start. If a live listener cannot be attested to a runtime PID (including a pre-update proxy), restart fails closed without an ensure or stop/start fallback. After confirming ownership, use ocx stop then ocx start for a standalone proxy. For a service-managed proxy, use ocx stop followed by ocx service start so supervision is restored.

Port recovery after stop or update respects a failed OCX process check even when the PID was recorded before shutdown. A rejected live holder is left running and prevents TCP-row cleanup. If it stays unverified, the bounded recovery wait can expire with the port still busy. Check the current port holder and retry the restart after the conflict is resolved.

Idempotently ensure a background proxy is running, then sync its live model catalog. If codexAutoStart is false, it prints that autostart is disabled and does nothing.

Restore native Codex without stopping the proxy — strips the injected config lines and routed catalog entries so plain codex works natively again. eject is an alias of restore.

Restored catalog output excludes retired native models, including gpt-5.3-codex-spark, whether stored as bare ids or trusted account-qualified rows. This applies with or without a catalog backup; the original backup and historical user-selected configuration are preserved.

Restoration reports failure instead of replacing changed configuration files when a saved journal lacks the corresponding injection hashes. The current files and journal remain available for review; see recovery without injection hashes.

Pass back to either spelling to re-point plain codex at an already-running proxy without changing the proxy lifecycle:

Terminal window
ocx restore back
ocx eject back

Explicit recovery for older development builds that remapped Codex App history before reversible backup support existed. Close Codex first if its history database is locked.

This is a broad, destructive relabel: every user-message thread currently tagged opencodex is changed to openai, exec is normalized to cli, and the event marker is set. That includes legitimate dedicated-provider history. Back up the state and run it only when that full scope is intended.

ocx recover-history --ocx-compaction <thread-id> --yes

Section titled “ocx recover-history --ocx-compaction <thread-id> --yes”

Repair one thread that was compacted through a routed provider before resuming it through native Codex. The command reads the exact thread selected by UUID, saves a private byte-for-byte backup, then converts only OpenCodeX-owned ocx1: compaction state into a plain summary that native Codex can replay. Native encrypted content and other threads are left unchanged. Close the selected thread before running the command; a concurrent rollout change makes recovery stop without replacing the file.

Stop the service and proxy, remove the service and Codex shim, restore native Codex, then remove opencodex local config only if all restore steps succeeded. remove is an alias of uninstall. Config cleanup requires ownership metadata created by a fresh install; legacy or shared directories are left in place.

Status and ocx doctor compare this CLI’s version with the running proxy. If the CLI is newer, restart the proxy using the intended current installation; for a background service, run ocx service restart — a version skew leaves the service definition byte-identical, so ocx service repair would reload nothing and keep the old process serving. If the proxy is newer, upgrade the CLI or resolve PATH to the intended installation. These diagnostics do not repair the service or change whether requests are allowed.

Identical version strings and the unknown / 0.0.0 placeholders suppress the warning, as does an absent proxy version. Doctor does not report placeholders as a confirmed match. Different strings still produce a neutral warning when they cannot be strictly parsed as SemVer or differ only in build metadata; neither side is called older. Versions are not trimmed and a leading v is not normalized. JSON exposes the same advice in versionSkew, whose fields remain cliVersion, proxyVersion, skewed, and warning.

Print a read-only diagnostic summary: proxy PID, /healthz reachability, dashboard URL, config path, default provider, Codex autostart setting, service state, shim state, and the redacted effective Codex home. Only the explicit, high-confidence Windows Orca runtime-home signature adds an actionable App-home mismatch warning; it never changes CODEX_HOME automatically.

Human output also includes an OAuth health block after the OAuth logins summary: OAuth health: ok when every known account is healthy, or OAuth health: warning with one redacted line per non-healthy account (provider, masked account id, status such as reauthentication required, rate or quota limited, or refresh conflict) plus an optional Action: hint. Account ids are redacted; tokens and emails are never printed. The --json contract does not currently include this health block.

Terminal window
ocx status
ocx status --json

Abbreviated example shape:

{
"schemaVersion": 1,
"proxy": {
"running": false,
"pid": null,
"health": {
"ok": false,
"url": "http://127.0.0.1:10100/healthz",
"message": "unreachable"
}
},
"dashboard": {
"url": "http://localhost:10100/"
},
"paths": {
"config": "/Users/example/.opencodex/config.json",
"pid": "/Users/example/.opencodex/ocx.pid",
"runtime": "/path/to/bun"
},
"runtime": {
"source": "bundled"
},
"codexHome": {
"effectiveCodexHome": "C:\\Users\\[USER]\\.codex",
"appCodexHome": "C:\\Users\\[USER]\\.codex",
"mismatch": false,
"warning": null,
"action": null
},
"codexAutostart": true,
"defaultProvider": "openai",
"service": {
"summary": "not installed (logs: /Users/example/.opencodex/service.log)"
},
"codexShim": {
"summary": "Codex autostart shim: not installed"
}
}

The real object also includes listen (port, hostname, runtime/config source), config load diagnostics, and bundled Codex plugin diagnostics. The JSON schema is additive-only: future versions may add fields, but existing fields should stay stable. It intentionally excludes API keys, OAuth tokens, authorization headers, request content, emails, and account identities.

Identity-check the live proxy. Human output reports PID/port; --json emits {ok, pid, port}. The command exits 0 only when healthy and 1 otherwise, making it suitable for service probes.

ocx ready [--json] [--wait [--timeout <seconds>]]

Section titled “ocx ready [--json] [--wait [--timeout <seconds>]]”

Check post-sync readiness through the unauthenticated GET /readyz endpoint. It returns 200 when ready, or 503 with Retry-After: 1 for pending and terminal failed. Its sanitized HTTP identity is {service, version, uptime, pid, port, status} plus the remote-hub protocol fields {protocol, minimumClientProtocol, managementUrl}. protocol is the hub protocol this proxy speaks and minimumClientProtocol the oldest client it still accepts, so a client can refuse an incompatible pairing before sending anything else. managementUrl is the origin a client should use for the management plane: the configured hub.managementPublicOrigin when runtimeRole is hub, and otherwise the origin the request itself arrived on. A readiness request with no HTTP(S) origin is rejected rather than answered with a guess. Old proxies without /readyz fail closed as unreachable; /healthz is separate liveness, not readiness. The command performs one probe by default; --wait polls until ready or timeout, but exits immediately when it observes the terminal failed state. The default timeout is 45 seconds; --timeout <seconds> requires --wait and accepts positive integer seconds from 1–300. The CLI’s own --json output is deliberately narrower than the HTTP body: it emits {ready, status, pid, port}, where status is ready, pending, failed, or unreachable. Exit codes are 0 for ready; 1 for not-ready, pending, failed, timeout, or unreachable; and 64 for invalid arguments.

The default report includes the native-write coordinator state and exact path using immutable read-only SQLite inspection. Zero-byte, empty-unversioned, and rowless states are shown separately from catalog/app-server health, so a successful catalog refresh is not mistaken for successful Codex config injection.

After stopping the OpenCodex proxy/service, explicitly preserve and move a proven non-authoritative coordinator, then retry sync:

Terminal window
ocx doctor --recover-zero-byte-coordinator --yes
ocx sync

The recovery accepts only a proven zero-byte remnant. It refuses every non-empty, valid, unknown, changed, unsafe, or busy database and creates a same-directory .zero-byte-backup-* file instead of deleting anything.

Run read-only environment and connectivity diagnostics: state paths and filesystem type, WSL dual installs, proxy environment/config, ChatGPT reachability, Codex plugin and project-config warnings, and pending history migration. The Codex app-home targeting section also detects the narrow Windows Orca runtime-home mismatch and explains service migration when applicable. Paths shown by this diagnostic redact the OS username. Doctor prints repair hints but does not apply them.

Project-config diagnostics ignore provider examples inside TOML multiline strings, including developer_instructions. Real provider and profile settings after the closing delimiter are still checked, even when an escaped quote immediately precedes that delimiter.

The OAuth reliability section reports whether credential storage is writable, whether refresh single-flight/lock files can be created under OPENCODEX_HOME, non-healthy OAuth or Codex pool accounts (redacted ids) with a recovery Action:, and a static OK that the Codex forward path does not fabricate official-client metadata. Doctor never mutates credentials or applies repairs.

ocx sync [--restart-codex] [--restart-app-server-only]

Section titled “ocx sync [--restart-codex] [--restart-app-server-only]”

Fetch the live model list from every configured provider and re-inject the merged catalog into Codex. Run it after adding a provider or to refresh available models.

Before provider discovery or catalog/cache replacement, ocx sync validates that the managed Codex configuration can be injected. If that validation refuses the config, the command exits nonzero, prints the concrete reason on stderr, and leaves the existing catalog and cache unchanged. ocx restore back uses the same no-write preflight before it re-enables routing.

If long-lived Codex app-server processes are still running, ocx sync warns that they may keep serving the previous in-memory model list even though opencodex-catalog.json / models_cache.json were updated. Pass --restart-codex to restart matching codex … app-server and codex-code-mode-host processes and fully quit and relaunch the Codex desktop app, on macOS, Linux, and Windows, so the model picker re-reads the catalog. Live conversations end. Broad pkill -f codex matching is intentionally avoided.

--restart-desktop-app is a deprecated alias of --restart-codex. It still works, prints a deprecation notice, and is not Windows-only.

--restart-app-server-only restores the older, narrower behaviour: SIGTERM only to matching app-server and code-mode-host processes owned by the current user, with the desktop app left running. Active turns may still be interrupted. If it is combined with --restart-codex or --restart-desktop-app, the narrow scope wins, because losing live conversations is unrecoverable and a stale picker is not.

When the command runs from inside the Codex app, the restart is handed off to a detached helper and this session ends with the app.

ocx sync-cache [--restart-codex] [--restart-app-server-only]

Section titled “ocx sync-cache [--restart-codex] [--restart-app-server-only]”

Invalidate Codex’s local model picker cache so it is rebuilt from the active opencodex catalog. The same stale-app-server warning and optional restart flags as ocx sync apply.

ocx catalog pull <https-url> [--auth-env <NAME>] [--json] [--restart-codex] [--restart-app-server-only]

Section titled “ocx catalog pull <https-url> [--auth-env <NAME>] [--json] [--restart-codex] [--restart-app-server-only]”

Install a complete catalog served by another OpenCodex instance’s /v1/catalog endpoint, then synchronize models_cache.json. Unlike ocx sync, this command does not discover configured providers or inject Codex configuration. Unlike ocx sync-cache, it replaces the active catalog before rebuilding the cache. It works even when the local Codex integration desired state is off.

The URL must be HTTPS; loopback HTTP is accepted for local testing. Embedded URL credentials, queries, fragments, redirects, oversized responses, malformed JSON, duplicate or unsafe slugs, and unknown input_modalities are refused before any local write.

Loopback HTTP requests are refused before authentication headers are attached or any request is sent when HTTP_PROXY or http_proxy applies without a matching NO_PROXY or no_proxy bypass. ALL_PROXY/all_proxy and settings limited to HTTPS_PROXY/https_proxy do not trigger this HTTP restriction; HTTPS catalog acquisition remains allowed. The refusal message includes neither the proxy address nor the authentication token. Nonempty http_proxy and no_proxy take precedence over HTTP_PROXY and NO_PROXY, respectively. For Bun-compatible bypass rules, use hostnames, matching host:port entries, bracketed IPv6 addresses such as [::1], or *; do not use URLs, paths, or *. prefixes.

Authentication is optional and is read only by environment-variable reference:

Terminal window
export OPENCODEX_CATALOG_AUTH_TOKEN='...'
ocx catalog pull https://proxy.example.com/v1/catalog \
--auth-env OPENCODEX_CATALOG_AUTH_TOKEN

The value is sent as a Bearer token but is never accepted as an argv value. Redirects are refused, so authorization cannot cross origins. Catalog and cache writes use the shared Codex catalog lock and atomic writer. A failed fetch, validation, lock acquisition, catalog write, or cache rebuild preserves the last-known-good files. Identical catalog bytes are a no-op that preserves mtimes and never touches processes. --restart-codex, --restart-app-server-only, and the deprecated --restart-desktop-app alias mean the same thing here as they do on ocx sync and ocx sync-cache, and they apply only after a real write.

The URL must name /v1/catalog at the host root. A reverse proxy that serves the endpoint under a path prefix is not supported by this command.

The command downloads the full catalog and compares bytes locally instead of issuing an ETag / If-None-Match conditional request. Identical bytes are treated as a complete no-op, so a Codex home whose catalog is correct but whose models_cache.json is missing or stale is not repaired by this command; use ocx sync-cache for that.

--json emits one stable envelope on stdout. schemaVersion, ok, status, catalogWritten, cacheSynced, and codexRestarted are always present. codexRestarted still means app-servers only. desktopAppRestarted is present only when a desktop restart was requested, and is true only when the relaunch actually started; a handoff is not a success. status is updated, unchanged, or failed. A successful pull adds modelCount; a failure adds code, which is the field a script branches on:

code Meaning Exit
usage The arguments were not a valid catalog pull invocation 2
auth_env_missing --auth-env named a variable that is not set 1
url_invalid, insecure_http_refused The URL was refused before any request 1
request_failed, redirect_refused, http_error The request did not produce a usable response 1
body_too_large, body_invalid, catalog_invalid The response was refused before any local write 1
write_failed, lock_database, unsafe_path The coordinated write did not complete; files are unchanged 1
lock_busy Another writer holds the Codex catalog lock 3
restart_incomplete The catalog and cache landed, but a Codex app-server survived --restart-codex or --restart-app-server-only 1

restart_incomplete is the one failure that reports real writes: catalogWritten and cacheSynced stay true and ok is false, because a surviving app-server still serves the previous catalog from memory.

ocx service [install|repair|restart|start|stop|status|uninstall|remove]

Section titled “ocx service [install|repair|restart|start|stop|status|uninstall|remove]”

Run opencodex as a login-managed background service (macOS launchd, Linux systemd user unit, Windows Task Scheduler) that auto-starts on login and auto-restarts on crash. Service runs set OCX_SERVICE=1 so a restart does not churn the Codex config.

Windows Task Scheduler installs use normal process priority (Priority=4). The older background priority (7, also the scheduler default when omitted) can delay the proxy’s health responses under CPU contention, making the tray report Offline even while the process is alive. After upgrading, run ocx service repair to migrate that registered priority and restart the service. This migration may request UAC approval; a priority already set to normal or high does not itself trigger replacement.

The Windows wrapper verifies its baked Bun runtime and CLI entry before every start attempt. If an interrupted package update removed either file, it logs one installation is incomplete message and stops instead of retrying the same missing executable every five seconds. Reinstall opencodex, then run ocx service repair to refresh the task with the restored package paths.

On macOS and Linux, the launchd plist and the systemd unit invoke the first regular, executable ocx file found on PATH at install time rather than the Bun and CLI paths inside the installed package tree. Version managers such as mise and asdf install into a versioned directory and delete the old one on upgrade, which used to leave the service definition pointing at files that no longer existed — systemd then restart-looped while still reporting the service as installed, and launchd kept the old build serving until it was restarted by hand. A shim path survives the upgrade, so the definition keeps resolving. Source checkouts without an ocx launcher keep the previous direct Bun + CLI form. A trusted OPENCODEX_BUN_PATH selected before Bun starts is preserved through the shim; package-local bundled Bun paths are deliberately rediscovered after upgrades instead of being pinned in the unit.

Definitions installed before this change still carry the old versioned paths and cannot migrate themselves — once the old executable is deleted, no opencodex code runs to fix it. Run ocx service repair once after upgrading; after that, each service start follows the launcher. An already-running proxy is not replaced by an external upgrade: when the installed CLI is newer than the running proxy, run ocx service restart so the new build serves. repair is not enough there: the definition did not change, and a repair that changes nothing reloads nothing. If the proxy is newer instead, check the CLI installation and PATH as described under ocx status.

Subcommand Action
none Install and start when absent; otherwise repair the existing service. A healthy Windows scheduler definition is reused; a stale definition may be re-registered and require elevation.
install Create and start the service. Registers it, which on Windows needs elevation.
repair Refresh an installed service in place, reloading the manager only when something changed — so on macOS a healthy, unchanged job keeps running and the repair is not an outage. A healthy Windows scheduler definition is reused; a stale definition may be re-registered and require elevation.
restart The same refresh, but it always restarts. On macOS an unchanged, already-loaded job is kickstarted in place. Not an alias of repair.
start Start an installed service.
stop Stop the service and restore native Codex.
status Report service and proxy diagnostics plus log paths.
uninstall Remove the service and restore native Codex.
remove Alias of uninstall.

On Windows, a bare ocx service runs the install path only after both Task Scheduler and WinSW are proven absent. If either status query is inconclusive, it refuses to register anything and asks you to run ocx service status; use explicit ocx service install only after confirming absence.

Terminal window
ocx service
ocx service install
ocx service repair
ocx service restart
ocx service status
ocx service uninstall

install, start, and repair confirm that a proxy actually answers on the port baked into the installed service before reporting success — on all three platforms. They wait up to 20 seconds and then print the serving port:

✅ opencodex service installed and serving on port 10100.

If nothing answers, they warn and exit non-zero:

⚠️ Service installed, but no proxy answered on port 10100 within 20s.
The manager registered the job; that is not the same as serving.
Log: ~/.opencodex/service.log
Meanwhile: ocx start (serves in the foreground)

A non-zero exit here means registered but not serving — not not installed. The service manager accepted the job; the proxy behind it never bound the port. Read the log named in the message, and use ocx start to serve in the foreground meanwhile.

ocx service status reports the same three states rather than raw manager output:

✅ installed and loaded (launchd; logs: …)
Serving on port 10100.
⚠️ installed and loaded (launchd; logs: …)
Registered, but no proxy is answering on port 10100.
launchd is running an OLDER plist than the one on disk.
Fix: launchctl bootout gui/$(id -u)/com.opencodex.proxy && ocx service repair
Log: ~/.opencodex/service.log
Repair: ocx service repair
Meanwhile: ocx start (serves in the foreground)

It no longer prints the raw launchctl list / systemctl status line, which reported a registered job identically whether it was serving, bound to nothing, or running a previous definition. The Diagnostics: line still carries the log path and any stale-baked-path finding.

On Windows the scheduler backend keeps its own richer status output, which already reported Task Scheduler registration separately from proxy reachability.

On macOS this also covers a subtler failure: launchctl load reports failure on stderr while exiting 0, so a load that did not take used to leave launchd running a previous version of the service definition while the command printed a checkmark. install now fails loudly in that case and names the launchctl bootout command that clears the stale job.

On Windows, ocx service status reports Task Scheduler registration separately from identity-verified OpenCodex proxy reachability. It does not print the localized schtasks table, so the summary remains readable across Windows code pages.

On Windows, creating the Task Scheduler entry requires elevation. Recognized localized access-denied text keeps the existing guidance path. If that text is unreadable, the fallback requires the owned command shape /create /tn opencodex-proxy /xml <non-empty-path> /f, status 1, and a confirmed non-elevated token; the dashboard’s Startup Safety action can then request UAC automatically. If that fallback cannot determine the token state, it retains the original scheduler error. Foreign tasks and operations can never emit the automatic-elevation marker. Approve the dashboard UAC prompt or rerun ocx service install in an elevated PowerShell window.

For a fresh install where the OpenCodex scheduler task is confirmed absent, UAC approval now happens before the installer stops any existing proxy. Its unique registration XML is staged in an ACL-hardened private directory outside the OpenCodex config root, and the task is registered without being run. Only after registration succeeds does OpenCodex remove that XML, require ownership metadata for a genuinely new config root, stop the old listener, remove and boundedly re-verify any native WinSW registration, publish the service assets, and start the scheduled task. Cancelling or denying UAC, or failing to claim a new root safely, therefore leaves the working proxy and its Codex routing in place. Existing or conflicting scheduler registrations continue to fail closed rather than being deleted as an unsafe best-effort rollback.

ocx codex-shim <install|status|uninstall|remove>

Section titled “ocx codex-shim <install|status|uninstall|remove>”

Wrap a script-based codex launcher on PATH with a lightweight autostart script. Real codex.exe targets are left untouched to avoid breaking exact executable invocations.

Before an install or repair is committed, OpenCodex runs the saved launcher with --version while service startup is bypassed. It refuses the change and rolls back when the launcher resolves codex back to the shim, exits nonzero, exceeds five seconds, leaves descendants running, or cannot be validated and cleaned up safely. Therefore codex-shim install is not unconditional. If it is refused, reinstall Codex so the PATH entry is a concrete executable or launcher and retry; use ocx service install instead when a dynamic command-manager launcher cannot meet these checks. Cleanup refusals include a bounded diagnostic suffix identifying the probe phase, a recognized native error code or signal, and the exit status when known. It does not include launcher paths or raw child output, and does not relax the validation or rollback checks. During upgrades, an installed Unix shim that lacks the current validation guard is regenerated and probed. If its saved launcher is unsafe, OpenCodex removes the obsolete shim and restores the original launcher instead of leaving the unsafe wrapper installed.

Launcher installation alone does not prove that Codex requests will use OpenCodex. After a healthy install, the command checks the current Codex routing and reports a warning instead of a green result when routing is external, user-owned, or unverifiable. It also warns when outbound proxy variables exist only in the current process while config.proxy is unset or unresolved, because Codex launchers and background services may not inherit that environment. These checks are read-only and never print proxy values; resolve the reported handoff and run ocx doctor before relying on autostart.

If a completed external Codex update overwrites an installed shim, the next ordinary ocx command backs up the stable new launcher and restores the shim before dispatch. The zero-effect ocx system codex-cli-update check inspection command and malformed invocations in its reserved ocx system codex-cli-update namespace never perform that repair. A launcher that is still changing is left untouched and retried later. Repair failures warn without failing the requested command; manual fallback: ocx codex-shim install. Set codexShimAutoRestore to false, or set OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0 for a process-level opt-out.

That restore needs the original launcher OpenCodex saved next to the shim. A version manager — mise, asdf, volta — rewrites its whole install tree on upgrade, which destroys the shim and that backup, so there is nothing left to restore from. A version-manager install tree is not a supported shim target. OpenCodex reports the condition and stops rather than wrapping the newly installed binary as a replacement original: doing so would record a history that never happened, and the next upgrade would overwrite it again, so the repair would silently undo itself on the version manager’s schedule.

If your codex is owned by a version manager, route through Codex configuration instead of the launcher: ocx start writes openai_base_url, and ocx service install provides autostart. Run ocx status to confirm — it reports the active routing, and warns when a running proxy is not the one Codex is pointed at.

Subcommand Action
install Install the shim (or repair if stale).
uninstall Remove the shim and restore the original Codex binary.
remove Alias of uninstall.
status Report shim state (installed, stale, or missing).
Terminal window
ocx codex-shim install
ocx codex-shim status
ocx codex-shim uninstall

On a non-loopback bind the injected provider carries env_key = "OPENCODEX_API_AUTH_TOKEN". That line tells Codex which variable to read; it does not create it. Codex refuses to start a request when the variable is missing (Missing environment variable: OPENCODEX_API_AUTH_TOKEN), and the proxy is never reached. The value lives in $OPENCODEX_HOME/service-api-token; the launching process must supply it in Codex’s environment.

Use the maintained shim installed by ocx codex-shim install. When the launching context resolves this shim, it reads the token file created by OpenCodex and supplies the variable to Codex. Desktop, cron, and service launches must use a PATH or launcher path that selects the shim; installation does not configure those environments automatically. Codex’s own child processes may still inherit the token.

Do not export this bearer token from a shell startup file or copy it into config.toml. The service-api-token file contains the raw token, not NAME=value assignments, so it cannot be used directly as a systemd EnvironmentFile=.

An EnvironmentFile= or OCX_API_TOKEN_FILE on opencodex-proxy.service configures the proxy process only and never flows into an independently launched codex exec.

A Codex upgrade that replaces the launcher removes the shim; the next ordinary ocx command restores it (see above), but a codex exec that runs before that fails. ocx doctor reports this exact state under “Codex env_key launch readiness” (env_key configured, variable unset, shim missing or unhealthy, token file present) with the repair command, and never prints the token. Reading the token file is not part of the injected env_key contract; the launching process must supply that variable.

ocx tray <install|start|stop|status|uninstall|remove> [--json] [--no-start]

Section titled “ocx tray <install|start|stop|status|uninstall|remove> [--json] [--no-start]”

Install and control the Windows status tray icon. It starts at Windows login and provides one-click proxy controls. start and stop control the icon only; use its menu to control the proxy. --no-start applies to install and installs the tray without launching it immediately.

Open the web dashboard at http://localhost:<port> — or at http://127.0.0.1:<management port> when hub management ingress is enabled — auto-starting the proxy if it is not running.

ocx update updates OpenCodex itself; it does not update the Codex CLI. Use the system inspection commands to inspect the configured Codex CLI candidate with bounded, read-only provenance inspection. ocx system codex-cli-update check does not query a package registry or install an update.

Self-update opencodex from npm. Stable installs use @latest; preview installs stay on @preview unless you pass --tag latest|preview. It detects a source checkout and tells you to git pull && bun install instead, and is a no-op if you are already on the newest version for that tag. Before stopping anything, npm installations run a bounded Unix cache ownership and access check. Nested symlinks are checked with lstat but not followed; Windows explicitly skips this Unix-only check. A failure aborts while the tray and proxy are still running. A running proxy is then stopped before files are replaced; an installed service is rebuilt and started automatically, while a foreground installation prints ocx start as the next step. Dashboard update records redact profile/cache paths and UID/GID values before they are persisted.

Terminal window
ocx update
ocx update --tag preview

New versions become available when the Release workflow publishes them to npm.

Use ocx connect <url> --pairing-code-stdin, ocx connect status, ocx sync, and ocx connect rotate --pairing-code-stdin. The initial catalog download fails after five seconds without incoming bytes, but active transfers may run longer; use --catalog-timeout <seconds> (1–120) to override that inactivity window. ocx disconnect restores local state offline and does not revoke the hub key. While connected only, ocx connect revoke --admin-token-stdin revokes the persisted apiKeyId; after disconnect use the hub’s Integrations → API Keys page. Secrets are stdin-only and never belong in argv.