Skip to content

WorktreePilot/worktree-pilot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WorktreePilot

Run every AI coding task in its own isolated Git worktree, with optional dev services, logs, ports, and safe cleanup.

WorktreePilot (wtp) is a small, local-first CLI for developers using AI coding agents such as Claude Code, Codex, Gemini CLI, Aider, or similar tools.

It helps you run multiple AI coding tasks in parallel without letting them edit the same physical checkout.

WorktreePilot is framework-agnostic by default. The default wtp init creates a generic config with no assumptions about your package manager, framework, platform, or dev servers. Stack-specific setups are available as opt-in presets and examples.

Status: v0.3.0 experimental. Optimized first for WSL + Windows Terminal. Other terminals currently use fallback commands.

Installation is currently GitHub/source-based only. WorktreePilot is not published to npm yet.


Why this exists

AI coding agents are starting to behave less like autocomplete and more like parallel contributors.

That creates a real workflow problem.

If multiple agents work in the same repo folder, they can:

  • overwrite each other's files
  • mix unrelated changes into one working tree
  • create messy diffs
  • cause hard-to-recover Git conflicts
  • contaminate the running dev server
  • make review and merge order chaotic

The fix is not “trust the agent more.”

The fix is better isolation.


What WorktreePilot does

For each task, WorktreePilot gives the agent its own isolated environment:

  • one task — a named unit of work
  • one Git worktree — a separate folder on disk
  • one branch — isolated commit history
  • one agent session — no cross-talk
  • optional dev services — web, mobile, API, worker, etc.
  • assigned ports — avoids collisions between tasks
  • logs and session metadata — inspect what happened
  • safe cleanup — stop runtime separately from removing work

WorktreePilot orchestrates the workspace.

You decide what runs inside it.


Install from GitHub

Clone the repo, install dependencies, build the CLI, and link it locally:

git clone https://github.com/WorktreePilot/worktree-pilot.git
cd worktree-pilot

npm install
npm run build
npm link

wtp --version

After npm link, the wtp command should be available globally on your machine.

To update later:

cd worktree-pilot
git pull
npm install
npm run build
npm link

To unlink:

npm unlink -g worktree-pilot

Quickstart

Inside any Git repo:

wtp init
wtp doctor
wtp start fix-login-bug

The default config is intentionally minimal. It starts only the agent in an isolated worktree. No install command and no dev services are configured until you add them.

wtp start <task> will:

  1. Create or reuse .worktree-pilot/worktrees/<task>.
  2. Create or reuse branch worktree-<task>.
  3. Open an agent terminal inside the worktree.
  4. Run optional configured install/service commands.
  5. Auto-select free ports for configured services.
  6. Track session state under .worktree-pilot/sessions/<task>/.

Lifecycle

wtp start <task>
   │
   │  agent works inside its isolated worktree
   │
   ▼
/exit inside the agent
   │
   │  runtime stops, worktree is preserved
   │
   ▼
review, test, commit
   │
   ▼
wtp finish <task>
wtp finish <task> --remove-worktree
wtp finish <task> --remove-worktree --delete-branch

Important guarantees:

  • /exit does not delete the worktree.
  • wtp stop is runtime cleanup only.
  • wtp finish is post-review cleanup.
  • wtp finish --remove-worktree refuses to remove a dirty worktree unless --force is passed.
  • wtp finish --remove-worktree refuses to remove a worktree if live processes still reference it.

Parallel building is okay.

Parallel merging is not.


Generic config

wtp init writes this kind of minimal config:

agent:
  command: claude
  cwd: worktree
  interactive: true
  captureOutput: false

worktree:
  path: .worktree-pilot/worktrees/{{task}}
  create: true
  branch: worktree-{{task}}
  base: HEAD

install:
  command: ""

terminal:
  provider: auto

services: {}

cleanup:
  stopServicesWhenAgentExits: true

Placeholders:

  • {{task}} — replaced with the task name passed to wtp start <task>
  • {{port}} — replaced with the actual port assigned to a service

Empty install command means install is disabled.


Presets

Use presets when you want a starting config for a common setup:

wtp init --preset basic
wtp init --preset node
wtp init --preset next
wtp init --preset expo
wtp init --preset pnpm-monorepo

Or ask WorktreePilot to inspect the repo and recommend a preset:

wtp init --detect
wtp init --detect --preset <name>

--detect is read-only unless a preset is explicitly selected.


Examples

These are examples, not defaults.

Node

install:
  command: npm install

services:
  app:
    command: npm run dev -- --port {{port}}
    port: 3000
    interactive: false
    captureOutput: true

Next.js

install:
  command: npm install

services:
  web:
    command: npm run dev -- --port {{port}}
    port: 3000
    interactive: false
    captureOutput: true

Some package managers forward arguments differently. If your script turns into something like next dev -- -p 3000, call the binary directly:

services:
  web:
    command: pnpm --filter web exec next dev -p {{port}}
    port: 3000
    interactive: false
    captureOutput: true

Expo

Expo is interactive. It needs real terminal I/O for QR codes, hotkeys, and split-pane UI.

install:
  command: npm install

services:
  mobile:
    command: npx expo start --lan --port {{port}}
    port: 8081
    interactive: true
    captureOutput: false

pnpm monorepo

install:
  command: pnpm install

services:
  web:
    command: pnpm --filter web exec next dev -p {{port}}
    port: 3000
    interactive: false
    captureOutput: true

  mobile:
    command: pnpm --filter mobile exec expo start --lan --port {{port}}
    port: 8081
    interactive: true
    captureOutput: false
    env:
      REACT_NATIVE_PACKAGER_HOSTNAME: auto-windows-lan-ip

Custom services

The service command is just a shell command:

services:
  api:
    command: cargo run --bin api -- --port {{port}}
    port: 8080
    interactive: false
    captureOutput: true

  worker:
    command: python -m worker --queue dev
    interactive: false
    captureOutput: true

Interactive vs captured processes

Some tools are normal log-producing services. Others are terminal UIs.

Process kind Recommended config Why
AI agent interactive: true, captureOutput: false Claude/Codex-style TUIs need real stdin/stdout
Expo interactive: true, captureOutput: false QR code and key handlers need a real TTY
Next.js / API / worker interactive: false, captureOutput: true Logs can be captured safely

For interactive processes, WorktreePilot logs lifecycle messages but does not pipe the tool's full terminal UI through tee.

For captured services, WorktreePilot writes full output into the session log.


Commands

Command Description
wtp init [--preset <name>] [--detect] [--with-skills] [--force] Create worktree-pilot.yml. Default preset is basic. --with-skills also installs the Claude Code skills.
wtp doctor Check Git, Node, config, terminal support, ports, WSL/PowerShell when relevant.
wtp start <task> [--dry-run] [--ip <ip>] Create/reuse the worktree and open the agent/services.
wtp list / wtp ls List sessions, worktrees, branches, services, ports, and statuses.
wtp logs <task> [service] [--tail] [-n <lines>] Show logs for the agent or services.
wtp stop <task> [--agent] [--force] Stop runtime processes. Does not remove the worktree or branch.
wtp finish <task> [--remove-worktree] [--delete-branch] [--force] Safe post-review cleanup.
wtp clean <task> [--force] Remove only session metadata.
wtp audit Scan for secrets, runtime artifacts, personal paths, and publish-risk files.
wtp skills install [--force] [--dry-run] / wtp skills list Install opt-in Claude Code skills (wtp-builder, wtp-reviewer) into .claude/skills/. Never installed by default.

WSL + Windows Terminal

WorktreePilot is currently optimized for WSL + Windows Terminal.

From WSL, wtp start opens tabs using:

wt.exe new-tab --title "<title>" wsl.exe --cd <cwd> -- bash -li -c "exec bash <wrapper>"

This shape matters:

  • wsl.exe --cd <cwd> opens the tab directly in the right folder.
  • bash -li loads login/interactive shell setup.
  • interactive tools keep access to a real terminal.
  • wrappers write status, logs, PID/PGID metadata, and cleanup signals.

If Windows Terminal is unavailable, WorktreePilot falls back to printing the exact commands you can run manually.


Agent skills

WorktreePilot is agent-agnostic by default. Plain wtp init never creates anything in .claude/ or .agents/.

If you use a supported AI coding agent, there are two optional project skills you can install into your repo to make the builder/reviewer workflow safer:

Skill Purpose
wtp-builder Keeps the builder agent scoped to its task worktree. Doesn't switch branches, doesn't merge, doesn't delete. Produces a focused diff and review notes.
wtp-reviewer Reviews one or many active task branches against main. Doesn't modify, doesn't merge, doesn't delete. Returns APPROVE / NEEDS CHANGES / REJECT per branch + a safe merge order.

Supported agents and install locations:

Agent --agent value Install dir
Claude Code claude .claude/skills/
Codex codex .agents/skills/
Both all both of the above

Install them only when you want them — these are never installed by plain wtp init:

# Standalone (default: Claude Code):
wtp skills install                       # → .claude/skills/
wtp skills install --agent claude        # explicit
wtp skills install --agent codex         # → .agents/skills/
wtp skills install --agent all           # both

wtp skills install --dry-run             # show what would be created
wtp skills install --force               # overwrite existing skill files

wtp skills list                          # see what's bundled / installed (Claude)
wtp skills list --agent codex            # check Codex install
wtp skills list --agent all              # check both

# Or during init:
wtp init --with-skills                          # default: claude
wtp init --with-skills --skills-agent codex     # Codex only
wtp init --with-skills --skills-agent all       # both
wtp init --preset next --with-skills --force

Files created (depending on --agent):

.claude/skills/wtp-builder/SKILL.md     # when agent=claude (default) or all
.claude/skills/wtp-reviewer/SKILL.md
.agents/skills/wtp-builder/SKILL.md     # when agent=codex or all
.agents/skills/wtp-reviewer/SKILL.md

If a SKILL.md already exists, wtp skills install skips it and tells you to pass --force to overwrite. (--force on wtp init --with-skills is forwarded to the skills install step.)

Invocation syntax

Skill bodies are identical across agents; only the invocation syntax differs:

Agent Invoke builder Invoke reviewer
Claude Code /wtp-builder /wtp-reviewer task1, /wtp-reviewer merge task1
Codex $wtp-builder $wtp-reviewer task1, $wtp-reviewer merge task1

The examples below use the Claude / form. For Codex, swap / for $.

Builder ↔ Reviewer feedback loop

The two skills are designed to pair. The reviewer emits a structured Builder Handoff when a branch isn't ready; the builder consumes it as a focused review-fix task. The loop:

  1. Start a builder task:

    wtp start <task>
  2. Use the builder skill in the agent tab:

    /wtp-builder
    <your task prompt>
    
  3. When the builder is done, committing is optional. If you want to commit yourself:

    cd .worktree-pilot/worktrees/<task>
    git status
    git add . && git commit -m "<message>"

    You can also leave the changes uncommitted — the builder should report Uncommitted but ready for review in its Review Readiness section. The reviewer can review both committed and uncommitted state, and if you later ask for integration, it will offer to create the commit for you (with explicit confirmation).

  4. From your main checkout (or a reviewer task), ask the reviewer:

    /wtp-reviewer <task>
    
  5. If the verdict is NEEDS CHANGES or REJECT, the reviewer's report ends with a ## Builder Handoff block — copy it into the builder session:

    /wtp-builder
    <paste Builder Handoff>
    
  6. The builder fixes only the listed issues, runs the listed validations, and replies with a Review Fix Summary ending in Ready For Reviewer: Yes | No.

  7. Re-run the reviewer:

    /wtp-reviewer <task>
    
  8. Once the reviewer says APPROVE, you can integrate. Default is still manual — the reviewer prints Approved Merge Commands (both merge and squash variants) you run yourself. Or opt into reviewer-driven integration:

    /wtp-reviewer merge <task>          # git merge --no-ff (commits immediately)
    /wtp-reviewer squash <task>         # git merge --squash (staged on main for review)
    /wtp-reviewer apply <task>          # alias for squash
    

    Both still ask for explicit confirmation before touching main, and again before cleanup.

How the contract works:

  • Reviewer produces the handoff. For non-APPROVE verdicts, the handoff is mandatory and copy-pasteable. For APPROVE, no handoff — you get Approved Merge Commands (both merge and squash variants) instead.
  • Builder consumes the handoff. Review-fix mode is scoped — no broad refactors, no unrelated edits, no merge, no cleanup.
  • Uncommitted task changes are first-class. The builder may leave changes uncommitted. The reviewer can review them, and if you opt into integration, the reviewer asks (once) before creating a commit on the task branch on your behalf.
  • Integration requires explicit confirmation. Whether merge, squash, or apply, the reviewer asks before touching main.
  • squash/apply also asks before the main commit. Changes land staged on main; the reviewer prints git diff --staged for you and asks again before committing.
  • Cleanup requires explicit confirmation. After integration + checks pass, the reviewer asks one more time before running wtp finish --remove-worktree --delete-branch. Never --force unless you say to discard.
  • Default reviewer mode is review-only. The reviewer never modifies, merges, or cleans up unless you opt into an integrate mode.

Using the reviewer skill

The reviewer has three modes: review-only (default, safe), merge (git merge --no-ff), and squash/apply (git merge --squash — staged on main for final review). Integrate modes always require explicit confirmation gates.

Review-only mode (default)

Pass task names — no need to type the full worktree-<task> branch:

/wtp-reviewer task1
/wtp-reviewer task1 task2 task3
/wtp-reviewer check task2
/wtp-reviewer review task2 task3 and recommend merge order
/wtp-reviewer all

How it interprets your input:

  • Bare tokens like task2 → expanded to worktree-task2. Tokens already starting with worktree- are used as-is.
  • Filler words (check, review, against, main, and, merge, readiness, recommend, order, branches) are stripped.
  • all / review all / active branches → reviews every local branch matching worktree-*.

Each branch gets a structured report: APPROVE | NEEDS CHANGES | REJECT, summary, risky files, possible conflicts with other active branches, required checks, and (only if approved) the exact manual merge commands ending in wtp finish <task> --remove-worktree --delete-branch. After per-branch reports, you get one integration plan with a recommended merge order.

Review-only mode never modifies, merges, or deletes anything. Use it before deciding to merge.

Use one reviewer for all your active branches — that's how it spots cross-branch conflicts.

Merge mode (opt-in)

Prefix the task with merge or integrate:

/wtp-reviewer merge task1
/wtp-reviewer integrate task1

The reviewer then walks a strict step-by-step:

  1. Review worktree-task1 against main. If the verdict is anything other than APPROVE, stop and output the Builder Handoff.
  2. Pre-flight on the task worktree. If it has uncommitted changes, the reviewer asks once: "The task has uncommitted changes. Do you want me to create a commit on worktree-task1 before integrating it?" — and only commits after explicit yes + approved message.
  3. Ask explicitly: "Do you want me to merge worktree-task1 into main now?" — wait for a clear yes.
  4. git checkout main → check that working tree is clean → git pull. Aborts on dirty main or failed pull.
  5. git merge --no-ff worktree-task1. On conflicts, stops and lists conflicted files — never auto-resolves.
  6. Run typecheck / lint / test (pnpm typecheck, pnpm lint by default; substitutes for npm/yarn/bun when obvious). If any check fails, stops.
  7. Ask again: "Merge and checks passed. Do you want me to clean up the task worktree and branch now?" — wait for yes.
  8. wtp finish task1 --remove-worktree --delete-branch. Never adds --force unless you explicitly say to discard the task.

Squash / apply mode (opt-in)

Prefix the task with squash or apply (aliases). This is the review-on-main flow — the task's changes land staged on main so you can review them with git diff --staged before any commit.

/wtp-reviewer squash task1
/wtp-reviewer apply task1

Exact behavior:

  1. Reviewer reviews worktree-task1 against main.
  2. If approved, reviewer asks permission to apply.
  3. Same uncommitted-task pre-flight as merge mode (asks before committing on the task branch).
  4. Reviewer runs git merge --squash worktree-task1.
  5. Changes appear staged on main. No commit yet.
  6. Reviewer runs checks (pnpm typecheck, pnpm lint, …).
  7. Reviewer prints: "The task changes are now staged on main. Review them with: git diff --staged".
  8. Reviewer asks: "Do you want me to commit these staged changes to main now?" — proposes a commit message, waits for yes + approved message.
  9. Only after commit, reviewer asks: "Do you want me to clean up the task worktree and branch now?"
  10. wtp finish task1 --remove-worktree --delete-branch.

merge vs squash/apply:

  • mergegit merge --no-ff. Creates a merge commit and integrates immediately on success.
  • squash / applygit merge --squash. Applies changes as staged changes on main; nothing is committed until you approve it.
  • There is no completed merge with no commit. "Merge but don't commit" is the squash/apply flow.

Guarantees (all integrate modes)

  • Review-only is the default. No surprise integrations.
  • One branch per invocation. Parallel merging is forbidden.
  • Explicit confirmation gates: before integration (merge or apply), before committing (squash/apply only), and before cleanup. Never silently destructive.
  • Uncommitted task changes ask once before being committed on your behalf.
  • Never --force cleanup unless you say so.
  • Stops on dirty main, on conflicts, on failed checks. Doesn't try to recover by guessing.

Use review-only before integrating. Use merge mode when you're confident the diff is ready and you want a normal merge commit. Use squash/apply mode when you want to eyeball the changes on main before committing.

Parallel building is okay. Parallel merging is not.


Reviewer workflow

A useful pattern is to run one task as the builder and another as the reviewer.

Builder

wtp start names-refactor

The builder works only in:

.worktree-pilot/worktrees/names-refactor

When finished:

cd .worktree-pilot/worktrees/names-refactor
git status
git diff
npm test
git add .
git commit -m "refactor: names"

Reviewer

Use a separate worktree or your main checkout to review the builder branch.

Prompt:

Review branch worktree-names-refactor against main.

Do not modify files unless explicitly asked.

Check:
- correctness
- hidden side effects
- unnecessary changes
- generated files that should not be committed
- secrets or personal data
- missing tests
- whether the diff matches the task

Merge

Merge one branch at a time from the main checkout:

git checkout main
git pull
git merge --no-ff worktree-names-refactor
npm test
git status

Then cleanup:

wtp finish names-refactor --remove-worktree --delete-branch

Repo safety audit

Before publishing or pushing public changes, run:

wtp audit

The audit checks for common publish risks:

  • .env files
  • private keys
  • local runtime folders
  • local worktree folders
  • logs
  • personal paths
  • suspicious API key patterns
  • project-specific terms

It is not a security guarantee. It is a practical guardrail.


Troubleshooting

Claude Code prints Input must be provided either through stdin or as a prompt argument when using --print

The agent likely lost an interactive terminal stream.

Make sure:

agent:
  interactive: true
  captureOutput: false

Then check:

wtp logs <task> agent

You want:

[wtp] tty stdin:  yes
[wtp] tty stdout: yes

If stdout is not a TTY, something is still piping the agent output.

Expo crashes with setRawMode EIO

Expo needs real terminal I/O.

Use:

services:
  mobile:
    command: npx expo start --lan --port {{port}}
    port: 8081
    interactive: true
    captureOutput: false

A service keeps running after wtp stop

Use force:

wtp stop <task> --force

If wtp finish --remove-worktree refuses because a process still references the worktree, that is intentional. Kill the listed process or process group, then retry.

A service has a port but ignores it

Make sure the command includes {{port}}:

services:
  web:
    command: npm run dev -- --port {{port}}
    port: 3000

If WorktreePilot has to auto-bump the port but the command does not contain {{port}}, the service may still try its default port.


Limitations

  • WSL + Windows Terminal is the primary supported path today.
  • macOS and native Linux currently use fallback commands.
  • Process cleanup is best-effort across detached terminal tabs.
  • No cloud, no dashboard, no team mode.
  • WorktreePilot isolates the workflow; it does not validate the agent's code.
  • Always review and test before merging.

Philosophy

Parallel building is okay. Parallel merging is not.

WorktreePilot is intentionally:

  • local-first
  • generic by default
  • framework-agnostic
  • config-driven
  • conservative about destructive cleanup
  • focused on the developer's machine, not a cloud platform

Development

npm install
npm run typecheck
npm run build

npm run dev -- init
npm run dev -- doctor
npm run dev -- start demo-task --dry-run

License

MIT

About

Run every AI coding task in its own isolated Git worktree, with optional dev services, logs, ports, and safe cleanup.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors