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...