# OMP Codex Bridge `@oh-my-pi/codex-bridge` is a compatibility shim that lets ChatGPT Desktop (and other clients expecting the Codex CLI / app-server protocol) connect over SSH and drive an [Oh My Pi (OMP)](https://github.com/can1357/oh-my-pi) agent session. The client talks standard Codex app-server protocol; the bridge translates it to OMP sessions, models, tools, and approval requests. ## Quick Start ### 1. Install the `codex` shim ```bash ./scripts/install-local.sh "$HOME/.local" ``` Verify that your SSH login shell can find it: ```bash ssh 'codex --version && codex doctor' ``` > **Note**: Ensure `~/.local/bin` is exported in your login shell config (e.g. `~/.zprofile`, `~/.bash_profile`, or `env.nu`), not just interactive rc files. ### 2. Configure default model and aliases Create `~/.omp/codex-bridge/config.json`: ```json { "backend": "auto", "defaultModel": "gemini-3.7-flash", "modelAliases": { "gemini-3.7-flash": "google-antigravity/gemini-3.7-flash", "claude-opus-5": "anthropic/claude-opus-5", "claude-sonnet-5": "anthropic/claude-sonnet-5", "gpt-5.6-luna": "openai-codex/gpt-5.6-luna" }, "defaultApprovalPolicy": "on-request", "defaultReasoningEffort": "medium" } ``` #### Using the Prime backend Prime is a separate agent binary, so ask for it explicitly and make sure `prime-agent` (Prime 0.8.0 or newer) is reachable from your login shell: ```json { "backend": "prime", "defaultModel": "gpt-5.6-luna", "modelAliases": { "gpt-5.6-luna": "openai-codex/gpt-5.6-luna" }, "defaultReasoningEffort": "medium", "sessionOptions": { "primeExecutable": "/opt/homebrew/bin/prime-agent" } } ``` `sessionOptions.primeExecutable` is optional — without it the bridge tries `OMP_CODEX_PRIME_BIN`, then `~/.local/bin`, `~/.bun/bin`, `~/.nix-profile/bin`, `/opt/homebrew/bin`, `/usr/local/bin`, then `prime-agent` on `PATH`. Check what it resolved and start it: ```bash OMP_CODEX_BACKEND=prime codex doctor # reports backendSelection + primeExecutable codex app-server --backend prime # one-off stdio server codex remote-control start --backend prime # or the shared daemon ``` Prime ships its own short model catalog, so the ChatGPT model picker lists Prime's models — `gpt-5.6-luna`, sent to Prime as the provider-qualified selector `openai-codex/gpt-5.6-luna` — instead of the bridge's OMP featured list. > **Warning**: Prime has no Codex command/file approval primitive and no sandbox. Under `backend: "prime"` the bridge cannot ask before a shell command or a file write: `defaultApprovalPolicy` is not applied and the agent runs with the daemon's own privileges. Use it only where unattended edits are acceptable. The OMP backends (`auto`, `sdk`, `rpc`) are unchanged and still prompt. #### Using OMP and Prime together Set `backend` to `both`. The bridge advertises itself as a custom model provider so Desktop/iOS accept backend-qualified model IDs: ```json { "backend": "both", "defaultModel": "gpt-5.6-sol-via-omp", "modelCatalog": { "include": ["gpt-5.6-*", "gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "claude-opus-5", "claude-sonnet-5", "claude-fable-5", "claude-haiku-4-5"], "excludeProviders": ["google-antigravity", "kimi-code", "laguna-local", "nanbeige-local", "ollama", "lmstudio"], "backendOrder": ["omp", "prime-agent"], "order": ["gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "claude-opus-5", "claude-sonnet-5", "claude-fable-5", "claude-haiku-4-5"] } ``` Models exposed by both agents appear twice: - `GPT-5.6 Luna (OMP)` — `gpt-5.6-luna-via-omp` - `GPT-5.6 Luna (Prime Agent)` — `gpt-5.6-luna-via-prime-agent` All OMP rows are ordered before all Prime Agent rows. The selected qualified ID chooses the agent when a thread is created. That choice is persisted with the thread, so inactive threads and forks reopen through the same agent. `modelCatalog` is local policy, not a built-in bridge allowlist. `include` and `exclude` accept `*` globs over canonical model IDs; `excludeProviders` removes whole providers; `backendOrder` groups agent rows; and `order` ranks matching models inside each group. Omitting the section preserves the backend catalogs' normal visibility and ordering. ### 3. Connect from ChatGPT Desktop Add your machine under ChatGPT Desktop's **SSH Connections** and select your project workspace. ## Features - **Protocol Compatibility**: JSONL over stdio, Unix domain socket WebSocket, and proxy transport. - **Model Discovery**: Dynamically queries OMP's model catalog and maps requests through configured aliases. - **Streaming & Reasoning**: Assistant text, reasoning/thinking blocks, and command output stream in real-time. - **Native Projections**: Translates OMP activity into Codex `commandExecution`, `fileChange`, `dynamicToolCall`, `mcpToolCall`, `webSearch`, and `imageView` items, including plan updates and unified diffs. - **Approvals & Sandbox**: Server-initiated approvals for shell commands and file mutations with session-level caching (OMP backends only; `backend: "prime"` enforces neither). - **Backends**: OMP in-process SDK or `omp` RPC subprocess (`auto`, `sdk`, `rpc`), Prime's `prime-agent` subprocess (`prime`), and a deterministic `mock` for tests. - **Goals**: Persists `thread/goal/*` state, synchronizes OMP `/goal` updates, accounts usage, and supplies active objectives to resumed turns. - **Daemon Lifecycle**: Background daemon management with `codex remote-control start|status|stop`. - **External Sessions**: Threads driven by another client - including hand-started terminal `omp` and `prime-agent` sessions - stream their turns and items live, and can be steered and interrupted (see below). ## Controlling externally started sessions ### Prime Agent With `backend: "prime"`, the bridge discovers saved sessions in `~/.prime/agent/sessions` (or `PRIME_AGENT_SESSION_DIR`) and correlates them with `prime-agent`'s daemon registry. Durable history uses the same Pi v3 JSONL projection as OMP; the bridge keys it by the session ID inside the file rather than assuming the filename is identical. Live Prime sessions use the local Prime daemon protocol for event replay, status, prompt/steer, interrupt, and compaction. If the daemon is unavailable, saved sessions remain readable and resumable, but an already-running session cannot be controlled until the daemon is reachable again. ### OMP The bridge can observe any OMP session by tailing its JSONL, but writing to a session it does not own needs a channel into that process. `extension/control-socket.mjs` is an ordinary OMP extension that gives each session a private Unix socket, so it survives OMP upgrades and needs no patched binary. Enable it for every session by listing it under `extensions` in the OMP config (`~/.omp/agent/config.yml`): ```yaml extensions: - /path/to/omp-codex-bridge/extension/control-socket.mjs ``` With it loaded, a thread another client is driving stops being read-only: `turn/start` steers the running turn and reports back the real turn it landed in, `turn/steer` queues into it, and `turn/interrupt` aborts it. Without it, those calls behave exactly as before - `turn/start` still reports `BUSY`. Sockets live in `~/.omp/codex-bridge/control/.sock` (override with `OMP_CONTROL_SOCKET_DIR`), are created `0600` inside a `0700` directory, and are removed on session shutdown. Anything able to open one can inject instructions into a running agent, which is why it is opt-in and owner-only. ## Testing ```bash # Run unit & integration test suite npm test # Check syntax of all modules npm run check # Full release verification ./scripts/verify-release.sh ``` ## Documentation - [AGENTS.md](./AGENTS.md) — Architecture, backend resolution, env vars, and debugging guide - [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) — Protocol mapping & internal data flow - [docs/COMPATIBILITY.md](./docs/COMPATIBILITY.md) — Detailed RPC method compatibility table - [SECURITY.md](./SECURITY.md) — Security boundaries and approval model