Status:
rejected · Version 0.1 · Filed 2026-04-26Title: Codex App-Server Signal Injection — local receiver bridge for Prism signals
Version
0.1Status
draftProblem
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 pollsprism_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:- Texi calls
prism_signal(to="Desiree", ...). - Texi MCP sends the signal to Prism FastAPI.
- Prism FastAPI cannot resolve an active Desiree session.
- Prism stores the signal in the backend queue.
- Desiree receives it on next bootstrap or Prism verb according to her surface strategy.
- Desiree calls
prism_signal(to="Texi", ...). - Desiree MCP sends the signal to Prism FastAPI.
- Prism resolves Texi’s active session.
- The signal reaches Texi only through piggyback/poll because Codex has no current push adapter.
Target v1
Desiree -> Texi with Codex app-server injection:- Desiree calls
prism_signal(to="Texi", ...). - Desiree MCP sends the signal to Prism FastAPI.
- Prism FastAPI resolves Texi’s active session and publishes onto the existing Prism session stream.
- Texi’s local MCP process receives the signal from Prism.
- Texi MCP sees
PRISM_AGENT_SURFACE=codexand a localPRISM_CODEX_APP_SERVER_URL. AppServerInjectStrategycalls local Codex app-serverthread/inject_items.- Codex app-server injects a model-visible item into Texi’s loaded Codex thread.
- 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|autodefault:auto-codex-app-server-url URLexplicit override for advanced/debug use- Optional future:
-codex-app-server-port PORTfor deterministic local testing
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.
- 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_MODEandPRISM_CODEX_APP_SERVER_URL. - Attempts to connect to the local app-server only when mode is not
offand 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
AppServerInjectStrategywhen 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
Addmcp/strategies/app_server_inject.py.
AppServerInjectStrategy.deliver(signal):
- Converts Prism signal envelope into a concise Codex-visible item.
- Calls Codex app-server
thread/inject_itemsagainst the active thread. - Returns
Trueon successful injection. - On connection failure, no loaded thread, protocol rejection, or timeout: buffers via piggyback fallback and returns
False.
- source: Prism
- signal type
- sender identity
- signal id
- concise payload summary
- instruction to call
prism_signals_pendingonly 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_idagent_identityagent_surface=codexmachine_idapp_server_modeapp_server_urlredacted or loopback-onlylast_seen_at
Install Contract
Install script changes are capability checks only:- Verify
codexbinary exists when installing Codex support. - Verify
codex app-server --helpincludes--listenbefore advertising app-server injection support. - Continue writing
~/.codex/config.tomlMCP config. - Continue installing
coderlauncher. - Do not start app-server during install.
- Do not reserve ports during install.
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:coder -agent codex -codex-app-server off -dry-runshows no--remoteand exports modeoff.coder -agent codex -codex-app-server auto -dry-runshows the app-server discovery/start plan and fallback behavior.- Fake
codexbinary smoke verifies child process receivesPRISM_CODEX_APP_SERVER_URLwhen app-server is enabled. - Existing Codex CLI mappings remain green:
--cd,--sandbox,--ask-for-approval,--full-auto.
PRISM_AGENT_SURFACE=codex, no app-server URL ->PiggybackStrategy.PRISM_AGENT_SURFACE=codex, fake app-server reachable ->AppServerInjectStrategy.- Fake app-server inject succeeds -> signal delivered, no piggyback buffer.
- Fake app-server inject fails -> signal buffered for piggyback.
on_bootstrapandon_wrapare idempotent.
- Desiree -> Texi with no app-server still arrives through piggyback/poll.
- 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
- Whether
codershould 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. - 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. - Whether a future LAN mode should be supported at all, given Prism already has the authenticated session stream and local MCP bridge.

