# OMP Codex Bridge — Agent & Developer Reference This document covers the internal architecture, protocol mechanics, backend integration paths, and development workflows for `@oh-my-pi/codex-bridge`. ## System Overview `@oh-my-pi/codex-bridge` is an adapter that speaks the Codex CLI and app-server JSON-RPC / WebSocket protocols on the frontend while driving [Oh My Pi](https://github.com/can1357/oh-my-pi) on the backend. ``` +---------------------+ +--------------------------------------+ | ChatGPT Desktop | --(SSH/stdio)-->| codex shim (bin/codex.mjs) | | or Remote Control | --(Unix sock)->| | | +---------------------+ | v | | AppServer (src/app-server.mjs) | | | | | +--> Backend (src/backend/omp.mjs)| | | | +-----------|--------------------------+ v +-----------------------+ | Oh My Pi (OMP) | | (SDK / RPC Process) | +-----------------------+ ``` ## Backend Modes Configured via `backend` in `config.json` or `OMP_CODEX_BACKEND` (`auto`, `sdk`, `rpc`, `prime`, `both`, `mock`): 1. **`auto` (default)**: Tries direct SDK import first; if unavailable, falls back to the `omp` CLI in RPC mode. 2. **`sdk`**: Imports the OMP coding-agent module directly in-process. Resolves in order: - `process.env.OMP_CODEX_OMP_MODULE` (explicit path or package name) - `@oh-my-pi/pi-coding-agent` - `@oh-my-pi/coding-agent` - `@oh-my-pi/agent` - Local Bun workspace paths (`packages/coding-agent/src/index.ts`) 3. **`rpc`**: Spawns `omp` as a subprocess with JSONL RPC communication (`omp --mode rpc-ui`). Override binary path with `OMP_CODEX_OMP_BIN` and args with `OMP_CODEX_OMP_RPC_ARGS`. 4. **`prime`**: Spawns Prime (`prime-agent`, Prime 0.8.0 or newer) as a subprocess speaking Prime's own JSONL RPC protocol (`--mode rpc`). Reached through a dynamic import of `src/backend/prime.mjs`, so `auto` never loads it and a machine without Prime installed starts exactly as before. Binary resolution order: - `primeExecutable` passed programmatically or set under `sessionOptions` in `config.json` - `OMP_CODEX_PRIME_BIN` - `~/.local/bin`, `~/.bun/bin`, `~/.nix-profile/bin`, `/opt/homebrew/bin`, `/usr/local/bin` - `prime-agent` on `PATH` Extra flags come from `OMP_CODEX_PRIME_RPC_ARGS` (JSON array) and are *appended* — unlike `OMP_CODEX_OMP_RPC_ARGS`, they never replace the base argument vector, so `--resume`/`--model`/`--cwd` survive. Prime publishes its own short model catalog, so the factory declares `modelCatalogPolicy = "all"` and `model/list` exempts its rows from the OMP featured-model filter (see below). Rows carry a bare `id` (`gpt-5.6-luna`) plus a provider-qualified `selector` (`openai-codex/gpt-5.6-luna`). Prime's own dialogs (`extension_ui_request`) map onto the Codex user-input request and are answered with `extension_ui_response`. **Prime enforces no approvals and no sandbox.** It has no Codex/OMP command or file approval primitive, so `defaultApprovalPolicy` is not applied, no approval round-trip is sent to the client, and shell commands and file writes run with the daemon's own privileges. Use it only where unattended edits are acceptable. 5. **`both`**: Loads the normal OMP `auto` backend and Prime together. It advertises a synthetic custom provider through `config/read`, allowing Desktop/iOS to accept unique model IDs such as `gpt-5.6-luna-via-omp` and `gpt-5.6-luna-via-prime-agent`. Display names append `(OMP)` or `(Prime Agent)`. Selecting the qualified ID chooses the backend for a new thread. Persisted `backend.kind` chooses the backend when a thread resumes; an existing thread cannot switch agent families through a later model change. Local `modelCatalog` policy controls filtering and ordering without changing the packaged catalogs. 6. **`mock`**: In-memory deterministic backend for unit tests, offline development, and verification suites. ## Model Catalog Visibility `model/list` hides every model outside `FEATURED_MODEL_IDS` (`src/backend/omp.mjs`), because OMP's catalog runs to hundreds of rows and the Desktop picker becomes unusable otherwise. A backend whose catalog is already short would lose all of its rows to that filter, so it opts out explicitly: - Factory-level: `modelCatalogPolicy = "all"` on the backend factory (instance or static). `createBackendFactory` defaults this for `prime` when the factory does not set it itself. - Row-level: `catalogPassthrough: true` on an individual model row. Neither is inferred from a provider name or id prefix. A row that sets `hidden: true` stays hidden regardless of policy. `modelCatalog` in bridge config is an optional local policy layer: - `include` / `exclude`: `*` glob patterns over canonical model IDs. - `excludeProviders`: exact provider IDs to remove. - `backendOrder`: backend tags such as `["omp", "prime-agent"]`. - `order`: ordered `*` glob patterns applied within each backend group. When `include` is present, matching rows bypass `FEATURED_MODEL_IDS`; omitted policy retains the existing backend-specific visibility and ordering. ## Transport Modes - **JSONL stdio** (`codex app-server`): Standard entry point invoked by SSH connections from ChatGPT Desktop. - **Unix Domain Socket** (`codex remote-control start`): Listens on `~/.omp/codex-bridge/run/app-server.sock` (mode `0600`). - **WebSocket Proxy** (`codex app-server proxy`): Bridges stdio to the running daemon's Unix socket. - **Loopback TCP WebSocket**: Available for local development. Binding to non-loopback addresses requires `OMP_CODEX_ALLOW_PUBLIC_LISTEN=1`. ## Environment Variables | Variable | Purpose | Default | |---|---|---| | `OMP_CODEX_BACKEND` | `auto`, `sdk`, `rpc`, `prime`, `both`, or `mock` | `auto` | | `OMP_CODEX_OMP_MODULE` | Explicit OMP SDK module or file URL | autodetected | | `OMP_CODEX_OMP_BIN` | Path to `omp` executable for RPC mode | autodetected via PATH | | `OMP_CODEX_OMP_RPC_ARGS` | JSON array of arguments for OMP RPC process | `["--mode","rpc-ui"]` | | `OMP_CODEX_PRIME_BIN` | Path to `prime-agent` executable for `prime` backend | autodetected via PATH | | `OMP_CODEX_PRIME_RPC_ARGS` | JSON array of extra flags appended to Prime's RPC argv | `[]` | | `OMP_CODEX_CONFIG` | Path to bridge config file | `~/.omp/codex-bridge/config.json` | | `OMP_CODEX_STATE_FILE` | Persistent state JSON path | `~/.omp/codex-bridge/state.json` | | `OMP_CODEX_DEFAULT_MODEL` | Default model identifier | `gemini-3.7-flash` | | `OMP_CODEX_MODEL_ALIASES` | JSON string of extra model aliases | `{}` | | `OMP_CODEX_RUNTIME_DIR` | Directory for daemon sockets/pids/logs | `~/.omp/codex-bridge/run` | | `OMP_CODEX_SOCKET` | Custom Unix domain socket path | `/app-server.sock` | | `OMP_CODEX_COMPAT_VERSION` | Version reported by `codex --version` | `0.145.0` | | `OMP_CODEX_DEBUG` | Enable verbose diagnostics to stderr | disabled | | `OMP_CODEX_QUIET` | Suppress non-error logs | disabled | | `OMP_CODEX_ALLOW_FS_OUTSIDE_WORKSPACE` | Disable workspace boundary checks | disabled (unsafe) | | `OMP_CODEX_ALLOW_PUBLIC_LISTEN` | Permit non-loopback TCP listeners | disabled (unsafe) | ## State & Persistence - **State file**: `~/.omp/codex-bridge/state.json` (atomic writes, mode `0600`). - Tracks thread IDs, turn history, approval cache ("accept for session"), model overrides, and associated OMP session IDs for resumption. - Direct filesystem requests (`fs/readFile`, `fs/writeFile`, etc.) are canonicalized and guarded against path traversal outside the active workspace root. ## Workspace & Worktree Isolation (Jujutsu & Git) The bridge provides automatic VCS workspace isolation for threads and forks: 1. **Automatic Detection (`src/workspace.mjs`)**: - Checks for a **Jujutsu (`jj`)** repository first via `jj root`. - If not found, checks for a **Git** repository via `git rev-parse --show-toplevel`. - Falls back to unisolated direct `cwd` if outside a repository. 2. **Jujutsu Workspaces (`jj workspace add`)**: - Preferred when `jj` is detected. - Creates an independent workspace without index locking, stash conflicts, or branch collision. - Snapshots all agent mutations automatically in the `jj` operation log. - Automatically forgotten (`jj workspace forget`) and cleaned up on thread deletion. 3. **Git Worktree Fallback (`git worktree add`)**: - Used in standard Git repositories when `jj` is not present. - Creates a detached HEAD worktree and removes it on thread deletion. 4. **Configuration**: - `workspaceIsolation` in `config.json` or `OMP_CODEX_WORKSPACE_ISOLATION`: `"auto"` (default), `"jj"`, `"git"`, or `"none"`. - Custom isolation directory via `OMP_CODEX_WORKSPACES_DIR` (defaults to `~/.omp/codex-bridge/workspaces`). ## Protocol Tracing & Replay To record live protocol exchanges from the real Codex binary or ChatGPT desktop: ```bash CODEX_REAL=/path/to/real/codex node ./scripts/codex-trace-wrapper.mjs app-server ``` Recorded traces are written to `~/.omp/codex-bridge/traces/` and can be inspected or replayed for debugging. ## Verification & Testing Run tests and release checks from the repo root: ```bash # Unit and integration test suite (15 tests) npm test # Lint/syntax check all JS modules node ./scripts/check.mjs # Full isolated release verification (clean-copy + daemon lifecycle) ./scripts/verify-release.sh # Install or refresh local shim in ~/.local/bin/codex ./scripts/install-local.sh "$HOME/.local" ```