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.
Prerequisites
You need these tools installed:
| Tool | Check | Where 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:
- Validate the branch name.
- Check that
gitandghare ready. -
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 - 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.
- 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.
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) 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
| Command | Description |
|---|---|
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
| Field | Type | Default | Description |
|---|---|---|---|
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.
-
--forceis 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
setupcommands 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:
| Message | Fix |
|---|---|
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