Are you still only working on one task at a time? Are you manually juggling between a few clones of the same repo?
Or... are you starting a new worktree for every agent session, losing all your installed dependencies and build cache each time, and wondering why your agents are slow?
Treehouse helps you manage a pool of reusable, isolated worktrees so each of your agents gets its own environment instantly — no cloning, no conflicts, no coordination overhead.
treehouse puts you into a clean worktree with zero hassel.$ cd myproject # start in your repo as usual
$ treehouse # get a worktree and drop into a subshell
🌳 Entered worktree at ~/.treehouse/myproject-a1b2c3/1/myproject. Type 'exit' to return.
# You're now in an isolated worktree.
# Run your AI agent, make changes, do whatever you need.
$ exit # exit the subshell when you're done
🌳 Terminated lingering processes: opencode (pid 12345)
🌳 Worktree returned to pool.
macOS / Linux
curl -fsSL https://kunchenguid.github.io/treehouse/install.sh | sh
Windows (PowerShell)
irm https://kunchenguid.github.io/treehouse/install.ps1 | iex
Nix
nix run github:kunchenguid/treehouse
# or pin a specific release tag:
nix run github:kunchenguid/treehouse/v3.1.2
Install into your Nix profile:
nix profile add github:kunchenguid/treehouse
Or add to your flake inputs:
treehouse = {
url = "github:kunchenguid/treehouse";
inputs.nixpkgs.follows = "nixpkgs";
};
The flake exposes #default and #treehouse package outputs, plus apps for nix run.
A Nix install upgrades through Nix: treehouse update refuses to run from the Nix store and the update notice stays silent there.
Go
go install github.com/kunchenguid/treehouse/v3@latest
From source
git clone https://github.com/kunchenguid/treehouse.git
cd treehouse
make install
Treehouse manages a pool of git worktrees per repository, stored under the configured treehouse root.
The default treehouse root is ~/.treehouse/.
You can instead keep the pool inside the project with --root ., so it lives next to the code and is removed with the project.
treehouse
│
▼
Find repo root
│
▼
git fetch origin
│
▼
┌──────────────────────────────────────────────────────┐
│ Scan pool for a safely reusable worktree │
│ (this clone's, idle, unleased, clean, and HEAD │
│ merged into the exact reset target; skip if safety │
│ or clone ownership is unprovable) │
└──────────┬───────────────────────────────────────────┘
│
┌────┴────┐
│ Found? │
└────┬────┘
yes/ \no
/ \
▼ ▼
Reset to Create new worktree
latest (detached HEAD at
default latest default
branch branch)
& add to pool
\ /
\ /
▼
Spawn subshell in worktree
(agent works here)
│
▼
exit subshell
│
▼
Terminate lingering worktree
processes and verify none remain
│
▼
Reset worktree & return to pool
(ready for next agent)
-b / --branch, worktrees use detached HEAD mode and reset to whichever of the local or remote default branch is further ahead. Pass treehouse get -b <name> to create and check out a new local Git branch at the acquired commit. See Base branch for base selection and branch-creation details.base_branch in treehouse.toml, or pass treehouse get --base <branch>, to cut worktrees from a branch other than the repository default. Opt-in; unset keeps today's inference. This composes with --branch: the new branch starts at the selected base.treehouse get --unique-leaf (or set unique_leaf in treehouse.toml) to name new slots <repo>-<slot> instead of <repo>, so tooling that derives per-checkout identity from the directory name tells the slots apart. Opt-in; off keeps today's layout, and existing worktrees are never moved.worktree_path in treehouse.toml, or pass treehouse get --worktree-path '<template>', to place new worktrees somewhere a tool requires instead of {pool}/{slot}/{repo}. Opt-in, and creation-only: worktrees already in the pool keep their recorded paths. See Worktree path.get creates a new worktree up to max_trees and otherwise fails with a message counting the foreign and unverifiable worktrees. A worktree whose owning clone cannot be proven is never reused, and neither is any worktree when the requesting clone's own identity cannot be proven. Non-colocated jj repositories have no Git common directory, so their worktrees are never reused; get creates a new one each time until max_trees is reached.treehouse, treehouse get, and treehouse enter start $SHELL as an interactive login shell when it resolves to bash, fish, or zsh. Other shells, fallback shells, and Windows use their default invocation. A regular executable that is merely named like a supported shell but does not accept -i -l (for example a wrapper script at /opt/tools/bash) is an accepted limitation: the resolved basename is the contract, and PATH-identity probing would reject genuine second installs of the same shell.get, destroy, and prune lifecycle work is running.treehouse get --lease reserves a worktree as a persistent home without keeping a process inside it. Each acquisition gets an immutable random lease identity, and the lease is recorded in treehouse's own state. An ordinary lease keeps the worktree out of later get and prune until you release it with treehouse return. Unlike process-based in-use detection, it survives with zero processes running inside the worktree; recovered leases follow the state recovery policy..worktreeinclude file for the default selection, or pass get --include-file <path> for a personal manifest. Selected local files are copied from the main checkout on each acquire. See Seeding gitignored files.git status output.treehouse prune removes only clean, idle managed worktrees with landed HEAD commits. See Base branch for the merge rule.
treehouse prune --all applies the same safety checks across every managed pool under the user-level treehouse root.
Backing-repository-missing orphans are reported by default; --prune-orphans includes them as unverified prune candidates, and --yes is required before deletion.
It is a dry run unless you pass --yes.treehouse get clears stale git worktree bookkeeping for the exact path it is about to create (e.g. left behind by a crashed or forcibly removed worktree), so a prunable registration never wedges the pool with a "missing but already registered worktree" error. Registrations for other paths are never touched, so a live worktree that the caller cannot see (for example under another account's private pool root) is never deregistered.| Command | Description |
|---|---|
treehouse |
Get a worktree and open a subshell (alias for get) |
treehouse get |
Acquire a worktree from the pool |
treehouse get --lease |
Durably lease a worktree withou |
| 日期 | 榜单 | 排名 | 周期新增 | 总 STAR |
|---|