Skip to main content
Status: rejected · Version 0.1 · Filed 2026-04-26

Title: Codex App-Server Signal Injection — local receiver bridge for Prism signals

Version

0.1

Status

draft

Problem

Codex sessions currently receive Prism signals through piggyback delivery: a signal becomes visible only when the receiving Codex agent calls another Prism verb or explicitly polls prism_signals_pending. This fails the operator goal for agent-to-agent communication: if Desiree sends Texi a signal, Texi should see it in the Codex session without manual polling. Claude Code has a channel-based push path. Codex does not have the same channel API. OpenAI Codex provides an experimental local app-server with JSON-RPC methods including thread/inject_items, which can inject items into a loaded Codex thread. That is the correct local adapter for Codex UI visibility, but it must not become Prism’s LAN/global signal router.

Goal

Implement a fallback-safe Codex signal push path: Sender MCP -> Prism FastAPI -> Receiver MCP -> local Codex app-server -> Codex thread The app-server is a local last-inch adapter only. Prism FastAPI remains the global/authenticated signal router. The receiver MCP process bridges from Prism’s session stream to the local Codex app-server.

Non-Goals

  • Do not reimplement Codex app-server in Prism FastAPI.
  • Do not expose Codex app-server directly on LAN in v1.
  • Do not route Prism FastAPI directly to 127.0.0.1:<codex-port> on another machine; localhost belongs to the FastAPI host, not the receiving agent machine.
  • Do not replace piggyback delivery; it remains the reliability fallback.
  • Do not create a general chat proxy between Codex and Prism.

Architecture

Current Today

Texi -> Desiree when Desiree is offline:
  1. Texi calls prism_signal(to="Desiree", ...).
  2. Texi MCP sends the signal to Prism FastAPI.
  3. Prism FastAPI cannot resolve an active Desiree session.
  4. Prism stores the signal in the backend queue.
  5. Desiree receives it on next bootstrap or Prism verb according to her surface strategy.
Desiree -> Texi today:
  1. Desiree calls prism_signal(to="Texi", ...).
  2. Desiree MCP sends the signal to Prism FastAPI.
  3. Prism resolves Texi’s active session.
  4. The signal reaches Texi only through piggyback/poll because Codex has no current push adapter.

Target v1

Desiree -> Texi with Codex app-server injection:
  1. Desiree calls prism_signal(to="Texi", ...).
  2. Desiree MCP sends the signal to Prism FastAPI.
  3. Prism FastAPI resolves Texi’s active session and publishes onto the existing Prism session stream.
  4. Texi’s local MCP process receives the signal from Prism.
  5. Texi MCP sees PRISM_AGENT_SURFACE=codex and a local PRISM_CODEX_APP_SERVER_URL.
  6. AppServerInjectStrategy calls local Codex app-server thread/inject_items.
  7. Codex app-server injects a model-visible item into Texi’s loaded Codex thread.
  8. If injection fails, the strategy falls back to piggyback buffering.

Launcher Contract

coder -agent codex gains optional app-server management. Flags:
  • -codex-app-server off|local|auto default: auto
  • -codex-app-server-url URL explicit override for advanced/debug use
  • Optional future: -codex-app-server-port PORT for deterministic local testing
Modes:
  • off: never start or use Codex app-server; Codex remains piggyback only.
  • local: require a local app-server path; fail or clearly warn if unavailable.
  • auto: try to start/discover local app-server; silently fall back to piggyback if unavailable.
For v1, app-server listens on loopback only:
codex app-server --listen ws://127.0.0.1:<port>
codex --remote ws://127.0.0.1:<port> --cd <project> ...
The launcher exports:
PRISM_CODEX_APP_SERVER_MODE=auto|local|off
PRISM_CODEX_APP_SERVER_URL=ws://127.0.0.1:<port>
Port policy:
  • Prefer deterministic local port range for operator/debug visibility.
  • If the chosen port is occupied, either reuse only when it is verified as the matching Codex app-server/session, or increment to the next free port and export/register the actual URL.
  • Port collision must not break auto; it falls back or selects another port.

MCP Surface Contract

mcp/agent_surfaces/codex.py owns Codex bootstrap/wrap behavior. CodexSurface.on_bootstrap(ctx):
  • Reads PRISM_CODEX_APP_SERVER_MODE and PRISM_CODEX_APP_SERVER_URL.
  • Attempts to connect to the local app-server only when mode is not off and URL is present/discoverable.
  • Discovers/records the active loaded thread id if required by the app-server protocol.
  • Stores connection/thread metadata on the surface instance.
  • Non-fatal on all failures; logs and stays piggyback.
CodexSurface.signal_strategy():
  • Returns AppServerInjectStrategy when app-server connection and thread metadata are available.
  • Otherwise returns PiggybackStrategy.
CodexSurface.on_wrap(ctx):
  • Closes any app-server client handle.
  • Clears local thread metadata.
  • Does not kill an app-server that it did not start.

Strategy Contract

Add mcp/strategies/app_server_inject.py. AppServerInjectStrategy.deliver(signal):
  • Converts Prism signal envelope into a concise Codex-visible item.
  • Calls Codex app-server thread/inject_items against the active thread.
  • Returns True on successful injection.
  • On connection failure, no loaded thread, protocol rejection, or timeout: buffers via piggyback fallback and returns False.
The injected item must clearly identify:
  • source: Prism
  • signal type
  • sender identity
  • signal id
  • concise payload summary
  • instruction to call prism_signals_pending only if full structured payload is needed

Backend/FastAPI Contract

Prism FastAPI remains the global router. v1 does not require FastAPI to talk directly to Codex app-server. Optional metadata registration may be added later for observability:
  • session_id
  • agent_identity
  • agent_surface=codex
  • machine_id
  • app_server_mode
  • app_server_url redacted or loopback-only
  • last_seen_at
But signal delivery v1 should not depend on FastAPI initiating app-server calls.

Install Contract

Install script changes are capability checks only:
  • Verify codex binary exists when installing Codex support.
  • Verify codex app-server --help includes --listen before advertising app-server injection support.
  • Continue writing ~/.codex/config.toml MCP config.
  • Continue installing coder launcher.
  • Do not start app-server during install.
  • Do not reserve ports during install.
Runtime launcher owns app-server start/discovery.

Security

  • v1 uses loopback only: ws://127.0.0.1:<port>.
  • No LAN exposure of Codex app-server in v1.
  • If LAN mode is added later, it requires explicit operator opt-in and WebSocket auth.
  • Prism API key is never passed as a URL query parameter.
  • App-server auth tokens/secrets, if used, are stored locally and never persisted into Prism logs.

Acceptance Tests

Launcher:
  1. coder -agent codex -codex-app-server off -dry-run shows no --remote and exports mode off.
  2. coder -agent codex -codex-app-server auto -dry-run shows the app-server discovery/start plan and fallback behavior.
  3. Fake codex binary smoke verifies child process receives PRISM_CODEX_APP_SERVER_URL when app-server is enabled.
  4. Existing Codex CLI mappings remain green: --cd, --sandbox, --ask-for-approval, --full-auto.
MCP surface:
  1. PRISM_AGENT_SURFACE=codex, no app-server URL -> PiggybackStrategy.
  2. PRISM_AGENT_SURFACE=codex, fake app-server reachable -> AppServerInjectStrategy.
  3. Fake app-server inject succeeds -> signal delivered, no piggyback buffer.
  4. Fake app-server inject fails -> signal buffered for piggyback.
  5. on_bootstrap and on_wrap are idempotent.
End-to-end:
  1. Desiree -> Texi with no app-server still arrives through piggyback/poll.
  2. Desiree -> Texi with fake/local app-server inject path causes Texi’s Codex thread to receive an injected Prism signal item without manual prism_signals_pending.

Open Questions

  1. Whether coder should launch one app-server per Codex session in v1 or share a per-machine app-server. Recommendation: one app-server per coder-launched Codex session for a clear thread/session mapping.
  2. Exact app-server JSON-RPC request/response shape for thread/inject_items; implementation must verify against the installed Codex CLI/app-server generated schema or official docs.
  3. Whether a future LAN mode should be supported at all, given Prism already has the authenticated session stream and local MCP bridge.
Last modified on May 18, 2026