# Codex Connect: Alpha design ## Ownership and composition The package registers `openai-codex` through Harness's public `LlmRuntime` and `PiAiAdapter` surfaces. The main model path is not a one-shot subagent: it remains the normal Harness agent loop, preserving native tool approvals, permission policy, streaming, attachment resolution, reasoning replay, session persistence, compaction, and recovery. The bundle patch inserts only `llm-openai-codex`. It never writes `agent-default-model` or `web.searchProvider`. `enableSearch` and `enableImageTool` are capability gates defaulting to `false`; the optional service injections are not registered while disabled. The Host registers `llm-openai-codex` as the plugin-owned capability settings namespace. DSH's `llm-pi-ai` catalog owns the `openai-codex` configurable-provider directory entry, while Codex Connect registers the active adapter without redeclaring that entry. The browser binds the plugin namespace through Harness's settings-scope transport and renders account, quota, Save/Discard capability controls in the existing Plugin configuration card. Revision-fenced field writes preserve unrelated settings. Committed changes reconcile search and image registrations live. Default-model settings are never written. ## OAuth persistence The plugin uses `$DSH_HOME/.openai-codex-auth.json`, separate from Codex CLI/Desktop state. Format version 2 stores at most 16 OAuth accounts and names exactly one active account. Existing version-1 documents remain readable and migrate on the first credential mutation; that migration first creates the owner-only `.openai-codex-auth.json.v1-backup` rollback copy. A pre-existing rollback copy must be owner-only and match the current version-1 document or migration stops before replacing the main document. Removing any account or signing out deletes the rollback copy so removed credentials do not persist there. Documents are limited to 512 KiB. POSIX reads reject group/world-accessible files, non-regular files are rejected, writes are atomic, and mutations use the Harness cross-process file lock. Callers receive cloned credentials. Browser account routes expose deterministic plugin-derived keys, local display labels, masked email addresses when present in the OAuth token, and active state. They never expose the provider's account id or token fields. Activation and deletion are serialized with browser OAuth. Each model request captures its current account before auth resolution; a refresh updates only that captured account without changing the current selection. After OAuth resolution, quota, image-generation, and Auto-review requests resolve the account id stored with that exact access token, so a concurrent account switch cannot combine credentials from different accounts. Deleting the active account while another remains requires the caller to name the replacement; provider-global logout deletes every account. Browser-origin trust is a separate `$DSH_HOME/.openai-codex-trusted-origins.json` sidecar with `version: 1`, `mode: "allowlist"`, and exact normalized HTTP(S) origins; it never contains OAuth material and is changed only by the standalone CLI. The settings routes and CLI reuse the existing OAuth path and route names for migration compatibility. Only an explicit login operation emits an authorization URL or code. Browser requests are accepted by default only from loopback; a remote request must use an exact effective HTTP(S) origin in the current sidecar, must not carry cross-site Fetch Metadata, and must match any supplied Origin exactly. The sidecar is re-read for every request, and unknown fields or modes fail closed. A login challenge accepts only credential-free HTTPS URLs and fails closed after 30 seconds or when the provider finishes without a URL; logout and disposal cancel pending waiters. Status responses are redacted. Doctor uses `lstat` metadata and never opens the document. Browser account and update requests have a 45-second deadline covering response headers and JSON bodies. A timed-out account mutation is not retried automatically: while the account view is observed, the browser reads server state again because the mutation may already have committed. Failed state reads retry after five seconds, including when no account is stored. Plugin disposal aborts browser waits without logging out the server account. ## Search and images When `enableSearch: true`, the plugin registers its standalone search provider. It does not append a plugin-owned required-on-read Session event because an external package cannot guarantee that its `@deepseek-ai/dsh-session` module instance owns the Host persistence vocabulary; the standard web Tool call and result remain in the Session log. DSH `0.1.2-rc.1` does not expose the WebRuntime provider selection through its settings service, so the compatibility adapter verifies that release's runtime field, records the previous provider, and selects Codex only while the capability is active. Disable and disposal restore the recorded provider unless another owner has selected a newer route. An unsupported runtime fails activation instead of reporting a route change that did not occur. Search responses are mapped to Harness text and citation records. When `enableImageTool: true`, `view_image` is registered only after tools, filesystem, and attachment services are available. Local files remain bounded by the Harness filesystem surface. Remote images allow only credential-free public HTTP(S): all DNS answers must be public unicast, each redirect is revalidated, and each socket is pinned to the validated address to close DNS-rebinding gaps. The tool also checks bounded bytes, accepted media signatures, and current-model image support before saving a Harness attachment. Each remote-image redirect hop has one 30-second deadline covering DNS, connection, and body consumption. Cancellation settles the caller's wait immediately; an operating-system DNS lookup may still finish later, but its result cannot start a new HTTP request after cancellation or timeout. ## Conflicts and diagnostics Before registration the plugin checks current provider ids. An existing `openai-codex` adapter produces a focused message naming the likely legacy-bundle or manual-provider cause. The boot-free CLI `doctor` reports package/runtime version, OAuth path metadata, capability defaults, and safe conflict guidance without returning auth content. ## Compatibility boundary Alpha 4.27 pins Harness `0.1.2-rc.1` development dependencies and follows its pi-ai range `^0.84.2`. Supported Node.js remains `^22.19.0 || >=24.0.0`. The keyed `settings.plugin.item` integration remains, while client types come from their Session Controller, Settings, Store, and Renderer owners. The published compatibility record lists the exact Alpha 4.27 and DSH `0.1.2-rc.1` pair. Backend eligibility, quotas, models, service-side context capacity, and protocol details remain controlled upstream. Tests use temporary OAuth documents and mocked network responses; CI does not perform real authentication.