Dev workspace switcher for git worktrees
Boot, switch, and manage parallel dev environments
for AI-assisted multi-agent coding workflows.
Install Β· Quick Start Β· Commands Β· Config Β· How It Works
forest is a CLI tool that bridges git worktrees, Docker Compose, and host services so you (and your AI coding agents) can work in parallel worktrees while you test one at a time.
In multi-agent workflows, each AI coding agent operates in its own git worktree. forest provides a single command to:
- See all worktrees at a glance with branch context and status
- Boot the full dev stack (Docker + host services) for any worktree
- Hot-switch between worktrees in seconds
- Track which worktree is active and what's running
When you have 5 agents working in parallel worktrees, you need:
| Problem | forest solves it with |
|---|---|
| "Which worktree is running right now?" | forest status |
| "Switch to that agent's work to test it" | forest switch <name> |
| "I need pre-boot hooks (k8s, migrations, installs)" | Configurable hooks (pre, pre-services, post) |
| "Host services (Vite) need env vars from .env" | Auto-sources .env before starting services |
| "Logs are noisy, I want them quiet" | Logs go to .forest/logs/ by default |
| "Detached HEAD β what was this worktree doing?" | Smart branch memory + labels |
curl -fsSL https://raw.githubusercontent.com/prbdias/forest-cli/main/install | bashgit clone https://github.com/prbdias/forest-cli.git ~/.forest-cli
ln -sf ~/.forest-cli/forest ~/.local/bin/forestMake sure ~/.local/bin is in your PATH:
export PATH="$HOME/.local/bin:$PATH" # add to ~/.zshrc or ~/.bashrcforest --version
# forest v0.1.0# 1. Navigate to your project (must be a git repo with docker-compose)
cd ~/projects/my-app
# 2. Run the setup wizard
forest init
# 3. Boot the interactive menu
forestThe setup wizard will:
- Check requirements (git, docker, jq)
- Auto-detect your Docker Compose file
- Configure host services (e.g. Vite dev servers)
- Set up pre/post boot hooks
- Install
forestglobally
| Command | Description |
|---|---|
forest |
Interactive boot menu (default) |
forest init |
Setup wizard β configure project for forest |
forest doctor |
Check all requirements |
forest list |
List worktrees with branch/issue info |
forest boot [name] |
Boot dev stack for a worktree |
forest stop |
Stop the active dev stack |
forest switch [name] |
Stop current + boot another |
forest status |
Show running state |
forest logs [service] |
Tail logs (docker + host services) |
forest label [name] [l] |
Set a label for a worktree |
forest cleanup [name] |
Tear down resources (volumes, etc.) |
forest help |
Show help |
| Flag | Description |
|---|---|
-f, --follow |
Follow service logs after boot/switch |
--project <path> |
Specify project root explicitly |
--version |
Show version |
# Interactive menu β pick a worktree to boot
forest
# Boot worktree by index
forest boot 1
# Boot worktree by name
forest boot feature-auth
# Switch to another worktree and follow logs
forest switch atf -f
# Tail a specific host service log
forest logs web
# Tail a Docker Compose service log
forest logs postgres
# Label a detached worktree
forest label 1 "payment-refactor"
# Check what's running
forest statusWhen a command needs a worktree but you don't specify one, forest shows an interactive picker automatically.
forest auto-detects your editor and reads config from (in priority order):
| Config file | Key | Used by |
|---|---|---|
.cursor/worktrees.json |
"forest" |
Editors using .cursor/ config |
.claude/settings.json |
"forest" |
Editors using .claude/ config |
.forest/config.json |
root level | Standalone / any editor |
{
"forest": {
"project-name": "my-app",
"compose-file": "docker-compose.yml",
"hooks": {
"pre": ["scripts/pre-boot.sh"],
"pre-services": ["pnpm install --frozen-lockfile"],
"post": []
},
"services": {
"web": {
"cmd": "cd frontend && npx vite --port 5173 --host",
"label": "Frontend (Vite)",
"port": 5173
}
},
"urls": {
"App": "http://localhost:3000",
"API": "http://localhost:3001"
},
"branch-pattern": "^(feat|feature|bugfix|fix|chore|hotfix)/(\\d+)?-?(.+)$"
}
}For standalone mode (
.forest/config.json), omit the wrapping"forest"key β put everything at the root level.
| Field | Description |
|---|---|
project-name |
Docker Compose project name |
compose-file |
Path to your Docker Compose file |
hooks.pre |
Scripts to run before docker compose up (e.g. k8s setup) |
hooks.pre-services |
Commands to run before host services (e.g. pnpm install) β sequential |
hooks.post |
Scripts to run after everything is up |
services |
Host processes (not Docker) β e.g. Vite, webpack, tsc --watch |
services.<key>.cmd |
Shell command to run |
services.<key>.label |
Display name in logs/status |
services.<key>.port |
Port for status display |
urls |
Quick-reference URLs shown after boot |
branch-pattern |
Regex to extract issue numbers from branch names |
Hooks run in the context of the worktree directory with these env vars available:
| Variable | Description |
|---|---|
WORKSPACE_ROOT |
Path to the active worktree |
MAIN_ROOT |
Path to the main (root) worktree |
You (human)
β
βΌ
βββββββββββ forest boot 2 ββββββββββββββββββββββββ
β forest β βββββββββββββββββββΆ β Worktree #2 β
β CLI β β feature/payment-flow β
βββββββββββ ββββββββββββ¬ββββββββββββ
β
ββββββββββββββββββββββΌβββββββββββββββββββββ
βΌ βΌ βΌ
βββββββββββββ βββββββββββββββ ββββββββββββ
β Docker β β Host Svc 1 β β Host Svc β
β Compose β β (Vite web) β β (Vite β
β Stack β β port 5173 β β admin) β
βββββββββββββ βββββββββββββββ ββββββββββββ
Meanwhile, other agents keep working in:
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Worktree #1 β β Worktree #3 β β Worktree #4 β
β (idle) β β (idle) β β (idle) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
- Pre-hooks β Run scripts like k8s cluster setup, DB migrations
- Docker Compose β
docker compose up -d --buildwith proper env/project flags - Pre-services hooks β Sequential commands like
pnpm install - Host services β Start Vite, webpack, etc. (output redirected to
.forest/logs/) - Post-hooks β Seed data, health checks, etc.
- Summary β Print URLs and status
When a worktree has a branch, forest remembers it. If the worktree later enters detached HEAD state (common during rebases or agent operations), forest displays the remembered branch name prefixed with ~ instead of a cryptic SHA.
You can also set manual labels with forest label for extra context.
All runtime state lives in .forest/ (add to .gitignore):
.forest/
βββ active.json # Currently running worktree info + PIDs
βββ meta.json # Persisted labels and branch memory
βββ logs/
βββ web.log # Host service stdout/stderr
βββ admin.log
| Tool | Min version | Notes |
|---|---|---|
| bash | 3.2+ | macOS default works fine |
| git | 2.5+ | Worktree support required |
| docker | 20+ | With Docker Compose v2 |
| jq | 1.6+ | JSON processing |
Run forest doctor to verify everything.
forest is designed for the modern AI-assisted development workflow:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Project β
β β
β main/ β stable base β
β βββ wt-1/ β Agent 1: working on auth refactor β
β βββ wt-2/ β Agent 2: working on payment flow β
β βββ wt-3/ β Agent 3: fixing CSS bug β
β βββ wt-4/ β Agent 4: adding API endpoint β
β β
β You: `forest switch 2` β test Agent 2's payment flow β
β You: `forest switch 3` β review Agent 3's CSS fix β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Each agent works independently in its own worktree. When you want to test or review, just forest switch to that worktree β the full stack boots in seconds.
Contributions are welcome! Please:
- Fork the repo
- Create a feature branch (
git checkout -b feature/my-feature) - Run ShellCheck:
shellcheck forest - Submit a PR
# Clone
git clone https://github.com/prbdias/forest-cli.git
cd forest-cli
# Run ShellCheck
shellcheck forest
# Run tests
bash test/test_forest.sh
# Test locally
./forest --versionMIT β Paulo Dias
π² forest β because your agents deserve their own trees.
