fix(codex): seed the spawn-window agent status from launch metadata - #14611
brennanb2025 wants to merge 1 commit into
Conversation
Codex CLI publishes no hook while its TUI idles — measured on codex-cli 0.147.0, a fresh or `codex resume` TUI posts zero hooks for 40s, and SessionStart only fires alongside the first UserPromptSubmit. A Codex pane therefore has no status row at all between spawn and the user's first message (#6643). Generalize the existing `paneStartup.initialAgentStatus` seam, which already covered Command Code's identical spawn window, into a declarative `seedsLaunchStatus` capability on TUI_AGENT_CONFIG and one shared payload builder. A submitted prompt seeds `working`; a promptless or draft launch seeds the idle `sessionBoundary` done row Claude's SessionStart already uses (STA-3386), so an idle TUI never spins a phantom spinner and completion-reactive consumers skip it. Runtime-spawned startup terminals (CLI create, automations, backend-spawned startups) mount no renderer pane, so main seeds those from the same builder via AgentHookServer.seedLaunchAgentStatus. Any existing row always wins.
|
Warning Review limit reached
Next review available in: 21 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (14)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ELI5
When you start a Codex agent in Orca, the agent row in the status surface used to be missing entirely until you sent your first message. That's because Codex's CLI doesn't tell Orca anything while it's sitting at an idle prompt — it only starts reporting once you actually submit something. This PR fills that gap with what Orca already knows at launch time: which agent it started and whether it started it with a prompt.
What Changed
seedsLaunchStatuscapability onTUI_AGENT_CONFIG, set forcodexand the already-coveredcommand-code. It names the property those two share: no hook until the first prompt.src/shared/agent-launch-status-seed.ts— one predicate and one payload builder shared by every seeding site:workingrow carrying that promptdonerow withsessionBoundary: truepaneStartup.initialAgentStatusseam (previously hardcoded tocommand-code) across its three producers — new agent tab, workspace-creation flow, new-workspace composer — and its consumer inpty-connection.ts.AgentHookServer.seedLaunchAgentStatus+ a call fromcreateManagedWorktree's two local startup-terminal sites, for runtime-spawned panes (CLIworktree create --agent codex, automations, backend-spawned startups) that mount no renderer pane. Any status the pane already reported always wins.Behavior changes worth calling out
command-codetab now also gets the idle presence row. Previously it was seeded only when launched with a prompt. This falls out of the single uniform rule; special-casing it back would reintroduce the per-agent hardcoding this PR removes.sessionBoundarydone, the same shape Claude'sSessionStarthas landed since STA-3386, so notifications, automation runs, unread badges and finished timestamps already ignore it.Why
Measured on codex-cli 0.147.0 (macOS, all eight managed hook events trusted via
codex app-serverhooks/list+config/batchWrite, captive receiver on a tempCODEX_HOME):codex resume --last, 40 s idle/clearon a live session/newon a live sessionSessionStart(source: startup),UserPromptSubmit,StopSessionStartandUserPromptSubmitlanded in the same wall-clock second. So the spawn window is genuinely hook-free: no change to hook handling can put a row on screen there, and launch metadata is the only signal Orca has. That is why this fix lives at launch time rather than in the normalizer.paneStartup.initialAgentStatusalready existed for exactly this problem — the code comment read "command-code shows its prompt in the tab status before the first hook fires" — so this makes that seam agent-declarative instead of adding a parallel mechanism.Relationship to the other open PRs on this cluster
InitialAgentStatusSeedtype through IPC/RPC/preload/store/PTY-bind. That plumbing has since landed in a narrower form aspaneStartup.initialAgentStatus, so the remaining gap is only the agent gate — this PR closes it without new wire fields.sessionBoundaryidle-row choice are theirs, and both are kept here). Differences: that PR seeds only runtime-built spawns and assumes the renderer path already covers UI-created panes, but on currentmainthe renderer path is gated tocommand-code, so UI-launched Codex panes stayed uncovered. It also skipped seeding whenever the caller suppliedstartup, which is a case where the renderer also skips (the renderer only seeds whenbackendSpawned === false), leaving a hole. Here the runtime seeds exactly when it spawned the terminal itself, so the two halves are complementary by construction.SessionStartmapping toworkingto avoid an "idle running flash" — but per the table above,SessionStartnever arrives while the TUI is idle, and when it does arriveUserPromptSubmitfollows in the same second with the sameworkingstate, so there is no observable flash on codex-cli 0.147.0. Its other contents (subagent lifecycle, interrupt handling, richer tool previews) have largely landed onmainsince. I have deliberately not bundled its normalizer/relay changes here; whether the remaining pieces (remote hook prepend + trust-key migration, native "Action Required" title detection) should land is a separate call on their own evidence, and I have not commented on that PR.app-server. It is inside Codex's own launch path and is untouched here.Linked Issue
Fixes #6643
Refs #7950, #11941
Visual Proof
N/A— no visual redesign. The change is which status row exists for a pane during the spawn window; there is no new UI surface, token, layout or copy. The reviewer-checkable evidence is the measurement table above plus the assertions in the tests below, which pin the exact published payloads (working+ prompt, ordone+sessionBoundary).Testing
Automated (all added tests fail when
seedsLaunchStatusis removed fromcodex, or when the payload builder is reverted to the old hardcodedworkingshape — verified by reverting each and re-running):src/shared/agent-launch-status-seed.test.ts— predicate coverage and both payload shapes, including whitespace-only promptssrc/main/agent-hooks/server.test.ts—seedLaunchAgentStatus: a row exists at spawn before any hook; promptless spawn lands the idle boundary row; duplicate seeds stay one row and notify once; an existingPermissionRequestwaiting is never overwritten; a retired pane is not resurrected; the first real turn replaces the seed and keeps its provider session; duplicate identical hook delivery stays a single rowsrc/main/runtime/orca-runtime.test.ts— CLI-created local worktree seeds with the injected prompt; a seeding failure does not turn into a startup-terminal warningsrc/renderer/src/lib/launch-agent-in-new-tab-launch-status-seed.test.tsandworktree-creation-flow-startup.test.ts— producer gating, including draft launches seeding presence only and hook-at-startup agents staying unseededsrc/renderer/src/components/terminal-pane/pty-connection.test.ts— consumer publishes the right payload for both shapes, over an SSH-connected paneCommands run locally (macOS):
pnpm exec vitest run --config config/vitest.config.ts <the six affected files>— 6 files, 2000 passed / 1 skippedAdjacent suites:
useComposerState-host-*,worktree-creation-flow,agent-status-types,store/slices/agent-status— 5 files, 166 passedtsc --noEmitfortsconfig.node.json,tsconfig.cli.json,tsconfig.web.json— all cleanoxlint,oxlint --config config/oxlint-react-doctor.json,oxfmt --checkon every changed file — cleannode config/scripts/check-changed-code-quality.mjs— 0 new findings across 14 filespnpm check:max-lines-ratchet— OK, no new bypasses (new renderer tests went into their own file rather than pushinglaunch-agent-in-new-tab.test.tspast the 800-line cap)I manually tested these changes locally
Automated tests added/updated, or explained why not below
Manual: the live measurement above was run against real
codex0.147.0 through a pty with a captive hook receiver, which is what establishes the spawn window is hook-free. Not yet exercised: an Electron pass on Windows/Linux, and a live SSH Codex launch.AI Disclosure
Claude Opus 5 via Claude Code.
Review
ingestTerminalStatus, so it passes the same pane-key validation, length bound and disposition checks as OSC-derived status.AgentStatusRouting, so SSH panes are stamped with their realconnectionId(covered by the SSH-pane test). The main-process seed is deliberately local-only: it would have to writeconnectionId: null, which would contradict the relay-stamped rows a remote pane's hooks produce.createManagedWorktreebranches, git worktree and folder workspace.initialAgentStatusis renderer-internal startup metadata andsessionBoundaryis an existing optional field older clients already handle.AgentStatusEntryrows; asessionBoundarydoneis already the shape it receives from Claude.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)— targeted lint/format/quality gates, all three
tscprojects, and the affected + adjacent vitest files were run locally; the full suite andpnpm buildare left to CI.Author