Wtdev – deterministic dev-server ports for parallel Git worktrees

pemakenemi561 pts0 comments

GitHub - Dave-56/wtdev: One dev server per git worktree — deterministic ports, no collisions, live dashboard · GitHub

/" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

Dave-56

wtdev

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>10 Commits<br>10 Commits

LICENSE

LICENSE

README.md

README.md

wtdev

wtdev

View all files

Repository files navigation

wtdev

One dev server per git worktree. No port collisions, stable URLs, and a live dashboard of every checkout.

If you run coding agents (Claude Code, Cursor, etc.) in parallel git worktrees, you've hit this: every worktree's dev server wants port 3000, agents kill each other's servers or drift to random ports, and you can never remember which branch is on which port.

wtdev fixes it with one rule: the port is a pure function of the worktree's path.

main checkout → 3000

every linked worktree → a stable port in 3001–3999, hashed from its path

Same worktree, same port, every time — across restarts, across agents, with zero coordination and zero state. In the rare case two worktrees hash to the same port, the later one (in git worktree list order) simply takes the next free port, so ports stay unique without anything to configure.

Install

curl -fsSL https://raw.githubusercontent.com/Dave-56/wtdev/main/wtdev -o /usr/local/bin/wtdev<br>chmod +x /usr/local/bin/wtdev

It's a single dependency-free POSIX shell script; you can also just copy it into your repo.

Usage

wtdev run # start the dev server on this checkout's port<br>wtdev run pnpm dev # ...with an explicit command ({port} is substituted)<br>wtdev up # start it in the background if not already serving<br>wtdev port # print this checkout's port<br>wtdev list # every worktree with its branch + port<br>wtdev dashboard # generate a live-status HTML dashboard

The easiest setup is to route your dev script through it, so agents and humans alike get the right port without thinking:

{ "scripts": { "dev": "wtdev run next dev -p {port}" } }

wtdev run exports PORT (which Next.js, Vite via config, CRA, Remix, and most Node servers respect) and also substitutes {port} into the command for tools that want a flag.

It also copies gitignored env files (.env, .env.local by default) from the main checkout into fresh worktrees, since those never come along with git worktree add.

Zero-touch dev servers for agent sessions

wtdev up is run for automation: it starts the server in the background (logging to .wtdev.log — add it to .gitignore) only if the checkout's port isn't already serving, and prints the URL either way. Because it's idempotent, any number of sessions can call it without double-starting servers.

Wire it into your agent's session-start hook and every session begins with its checkout's dev URL already in context. For Claude Code, put this in .claude/settings.json at the repo root:

/dev/null 2>&1; wtdev up 2>/dev/null || true",<br>"timeout": 180,<br>"statusMessage": "Starting dev server for this checkout"<br>],<br>"PostToolUse": [<br>"matcher": "EnterWorktree",<br>"hooks": [<br>"type": "command",<br>"command": "[ -d node_modules ] || npm install >/dev/null 2>&1; wtdev up 2>/dev/null || true",<br>"timeout": 180,<br>"statusMessage": "Starting dev server for this worktree"<br>}">{<br>"hooks": {<br>"SessionStart": [<br>"hooks": [<br>"type": "command",<br>"command": "[ -d node_modules ] || npm install >/dev/null 2>&1; wtdev up 2>/dev/null || true",<br>"timeout": 180,<br>"statusMessage": "Starting dev server for this checkout"<br>],<br>"PostToolUse": [<br>"matcher": "EnterWorktree",<br>"hooks": [<br>"type": "command",<br>"command": "[ -d node_modules ] || npm install >/dev/null 2>&1; wtdev up 2>/dev/null || true",<br>"timeout": 180,<br>"statusMessage": "Starting dev server for this worktree"

Both hooks matter. SessionStart covers the checkout a session launches in — but a worktree created mid-session (Claude Code's EnterWorktree) never re-fires it, so without the PostToolUse hook those worktrees silently run without a server until someone notices. The hook runs after the session has switched into the new...

wtdev port worktree server checkout session

Related Articles