ClaudeWrapper.Worktrees (ClaudeWrapper v0.8.1)

Copy Markdown View Source

Read-side introspection for git worktrees.

Claude Code's --worktree [name] flag (and its DuplexSession equivalent) creates fresh git worktrees so an agent's writes can land somewhere other than the current working tree. Hosts that orchestrate worktree-isolated chats need a way to enumerate the worktrees that exist for a given repo, see what branches they're on, and notice when one is locked or prunable.

This module is a thin Elixir API over git worktree list --porcelain. It is read-only on purpose; mutations (pruning, removing worktrees) are out of scope so consumers that only want to introspect don't opt into write semantics.

Why shell out

Reading .git/worktrees/ directly is brittle: git tracks locked, prunable, detached-HEAD, and bare-repo state in ways that have evolved across releases. Asking git itself is the cheap, correct option, and git is already a transitive dependency of any worktree-using workflow.

Example

{:ok, root} = ClaudeWrapper.Worktrees.for_repo(".")
{:ok, worktrees} = ClaudeWrapper.Worktrees.list(root)

for wt <- worktrees do
  IO.puts("#{wt.path}  #{wt.branch || "(detached)"}")
end

Summary

Functions

Address worktrees for the repository containing path.

List every worktree git knows about for this repository.

The configured repository path.

Types

t()

@type t() :: %ClaudeWrapper.Worktrees{repo_path: String.t()}

Functions

for_repo(path)

@spec for_repo(String.t()) :: {:ok, t()} | {:error, ClaudeWrapper.Error.t()}

Address worktrees for the repository containing path.

path can be any directory inside the repo; git's -C handling resolves the .git itself. Runs git worktree list --porcelain once to validate that path is in fact inside a git repository.

Returns {:error, %ClaudeWrapper.Error{kind: :not_a_git_repo}} when path is not inside a repository (the path is in :reason), {:error, %ClaudeWrapper.Error{kind: :git_failed}} for other non-zero git exits, and {:error, %ClaudeWrapper.Error{kind: :git_unavailable}} when the git binary cannot be spawned.

list(root)

@spec list(t()) ::
  {:ok, [ClaudeWrapper.Worktrees.Worktree.t()]}
  | {:error, ClaudeWrapper.Error.t()}

List every worktree git knows about for this repository.

Spawns git -C <repo_path> worktree list --porcelain and parses the output. The first entry is the main worktree (is_main? == true).

Returns the same error shapes as for_repo/1.

path(worktrees)

@spec path(t()) :: String.t()

The configured repository path.