Skip to content

ADR 002 Codex Plugin Lifecycle

Joseph Roberts edited this page Oct 2, 2026 · 4 revisions
  • ID: ADR-002
  • Status: Accepted
  • Date: 2026-08-27
  • Date meaning: Original decision date; normalization recorded 2026-10-02.
  • Implementation: No implementation information was recorded in the source status; tickets own progress.
  • Approval qualification: Recorded accepted decision; dated delivery conditions are historical, not new execution authorization.

Context

Release Radar must ship and version a local Codex plugin and let the owner install, update, remove, detect modification, and reinstall it from the macOS application. A clean managed installation must update with the application, while a never-installed, removed, or modified installation must not be silently installed or overwritten.

Codex owns plugin configuration and installed cache state under the owner's Codex home. Release Radar remains sandboxed, and sandbox extensions granted to the running app are not inherited by a child process. Directly editing Codex configuration or cache would create an unsupported competing owner.

Decision

Release Radar will ship a canonical local marketplace and release-radar plugin as signed application resources. Codex remains the owner of installed plugin state, enablement, approval, and permissions.

Release Radar may register one separately signed, same-user lifecycle helper. The helper remains inside App Sandbox and invokes the verified ChatGPT-bundled Codex CLI only for the fixed Release Radar plugin. Its private typed XPC interface contains exactly status, install, remove, and reinstall. It accepts no arbitrary command, path, identity, source, arguments, or environment.

The helper has no app-group, Keychain, folder-bookmark, network, SQLite, MCP, STDIO, URL, or agent-facing authority and does not link ReleaseRadarCore. It authenticates the same-user Release Radar caller, directly invokes only the fixed verified Codex executable with fixed arguments and a sanitized environment, strictly parses bounded results, and fails closed.

Feasibility condition

This decision authorizes the boundary but not an unproven implementation. A signed, isolated feasibility gate must prove fixed local-marketplace behavior, CLI install/update/remove postconditions, package-integrity observation, MCP executable resolution, XPC admission, and fail-closed executable verification. The proof may read and change owner Codex plugin state only through the verified official CLI and only for the exact release-radar marketplace/plugin, legacy release-radar MCP target, and bundled release_radar MCP target. Task 1 requires the plugin and marketplace to start and end absent. Its MCP baseline may be absent or the exact recognized legacy entry, while bundled key release_radar must start and end at the pinned exact-absence tuple. Any present, malformed, or ambiguous bundled-key result stops before mutation. The proof must restore the legacy baseline and preserve unrelated state. The only direct Codex-state read is the owner-authorized exact-root plugin-cache digest; direct cache/configuration writes and all unrelated configuration/cache reads remain prohibited. Product behavior for an existing recognized managed install remains subject to the evidence established within that absent-baseline lifecycle.

The remaining feasibility gate passes when a derived installed plugin resolves to the freshly built packaged AgentTools, a fresh Codex task discovers the installed skill and initializes its STDIO MCP server, and the existing signed runtime lane commits one typed ticket transition with exactly one matching request receipt and audit in a temporary app-owned database. The existing wrong-tool acceptance case supplies negative peer-admission evidence.

Because public SMAppService.agent(plistName:) resolves relative to the calling application bundle, the standalone controller makes no bridge-service status claim; it verifies only that the normal Release Radar app is not running. The existing Release Radar app-hosted acceptance test requires initial exact .notRegistered, treats .notFound and every other state as a stop, registers the bridge itself, records ownership only after successful registration, and unregisters only that owned registration before requiring final .notRegistered.

Every CLI or MCP process started by the proof uses a fixed executable and arguments, bounded output, and a fixed deadline. The controller records the exact directly owned PID and, when it creates a dedicated process group, the exact PGID. On timeout or cancellation it revalidates ownership, sends TERM and then KILL after a bounded grace period if necessary, and reaps the direct child. It never enumerates, signals, or reconciles processes by shared path or same-user identity.

If the bundled Codex CLI cannot support safe update or marketplace confinement, or if exact-root read-only digesting cannot prove integrity, the implementation remains blocked. Direct configuration/cache writes, broader cache reads, a shell wrapper, HTTP, generic XPC execution, or an expanded agent bridge are not acceptable fallbacks.

Consequences

The application gains one narrow installation-management component and its signing/package verification obligations. It does not gain general filesystem or command execution authority. The plugin lifecycle and the runtime delivery bridge remain separate trust boundaries.

The canonical product-name choice requires one narrowly recognized CLI migration for existing installations and therefore a rollback path during first Install. Codex's callable namespace constraint requires the internal bundled-server identifier release_radar. In exchange, Release Radar exposes one installed plugin and one callable tool surface instead of carrying a second plugin/server alias such as release-radar-plugin indefinitely. No persisted migration flag is needed: the existing lifecycle intent distinguishes the first successful managed Install from later operations.

The detailed product, state, UX, security, and acceptance contract is owning product specification.

Rejected alternatives

  • User-mediated commands alone: safer, but they do not meet app-owned buttons and automatic clean-install updates.
  • Main-app write access, direct Codex cache/configuration writes, or broader cache reads: unsupported ownership and sandbox boundary.
  • Expanding the existing bridge, MCP server, or dispatcher: mixes plugin installation authority with delivery mutation authority.
  • Naming the plugin or bundled server release-radar-plugin: creates a second durable product alias and makes discovery and troubleshooting ambiguous.
  • Keeping release-radar as the bundled server key: the pinned Codex CLI lists it but cannot expose its tools because the hyphen cannot form a callable model tool namespace.
  • A generalized legacy-entry migrator, persisted migration state, or periodic reconciliation: unnecessary for one exact supported-CLI replacement during first managed Install.
  • HTTP, shell, generic command/XPC, root helper, periodic reconciliation, or a second SQLite writer: unnecessary and outside the approved product.
  • A generated feasibility application, duplicate lifecycle helper, alternate Mach service, same-core test executable, synthetic runtime tracer, or custom process framework: duplicates established boundaries and makes the proof larger than the product behavior being evaluated.

Codex plugin lifecycle boundary — 2026-08-27

The fixed plugin lifecycle contract authorizes one separately signed, same-user, fixed-purpose helper for the lifecycle of the single app-shipped release-radar Codex plugin. The helper is not part of the agent runtime path: it cannot access SQLite, the app group, project folders, credentials, networking, arbitrary commands, or ticket mutations. The app remains sandboxed and Codex remains the owner of its plugin configuration and cache.

This authorization is conditional on a signed, isolated feasibility gate that proves the supported Codex CLI can perform confined marketplace and plugin lifecycle operations, verify their postconditions, and distinguish a clean managed install from modified or inconsistent content. Direct Codex config/cache writes, HTTP, generic command execution, or expansion of the existing mutation bridge remain prohibited.

Clone this wiki locally