Repository navigation
fix(sidebar): an agent's row stays while it runs, whatever its tab title - #23948
Conversation
…r its title Codex retitles its pane to the project name, so the sidebar's title-derived row (which required the title to name an agent) vanished while Codex kept running (#23767). Rows now take identity from the canonical pane resolver over the pane's foreground-process read and launch record, then the title; the title only decides idle/working/needs-input. The row still goes away when the PTY exits, the process tracker proves the shell is back, or the title is a shell or default title.
Review of the previous commit found ghost rows: the tab launch record is a latch nothing clears on WSL, after an SSH exit, or for a launch that never started, and a parked pane's process read went stale because only the mounted tracker re-derives it. - The launch record returns to main's role: a fallback only for titles that show activity, ranked below a title naming another agent (pane reuse), matching the tab icon's order. - A parked pane's command boundary retires its unconfirmable process read, like the mounted ladder's unavailable path; reveal re-reads it.
…it Bash prompt titles as the shell - A parked pane's end-of-command marker can be a nested shell's leak under a still-running full-screen agent, so confirm the foreground first (as the mounted ladder does) and retire the process read only on a shell or no answer. SSH/remote parked panes hold no incarnation to fence a host read with, so they still retire. - Git Bash emits no command marks; its `$MSYSTEM:$PWD` prompt title (MINGW64:/c/repo) is now shell evidence, so a stale Codex read there no longer keeps a ghost row after Codex exits.
…r-worktree foreground selector groups by tab A daemon reattach seeds the pane's foreground entry with its launch agent, which can outlive the process while Orca is closed. The entry now records where its agent came from (agentEvidence), and the sidebar/dashboard title-derived rows only keep a plain-title row on an actual process read. Routing and the tab icon are unchanged. selectPaneForegroundAgentsForWorktree grouped every pane key per worktree; it now groups by tab once per map identity and skips worktrees with no tabs.
…the same agent The reattach seed marked a returning parked Codex pane as launch-record evidence, over the process read this session already took, so its row blinked out on reveal and stayed hidden if the user left the tab before the visible read landed. Keep the read when it names the same agent; the seed still drops byte-routing trust.
Codex clears its title when it exits, and the tab then shows its default title. A pane without shell command marks never re-reads its foreground process, so the retained read kept a "Codex · Idle" row after /quit (permanently for a hand-typed Codex; about 15 s while the marked-pane confirm ladder ran). Treat a blank title like the default title it shows.
…ocess read A hook-less pane keeps its sidebar row from the tracker's foreground-process read, but nothing re-derived that read in a pane without OSC 133 command marks. After Codex exited there, a "Codex · Idle" row stayed: permanently when the shell titles its prompt, or when a killed Codex leaves its last title. The pane's agent-completion process monitor already confirms an agent's exit (no agent and no child processes, held past its settle window). It now reports that exit to the tracker, which retires its own process read and runs the confirmed-shell path the visible-pty read uses. A tracker read that names an agent seeds the monitor, so hidden panes and panes the monitor had not polled yet are watched too. A command read in flight still decides the pane, and launch records or other agents' reads are left alone.
…marked pane identifiable The process-exit retire published shellForeground:true and left the one-shot visible sample settled; a pane without command marks has no command start to lift either, so a Codex typed again after quitting was never read and lost its row on retitle. Publish shellForeground:false and reopen the sample.
Review status (head b7e9362)The problem: launch Codex in an Orca terminal without agent status hooks. The sidebar shows "Codex · Idle", then the row disappears once Codex renames its tab to the project name, even though Codex is still running (#23767, part a). The row existed only while the tab title named the agent. What changes for users: the row now stays while Codex runs and shows Working or Idle from the title. It goes away when Codex exits. This was confirmed live on an M4Air with real Codex 0.158: main loses the row at the retitle; this branch keeps it through tab switches, background workspaces and a restart. Fixed during review:
Deferred (known limits, listed in the description):
Verified:
Not verified:
|
|
| if (processName === null || isShellProcess(processName)) { | ||
| state.setPaneForegroundAgent(paneKey, { agent: null, shellForeground: false }) |
There was a problem hiding this comment.
Unconfirmed Exit Hides Agent When a parked pane receives a command-finished marker from a nested shell, a foreground check can return
null because inspection is unavailable even while the agent is running. This branch treats null as an exit and clears the agent’s process identity, so its sidebar row can disappear until the pane is shown again. A parked remote pane also reaches this branch with null because its check is skipped. Please keep a missing answer distinct from a confirmed exit.
Knowledge Base Used: Terminal runtime and interaction
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (33)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review. 📝 WalkthroughWalkthroughForeground-agent entries now distinguish process-read evidence from launch-record evidence. Confirmed process exits and parked command boundaries can retire foreground-agent state. Sidebar and dashboard row builders now consume pane foreground-agent data, and dashboard cache reuse accounts for changes to that data. Tests cover evidence lifecycle, row resolution, shell-title detection, and cache updates. Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to The change keeps a sidebar row while an agent runs and removes it once the agent exits. The supplied tests cover exit, restart, split-pane, and cache-invalidation cases. The remaining risk is the untested Windows, Git Bash, WSL, and SSH paths, which the author already listed, and I found no concrete defect there. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The inspected changes preserve separation between display labels and input authority, and add safeguards against stale session identity. No new security issue was established, but incomplete coverage limits confidence in the broader change. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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 |
There was a problem hiding this comment.
Important
One gap in the new process-exit retirement path can leave the ghost row this PR sets out to remove: onProcessExitConfirmed defers to an in-flight command read that can terminate without clearing the stored read (inline). A minor regex miss for Git for Windows SDK titles is inline too.
Reviewed changes
- New sidebar pane-identity resolver —
resolveTitleDerivedPaneAgentranks a live process read above an agent-naming title, which ranks above the launch record (title showing activity only);resolveTitleDerivedAgentTypemoved alongside it. - Store evidence tag —
PaneForegroundAgentEntrygainsagentEvidence: 'process-read' | 'launch-record', included in the slice's equality check, so only a live read can back a plain-title row. - Exit retirement — the pane's completion monitor now reports a confirmed exit back to the tracker (
onForegroundAgentExited→onProcessExitConfirmed), which clears a stored process read; a reattach keeps this session's read of the same agent. - Parked panes —
retireForegroundAgentUnlessConfirmedmakes one confirm read at a parked command boundary before retiring. - Git Bash titles —
titleShowsNoAgenttreatsMINGW64:/…-style prompt titles as shell titles. - Cache/selector plumbing — per-worktree foreground selectors and dashboard/sidebar rows caches now key on
paneForegroundAgentByPaneKey.
ℹ️ Nitpicks
src/renderer/src/lib/use-tab-agent.ts:26keeps its owntitleShowsNoAgentwithout the new MSYS branch, whiletab-agent-from-signals.tsconsumes the shared one. After this PR the tab-bar icon and the tab-search occupant can disagree on a Git Bash prompt title. The PR body notes this copy is unchanged; folding it onto the shared helper would remove the drift.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
| const published = deps.getPublishedEntry?.() | ||
| if ( | ||
| disposed || | ||
| hasCommandReadInFlight() || |
There was a problem hiding this comment.
This deferral hands the pane to the in-flight command-finished read, but that read has a terminal branch which clears nothing: when it ends unverifiable (remoteEvidenceVerdict !== null && !== 'live', lines 248–251) it calls onCommandFinishedUnavailable() and returns without clearAgentEvidence() or a publish. By then the completion monitor has already set lastForegroundAgent = null and cleared hasAgentRunEvidence, so it can never re-confirm, and the stored process-read survives. On a stale agent-naming title — exactly the killed-Codex case this PR targets — the sidebar row lingers.
Technical details
# Confirmed exit can be swallowed by an in-flight command read
## Affected sites
- `pane-foreground-agent-tracker.ts:362-372` — `onProcessExitConfirmed` returns on `hasCommandReadInFlight()` without recording a pending exit.
- `pane-foreground-agent-tracker.ts:247-258` — the `command-finished` unverifiable branch returns without clearing evidence.
- `agent-completion-inspection-result.ts:171-194` — the monitor sets `lastForegroundAgent = null` and `clearAgentRunEvidence()` before firing `onForegroundAgentExited`, so it cannot re-confirm.
- `pane-foreground-process-reader.ts:44-47,74-78` — a local read that throws or returns a client-only unverifiable result maps to `remoteEvidenceVerdict = 'unverifiable'` with `processName = null`.
## Sequence
1. `process-read` entry published; tracker read armed the monitor (`lastForegroundAgent` set, `hasAgentRunEvidence` true).
2. Agent exits; shell emits `133;D`; `onCommandFinished` schedules a `command-finished` read → `hasCommandReadInFlight()` true.
3. Monitor cadence misses the agent twice over `LOCAL_PROCESS_EXIT_SETTLE_MS` and confirms exit; fires `onForegroundAgentExited` → `onProcessExitConfirmed`, which returns at line 367.
4. The command-finished read ends unverifiable (throw / client-only local result) → lines 248–251 return without clearing; tracker flags stay set on the entry.
5. Monitor state is now inert (`lastForegroundAgent` null, no run evidence); nothing re-derives the read until the tab is shown or the next command starts.
## Required outcome
- A monitor-confirmed exit must retire the stored process read even if a command read is in flight and later ends unverifiable.
## Suggested approach (optional)
- Record a pending confirmed exit on the tracker when the guard fires, and have the `command-finished` unverifiable terminal branch (and `dispose`) honor it by clearing/publishing; or move the `hasCommandReadInFlight()` check so an unverifiable completion falls through to `clearAgentEvidence()` when a monitor exit was reported.
## Open questions for the human (optional)
- Is a local confirm read rejecting realistic enough in practice, or is the client-only-unverifiable case the only one worth covering?| /** A shell name or the tab's neutral default title; blank titles are no evidence. */ | ||
| // Why: Git for Windows' prompt titles the pane `$MSYSTEM:$PWD` (`MINGW64:/c/repo`), and Git Bash | ||
| // has no command marks, so that repaint is the only sign an agent there handed back to the shell. | ||
| const MSYS_PROMPT_TITLE_RE = /^(?:MINGW(?:32|64)|MSYS|UCRT64|CLANG(?:32|64|ARM64)):\// |
There was a problem hiding this comment.
This matches stock MSYSTEM titles, but Git for Windows SDK installs set TITLEPREFIX=SDK-${MSYSTEM#MINGW} (so the title is SDK-MINGW64:/c/repo), and a user ~/.config/git/git-prompt.sh can override TITLEPREFIX entirely. Those panes are not read as shells, so a stalled process read isn't retired at the prompt — the case this rule exists to close. An optional (?:SDK-)? prefix (and a test row) would cover the SDK builds.
Catches up stablyai/orca to e2c5414. Notable for this fork: Codex runs without its shared background server in Orca terminals, terminal opens no longer strip hooks from the real ~/.codex, and worktree creation stops rescanning large repositories. Upstream's foreground-process agent identity (stablyai#23948) replaces the fork's title-based fallback, so worktree-title-agent-identity.ts is gone; the fork keeps its regression cases against the new logic. The statusLine badge wrapper now sits inside upstream's version-aware install plan and unwraps before a retire. The duplicate agentSubagentsEqual module and the removed agent-trust IPC registration are dropped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

ELI5
The sidebar shows a row for each agent running in a workspace, such as "Codex · Idle". Orca decided whether that row exists by reading the terminal tab's title. Codex renames its tab to the project name, and that title has no "codex" in it, so the row disappeared while Codex was still running. Now the row's agent comes from Orca's check of which program is running in the terminal, and the title only decides whether it shows as working or idle.
What Changed
The problem users see (#23767, part a): launch Codex in an Orca terminal. The sidebar briefly shows "Codex · Idle", then the entry disappears once Codex retitles the tab to the project name, even though Codex is still running and accepts input. Older reports of the same kind: #14464, #10258, #8711. The workaround was
codex -c 'tui.terminal_title=["app-name","spinner","project"]'.Scope: sidebar agent rows and dashboard counts on desktop, for every agent, not only Codex. The Git Bash title rule below also reaches the agent icons in the tab search palette, which share that helper. Not changed: mobile, which builds its own status on the host and still loses a Codex titled with the project name, and the worktree status dot.
How the sidebar decides each agent row, in order (the whole picture after this PR):
MINGW64:/…-style prompt titles now count), or the terminal exits. For a hidden (parked) tab, an end-of-command marker triggers one process check before the row is cleared.Before: a row existed only if the title showed both activity and an agent name (
worktree-title-derived-agent-rows.ts). The fallback to the agent Orca launched ran only after that check, and the rows didn't use Orca's existing check of which program is running in the pane (the tab icon already did).After:
agentEvidence: a process check, or the launch record Orca restores when it reattaches a terminal after a restart). Rows trust only a process check, so a background tab whose Codex exited before a restart doesn't come back as "Codex · Idle".MINGW64:/…prompt titles count as shell titles.Why
Known limits:
orcaCLI in a workspace you haven't opened, or background tabs after a restart) has no process check yet, so it behaves as before this PR until the tab is shown./quitclears the row at once (measured 0.1 s). Two cases wait for the process monitor to confirm the exit instead:/quitthe row stays, labelled with the prompt title.Linked Issue
Refs #23767 (part a; part b was the shared-server bug, fixed by #23900)
Related: #14464, #10258, #8711
Visual Proof
Live QA on an M4Air Mac with real Codex 0.158, agent status hooks off (the hook-less path this PR changes), in an isolated test build of Orca.
Before (main): Codex is still running in tab "rowqa", but the rowqa card has no agent row.

After (this PR):








Testing
I manually tested these changes locally
Automated tests added/updated, or explained why not below
At the final head, 328 related test files (3,098 tests: terminal pane connection, foreground tracker, agent-completion monitor, parked panes, sidebar, dashboard, tab agent, and the foreground-confirmation unit tests under tests/e2e) pass. The full suite runs in CI.
New tests:
user@host: ~/repo, or an unchanged title after a kill; a nested shell inside Codex keeps the row; a Codex typed again in the same terminal gets its row back.Several fail against the unfixed code.
Typecheck clean (web); oxlint, React Doctor and the changed-code quality gate clean.
AI Disclosure
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
use-tab-agent.tshas its own copy of the shell-title check and wasn't changed.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)