Expand description
Client-side codex exec ask path (ab-0429c6e1).
codex is a one-shot codex exec --json subprocess (NOT a PTY agent):
it emits a JSONL stream to stdout, the Rust client drains and parses it,
and returns the reply text. The fno daemon cannot handle this path because
handle_ask renders a PTY screen; byte-parity with Python’s
providers/codex.py requires a direct subprocess approach.
Byte-parity is the contract. The observable behavior (stdout reply, exit code, events.jsonl fields) must match Python’s implementation.
§Architecture
- Wave B1 (this file, pure core): argv builders,
inject_from_name, JSONL line parser, error enum + exit-code map. No I/O. - Wave B2 (this file, subprocess driver):
run_codexsubprocess with own-pgrp, watchdog SIGTERM->SIGKILL, grace reap, output.jsonl tee;codex_create/codex_resume;dispatch_codex_askorchestrator;maybe_run_codex_askclient entry point.
§Locked Decisions (from Python codex.py)
- bounded default (create): global
--ask-for-approval neverbeforeexecplus theexecflag--sandbox workspace-writeafter it. (-ais a top-level codex flag in >= 0.133.0, not anexecflag.) - full yolo (explicit):
--dangerously-bypass-approvals-and-sandbox. - LD7:
inject_from_nameis plain[from: X]\n\n<prompt>, no escaping. - LD8:
output.jsonlis append-only, line-buffered tee (create & resume). - LD11: stdin=DEVNULL.
- LD12: stderr merged into stdout (stderr=STDOUT).
- LD14 warn-on-drift: NoSessionId carries observed event type names.
Structs§
- AskOutcome
- Outcome of
dispatch_codex_ask. - Codex
Result - Result of a successful codex create or resume invocation.
Enums§
- Codex
AskError - Errors from the codex ask path. Each variant maps to a specific Python- compatible exit code.
- Jsonl
Event - Parsed variant of one codex JSONL line.
Functions§
- approval_
flag - Argv tokens for the create-path approval policy (bounded-posture amendment).
- build_
argv_ create - Build the create argv:
codex exec --json -C <cwd> --skip-git-repo-check <sandbox> <full_prompt>.full_promptshould already have been built viainject_from_name. The subprocess cwd is NOT set via Popen(cwd=…) on the create path (the-Cflag handles it); Python codex.create passespopen_cwd=None. - build_
argv_ resume - Build the resume argv:
codex exec resume <session_id> --json --skip-git-repo-check <sandbox_resume> <full_prompt>.full_promptshould already have been built viainject_from_name. Resume does NOT use-C; the subprocess cwd is pinned viaCommand::current_dir. - codex_
create - Spawn
codex exec --json -C <cwd> ...and parse the JSONL stream.agent_selfis the name of this agent (injected into spawn env for nestedfno agents askattribution). - codex_
resume - Spawn
codex exec resume <session_id> --json ...fromcwd. Resume does NOT accept--cd; cwd is pinned viaCommand::current_dir. - dispatch_
codex_ ask - Orchestrate one codex
ask: validate, lock, decide create-vs-resume, stamp the registry, emit events, and return stdout/stderr/exit_code. - dispatch_
codex_ once - Orchestrate one codex
spawn --once: validate, lock, collision-check, create + exchange, teardown registry row, return reply on stdout and teardown receipt on stderr. Reusesdispatch_createmachinery. - inject_
from_ name - Prepend
[from: <from_name>]\n\ntoprompt(Locked Decision 7). Plain concatenation; no escaping of any kind. - maybe_
run_ codex_ ask - Route a codex
askto the client-sidecodex execpath, bypassing the daemon (mirrorsmaybe_run_claude_askin client.rs). - parse_
jsonl_ line - Parse one raw line from the codex JSONL stream.
- sandbox_
flag - Argv tokens for the create-path sandbox posture (bounded-posture amendment).
- sandbox_
flag_ resume - Argv tokens for the sandbox mode on the resume path.
codex exec resumeonly accepts the bypass flag;--sandboxis not honored on resume (verified against codex 0.130.0 –help).