Multi-Agent Git Worktree Support — Plan (Option C: Hybrid)
Goal: Allow users to start agent threads in isolated git worktrees so that multiple agents can work on the same codebase in parallel without interfering with each other.
Approach: Hybrid — automatic by default, fully configurable. The user picks "New Worktree" from a dropdown before starting a thread. Zed creates a git worktree, opens it as a new workspace inside the
MultiWorkspace, and starts the agent thread there.
Scope and Rollout
- Primary UI target:
AgentPanelincrates/agent_ui. agent_ui_v2/AgentsPanelis out of scope and will be removed.- Local + remote support are both in scope.
- Remote plumbing is the final implementation milestone, after local behavior is complete and stable.
Terminology
Throughout this document:
| Term | Meaning |
|---|---|
| Zed Worktree | A folder open in a Zed project (project::Worktree / worktree::Worktree). This is Zed's concept of a directory tree, not a git worktree. |
| Git Worktree | A git worktree add checkout — an additional working directory sharing the same .git object store (git::repository::Worktree). |
| Workspace | A workspace::Workspace entity — one project context inside a Zed window. |
| MultiWorkspace | The root view of a Zed window (workspace::MultiWorkspace). Contains one or more Workspace entities and can switch between them. |
The git worktree APIs live in crates/git/src/repository.rs on the GitRepository trait:
fn worktrees() -> Vec<git::repository::Worktree>— lists git worktreesfn create_worktree(name, directory, from_commit) -> Result<()>— creates a git worktreefn rename_branch(branch, new_name) -> Result<()>— already exists
These must not be confused with project::Worktree / worktree::Worktree which
represent open folders in the editor.
Feature Flag
All work is gated behind the existing agent-v2 feature flag
(AgentV2FeatureFlag in crates/feature_flags/src/flags.rs).
Use cx.has_flag::<AgentV2FeatureFlag>() to gate UI and behavior. No new flag
is needed.
Phase 1: UI — Thread Target Selector
1.1 "Start Thread In…" Dropdown
Where: The agent panel toolbar, adjacent to the existing "New Thread" (+)
menu.
What the user sees:
┌──────────────────────┐
│ Start Thread In... │
│ Local Project │ ← default, current workspace
│ New Worktree │ ← creates a git worktree
└──────────────────────┘
With a tooltip on "New Worktree":
You currently have "main" checked out and by default, Zed creates a new branch for worktrees based off the selected branch.
Reuse existing UI components:
PopoverMenu+ContextMenu— same pattern as the mode selector (crates/agent_ui/src/acp/mode_selector.rs) and the existing new-thread menu inAgentPanel::render_toolbar().ContextMenuEntrywith.icon(),.icon_color(),.handler(),.documentation_aside()for the tooltip — all already used in the new-thread menu.Tooltip::for_action_in()for keyboard shortcut hints.Buttonwith.label_size(LabelSize::Small)+.icon(IconName::ChevronDown)as the trigger — same pattern asModeSelector's trigger button.
Implementation location: crates/agent_ui/src/agent_panel.rs — modify
render_toolbar() and the new-thread menu construction.
Behavior:
- "Local Project" is always available and is the default.
- "New Worktree" is only shown when
cx.has_flag::<AgentV2FeatureFlag>(). - "New Worktree" is disabled (grayed out with tooltip) when:
- The project has no git repository.
- The project is remote/collab during the local-only implementation milestones.
- Selecting "New Worktree" does not immediately create the worktree. It sets
the panel's next thread target to
ThreadTarget::NewWorktree. - Worktree creation happens when the user explicitly starts a new ACP thread from the toolbar/menu. It does not wait for first message send.
New types:
#[derive(Clone, Debug, Default, PartialEq)]
pub enum ThreadTarget {
#[default]
LocalProject,
NewWorktree,
ExistingWorktree {
/// Path to the git worktree on disk.
path: PathBuf,
/// The branch name checked out in the worktree.
branch: String,
},
}
Store ThreadTarget on the AgentPanel or on the individual thread view state.
1.2 Worktree Indicator on Running Threads
Where: ACP thread history rendering in
crates/agent_ui/src/acp/thread_history.rs (render_history_entry()).
Current ACP history uses ListItem, not ThreadItem. We should add a secondary
line in the existing ListItem entry that shows branch/worktree data from
session metadata.
What the user sees:
┌──────────────────────────────────────┐
│ ⑀ link-agent-panel │
└──────────────────────────────────────┘
The branch icon (⑀) + branch/worktree name is shown beneath the thread title.
Wiring up:
- Extend the thread history row model to include optional worktree display text.
- If session metadata contains worktree info, render a second muted line with branch icon + branch/worktree label.
- Use
ThreadItemstyle as visual reference, but keep implementation inAcpThreadHistoryfor now to avoid broad UI refactors.
1.3 Loading / Indeterminate States
When "New Worktree" is selected and the user starts a new ACP thread, several async operations happen before session creation:
- Creating the git worktree (
git worktree add ...) - Opening the worktree path as a new project
- Adding the workspace to
MultiWorkspace - Starting the agent thread in the new workspace
During this time, the UI needs to show indeterminate/loading states.
Reuse existing components:
SpinnerLabel(crates/ui/src/components/label/spinner_label.rs) for creation progress.- Existing error notification/prompt patterns from workspace/git UI for failures that occur before ACP thread creation.
AcpThreadView::thread_errorcan still be used for failures after thread view exists.
States to support:
- The toolbar selector + new-thread trigger should be disabled while creation is in progress for that action.
- Show
SpinnerLabelstatus text during worktree creation (e.g., "Creating worktree…"). - If creation fails before thread creation, show an actionable error and keep the user in the current workspace without creating a partial thread.
Note: The exact visual design of these loading states needs further discussion with the team. The infrastructure to support them should be built, but the specific UI treatment is TBD.
Phase 2: Git Repository API Changes
2.1 Add remove_worktree() to GitRepository
The GitRepository trait (crates/git/src/repository.rs) currently has
worktrees() and create_worktree() but no way to remove a worktree.
Add to the trait:
fn remove_worktree(
&self,
path: PathBuf,
force: bool,
) -> BoxFuture<'_, Result<()>>;
Implementation on RealGitRepository: run
git worktree remove <path> [--force].
Implementation on FakeGitRepository (crates/fs/src/fake_git_repo.rs):
track created worktrees in FakeGitRepositoryState and allow removal. The
current implementations of worktrees() and create_worktree() on
FakeGitRepository are unimplemented!() — these need to be filled in as part
of this work to support testing.
2.2 Add rename_worktree() to GitRepository
Git worktrees can be moved/renamed via git worktree move <worktree> <new-path>.
This is useful if we want to rename the worktree directory to match the thread
title after it's generated.
Add to the trait:
fn rename_worktree(
&self,
old_path: PathBuf,
new_path: PathBuf,
) -> BoxFuture<'_, Result<()>>;
Implementation on RealGitRepository: run
git worktree move <old_path> <new_path>.
Implementation on FakeGitRepository: update the tracked worktree entry.
2.3 Repository Handle + Proto Plumbing
GitRepository trait changes are not enough on their own. AgentPanel uses
project-level repository handles (project::Repository in
crates/project/src/git_store.rs), which handle both local and remote paths.
Add matching methods on project::Repository:
remove_worktree(path, force)rename_worktree(old_path, new_path)
Add corresponding RPC plumbing:
- New messages in
crates/proto/proto/git.proto - Message registration in
crates/proto/src/proto.rs - Request handlers in
GitStorefor remote mode - Local + remote branches in repository job execution logic
2.4 Branch Naming
When creating a git worktree for an agent thread, Zed needs to generate a branch name. The default pattern:
zed/agent/<short-id>
Where <short-id> is a random 5-character alphanumeric string (e.g., a4Xiu).
The branch can be renamed via the existing GitRepository::rename_branch()
once the agent generates a thread title (similar to how Conductor handles it —
start with a placeholder, rename once context is available).
2.5 Worktree Storage Location
Git worktrees are created via git worktree add <path> -b <branch> <base>. The
<path> determines where the working directory lives on disk.
Default location: A managed directory under the Zed data directory.
On macOS:
~/Library/Application Support/Zed/agent-worktrees/<repo-name>/<branch-name>/
On Linux:
~/.local/share/zed/agent-worktrees/<repo-name>/<branch-name>/
This keeps worktrees out of the project directory and avoids .gitignore issues.
Project-level override: Users can configure a custom worktree path via the
git section of project settings. This requires changes in both:
crates/settings_content/src/project.rs(settings_content::GitSettings)crates/project/src/project_settings.rs(project::GitSettings)
Add a new field to both GitSettings structs:
pub struct GitSettings {
// ... existing fields ...
/// Directory where agent worktrees are created.
/// If not set, defaults to the Zed data directory.
///
/// Can be an absolute path or relative to the project root.
///
/// Default: null (uses system default)
pub agent_worktree_directory: Option<String>,
}
Because this field is not Copy, existing Copy derives on Git settings types
must be removed where necessary.
This allows teams to colocate worktrees with the project (e.g.,
.worktrees/) or use a shared location. Users set this in
.zed/settings.json:
{
"git": {
"agent_worktree_directory": ".worktrees"
}
}
2.6 Creation Flow
Use the existing GitRepository::create_worktree() method:
fn create_worktree(
&self,
name: String, // branch name
directory: PathBuf, // parent directory for the worktree
from_commit: Option<String>, // base commit/branch (e.g., "main")
) -> BoxFuture<'_, Result<()>>;
This runs git worktree add <directory>/<name> -b <name> <from_commit>.
The base commit should be the currently checked-out branch HEAD in the main worktree so the agent starts from the same state the user is looking at.
2.7 Trust Management
The existing worktree picker (crates/git_ui/src/worktree_picker.rs) already
handles trust for newly created worktrees via TrustedWorktrees. The same
pattern should be followed: if the parent project is trusted, automatically trust
the new worktree path. See WorktreeListDelegate::create_worktree() for the
reference implementation.
Phase 3: Workspace Integration
3.1 Sequence of Operations
When the user starts a new ACP thread while ThreadTarget::NewWorktree is
selected:
-
Create the git worktree (async)
- Generate branch name (
zed/agent/<id>) - Determine storage path (default or from
GitSettings.agent_worktree_directory) - Call
GitRepository::create_worktree() - Trust the new path (following
worktree_picker.rspattern)
- Generate branch name (
-
Open the worktree as a new Zed project (async)
- Use the workspace open path flow with
open_new_workspace: Some(true)so we deterministically create a new workspace instead of reusing an existing one. - Reference behavior:
workspace::open_pathsincrates/workspace/src/workspace.rs
- Use the workspace open path flow with
-
Attach workspace to the current
MultiWorkspace- If open-path flow returns a workspace not yet attached to this window's
MultiWorkspace, calladd_workspace()explicitly.
- If open-path flow returns a workspace not yet attached to this window's
-
Activate the new workspace
- Ensure the new workspace becomes active (
activate()/activate_index()as appropriate).
- Ensure the new workspace becomes active (
-
Start the thread
- Call
AgentPanel::new_agent_thread()in the new workspace's agent panel. - The thread runs against the new workspace's project, which points at the git worktree on disk
- Persist
AgentGitWorktreeInfoas soon as the session id is known
- Call
-
Failure rollback
- If worktree creation succeeds but workspace open or thread startup fails, clean up the created git worktree and surface an error to the user.
3.2 Implementation Location
The orchestration logic for steps 1–6 should live in a new module:
crates/agent_ui/src/agent_worktree.rs. This keeps it close to the UI that
triggers it while being separate enough to test independently.
The async work should be spawned via cx.spawn() from the AgentPanel, with
WeakEntity<Workspace> and the MultiWorkspace root captured for the later
workspace management steps.
3.3 Workspace ↔ Thread Association
Each thread needs to know which git worktree (if any) it belongs to. Use persisted thread data as source of truth, with ACP meta as a transport copy.
pub struct AgentGitWorktreeInfo {
/// The branch name in the git worktree.
pub branch: String,
/// Absolute path to the git worktree on disk.
pub worktree_path: PathBuf,
/// The base branch/commit the worktree was created from.
pub base_ref: String,
}
Storage model:
- Persist
AgentGitWorktreeInfoin the agent thread DB model (DbThread) so it survives restarts. - Expose enough metadata in thread list results so history rendering can display branch/worktree labels without loading every full thread.
- Mirror this metadata into
AgentSessionInfo.metawhen returning session lists. - Keep
AcpServerViewstate as runtime cache only, not source of truth.
This enables:
- History rows to display branch/worktree labels
- Cleanup to find and remove git worktrees reliably
- Resume flow to reopen the correct workspace path
Phase 4: Cleanup & Lifecycle
4.1 When to Clean Up
Git worktrees should be cleaned up (removed) when:
- The user explicitly discards a thread that was running in a worktree
- The user applies/merges changes back (future work)
- The worktree's workspace is closed and the thread is complete
Worktrees should not be cleaned up when:
- The thread is still running
- The user might want to resume the thread later
- The workspace is just temporarily not active in
MultiWorkspace
4.2 Cleanup Operations
- Look up persisted
AgentGitWorktreeInfofor the session. - Remove the workspace from
MultiWorkspace::remove_workspace()if present. - Run
remove_worktree(path, force)throughproject::Repository. - Optionally delete the branch via existing branch APIs when safe.
4.3 Orphan Detection
On startup, compare:
- Persisted
AgentGitWorktreeInfoentries from thread storage. - Actual git worktrees from repository APIs.
If a managed worktree exists without an associated live thread/session record, mark it orphaned and offer cleanup (or auto-cleanup after policy delay).
Phase 5: Testing
5.1 Unit Tests — Git Repository API
Location: crates/git/src/repository.rs (in the existing mod tests block)
test_parse_worktrees_from_str: Verify parsing ofgit worktree list --porcelainoutput. Test with zero, one, and multiple worktrees. Test with detached HEAD entries and bare repos.test_create_and_list_worktrees: Create a real git repo in a temp dir, add a worktree via the API, verifyworktrees()returns it.test_remove_worktree: Create a worktree, remove it, verify it's gone fromworktrees()and the directory is deleted.test_remove_worktree_force: Create a worktree with uncommitted changes, verify non-force removal fails, force removal succeeds.test_rename_worktree: Create a worktree, move it to a new path, verify the old path is gone and the new path exists.
5.2 Unit Tests — FakeGitRepository
Location: crates/fs/src/fake_git_repo.rs
Implement worktrees(), create_worktree(), remove_worktree(), and
rename_worktree() on FakeGitRepository backed by
FakeGitRepositoryState. These are currently unimplemented!().
test_fake_worktree_lifecycle: Create, list, remove worktrees on the fake to verify the test infrastructure works.
5.3 Unit Tests — Branch Name Generation
Location: crates/agent_ui/src/agent_worktree.rs
test_branch_name_generation: Verify generated names match thezed/agent/<id>pattern, are valid git branch names, and are unique across
Lines 1–500 of 701. Load more
# Multi-Agent Git Worktree Support — Plan (Option C: Hybrid) > **Goal**: Allow users to start agent threads in isolated git worktrees so that > multiple agents can work on the same codebase in parallel without interfering > with each other. > **Approach**: Hybrid — automatic by default, fully configurable. The user picks > "New Worktree" from a dropdown before starting a thread. Zed creates a git > worktree, opens it as a new workspace inside the `MultiWorkspace`, and starts > the agent thread there. ## Scope and Rollout - Primary UI target: `AgentPanel` in `crates/agent_ui`. - `agent_ui_v2` / `AgentsPanel` is out of scope and will be removed. - Local + remote support are both in scope. - Remote plumbing is the final implementation milestone, after local behavior is complete and stable. --- ## Terminology Throughout this document: | Term | Meaning | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | | **Zed Worktree** | A folder open in a Zed project (`project::Worktree` / `worktree::Worktree`). This is Zed's concept of a directory tree, **not** a git worktree. | | **Git Worktree** | A `git worktree add` checkout — an additional working directory sharing the same `.git` object store (`git::repository::Worktree`). | | **Workspace** | A `workspace::Workspace` entity — one project context inside a Zed window. | | **MultiWorkspace** | The root view of a Zed window (`workspace::MultiWorkspace`). Contains one or more `Workspace` entities and can switch between them. | The git worktree APIs live in `crates/git/src/repository.rs` on the `GitRepository` trait: - `fn worktrees() -> Vec<git::repository::Worktree>` — lists git worktrees - `fn create_worktree(name, directory, from_commit) -> Result<()>` — creates a git worktree - `fn rename_branch(branch, new_name) -> Result<()>` — already exists These must not be confused with `project::Worktree` / `worktree::Worktree` which represent open folders in the editor. --- ## Feature Flag All work is gated behind the existing `agent-v2` feature flag (`AgentV2FeatureFlag` in `crates/feature_flags/src/flags.rs`). Use `cx.has_flag::<AgentV2FeatureFlag>()` to gate UI and behavior. No new flag is needed. --- ## Phase 1: UI — Thread Target Selector ### 1.1 "Start Thread In…" Dropdown **Where**: The agent panel toolbar, adjacent to the existing "New Thread" (`+`) menu. **What the user sees**: ``` ┌──────────────────────┐ │ Start Thread In... │ │ Local Project │ ← default, current workspace │ New Worktree │ ← creates a git worktree └──────────────────────┘ ``` With a tooltip on "New Worktree": > You currently have "main" checked out and by default, Zed creates a new > branch for worktrees based off the selected branch. **Reuse existing UI components**: - `PopoverMenu` + `ContextMenu` — same pattern as the mode selector (`crates/agent_ui/src/acp/mode_selector.rs`) and the existing new-thread menu in `AgentPanel::render_toolbar()`. - `ContextMenuEntry` with `.icon()`, `.icon_color()`, `.handler()`, `.documentation_aside()` for the tooltip — all already used in the new-thread menu. - `Tooltip::for_action_in()` for keyboard shortcut hints. - `Button` with `.label_size(LabelSize::Small)` + `.icon(IconName::ChevronDown)` as the trigger — same pattern as `ModeSelector`'s trigger button. **Implementation location**: `crates/agent_ui/src/agent_panel.rs` — modify `render_toolbar()` and the new-thread menu construction. **Behavior**: - "Local Project" is always available and is the default. - "New Worktree" is only shown when `cx.has_flag::<AgentV2FeatureFlag>()`. - "New Worktree" is disabled (grayed out with tooltip) when: - The project has no git repository. - The project is remote/collab during the local-only implementation milestones. - Selecting "New Worktree" does **not** immediately create the worktree. It sets the panel's next thread target to `ThreadTarget::NewWorktree`. - Worktree creation happens when the user explicitly starts a new ACP thread from the toolbar/menu. It does **not** wait for first message send. **New types**: ```rust #[derive(Clone, Debug, Default, PartialEq)] pub enum ThreadTarget { #[default] LocalProject, NewWorktree, ExistingWorktree { /// Path to the git worktree on disk. path: PathBuf, /// The branch name checked out in the worktree. branch: String, }, } ``` Store `ThreadTarget` on the `AgentPanel` or on the individual thread view state. ### 1.2 Worktree Indicator on Running Threads **Where**: ACP thread history rendering in `crates/agent_ui/src/acp/thread_history.rs` (`render_history_entry()`). Current ACP history uses `ListItem`, not `ThreadItem`. We should add a secondary line in the existing `ListItem` entry that shows branch/worktree data from session metadata. **What the user sees**: ``` ┌──────────────────────────────────────┐ │ ⑀ link-agent-panel │ └──────────────────────────────────────┘ ``` The branch icon (⑀) + branch/worktree name is shown beneath the thread title. **Wiring up**: - Extend the thread history row model to include optional worktree display text. - If session metadata contains worktree info, render a second muted line with branch icon + branch/worktree label. - Use `ThreadItem` style as visual reference, but keep implementation in `AcpThreadHistory` for now to avoid broad UI refactors. ### 1.3 Loading / Indeterminate States When "New Worktree" is selected and the user starts a new ACP thread, several async operations happen before session creation: 1. Creating the git worktree (`git worktree add ...`) 2. Opening the worktree path as a new project 3. Adding the workspace to `MultiWorkspace` 4. Starting the agent thread in the new workspace During this time, the UI needs to show indeterminate/loading states. **Reuse existing components**: - `SpinnerLabel` (`crates/ui/src/components/label/spinner_label.rs`) for creation progress. - Existing error notification/prompt patterns from workspace/git UI for failures that occur before ACP thread creation. - `AcpThreadView::thread_error` can still be used for failures after thread view exists. **States to support**: - The toolbar selector + new-thread trigger should be disabled while creation is in progress for that action. - Show `SpinnerLabel` status text during worktree creation (e.g., "Creating worktree…"). - If creation fails before thread creation, show an actionable error and keep the user in the current workspace without creating a partial thread. > **Note**: The exact visual design of these loading states needs further > discussion with the team. The infrastructure to support them should be built, > but the specific UI treatment is TBD. --- ## Phase 2: Git Repository API Changes ### 2.1 Add `remove_worktree()` to `GitRepository` The `GitRepository` trait (`crates/git/src/repository.rs`) currently has `worktrees()` and `create_worktree()` but no way to remove a worktree. **Add to the trait**: ```rust fn remove_worktree( &self, path: PathBuf, force: bool, ) -> BoxFuture<'_, Result<()>>; ``` **Implementation on `RealGitRepository`**: run `git worktree remove <path> [--force]`. **Implementation on `FakeGitRepository`** (`crates/fs/src/fake_git_repo.rs`): track created worktrees in `FakeGitRepositoryState` and allow removal. The current implementations of `worktrees()` and `create_worktree()` on `FakeGitRepository` are `unimplemented!()` — these need to be filled in as part of this work to support testing. ### 2.2 Add `rename_worktree()` to `GitRepository` Git worktrees can be moved/renamed via `git worktree move <worktree> <new-path>`. This is useful if we want to rename the worktree directory to match the thread title after it's generated. **Add to the trait**: ```rust fn rename_worktree( &self, old_path: PathBuf, new_path: PathBuf, ) -> BoxFuture<'_, Result<()>>; ``` **Implementation on `RealGitRepository`**: run `git worktree move <old_path> <new_path>`. **Implementation on `FakeGitRepository`**: update the tracked worktree entry. ### 2.3 Repository Handle + Proto Plumbing `GitRepository` trait changes are not enough on their own. `AgentPanel` uses project-level repository handles (`project::Repository` in `crates/project/src/git_store.rs`), which handle both local and remote paths. Add matching methods on `project::Repository`: - `remove_worktree(path, force)` - `rename_worktree(old_path, new_path)` Add corresponding RPC plumbing: - New messages in `crates/proto/proto/git.proto` - Message registration in `crates/proto/src/proto.rs` - Request handlers in `GitStore` for remote mode - Local + remote branches in repository job execution logic ### 2.4 Branch Naming When creating a git worktree for an agent thread, Zed needs to generate a branch name. The default pattern: ``` zed/agent/<short-id> ``` Where `<short-id>` is a random 5-character alphanumeric string (e.g., `a4Xiu`). The branch can be renamed via the existing `GitRepository::rename_branch()` once the agent generates a thread title (similar to how Conductor handles it — start with a placeholder, rename once context is available). ### 2.5 Worktree Storage Location Git worktrees are created via `git worktree add <path> -b <branch> <base>`. The `<path>` determines where the working directory lives on disk. **Default location**: A managed directory under the Zed data directory. On macOS: ``` ~/Library/Application Support/Zed/agent-worktrees/<repo-name>/<branch-name>/ ``` On Linux: ``` ~/.local/share/zed/agent-worktrees/<repo-name>/<branch-name>/ ``` This keeps worktrees out of the project directory and avoids `.gitignore` issues. **Project-level override**: Users can configure a custom worktree path via the `git` section of project settings. This requires changes in both: - `crates/settings_content/src/project.rs` (`settings_content::GitSettings`) - `crates/project/src/project_settings.rs` (`project::GitSettings`) Add a new field to both `GitSettings` structs: ```rust pub struct GitSettings { // ... existing fields ... /// Directory where agent worktrees are created. /// If not set, defaults to the Zed data directory. /// /// Can be an absolute path or relative to the project root. /// /// Default: null (uses system default) pub agent_worktree_directory: Option<String>, } ``` Because this field is not `Copy`, existing `Copy` derives on Git settings types must be removed where necessary. This allows teams to colocate worktrees with the project (e.g., `.worktrees/`) or use a shared location. Users set this in `.zed/settings.json`: ```json { "git": { "agent_worktree_directory": ".worktrees" } } ``` ### 2.6 Creation Flow Use the existing `GitRepository::create_worktree()` method: ```rust fn create_worktree( &self, name: String, // branch name directory: PathBuf, // parent directory for the worktree from_commit: Option<String>, // base commit/branch (e.g., "main") ) -> BoxFuture<'_, Result<()>>; ``` This runs `git worktree add <directory>/<name> -b <name> <from_commit>`. The base commit should be the currently checked-out branch HEAD in the main worktree so the agent starts from the same state the user is looking at. ### 2.7 Trust Management The existing worktree picker (`crates/git_ui/src/worktree_picker.rs`) already handles trust for newly created worktrees via `TrustedWorktrees`. The same pattern should be followed: if the parent project is trusted, automatically trust the new worktree path. See `WorktreeListDelegate::create_worktree()` for the reference implementation. --- ## Phase 3: Workspace Integration ### 3.1 Sequence of Operations When the user starts a new ACP thread while `ThreadTarget::NewWorktree` is selected: 1. **Create the git worktree** (async) - Generate branch name (`zed/agent/<id>`) - Determine storage path (default or from `GitSettings.agent_worktree_directory`) - Call `GitRepository::create_worktree()` - Trust the new path (following `worktree_picker.rs` pattern) 2. **Open the worktree as a new Zed project** (async) - Use the workspace open path flow with `open_new_workspace: Some(true)` so we deterministically create a new workspace instead of reusing an existing one. - Reference behavior: `workspace::open_paths` in `crates/workspace/src/workspace.rs` 3. **Attach workspace to the current `MultiWorkspace`** - If open-path flow returns a workspace not yet attached to this window's `MultiWorkspace`, call `add_workspace()` explicitly. 4. **Activate the new workspace** - Ensure the new workspace becomes active (`activate()` / `activate_index()` as appropriate). 5. **Start the thread** - Call `AgentPanel::new_agent_thread()` in the new workspace's agent panel. - The thread runs against the new workspace's project, which points at the git worktree on disk - Persist `AgentGitWorktreeInfo` as soon as the session id is known 6. **Failure rollback** - If worktree creation succeeds but workspace open or thread startup fails, clean up the created git worktree and surface an error to the user. ### 3.2 Implementation Location The orchestration logic for steps 1–6 should live in a new module: `crates/agent_ui/src/agent_worktree.rs`. This keeps it close to the UI that triggers it while being separate enough to test independently. The async work should be spawned via `cx.spawn()` from the `AgentPanel`, with `WeakEntity<Workspace>` and the `MultiWorkspace` root captured for the later workspace management steps. ### 3.3 Workspace ↔ Thread Association Each thread needs to know which git worktree (if any) it belongs to. Use persisted thread data as source of truth, with ACP meta as a transport copy. ```rust pub struct AgentGitWorktreeInfo { /// The branch name in the git worktree. pub branch: String, /// Absolute path to the git worktree on disk. pub worktree_path: PathBuf, /// The base branch/commit the worktree was created from. pub base_ref: String, } ``` Storage model: - Persist `AgentGitWorktreeInfo` in the agent thread DB model (`DbThread`) so it survives restarts. - Expose enough metadata in thread list results so history rendering can display branch/worktree labels without loading every full thread. - Mirror this metadata into `AgentSessionInfo.meta` when returning session lists. - Keep `AcpServerView` state as runtime cache only, not source of truth. This enables: - History rows to display branch/worktree labels - Cleanup to find and remove git worktrees reliably - Resume flow to reopen the correct workspace path --- ## Phase 4: Cleanup & Lifecycle ### 4.1 When to Clean Up Git worktrees should be cleaned up (removed) when: - The user explicitly discards a thread that was running in a worktree - The user applies/merges changes back (future work) - The worktree's workspace is closed and the thread is complete Worktrees should **not** be cleaned up when: - The thread is still running - The user might want to resume the thread later - The workspace is just temporarily not active in `MultiWorkspace` ### 4.2 Cleanup Operations 1. Look up persisted `AgentGitWorktreeInfo` for the session. 2. Remove the workspace from `MultiWorkspace::remove_workspace()` if present. 3. Run `remove_worktree(path, force)` through `project::Repository`. 4. Optionally delete the branch via existing branch APIs when safe. ### 4.3 Orphan Detection On startup, compare: - Persisted `AgentGitWorktreeInfo` entries from thread storage. - Actual git worktrees from repository APIs. If a managed worktree exists without an associated live thread/session record, mark it orphaned and offer cleanup (or auto-cleanup after policy delay). --- ## Phase 5: Testing ### 5.1 Unit Tests — Git Repository API Location: `crates/git/src/repository.rs` (in the existing `mod tests` block) - **`test_parse_worktrees_from_str`**: Verify parsing of `git worktree list --porcelain` output. Test with zero, one, and multiple worktrees. Test with detached HEAD entries and bare repos. - **`test_create_and_list_worktrees`**: Create a real git repo in a temp dir, add a worktree via the API, verify `worktrees()` returns it. - **`test_remove_worktree`**: Create a worktree, remove it, verify it's gone from `worktrees()` and the directory is deleted. - **`test_remove_worktree_force`**: Create a worktree with uncommitted changes, verify non-force removal fails, force removal succeeds. - **`test_rename_worktree`**: Create a worktree, move it to a new path, verify the old path is gone and the new path exists. ### 5.2 Unit Tests — FakeGitRepository Location: `crates/fs/src/fake_git_repo.rs` Implement `worktrees()`, `create_worktree()`, `remove_worktree()`, and `rename_worktree()` on `FakeGitRepository` backed by `FakeGitRepositoryState`. These are currently `unimplemented!()`. - **`test_fake_worktree_lifecycle`**: Create, list, remove worktrees on the fake to verify the test infrastructure works. ### 5.3 Unit Tests — Branch Name Generation Location: `crates/agent_ui/src/agent_worktree.rs` - **`test_branch_name_generation`**: Verify generated names match the `zed/agent/<id>` pattern, are valid git branch names, and are unique across