Skip to content

bug(shellterm): terminal opened from a session starts in the project root instead of the session worktree #3061

Description

@illegalcall

Bug

Opening a standalone shell terminal while viewing an agent session starts the shell in the registered project's main root, not in the worktree where that session is running.

This makes the terminal look colocated with the active agent while commands actually run against a different checkout/branch. A user can easily inspect, build, or edit the wrong tree.

Source: user report after the standalone terminal feature landed in #2861 / #2828
Analyzed against: main at d79977a9f5ed5b33f1b6188fe704b5d309023679 (2026-07-24)
Confidence: High — the current request path drops session context and resolves only the project root.

Reproduction

  1. Open a project in AO.
  2. Spawn an agent session that runs in its own generated worktree.
  3. Navigate to that session's terminal view.
  4. Open a standalone terminal using either the + terminal-tab action or `Ctrl+Shift+``.
  5. Run:
pwd
git rev-parse --show-toplevel
git branch --show-current

Expected

When the action is invoked from a session view, the new terminal starts in that session's current workspace/worktree (SessionRecord.Metadata.WorkspacePath) and therefore on the same checkout/branch as the agent.

Opening a terminal from a project board can continue to use the registered project root. Opening one without project or session context can continue to use the daemon data-dir fallback.

Actual

The new shell starts in the registered project root (the main worktree), even though it was opened from a worker session running in a different worktree.

Root cause

The session route is reduced to project scope before the open request is made:

  • frontend/src/renderer/routes/_shell.tsx derives scopedProjectId from the current route/session and calls openShellTerminal.mutate(scopedProjectId).
  • frontend/src/renderer/hooks/useShellTerminals.ts sends only { projectId } to POST /api/v1/shell-terminals.
  • controllers.OpenShellTerminalRequest and shellterm.OpenShellTerminalInput have no session identifier.
  • shellterm.Service.resolveShellTerminalWorkingDir can therefore only call ProjectRootLocator.ProjectRoot, so it deterministically chooses the main project root.

The UI knows which session is active, but that context never reaches the daemon.

Fix shape

Add a session-scoped way to open a shell without accepting an arbitrary filesystem path from the renderer:

  • Extend the open-shell request/input with sessionId (define precedence or validation if both sessionId and projectId are present).
  • When the current route is a session, have both the + action and shortcut pass that session id.
  • Resolve the id server-side through the session/service boundary and use the durable session workspace path.
  • Preserve the existing project-root and data-dir fallbacks outside a session.
  • Regenerate the OpenAPI spec and frontend schema after changing the DTO.

Acceptance criteria

  • A terminal opened from a worker session starts in that worker's worktree.
  • A terminal opened from an orchestrator/session with a workspace starts in that session's workspace.
  • Both the terminal-tab + action and `Ctrl+Shift+`` behave the same way.
  • A terminal opened from a project board still starts at the registered project root.
  • A terminal opened with no project/session context still uses the existing daemon data-dir fallback.
  • The renderer does not send an arbitrary raw path; the daemon resolves the session id to its workspace.
  • Controller/service tests cover session resolution, unknown/missing session workspace, and existing fallbacks.
  • Frontend tests assert that session routes submit session scope while board routes submit project scope.

Duplicate search

Searched open and closed issues for combinations of: terminal, standalone terminal, shell terminal, worktree, working directory, cwd, project root, session worktree, shellterm, workingDir, and references to #2828/#2861. No issue covering this behavior was found. #2828 is the completed feature request and specifies project-root scope, but it does not track the session-worktree context bug introduced by the landed implementation.

Metadata

Metadata

Labels

P2Significant degradation with a workaround or bounded impact.bugSomething isn't workingcomp/daemonGo daemon, process lifecycle, and backend control plane.comp/desktopElectron main process and React renderer.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions