One branch, every repo.
One command checks a branch out in every repository of a project, runs each repo's setup, and lays the result out in tmux or herdr.
$ curl -fsSL https://raw.githubusercontent.com/anton-fomin/ws/main/install.sh | shThe problem
A feature touches the API and the web app. So you git switch in one repository, then the other, then you remember the infrastructure repo. Halfway through a review someone needs a hotfix, and every one of them has to move again.
Worktrees help, but one repository at a time: each new one starts without your .env, without node_modules, and without the setup steps nobody wrote down.
# without ws, for every branch
cd ~/src/api && git switch -c feature/login
cd ~/src/web && git switch -c feature/login
cd ~/src/infra && git switch -c feature/login
cp ../.env.backup .env # which one was it?
pnpm install # againHow it works
A workspace is a directory with a ws.yaml. It holds one bare clone per repository and one branch directory per branch, with a worktree of every repository inside. Which branch is where is always read back from git.
acme/
ws.yaml # repositories, setup, overrides
.bare/api.git .bare/web.git # one bare clone per repository
local/api/.env # untracked files for every worktree
main/api main/web # a branch directory per branch…
feature-login/api # …with one worktree per repository
feature-login/webws switch feature/login creates the worktrees, places your local files, installs dependencies, runs each repository's setup and opens the session. More on the layout →
What comes with a switch
tmux or herdr
Each switch opens a session over the branch directory: one window per repository, plus one for the branch directory itself.
Pick and jump
ws picklists checked-out and remote branches in fzf; every worktree is registered with zoxide, soz feature-xgets you there.Local files
Keep
.env,.npmrcand editor settings once inlocal/. They are linked or copied into every new worktree.Dependencies, seeded
yarn, pnpm, npm and uv install held to the lockfile; yarn and pnpm start from hard links of the branch you came from.
ws run
Run
dev,testorlintin every repository at once, from justfiles, Taskfiles or package.json, with prefixed output and logs.Setup commands
Per-repository setup runs once per worktree, with
{branch},{worktree}and{env:NAME}filled in.
git is the only requirement. Every integration turns on when its program is installed, and none of them can fail a switch.
Works with coding agents
Type /ws <task> in Claude Code, OpenCode or pi. The agent picks a branch name from your repositories' conventions, runs ws switch, and starts a fresh agent on the task in the new workspace's session.
A second skill teaches every agent inside a workspace how to find its way around: ws status, each repository's own instructions, ws runfor tasks. Coding agents →
$ npx skills add anton-fomin/ws -g -a claude-code opencodeInstall
Then add the shell wrapper so ws switch also changes directory, and shell completion. Getting started →