cmux NEXT: an agent-opened session workspace records its lineage parent
Status: done. Codex xhigh SHIP at 1a617560; fleet compile-check --app passed at 1a617560; fleet suites AgentSessionLineageTests (8 tests), SidebarSessionTreeTests and RemoteChildSessionsTests all pass (run on 1a617560 on top of base 7d50820b, because base's SidebarNowLineTests.swift has conflict markers that stop every CmuxNext test build).
Leo: "LIKE E.G. AGENT SESSION CREATION LINEAGES... CLAUDE CODE MOSTLY JUST HAS ONE LAYER... WHAT IF WE DID MORE? OR DIFFERENT?"
Leo-ask: ask-19882abbc3
Session lineage, PR 2 of the plan (app: an agent-opened session workspace records its parent).
What changes
agent.openSessionWorkspace(cmux agent open,acpmux new --group, the MCP open tools) passes the invocation'scallerAgentSessionthrough toopen(...). Once the chat tab opens, it records that caller as the opened session's lineage parent in a newAgentSessionParentsstore (child session -> parent session, kept in UserDefaults undercmux.next.agentSession.lineageParents, capped at 4096, oldest dropped). A person's open (no caller), a blank caller, or a session naming itself records nothing.- The re-homed-lane reuse path (a tab in the predecessor's row) records the parent too.
SidebarSessionTreeFeed.passreads the recorded parents as a fallback, applied last and never where it would close a loop: a workspace gets its recorded parent only when neither the remote daemon'sstartedBy/spawnedBy(RemoteAgentSessionLinks) nor this Mac's lanespawnedBynames one. Daemon lineage always wins.- The field is named
parentto match the acpmux lineage summary field (parent/root/depth) another lane is adding; this PR does not depend on it.
No default changes. The tree itself stays behind sidebar.sessionTree (off by default). No sidebar layout or fold changes (#21836 owns those; this touches only pass(...)'s parents map, not the agentStates lines #21836 adds there).
Tests (test-first)
CmuxNextAppTests.AgentSessionLineageTests:
- opening with a caller session and no daemon lineage (local older daemon, and remote) nests the workspace under the caller's;
- a person's open records nothing;
- daemon lineage (local
spawnedBy, remotestartedBy) wins over the recorded parent; - recorded parents survive a relaunch and the newest record wins;
- a record that would close a loop is refused, in the store and against the daemon's lineage in the tree.
No capture: records data only; the nested view stays behind sidebar.sessionTree until the nesting PR
š¤ Generated with Claude Code
Agent session: cosmic-gray