| name | parallel-dev-setup |
| description | Sets up a monorepo for parallel agent development by assigning each git worktree deterministic ports, an isolated database, and a dev launcher — so multiple agents can run dev servers simultaneously with live-previewable URLs. This skill should be used when someone asks to "set up parallel development", "enable worktree port isolation", "preview multiple branches at once", "make dev servers work in parallel", "set up isolated dev environments", "fix port conflicts between agents", or "run multiple feature branches simultaneously". |
Parallel Dev Preview Setup
Enable multiple agents to develop features simultaneously in git worktrees, each with
its own dev server on unique ports, isolated database, and previewable URL. A reviewer
visits localhost:6300 for one feature and localhost:5820 for another — at the same time.
When to Use
- Project uses a monorepo with multiple services (web + APIs)
- Multiple agents will work on different features in parallel using git worktrees
- A reviewer (human or QA agent) needs to preview each feature's changes via browser
- Services read ports from environment variables
Prerequisites
Before starting, verify the project has:
- Multiple services with configurable ports via env vars (e.g.,
PORT, WEB_PORT)
- Git worktrees (Claude Code's
isolation: "worktree" creates these automatically)
- A database that can be duplicated per worktree (PostgreSQL, MySQL, SQLite)
- macOS or Linux — scripts use
lsof for port detection and kill for process cleanup
Implementation Steps
Step 1: Audit Port Configuration
Identify how each service reads its port. Use the Grep tool to search for port patterns:
pattern: "PORT|listen|port" in apps/*/src/main.*
pattern: "port|PORT" in apps/*/package.json
Map each service to its port env var and default:
| Service | Env Var | Default |
|---|
| web | WEB_PORT | 5100 |
| api | API_PORT | 5110 |
If services use hardcoded ports, refactor them to read from env vars first.
If the web app proxies to APIs (e.g., Next.js rewrites, Vite proxy), verify those
proxy targets also read from the same env vars.
Step 2: Create Shared Utilities
Create scripts/lib/env-utils.mjs with reusable helpers. See references/env-utils-template.mjs
for a complete template. Key exports:
parseEnvFile(filePath) — parse .env files into key-value objects (handles comments, quotes)
getMainRoot(cwd) — resolve the main repo root from inside a worktree
killPort(port) — kill processes on a port via lsof
isPortListening(port) — check if a port is in use
Step 3: Create Worktree Env Setup Script
Create scripts/setup-worktree-env.mjs. See references/setup-worktree-template.mjs.
- Detect worktree context — match the cwd against
.claude/worktrees/{any-name}/
(NOT just agent-{hex} — users create named worktrees like twilio, line-notif)
- Compute deterministic ports — for
agent-{hex} names use the hex directly; for arbitrary
names, derive a hex hash from the directory name:
const worktreeMatch = cwd.match(/\.claude\/worktrees\/([^/]+)/);
const agentHexMatch = agentDir.match(/^agent-([a-f0-9]+)$/);
const agentHex = agentHexMatch
? agentHexMatch[1]
: Array.from(agentDir).reduce((h, c) => (((h << 5) - h) + c.charCodeAt(0)) >>> 0, 0)
.toString(16).padStart(8, '0');
const hexPrefix = parseInt(agentHex.slice(0, 4), 16);
const portOffset = ((hexPrefix % 199) + 1) * 10;
const webPort = BASE_WEB_PORT + portOffset;
- Create an isolated database — derive name from agent ID (e.g.,
myapp_agent_{shortId})
- Write
.env.local — merge base env vars with worktree-specific overrides
- Exit cleanly when not in a worktree (no-op for main repo)
Step 4: Create Dev Launcher
Create scripts/dev.mjs. See references/dev-launcher-template.mjs.
- Auto-install deps if
node_modules/ missing (worktrees don't share them)
- Run setup-worktree-env (idempotent)
- Load
.env.local into process.env (critical — pnpm doesn't auto-load it)
- Apply DB migrations if in a worktree (with stamp file to skip if unchanged)
- Clear stale processes on assigned ports
- Print port summary with clickable URLs
- Spawn the actual dev command with env vars inherited
Accept an optional filter arg: node scripts/dev.mjs web for single-service mode.
Also create scripts/clear-dev-ports.mjs. See references/clear-dev-ports-template.mjs.
Step 5: Create Port Discovery Script
Create scripts/list-worktrees.mjs for reviewers. See references/list-worktrees-template.mjs.
- Scan
.claude/worktrees/*/ directories
- Read each
.env.local for port assignments
- Check if ports are listening (via
lsof)
- Print a formatted table with ACTIVE/- status
Step 6: Create Teardown Script
Create scripts/teardown-worktree-env.mjs. See references/teardown-worktree-template.mjs.
Three modes:
- Default (auto-detect from cwd) — kill ports, drop DB, remove
.env.local
--all — drop all agent databases
--stale — find DBs whose worktree directories no longer exist, drop them
Step 7: Wire Up Package Scripts
Update the root package.json:
{
"scripts": {
"dev": "node scripts/dev.mjs",
"dev:web": "node scripts/dev.mjs web",
"dev:api": "node scripts/dev.mjs api",
"dev:ports": "node scripts/list-worktrees.mjs",
"dev:teardown": "node scripts/teardown-worktree-env.mjs",
"dev:teardown:stale": "node scripts/teardown-worktree-env.mjs --stale"
}
}
Step 8: Document in CLAUDE.md
Add a "Worktree Port Isolation" section so agents know:
- For agents: Just run
pnpm dev — everything auto-configures
- For reviewers:
pnpm dev:ports shows all URLs
- Cleanup:
pnpm dev:teardown or pnpm dev:teardown:stale
Step 9: Ensure .env.local and .migration-stamp Are Gitignored
Key Design Decisions
Deterministic Ports (Not Random)
Use a hash of the agent ID to compute ports. Same worktree always gets the same ports,
so URLs are bookmarkable and stable across restarts.
Port Offset Strategy
Offset by multiples of 10 from the base port. This groups related services
(e.g., web=5200, api=5210, worker=5201) and avoids collisions with the main repo defaults.
Migration Stamp File
Hash all migration files and write to .migration-stamp. Skip re-running if unchanged.
Saves 3-8 seconds on every pnpm dev after the first run.
Auto-Install Dependencies
Git worktrees share git objects but NOT node_modules/. The dev launcher must detect
missing node_modules/ and run the package manager's install automatically.
Common Pitfalls
- Worktrees from wrong branch —
isolation: "worktree" creates from HEAD of the default
branch. New uncommitted scripts won't exist in worktrees. Always commit scripts first.
- Never start dev servers from Claude's bash — streaming output fills the pipe buffer
and blocks all further commands. Ask the user to start servers, or use
nohup ... &.
- Next.js
outputFileTracingRoot — changes module resolution root, can break
dependency resolution in dev. Gate behind a DOCKER=1 env var.
- pnpm doesn't load
.env.local — the dev launcher must explicitly parse and inject
env vars into process.env before spawning child processes.
- Hardcoded
agent-{hex} regex — ALL three scripts (setup-worktree-env.mjs, dev.mjs,
AND teardown-worktree-env.mjs) need the generic worktree pattern. It's easy to fix one
and forget the others. The dev launcher uses isWorktree to gate migrations — if the regex
is wrong, migrations silently skip and the API crashes with missing tables. The teardown
script's --stale mode also needs the hash derivation to map directory names to DB short IDs.
.env.example file path values — setup-worktree-env.mjs merges .env.example into
worktree .env.local. If .env.example has file path values (e.g., SERVICE_ACCOUNT=./key.json),
worktrees will crash trying to read non-existent files. Comment out or leave empty any
file path env vars in .env.example. Services should use existsSync() before readFileSync().
- Background agents can't use Bash — when
defaultMode: acceptEdits, background agents
get Bash denied. Workaround: create worktrees, install packages, and run verification from
the main session. Dispatch agents with mode: acceptEdits for code-only work.
- Cherry-picking shared fixes — fixing scripts on
main doesn't propagate to worktree
branches. Use git cherry-pick {hash} in each worktree, or merge main into the branches.
Verification
After implementation, verify:
pnpm dev in main repo prints default ports, works normally
- In a worktree:
pnpm dev auto-generates .env.local with unique ports
pnpm dev:ports lists all worktrees with ports and ACTIVE status
- Two worktrees can run simultaneously with no port conflicts
pnpm dev:teardown cleans up completely (processes, DB, .env.local)
pnpm dev:teardown:stale finds and removes orphaned databases
Additional Resources
Reference Files
references/env-utils-template.mjs — Shared utility module template
references/dev-launcher-template.mjs — Dev launcher script template
references/setup-worktree-template.mjs — Worktree env setup template
references/clear-dev-ports-template.mjs — Port cleanup script template
references/list-worktrees-template.mjs — Port discovery script template
references/teardown-worktree-template.mjs — Full teardown script template
references/implementation-checklist.md — Step-by-step checklist for implementors