Disclaimer: this issue was drafted by Claude after I had it investigate the bug — I reviewed and agree with the contents.
Repro
aoe add /some/repo --cmd claude --cockpit
aoe add /some/repo --cmd claude --cockpit
(or any combination of two sessions with the same project_path and no --worktree branch; cockpit_mode is incidental, reproduces with tmux sessions too)
aoe serve
- Open the dashboard and refresh.
Expected
Both sessions appear in the sidebar.
Actual
Only the first session in the API response appears. The second session is in GET /api/sessions (visible in the network tab) but never rendered in the sidebar. Refreshing does not help.
Root cause
The sidebar groups sessions by (project_path, branch) into "workspaces" and then renders one SessionRow per workspace using workspace.sessions[0]. Sibling sessions in the same workspace are dropped from the visible UI.
Code references
web/src/hooks/useWorkspaces.ts:18
const key = `${repoPath}::${session.branch ?? "__default__"}`;
All sessions sharing (main_repo_path or project_path, branch) collapse into the same workspace entry.
web/src/components/WorkspaceSidebar.tsx:134-138
const label = workspace.branch ?? workspace.sessions[0]?.title ?? "default";
const runningSession = workspace.sessions.find((s) => isSessionActive(s));
const firstSession = workspace.sessions[0];
const sessionId = firstSession?.id;
const navigationSessionId = runningSession?.id ?? firstSession?.id ?? null;
The row binds to firstSession (or runningSession) only. There is no expansion / sub-list rendering workspace.sessions[1..].
web/src/components/WorkspaceSidebar.tsx:638-648
{showExpanded &&
group.workspaces.map((ws) => (
<SessionRow ... workspace={ws} ... />
))}
The group expansion iterates workspaces, not sessions, so the second session is never reached.
Concrete repro on a fresh checkout
Ethiopians project_path=/private/tmp/agent-of-empires
Italians project_path=/Users/seluj78/Projects/Personnal/agent-of-empires
Celts project_path=/Users/seluj78/Projects/Personnal/agent-of-empires
Magyars (separate workspace)
GET /api/sessions returns all 4
- Sidebar shows 2 rows (Magyars and Italians); Ethiopians and Celts are invisible
Workarounds
- Pass
--worktree <branch> on add so the session has a distinct (project_path, branch) key
- Delete the colliding session
- Use distinct
project_paths
Possible fixes (in increasing scope)
- Append a session-count badge to
SessionRow when workspace.sessions.length > 1, plus an expander that lists the sibling sessions (use their title, since branch is shared/null).
- Stop collapsing sessions into workspaces when
branch is null; render one row per session for the "no worktree" case.
- Group by
(project_path, branch, title) so identical branches still collide but distinct titles do not.
Environment
Notes
Originally surfaced while testing PR #953 (cockpit reconciler). The cockpit reconciler is unrelated; the same bug reproduces with --no-cockpit sessions sharing a project_path.
Repro
aoe add /some/repo --cmd claude --cockpitaoe add /some/repo --cmd claude --cockpit(or any combination of two sessions with the same
project_pathand no--worktreebranch;cockpit_modeis incidental, reproduces with tmux sessions too)aoe serveExpected
Both sessions appear in the sidebar.
Actual
Only the first session in the API response appears. The second session is in
GET /api/sessions(visible in the network tab) but never rendered in the sidebar. Refreshing does not help.Root cause
The sidebar groups sessions by
(project_path, branch)into "workspaces" and then renders oneSessionRowper workspace usingworkspace.sessions[0]. Sibling sessions in the same workspace are dropped from the visible UI.Code references
web/src/hooks/useWorkspaces.ts:18All sessions sharing
(main_repo_path or project_path, branch)collapse into the same workspace entry.web/src/components/WorkspaceSidebar.tsx:134-138The row binds to
firstSession(orrunningSession) only. There is no expansion / sub-list renderingworkspace.sessions[1..].web/src/components/WorkspaceSidebar.tsx:638-648The group expansion iterates workspaces, not sessions, so the second session is never reached.
Concrete repro on a fresh checkout
GET /api/sessionsreturns all 4Workarounds
--worktree <branch>onaddso the session has a distinct(project_path, branch)keyproject_pathsPossible fixes (in increasing scope)
SessionRowwhenworkspace.sessions.length > 1, plus an expander that lists the sibling sessions (use theirtitle, sincebranchis shared/null).branchis null; render one row per session for the "no worktree" case.(project_path, branch, title)so identical branches still collide but distinct titles do not.Environment
fix/cockpit-reconcile-spawn(againstnjbrake/native, PR fix(cockpit): auto-spawn ACP workers for sessions added while serve runs #953)Notes
Originally surfaced while testing PR #953 (cockpit reconciler). The cockpit reconciler is unrelated; the same bug reproduces with
--no-cockpitsessions sharing aproject_path.