Skip to content

feat(sessions): isolate parallel sessions from each other's working tree #883

Description

@adolfousier

Problem

Parallel sessions (multiple TUI panes, or an agent working alongside another) all operate on the same working tree. Two sessions editing the same file clobber each other, with no arbitration.

Live evidence: two concurrent sessions modified src/channels/telegram/agent.rs and src/channels/voice/voicebox_stt.rs in the same tree within seconds of each other, uncommitted edits racing. A third session had to avoid both files by hand for the rest of the day to stay out of the way.

State of the code, verified

The original text of this issue said worktree isolation "exists and works, wired only to sub-agents", citing WorktreeManager::create_worktree at src/agents/subagent.rs:192. That is not the case, and the work is larger than wiring:

  • No WorktreeManager exists. Zero references to it anywhere in src/. No create_worktree. No src/agents/subagent.rs.
  • The only occurrences of the word "worktree" in the codebase are two doc comments in src/utils/git_branch.rs explaining that .git may be a file rather than a directory.
  • Sub-agents are not isolated either. src/brain/tools/subagent/spawn.rs:235 calls .with_working_directory(context.working_dir()), so a child inherits the parent's directory.

What DOES exist, and why it is not enough

AgentService::working_dir_handle_for_session (src/brain/agent/service/builder.rs:763) gives each session its own Arc<RwLock<PathBuf>>, seeded from the global working directory. That is #703: a cd in one session cannot move another session's cwd.

It isolates which directory a session is pointed at, not the files themselves. Two sessions pointed at the same path still write to the same bytes on disk. This is the answer to the open question the previous text left unresolved.

Scope

Building isolation from scratch, not wiring an existing component. Design decisions that need answering before implementation:

  • Lifecycle. When is a worktree created, and what happens to uncommitted work when a session ends? Discarding it silently is unacceptable; keeping it forever leaks disk.
  • Opt-in or default. Two panes on the same branch are sometimes deliberate collaboration. Isolating every session by default breaks that workflow, so this likely needs to be a choice rather than automatic.
  • Cost. A worktree per session means a checkout per session. On a repo with a multi-GB target/, that matters, and cargo cannot share a build cache across worktrees without extra configuration.
  • Merging back. A session that produced good work in its own lane needs a path to land it. Without one, isolation converts a clobbering problem into a stranded-work problem.

Acceptance criteria

  • Two concurrent sessions can edit the same logical file without clobbering each other
  • Uncommitted work in a session's lane is never silently discarded
  • Worktrees are pruned on session end, with no orphans after a crash
  • Sessions that should share a tree still can
  • Disk and build-cache cost is measured, not assumed

Note

The failure this issue describes is real and reproducible. Only the diagnosis was wrong: it is absence of a feature, not a broken connection to an existing one. Anyone starting from the previous text would have gone looking for code that is not there.

Metadata

Metadata

Assignees

Labels

featureNew feature or requestsessionUpdates to sessions code.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions