Skip to content

fix(codex): seed the spawn-window agent status from launch metadata - #14611

Open
brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/codex-spawn-status-7950
Open

brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/codex-spawn-status-7950

Conversation

@brennanb2025

Copy link
Copy Markdown
Contributor

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

  • New seedsLaunchStatus capability on TUI_AGENT_CONFIG, set for codex and the already-covered command-code. It names the property those two share: no hook until the first prompt.
  • New src/shared/agent-launch-status-seed.ts — one predicate and one payload builder shared by every seeding site:
    • launch submits a prompt → working row carrying that prompt
    • promptless launch, or a prompt delivered as an unsent draft → idle done row with sessionBoundary: true
  • Generalized the existing paneStartup.initialAgentStatus seam (previously hardcoded to command-code) across its three producers — new agent tab, workspace-creation flow, new-workspace composer — and its consumer in pty-connection.ts.
  • AgentHookServer.seedLaunchAgentStatus + a call from createManagedWorktree's two local startup-terminal sites, for runtime-spawned panes (CLI worktree 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

  • A promptless command-code tab 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.
  • The idle row is a sessionBoundary done, the same shape Claude's SessionStart has 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-server hooks/list + config/batchWrite, captive receiver on a temp CODEX_HOME):

Scenario Hooks received
Fresh TUI, 40 s idle 0
codex resume --last, 40 s idle 0
/clear on a live session 0
/new on a live session 0
First prompt submitted 3 — SessionStart (source: startup), UserPromptSubmit, Stop

SessionStart and UserPromptSubmit landed 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.initialAgentStatus already 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

  • Supersedes Show prompt status for newly launched Codex agents #6829 (mine). It threaded a new InitialAgentStatusSeed type through IPC/RPC/preload/store/PTY-bind. That plumbing has since landed in a narrower form as paneStartup.initialAgentStatus, so the remaining gap is only the agent gate — this PR closes it without new wire fields.
  • Supersedes fix(codex): seed spawn-window agent status from launch metadata #14222 (thanks @tonite31 — the spawn-window diagnosis and the sessionBoundary idle-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 current main the renderer path is gated to command-code, so UI-launched Codex panes stayed uncovered. It also skipped seeding whenever the caller supplied startup, which is a case where the renderer also skips (the renderer only seeds when backendSpawned === false), leaving a hole. Here the runtime seeds exactly when it spawned the terminal itself, so the two halves are complementary by construction.
  • Does not supersede fix(codex): preserve hook-driven agent status #8292 (@bbingz). That PR is independent, not subsumed, and its premise did not reproduce for me. It stops Codex SessionStart mapping to working to avoid an "idle running flash" — but per the table above, SessionStart never arrives while the TUI is idle, and when it does arrive UserPromptSubmit follows in the same second with the same working state, 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 on main since. 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.
  • [Bug]: SSH Codex sessions emit no Orca hooks when the TUI reuses an existing app-server #11941 is a third, separate root cause — SSH Codex emitting zero hooks when the TUI reuses a pre-existing 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, or done + sessionBoundary).

Testing

Automated (all added tests fail when seedsLaunchStatus is removed from codex, or when the payload builder is reverted to the old hardcoded working shape — verified by reverting each and re-running):

  • src/shared/agent-launch-status-seed.test.ts — predicate coverage and both payload shapes, including whitespace-only prompts
  • src/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 existing PermissionRequest waiting 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 row
  • src/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 warning
  • src/renderer/src/lib/launch-agent-in-new-tab-launch-status-seed.test.ts and worktree-creation-flow-startup.test.ts — producer gating, including draft launches seeding presence only and hook-at-startup agents staying unseeded
  • src/renderer/src/components/terminal-pane/pty-connection.test.ts — consumer publishes the right payload for both shapes, over an SSH-connected pane

Commands run locally (macOS):

  • pnpm exec vitest run --config config/vitest.config.ts <the six affected files> — 6 files, 2000 passed / 1 skipped

  • Adjacent suites: useComposerState-host-*, worktree-creation-flow, agent-status-types, store/slices/agent-status — 5 files, 166 passed

  • tsc --noEmit for tsconfig.node.json, tsconfig.cli.json, tsconfig.web.json — all clean

  • oxlint, oxlint --config config/oxlint-react-doctor.json, oxfmt --check on every changed file — clean

  • node config/scripts/check-changed-code-quality.mjs — 0 new findings across 14 files

  • pnpm check:max-lines-ratchet — OK, no new bypasses (new renderer tests went into their own file rather than pushing launch-agent-in-new-tab.test.ts past 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 codex 0.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

  • Security — no new IPC method, command, credential, dependency or persisted secret. The seed reuses ingestTerminalStatus, so it passes the same pane-key validation, length bound and disposition checks as OSC-derived status.
  • Cross-platform — no path, shell, keyboard or platform-conditional code; the capability is a static config flag.
  • Remote / SSH — the renderer seam is transport-agnostic and publishes through the pane's existing AgentStatusRouting, so SSH panes are stamped with their real connectionId (covered by the SSH-pane test). The main-process seed is deliberately local-only: it would have to write connectionId: null, which would contradict the relay-stamped rows a remote pane's hooks produce.
  • Folder workspaces — the runtime seed is called on both createManagedWorktree branches, git worktree and folder workspace.
  • Backwards compatibility — no wire, RPC or payload shape change. initialAgentStatus is renderer-internal startup metadata and sessionBoundary is an existing optional field older clients already handle.
  • Performance — one extra status publication per agent spawn, replacing a row that would have been published moments later anyway. No polling, no new subscriptions, no hot-path work.
  • Mobile — mobile reads the same AgentStatusEntry rows; a sessionBoundary done is already the shape it receives from Claude.

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)
    — targeted lint/format/quality gates, all three tsc projects, and the affected + adjacent vitest files were run locally; the full suite and pnpm build are left to CI.

Author

  • X / Twitter: @BrennanKB5

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.
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@brennanb2025, you've reached your PR review limit, so we couldn't start this review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ee3c2da-872f-4041-a55b-d52c0de663dc

📥 Commits

Reviewing files that changed from the base of the PR and between 9bb8836 and 81498fd.

📒 Files selected for processing (14)
  • src/main/agent-hooks/server.test.ts
  • src/main/agent-hooks/server.ts
  • src/main/runtime/orca-runtime.test.ts
  • src/main/runtime/orca-runtime.ts
  • src/renderer/src/components/terminal-pane/pty-connection.test.ts
  • src/renderer/src/components/terminal-pane/pty-connection.ts
  • src/renderer/src/hooks/useComposerState.ts
  • src/renderer/src/lib/launch-agent-in-new-tab-launch-status-seed.test.ts
  • src/renderer/src/lib/launch-agent-in-new-tab.ts
  • src/renderer/src/lib/worktree-creation-flow-startup.test.ts
  • src/renderer/src/lib/worktree-creation-flow-startup.ts
  • src/shared/agent-launch-status-seed.test.ts
  • src/shared/agent-launch-status-seed.ts
  • src/shared/tui-agent-config.ts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex agent status missing until first user message

1 participant