From worktrees
Create an isolated worktree workspace for parallel branch development. Reads config from .claude/worktree.json.
npx claudepluginhub joaquincampo/workspaced-worktrees --plugin worktreesThis skill uses the workspace's default tool permissions.
Create an isolated workspace with git worktrees for each repo, so a Claude Code instance can work on a feature branch in parallel without affecting the main checkout.
Creates isolated Git worktrees for parallel development, risky refactoring, or multi-feature work without branch switching or conflicts.
Manages Git worktrees for isolated parallel development: creates from main with branch names, lists status, switches, cleans up; auto-copies .env files and trusts dev tools safely.
Creates git worktree with symlinked/copied assets, independent per-project environments (venv/npm), and direnv .envrc. Uses .worktree.yml or infers config.
Share bugs, ideas, or general feedback.
Create an isolated workspace with git worktrees for each repo, so a Claude Code instance can work on a feature branch in parallel without affecting the main checkout.
Branch name: $ARGUMENTS
If no argument provided, ask the user for the branch name.
Read .claude/worktree.json from the project root.
If the file does not exist:
[ -d "$dir/.git" ])package.json, pyproject.toml, Makefile, etc. in each repo. Also detect cross-service relationships (e.g., a frontend env var pointing to a backend API)..claude/worktree.json populated with the discovered repos. Use what you detected — only leave <FILL IN> placeholders for fields you truly cannot determine:{
"repos": [
{
"name": "<detected-dir>",
"port": 8000,
"install": "uv sync",
"start": "uv run uvicorn app.main:app --port {port}",
"env_files": [".env"],
"env_patches": {
"NEXT_PUBLIC_API_URL": "{backend.url}"
},
"cache_dirs": [".venv"]
}
]
}
Important: For env_patches that reference other repos, always use {<repo_name>.url} placeholders. These resolve correctly in both portless and fallback modes. Never hardcode http://localhost:{<repo_name>.port} — use {<repo_name>.url} instead.
Note on start commands: The start field is the raw server command with a {port} placeholder. Do not include portless in the start command — portless wrapping is applied automatically when generating workspace scripts (Step 11).
<FILL IN> placeholders remain, print:Created .claude/worktree.json — some fields need manual input.
Please fill in the <FILL IN> placeholders, then run /worktree again.
Stop here. Do not create any worktrees.
<FILL IN> placeholders), print the config as a table and proceed to Step 2 immediately.If the file does exist, proceed with the steps below.
SLUG=$(echo "$ARGUMENTS" | tr '/' '-')
WORKSPACE="../$(basename $(pwd))-wt-${SLUG}"
mkdir -p "$WORKSPACE"
Check if portless is installed:
command -v portless &>/dev/null
For each repo, derive a portless service name:
SERVICE_NAME="<repo.name>-${SLUG}"
Example: repo backend-parsanai on branch feature/auth → backend-parsanai-feature-auth
Build a URL map for env patching:
repo.name → http://<SERVICE_NAME>.localhost:1355
No port assignment, offset counting, or conflict resolution needed. Skip the fallback section below.
For each repo in the config, calculate its port:
OFFSET=$(cd <repo.name> && git worktree list | wc -l | tr -d ' ')
The port for each repo is repo.port + OFFSET.
If any assigned port is busy (lsof -i :<port>), increment all ports by 1 and check again.
Build a URL map for env patching:
repo.name → http://localhost:<assigned_port>
For each repo in the config:
cd <repo.name>
git worktree add "${WORKSPACE}/<repo.name>" -b "$ARGUMENTS" 2>/dev/null \
|| git worktree add "${WORKSPACE}/<repo.name>" "$ARGUMENTS"
If creation fails because the branch exists remotely but not locally:
git fetch origin "$ARGUMENTS"
Then retry.
Copy the root CLAUDE.md and .claude/ directory so the workspace inherits shared commands, skills, and rules:
cp CLAUDE.md "$WORKSPACE/" 2>/dev/null || true
cp -r .claude "$WORKSPACE/" 2>/dev/null || true
Create ${WORKSPACE}/.claude/rules/worktree.md so the agent automatically knows its environment. This file is auto-loaded into context.
Make sure the .claude/rules/ directory exists:
mkdir -p "${WORKSPACE}/.claude/rules"
Generate the file with the following content (replace all placeholders with actual values):
# Worktree Workspace
You are working in an isolated worktree workspace on branch `<branch_name>`.
## Servers
Start all servers:
\`\`\`bash
./start.sh
\`\`\`
Stop all servers:
\`\`\`bash
./stop.sh
\`\`\`
<for each repo>
### <repo.name>
- Path: <repo.name>/
- URL: http://<service_name>.localhost:1355
- Start individually: cd <repo.name> && portless <service_name> <repo.start with {port} replaced by \$PORT>
<end for>
## Rules
- **No migrations.** Never run migration tools (alembic, prisma migrate, knex migrate, etc.) or any command that auto-runs migrations on startup. The database is shared across all worktrees.
- **Schema changes = blocker.** If your feature requires database schema changes, STOP and report back to the user.
- **Don't push** to remote unless explicitly asked.
- **Commit freely** to your feature branch — commits stay local until pushed.
## Cleanup
When done, the user can run `./cleanup.sh` from the workspace root to stop servers, remove worktrees, and delete this workspace.
# Worktree Workspace
You are working in an isolated worktree workspace on branch `<branch_name>`.
## Servers
Start all servers:
\`\`\`bash
./start.sh
\`\`\`
Stop all servers:
\`\`\`bash
./stop.sh
\`\`\`
<for each repo>
### <repo.name>
- Path: <repo.name>/
- Port: <assigned_port>
- Start individually: cd <repo.name> && <repo.start with {port} replaced>
<end for>
## Rules
- **No migrations.** Never run migration tools (alembic, prisma migrate, knex migrate, etc.) or any command that auto-runs migrations on startup. The database is shared across all worktrees.
- **Schema changes = blocker.** If your feature requires database schema changes, STOP and report back to the user.
- **Don't push** to remote unless explicitly asked.
- **Commit freely** to your feature branch — commits stay local until pushed.
## Cleanup
When done, the user can run `./cleanup.sh` from the workspace root to stop servers, remove worktrees, and delete this workspace.
For each repo in the config, if repo.cache_dirs is defined and non-empty, clone each directory from the original repo into the worktree before installing. This avoids downloading everything from scratch.
On macOS (APFS), use cp -Rc for instant copy-on-write clones:
cp -Rc <repo.name>/<cache_dir> "${WORKSPACE}/<repo.name>/<cache_dir>"
On Linux, use hardlinks for speed:
cp -al <repo.name>/<cache_dir> "${WORKSPACE}/<repo.name>/<cache_dir>"
Skip any that don't exist in the original.
Hint for users configuring cache_dirs: APFS clones and hardlinks are fast for directories with few large files (e.g., .venv, vendor/), but slow for directories with many small files (e.g., node_modules). Package managers with global caches (pnpm, yarn berry, uv) often make a fresh install fast enough that cloning is unnecessary. When in doubt, leave cache_dirs empty and let the package manager handle it.
For each repo in the config:
cd "${WORKSPACE}/<repo.name>" && <repo.install>
This should be fast since cached directories were already copied.
For each repo in the config:
Copy each file listed in repo.env_files from the original repo into the worktree:
cp <repo.name>/<env_file> "${WORKSPACE}/<repo.name>/<env_file>" 2>/dev/null || true
Apply repo.env_patches: for each key-value pair, find and replace that key's value in the worktree's env file. Values support two kinds of placeholders:
{<repo_name>.url} — resolves to the full URL from the URL map built in Step 4. Works in both modes. Recommended.{<repo_name>.port} — resolves to the assigned port number in fallback mode. In portless mode, if the value matches the pattern http://localhost:{<repo_name>.port}, replace the entire pattern with the portless URL from the URL map. This ensures backward compatibility with existing configs.Create executable scripts in the workspace root so agents (or users) can start/stop servers without knowing the details.
start.sh#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
<for each repo>
echo "Starting <repo.name> → http://<service_name>.localhost:1355"
(cd "$SCRIPT_DIR/<repo.name>" && portless <service_name> <repo.start with {port} replaced by \$PORT>) &
<end for>
echo ""
echo "All servers started."
echo "Run ./stop.sh to shut them down."
wait
stop.sh#!/usr/bin/env bash
<for each repo>
echo "Stopping <service_name>..."
pkill -f "portless <service_name>" 2>/dev/null || true
<end for>
echo "All servers stopped."
start.sh#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Start each repo's server in the background
<for each repo>
echo "Starting <repo.name> on port <assigned_port>..."
(cd "$SCRIPT_DIR/<repo.name>" && <repo.start with {port} replaced>) &
<end for>
echo ""
echo "All servers started. PIDs logged above."
echo "Run ./stop.sh to shut them down."
wait
stop.sh#!/usr/bin/env bash
<for each repo>
echo "Stopping port <assigned_port>..."
lsof -ti :<assigned_port> | xargs kill 2>/dev/null || true
<end for>
echo "All servers stopped."
cleanup.sh#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
WORKSPACE_NAME="$(basename "$SCRIPT_DIR")"
# Stop any running servers
"$SCRIPT_DIR/stop.sh" 2>/dev/null || true
# Remove worktrees
<for each repo>
echo "Removing worktree <repo.name>..."
git -C "$PARENT_DIR/<original_project>/<repo.name>" worktree remove "$SCRIPT_DIR/<repo.name>" 2>/dev/null || true
<end for>
# Remove workspace directory
echo "Removing workspace..."
rm -rf "$SCRIPT_DIR"
echo "Cleanup complete."
Make all scripts executable:
chmod +x "${WORKSPACE}/start.sh" "${WORKSPACE}/stop.sh" "${WORKSPACE}/cleanup.sh"
Workspace ready for branch: $ARGUMENTS
Root: <WORKSPACE>/
<for each repo>
<repo.name>:
Path: <WORKSPACE>/<repo.name>
URL: http://<service_name>.localhost:1355
<end for>
Scripts:
./start.sh — start all servers
./stop.sh — stop all servers
./cleanup.sh — stop servers, remove worktrees, delete workspace
Launch agent:
cd <WORKSPACE> && claude --dangerously-skip-permissions
Workspace ready for branch: $ARGUMENTS
Root: <WORKSPACE>/
<for each repo>
<repo.name>:
Path: <WORKSPACE>/<repo.name>
Port: <assigned_port>
<end for>
Scripts:
./start.sh — start all servers
./stop.sh — stop all servers
./cleanup.sh — stop servers, remove worktrees, delete workspace
Tip: Install portless for stable named URLs → npm i -g portless
https://github.com/vercel-labs/portless
Launch agent:
cd <WORKSPACE> && claude --dangerously-skip-permissions