Problem or use case
An open session tells you which machine it is running on, but not where on that machine, or what is driving it. The four facts you configured at launch — host, working directory, worktree, harness — are surfaced in four different places, and two of them are effectively invisible.
What the session view shows today (ComposerStatusLine, web/src/pages/ChatPage.tsx ~L3927):
| Fact |
Where it appears |
Reachable in |
| Host / compute |
HostBadge in the status tray under the composer — name + green/red dot |
0 clicks |
| Worktree branch |
gitBranch from the chat store, next to the badge |
0 clicks, only when a branch exists |
| Harness / agent |
A "Harness" row in useSessionConfigSummary (~L6178), inside the gear config surface |
1–2 clicks, and suppressed for native wrappers — the status-line label bails on modelPickerKind !== null (~L6362), which is exactly the claude/codex/cursor/kiro/opencode sessions |
| Working directory |
Nowhere. session.workspace is read in ChatPage only to seed forks (~L1000, ~L1274). It is never rendered for the session you are looking at. |
|
The surprises this produces are concrete, and they are the expensive kind — you find out after the agent has already written files:
- Wrong directory. The composer's directory picker remembers, prefills from project config, and falls back to
$HOME. Two sessions on the same host with the same branch name look identical in the UI while pointing at different checkouts. Nothing on screen distinguishes them.
- Worktree vs. main work tree. The branch text renders the same whether the session is in an isolated worktree or sitting on that branch in the main repo.
worktreePathTail() already exists in NewChatDialog.tsx (~L493) to disambiguate exactly this in the picker — the session view has no equivalent.
- No branch, no clue.
showBranch requires a non-empty gitBranch, so a session started directly in a working directory shows only a host name. That is the case where knowing the directory matters most.
- Which harness. For native wrapper sessions the harness label is deliberately suppressed in favor of the model pill, so "am I in Claude or Codex here?" is answered by recognizing the model list.
Proposed solution
Treat host / directory / worktree / harness as one identity group and surface it in one place, keeping the status tray's density budget.
Inline (0 clicks), left cluster of ComposerStatusLine: keep HostBadge, and put the working directory beside it — the tail segment, not the absolute path (~/projects/omnigent, or …/omnigent-worktrees/feature-x for a worktree, reusing worktreePathTail). Truncate with the full path in title. Keep the branch chip as-is, and add a visual distinction (or a tooltip word) for "isolated worktree" vs "main work tree" — the composer already knows this at launch time via existing_worktree / the git opts it sends.
On hover/click (1 click): a single popover anchored on that cluster listing all four as labeled rows — Host, Working directory (full path, copyable), Worktree (branch + path, or "none"), Harness (composerHarnessLabel, rendered unconditionally here even when the model pill owns the inline slot). This is where the long values live so the inline row stays one line.
Harness in the config summary stays, unchanged — this adds a reliable path to it, it doesn't move it.
Data availability is not a blocker: session.workspace is already on the session record and read in ChatPage; sessionHarness / agentName are already in the chat store; composerHarnessLabel and worktreePathTail are already exported and tested.
Mobile / narrow. The tray is already width-constrained (CHAT_COLUMN_WIDTH, min-w-0 truncate, hidden … sm:block patterns elsewhere). Directory should be the first thing to collapse into the popover on narrow viewports; host and branch keep their current priority.
Acceptance criteria
- The session view shows the working directory without any clicks, on every host-bound session, including sessions with no git branch.
- A session in an isolated worktree is visually distinguishable from one on the same branch in the main work tree.
- Host, working directory, worktree, and harness are all readable from one popover, at most one click from the conversation, on every session type — native wrappers included.
- The full working-directory path is available (tooltip and/or copyable) even when the inline label is truncated.
- Nothing regresses for sub-agent sessions (
isSubAgentSession hides the host badge today) or for the offline-host reconnect affordance the badge carries.
- The tray stays one line at the current breakpoints; Vitest coverage extends
pages/ChatPage.statusLine.test.tsx.
Alternatives considered
- Put the four facts in the chat header instead of the composer tray. The header is already carrying the title, breadcrumb, view toggle, share and three-dot menu, and is the tightest real estate in the app. The tray is where the host and branch already live, so the group belongs there.
- Add the missing facts to the existing gear/config surface only. Cheapest, but it leaves the highest-value fact (which directory am I about to modify?) behind a click — and this class of surprise is one you want to catch before sending, not after.
- Show the absolute path inline. Correct but unreadable — real paths blow the tray's width budget on every session. Tail + tooltip + copyable full path in the popover gets the same information without the cost.
- Bake it into the session title (auto-title with repo/branch). Fragile: titles are user-editable and agent-generated, and they'd drift out of sync with a session that changes directory.
Harness
Not applicable
Platform or device
Not platform-specific
Harness mode
Not applicable
Expected reach
Most users
Authentication type
Not authentication-related
Problem or use case
An open session tells you which machine it is running on, but not where on that machine, or what is driving it. The four facts you configured at launch — host, working directory, worktree, harness — are surfaced in four different places, and two of them are effectively invisible.
What the session view shows today (
ComposerStatusLine,web/src/pages/ChatPage.tsx~L3927):HostBadgein the status tray under the composer — name + green/red dotgitBranchfrom the chat store, next to the badgeuseSessionConfigSummary(~L6178), inside the gear config surfacemodelPickerKind !== null(~L6362), which is exactly the claude/codex/cursor/kiro/opencode sessionssession.workspaceis read in ChatPage only to seed forks (~L1000, ~L1274). It is never rendered for the session you are looking at.The surprises this produces are concrete, and they are the expensive kind — you find out after the agent has already written files:
$HOME. Two sessions on the same host with the same branch name look identical in the UI while pointing at different checkouts. Nothing on screen distinguishes them.worktreePathTail()already exists inNewChatDialog.tsx(~L493) to disambiguate exactly this in the picker — the session view has no equivalent.showBranchrequires a non-emptygitBranch, so a session started directly in a working directory shows only a host name. That is the case where knowing the directory matters most.Proposed solution
Treat host / directory / worktree / harness as one identity group and surface it in one place, keeping the status tray's density budget.
Inline (0 clicks), left cluster of
ComposerStatusLine: keepHostBadge, and put the working directory beside it — the tail segment, not the absolute path (~/projects/omnigent, or…/omnigent-worktrees/feature-xfor a worktree, reusingworktreePathTail). Truncate with the full path intitle. Keep the branch chip as-is, and add a visual distinction (or a tooltip word) for "isolated worktree" vs "main work tree" — the composer already knows this at launch time viaexisting_worktree/ the git opts it sends.On hover/click (1 click): a single popover anchored on that cluster listing all four as labeled rows — Host, Working directory (full path, copyable), Worktree (branch + path, or "none"), Harness (
composerHarnessLabel, rendered unconditionally here even when the model pill owns the inline slot). This is where the long values live so the inline row stays one line.Harness in the config summary stays, unchanged — this adds a reliable path to it, it doesn't move it.
Data availability is not a blocker:
session.workspaceis already on the session record and read in ChatPage;sessionHarness/agentNameare already in the chat store;composerHarnessLabelandworktreePathTailare already exported and tested.Mobile / narrow. The tray is already width-constrained (
CHAT_COLUMN_WIDTH,min-w-0 truncate,hidden … sm:blockpatterns elsewhere). Directory should be the first thing to collapse into the popover on narrow viewports; host and branch keep their current priority.Acceptance criteria
isSubAgentSessionhides the host badge today) or for the offline-host reconnect affordance the badge carries.pages/ChatPage.statusLine.test.tsx.Alternatives considered
Harness
Not applicable
Platform or device
Not platform-specific
Harness mode
Not applicable
Expected reach
Most users
Authentication type
Not authentication-related