treehouse

repository·main·Indexed 21 days ago

https://github.com/kunchenguid/treehouse

A tool for managing a pool of reusable, isolated git worktrees to provide conflict-free environments for AI agents and developers. It preserves dependencies and build caches between sessions by managing worktrees in a pool, supporting interactive subshells, durable leases for automation, and lifecycle hooks for custom configuration.

Tokens
7.1K
Snippets
29
Records
38
Agent score
74%

What's inside treehouse

  1. Core Concept: How treehouse manages worktree isolation

    main

    treehouse provides fast, isolated, and reusable Git worktrees for parallel coding-agent work. It is designed to automate the lifecycle of these worktrees so that users or orchestration systems do not have to manage them manually.

    Key Principles:

    • Isolation: Each acquisition (lease) of a worktree ensures that no other acquisition can claim it until it is returned.
    • Reuse Safety: While pooling allows for fast reuse, a reused worktree must meet the same correctness standards as a new one. It must not be dirty, in-use, or unverifiable.
    • Lifecycle Ownership: treehouse owns the worktree lifecycle (creation, leasing, and cleanup) rather than delegating this to the agent orchestration or the user's development workflow.
    • Scope: treehouse is a local CLI primitive that composes with Git, shells, and coding agents. It is not a security sandbox; it isolates working directories and lifecycle ownership, but does not provide process-level security isolation.
  2. How Treehouse manages worktrees

    main

    Treehouse manages a pool of git worktrees per repository, stored by default in ~/.treehouse/.

    Core Workflow

    1. Find Repo Root: Locates the current repository.
    2. Fetch: Runs git fetch origin to ensure the latest state.
    3. Scan Pool: Looks for an available worktree that is not leased, not in-use, and not dirty.
    4. Acquisition:
      • If found: Resets the worktree to the latest default branch.
      • If not found: Creates a new worktree with a detached HEAD at the latest default branch.
    5. Execution: Spawns a subshell in the worktree for the user/agent.
    6. Cleanup: Upon exiting the subshell, Treehouse terminates lingering processes, resets the worktree, and returns it to the pool.

    Key Concepts

    • Detached HEAD: Worktrees use detached HEAD mode to avoid branch name conflicts.
    • No Daemon: All operations are performed via inline CLI commands. State is managed via an on-disk file protected by locks.
    • In-use Detection: Treehouse identifies in-use worktrees by scanning running processes and short-lived owner reservations.
    • Dirty Detection: Any tracked changes or untracked files are treated as "dirty," even if hidden by standard git configuration.
  3. Use durable leases for persistent worktrees

    main

    If you need to reserve a worktree as a persistent environment without keeping a process running inside it (e.g., for a long-running automation task), use the --lease flag.

    When you run treehouse get --lease, you receive an immutable random lease identity. This worktree is recorded in the treehouse state and will not be handed out to other users or removed by prune until you explicitly release it using treehouse return.

    # Example of acquiring a lease
    $ treehouse get --lease
    {"path":"...","lease_id":"...","lease_holder":"automation-A","leased_at":"..."}
    
    # When finished, return the lease
    $ treehouse return <lease_id>
  4. Build and develop treehouse

    main

    If you are contributing to or developing treehouse, use the provided Makefile for common tasks.

    make build          # Build the binary
    make test           # Run tests
    make lint           # Run gofmt + go vet
    make dist           # Cross-compile for all platforms
    make install        # Install to $GOPATH/bin or /usr/local/bin
    make clean          # Remove build artifacts
  5. Install Treehouse

    main

    Treehouse can be installed on various platforms using the following methods:

    macOS / Linux

    curl -fsSL https://kunchenguid.github.io/treehouse/install.sh | sh

    Windows (PowerShell)

    irm https://kunchenguid.github.io/treehouse/install.ps1 | iex

    Nix Use nix run or add it to your flake inputs:

    treehouse = {
      url = "github:kunchenguid/treehouse";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    Go

    go install github.com/kunchenguid/treehouse@latest

    From Source

    git clone https://github.com/kunchenguid/treehouse.git
    cd treehouse
    make install
  6. How to lease a worktree for automation

    main

    Standard treehouse get opens an interactive subshell that returns the worktree to the pool when the shell exits. For automation or persistent environments, use treehouse get --lease to acquire a durable lease.

    Key Behaviors

    • Non-interactive: Does not open a subshell.
    • Persistence: The worktree is marked as leased in the state and will not be handed out to others or removed by prune until explicitly released.
    • Output: By default, it prints only the absolute path to stdout. All banners/messages go to stderr. Use --json for machine-readable metadata.
    • Identification: You can specify a --lease-holder <label> or use the $TREEHOUSE_LEASE_HOLDER environment variable.

    Usage Examples

    Acquire path for a script:

    path=$(treehouse get --lease)

    Acquire with JSON metadata for automation:

    treehouse get --lease --lease-holder automation-A --json
    # Output: {"path":"...","lease_id":"...","lease_holder":"automation-A","leased_at":"..."}

    Releasing a Lease

    To release a lease, use treehouse return <path>. For retry-safe automation, use --if-lease-id or --if-lease-holder to ensure you only release the specific acquisition you intended to manage.

    treehouse return --force \
      --if-lease-id "$lease_id" \
      --if-lease-holder "$lease_holder" \
      "$path"
  7. Destroying worktrees

    main

    The treehouse destroy command is used for the deliberate removal of worktrees, including those with unlanded work. It is a dry-run by default and requires --yes to execute.

    Target Scopes

    • treehouse destroy <worktree-path>: Targets exactly one worktree.
    • treehouse destroy <pool-path> --all: Targets all worktrees in a specific pool (the pool path can be the directory, a worktree inside it, or . if inside the repo).

    Risk Overrides (Flags)

    To remove worktrees that are not considered 'disposable', you must explicitly opt-in using these flags:

    • --include-unlanded: Removes worktrees with uncommitted changes, unmerged HEADs, or unverified contents (e.g., missing backing repositories).
    • --include-in-use: Removes worktrees with running processes or owner reservations (processes are terminated cleanly first).
    • --include-leased: Removes a leased worktree. Note: This only works when naming the exact path; it is rejected when used with --all.

    Migration Note

    The --force flag has been removed. Use the specific --include-* flags instead.

  8. Pruning stale worktrees and orphans

    main

    Use treehouse prune to identify and remove idle worktrees that are safe to delete (merged, clean, and unleased).

    Command Options

    • treehouse prune: Dry-run for the current repository's pool. Requires being inside a git repo.
    • treehouse prune --all or --global: Dry-run across every managed pool under the user-level treehouse root.
    • treehouse prune --yes: Executes the deletion of identified candidates.
    • treehouse prune --prune-orphans: Includes worktrees whose backing repositories are missing in the prune candidates.
    • treehouse prune --verbose or -v: Shows detailed skip diagnostics (e.g., why a worktree was not pruned).

    Safety and Verification

    Treehouse verifies safety by checking if the worktree's HEAD is merged into the default branch (using origin if available, otherwise local default branch). It skips worktrees with uncommitted changes or unmerged commits. If origin is unreachable, it leaves the worktree untouched for safety.

  9. Quick Start with Treehouse

    main

    To use Treehouse, navigate to your repository and run the treehouse command. This will automatically find a suitable worktree from the pool (or create a new one), and drop you into an isolated subshell. When you are finished, type exit to terminate lingering processes and return the worktree to the pool for reuse.

    This workflow ensures that dependencies and build caches are preserved between sessions while providing complete isolation for your current task or AI agent.

    $ 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.
    
    # ... work in the isolated environment ...
    
    $ exit                         # exit the subshell when you're done
    🌳 Terminated lingering processes: opencode (pid 12345)
    🌳 Worktree returned to pool.
  10. Use the treehouse CLI

    main

    The treehouse CLI is used to manage a pool of reusable, pre-warmed git worktrees. This allows multiple AI coding agents to work on the same repository in parallel without interfering with each other.

    To use the CLI, execute the treehouse binary. The tool automatically checks for updates unless you are using a dev build or have suppressed the check using the TREEHOUSE_NO_UPDATE_CHECK environment variable.

    treehouse
  11. Configure worktree lifecycle hooks

    main

    You can automate tasks during the worktree lifecycle by adding a [hooks] section to your user-level config (~/.config/treehouse/config.toml). Note that hooks in a repo-level treehouse.toml are ignored for safety.

    Available Hooks

    • post_create: Runs after a worktree is provisioned or reset, immediately before treehouse get returns control to you. When using treehouse get --lease, the hook's stdout is routed to stderr so that the command's stdout remains the leased path.
    • pre_destroy: Runs before a worktree is removed via treehouse destroy <path> --yes, treehouse destroy <pool> --all --yes, or during pruning operations (treehouse prune --yes or treehouse prune --prune-orphans --yes).

    Execution Behavior

    • Commands run sequentially in the worktree directory using the OS shell (/bin/sh -c on Linux/macOS, %COMSPEC% /c on Windows).
    • If a command exits with a non-zero status, treehouse logs the command, the exit code, and stderr, but continues executing the remaining commands in the list.
    • A failing hook does not cause the overall get, destroy, or prune operation to fail.
    [hooks]
    post_create = ["./scripts/setup-venv.sh"]
    pre_destroy = ["./scripts/teardown.sh"]
  12. Configure treehouse settings

    main

    You can configure treehouse using either a repository-level configuration or a user-level configuration.

    • Repo-level: Create a treehouse.toml file in the repository root. This is used for repo-safe settings and takes precedence over user-level settings.
    • User-level: Create a file at ~/.config/treehouse/config.toml. This is used for global settings and hooks.

    If no configuration is found, the default pool size (max_trees) is 16.

    # Maximum number of worktrees in the pool
    max_trees = 16
    
    # Optional worktree root directory.
    # Empty uses $HOME/.treehouse.
    # Relative paths are resolved from the repo root for repo-scoped commands.
    # Use an absolute user-level root for treehouse prune --all.
    # root = "$HOME/worktrees"