Documentation

The Arborist guide

Everything you need to go from nothing to managing worktrees across multiple repositories with arb. Arborist is a single compiled binary that turns the multi-step ritual of cloning repos and hand-typing git worktree add into one guided command.

Pre-1.0. All commands documented here are implemented and tested. Behavior is stable, but flags and output may still change before 1.0.

Prerequisites

You need these tools installed:

ToolCheckWhere to get it
Git git --version git-scm.com
GitHub CLI (gh) gh --version cli.github.com
Go 1.23+ go version go.dev — only to build from source

Arborist uses the GitHub CLI for all GitHub access and never stores or logs GitHub tokens. Authenticate once:

gh auth login
gh auth status   # verify

Arborist clones repositories with gh repo clone, so this is the only authentication you need — no SSH keys or known_hosts setup.

Installation

The install script downloads the prebuilt binary for your platform (macOS/Linux, amd64/arm64) from the latest release, verifies its checksum, and puts arb on your PATH — no Go toolchain required:

curl -fsSL https://raw.githubusercontent.com/jjacoblee/arborist/main/install.sh | sh

Pin a version with ARBORIST_VERSION=v0.1.0, or change the destination with ARBORIST_INSTALL_DIR (default /usr/local/bin, falling back to ~/.local/bin). Prefer doing it by hand? Download an archive from the releases page and verify it against checksums.txt.

Building from source instead (contributors, or Windows) requires Go 1.23+:

git clone https://github.com/jjacoblee/arborist.git
cd arborist
make install        # builds, then links arb into /usr/local/bin

Confirm the install:

arb --version

Quick start

The whole lifecycle in five commands:

gh auth login                          # one-time GitHub CLI authentication

mkdir -p ~/work/acme && cd ~/work/acme # a folder for one GitHub owner
arb init --owner acme                  # set up the workspace (.arborist.json)

arb new feature/example-change         # pick repos and create worktrees
arb list                               # see your worktrees
arb remove feature/example-change      # clean up when you're done

Each step is covered in detail below.

Workspaces

Arborist is workspace-rooted, like Git. Each GitHub owner (user or organization) gets its own folder on disk with a hidden .arborist.json config at its root. That folder is also the repository root: base clones live directly under it, and worktrees go in a sibling worktrees/ folder by default.

~/work/acme/                 # workspace root, holds .arborist.json
  admin/                     # base clone   <workspace>/<repo>
  api/
  worktrees/                 # worktree root (default)
    admin/
      feature-x/             # a worktree   <worktreeRoot>/<repo>/<branch>

Creating one

mkdir -p ~/work/acme && cd ~/work/acme
arb init --owner acme

--owner is required — it's the GitHub user or org this workspace discovers repositories from. init won't overwrite an existing config without --force. Override the worktree location with --worktree-root.

Discovery

Every command except arb init finds the workspace by walking up from the current directory until it sees a .arborist.json — exactly like Git locates .git. So you operate on an owner by cd-ing into its folder (or any subdirectory). Use --dir <path> on any command to start the search elsewhere.

To work across several owners, create one workspace folder per owner and cd between them. There is no global, machine-wide config.

Creating worktrees — arb new

The flagship workflow:

arb new feature/my-change

Arborist will:

  1. Validate the branch name.
  2. Check that git and gh are ready.
  3. Discover your repositories and open an interactive picker — type to filter, Space to toggle, Enter to confirm, Esc to cancel without changes:
    Select repositories for branch: feature/my-change
    Space to select · Enter to confirm · Esc to cancel
    
    > [ ] acme/web-app (private)
      [ ] acme/api
      [x] acme/admin
  4. For each selected repository: clone it if it isn't local, fetch the latest refs, and create the worktree — reusing an existing local branch, tracking a remote branch, or creating a new branch from the repo's default branch, whichever applies.
  5. Print a summary of created, skipped, and failed worktrees with exact paths.

Short folder names — --name

Long branch names make for long folder names. Keep the folder short while creating the full branch:

arb new full-feature-branch-name --name short-name
# folder: <worktreeRoot>/<repo>/short-name   branch: full-feature-branch-name

Branching off something else — --base

arb new follow-up --base feature-x

--base accepts a local branch, a remote branch (resolved to origin/<name>), or a tag/commit. It applies only when the branch is newly created — if the branch already exists locally or on the remote, Arborist uses it as-is. Without --base, new branches start from the repo's default branch.

Already exists? If a worktree path already exists or a branch already has a worktree, Arborist safely skips it and shows the existing path — that's a skip in the summary, not an error.

Opening & setup

Open a worktree — arb open

arb open <id-or-branch> launches a worktree in your editor. Pick it per-run with --cursor, --code, or --editor <command>, or set a default once:

arb config set editor cursor   # then a bare `arb open <id>` uses it
arb open a3f9                  # opens that worktree in Cursor

Without a flag or config, arb open falls back to your $EDITOR. To jump into a worktree in your shell, use --print with a tiny helper in your ~/.zshrc (a program can't change your shell's directory):

acd() { cd "$(arb open "$1" --print)"; }
# then:  acd a3f9

Setup commands — arb setup

A fresh worktree is a clean checkout, so it usually needs dependencies installed before you can run it. Configure commands per repository under setup in the workspace config, and Arborist runs them in each new worktree right after arb new:

{
  "owner": "acme",
  "setup": {
    "admin": ["pnpm install", "uv sync", "pnpm run init:ruff"],
    "*": ["pnpm install"]
  }
}

The * entry applies to any repo without an exact match. Skip setup for one run with arb new <branch> --no-setup, or run it on demand against an existing worktree:

arb setup a3f9   # re-run setup for that worktree (by id or branch)
Setup commands run through a shell in the worktree directory. They come only from your own trust-checked config — never from a cloned repository — but commands like pnpm install can trigger a repo's own lifecycle scripts, so configure setup only for repositories you trust.

Local files — copyEnvFiles and copyFiles

Worktrees often need local, gitignored files. Set copyEnvFiles: true to copy top-level .env / .env.* files from the base clone into each new worktree, and list anything else under copyFiles (e.g. ["secrets.env"]). Only the repo root is scanned, symlinks are skipped, and copies are written with private (0600) permissions. Off by default because these files commonly contain secrets.

Listing & removing

arb list

Shows managed worktrees, each with a short, stable id. Paths are relative to the worktree root (--full for absolute):

ID    REPOSITORY  BRANCH             STATUS  PATH
7351  acme/admin  feature/my-change  clean   admin/feature-my-change

arb remove

Remove exactly one worktree by its id, or every worktree on a branch (alias: arb rm):

arb remove 7351                # one worktree, by id
arb remove feature/my-change   # every worktree on the branch

Either way, arb remove shows the exact paths and asks before deleting (--yes to skip the prompt). It never removes a worktree with uncommitted changes unless you explicitly pass --force.

arb prune

Cleans up stale worktree references — for example after a worktree folder was deleted outside Arborist.

Command reference

CommandDescription
arb init --owner <owner> Set up an owner workspace in the current directory (writes .arborist.json). --worktree-root to relocate worktrees, --force to overwrite.
arb new <branch> Pick repositories, clone any that are missing, create worktrees, then run configured setup commands. --name <short> for a short folder, --base <ref> to branch off a chosen ref, --no-setup to skip setup.
arb list List managed worktrees with short ids; relative paths (--full for absolute).
arb open <id-or-branch> Open a worktree in your editor (--cursor, --code, --editor <cmd>, or the configured default), or print its path with --print.
arb setup <id-or-branch> Run the workspace's configured setup commands in a worktree. Runs automatically after arb new.
arb remove <id-or-branch> Safely remove one worktree by id, or every worktree on a branch. Confirmation required (--yes to skip, --force for dirty worktrees). Alias: arb rm.
arb prune Clean up stale worktree references.
arb repo list List the workspace owner's GitHub repositories (via gh).
arb config View and edit the workspace configuration (list/get/set/path).

Every command except arb init runs inside a workspace; they locate it by walking up from the current directory. Add --dir <path> to start the search elsewhere.

Configuration

The workspace config is .arborist.json at the workspace root. Because it's hidden, prefer arb config over editing it by hand:

arb config                       # print the resolved configuration
arb config get worktreeRoot      # read one value
arb config set copyEnvFiles true # change a value (re-validated before saving)
arb config path                  # print the config file location

Fields

FieldTypeDefaultDescription
owner string — (required) The GitHub user or organization this workspace discovers repositories from.
worktreeRoot string <workspace>/worktrees Where worktrees live, as <worktreeRoot>/<repo>/<sanitized-branch>. Relative paths resolve against the workspace root; a leading ~ expands to your home directory.
copyEnvFiles bool false Copy top-level .env / .env.* files from a repo's base clone into each new worktree.
copyFiles array [] Extra repo-relative files to copy into each new worktree. Confined to the repo; copies are 0600.
editor string $EDITOR Command arb open uses by default, e.g. cursor or code --wait.
setup object {} Per-repo shell commands run in each new worktree. Key * is the fallback for repos without an exact entry.

get/set cover the scalar fields (owner, worktreeRoot, copyEnvFiles, editor). The structured fields (copyFiles, setup) are edited in the file itself — open it with $EDITOR "$(arb config path)".

The repository root is not stored — it's implicitly the directory containing the config. There's no clone-protocol setting either; cloning goes through gh repo clone with your GitHub CLI authentication.

Trust

Because Arborist discovers .arborist.json automatically (and its editor value is run by arb open), it refuses to load a config that is a symbolic link, not owned by you, or writable by group or others — similar to Git's safe.directory check. arb init and arb config set always write it 0600; if you create one by hand, keep it that way (chmod 600 .arborist.json).

Safety model

Arborist runs Git and gh and touches the filesystem, so it is conservative by default:

  • Commands are executed with argument arrays (os/exec) — never by building shell strings from user input.
  • Branch names are validated and sanitized before being used as path segments.
  • Destructive actions require explicit confirmation and print the exact paths that will be removed. A dirty worktree is never removed silently.
  • --force is only used when you explicitly pass a force flag; creating worktrees never uses Git's --force.
  • Filesystem changes stay inside the workspace and its worktree root.
  • GitHub tokens are never stored or logged; authentication is delegated to the GitHub CLI.
  • Cloned repositories are never run automatically — Arborist executes only the setup commands from your own trust-checked config, never code it finds in a repo.
  • No telemetry or analytics — Arborist runs entirely locally except for the Git and GitHub CLI operations you trigger.

Troubleshooting

Arborist aims to tell you exactly what to do. Common messages:

MessageFix
git is required but was not found Install Git and retry.
the GitHub CLI (gh) is required but was not found Install gh from cli.github.com.
the GitHub CLI (gh) is not authenticated Run gh auth login.
not inside an Arborist workspace cd into a workspace folder, or run arb init --owner <owner> to create one.
worktree path already exists / branch already has a worktree Not an error — Arborist safely skipped it and shows the existing path.

Limitations & roadmap

  • Pre-1.0: commands are stable in behavior, but flags and output may still change before 1.0.
  • Prebuilt binaries cover macOS and Linux (amd64 + arm64); Windows users build from source.
  • GitHub is the only supported provider, via the GitHub CLI.

Next up: enabling the Homebrew tap on a tagged release, more integration tests against real temporary Git repositories, and richer examples. Contributions welcome — see CONTRIBUTING.md; security issues go through SECURITY.md.

That's the whole guide. Go grow some trees — arb new feature/my-change