You can now bring a repo you cloned by hand into a workspace, without editing the
.code-workspace file yourself.
Cloned a repo into your workspace directory and want multirepo to manage it?
Run multirepo select and the untracked git repos in the workspace dir show up
as (new) rows — check one and it’s adopted, reading its source from its own
origin remote (the same inference workspace create uses). Adopting wires up
the folders[] entry and the .claudeignore / .geminiignore files in one
step, and re-running is safe.
This replaces hand-editing the workspace file (or re-scaffolding and losing your
settings). There’s no standalone add command — adoption lives in select,
which is already where you shape the repo set.
`). It leaves the workspace config and the derived files, but the clone on
disk stays.
A nudge when a repo isn’t tracked
When a git repo is sitting in the workspace directory but isn’t tracked,
multirepo sync and multirepo status now print a one-line note pointing you at
multirepo select to adopt it.
Disabling a repo now actually hides it in VSCode
Disabling a repo used to write a files.exclude glob into the .code-workspace,
but in a multi-root workspace that never hid anything — each repo is its own root,
and those globs are matched per-root. Now a disabled repo is simply left out of
the workspace’s folders[], which is the list VSCode reads, so it drops out of
the Explorer for real. Enabling it adds the folder back.
While here, the folders[] entries got tidier: the inert "enabled" field
(which VSCode ignored) is gone, and a "name" is written only when it differs
from the directory — so a normal repo is just { "path": "api" }, while a repo
cloned into _github from a .github remote stays { "name": ".github", "path": "_github" }. Old "<dir>/**" excludes are cleaned up on the next change.
Custom folder names that stick
Folder display names now live in multirepo.repositories[].name, not just in
folders[]. They’re auto-filled when a repo’s real name differs from its
directory (the _github → .github case), and you can set your own — edit
"name" on any repo entry. Because the name is stored on the repo, it survives
disabling and re-enabling, even though the folders[] entry is dropped while a
repo is hidden.
Commands reorganized: workspace, select, sync --all
Managing the set of known workspaces now lives under one workspace group (short
alias ws):
multirepo workspace ls # was: multirepo ls
multirepo workspace create # was: multirepo new
multirepo workspace rm # was: multirepo rm
multirepo ws ls # the short alias works too
Repo curation now lives in multirepo select (the old config/focus command
folded in — see the select section below). multirepo config no longer exists.
sync gained --all: multirepo sync --all reconciles every registered
workspace’s repos in place — clone missing, fetch, fast-forward/rebase — without
switching you out of your current workspace.
multirepo select with no name is one live screen over every workspace: ←/→
switch workspace (the repo list refreshes), ↑/↓ and space toggle its enabled
repos. Edits to every workspace you touch are kept; Enter saves them all and drops
you into the highlighted one. multirepo select <name> still switches straight
there.
Features: work on a subset of repos as git worktrees
Sometimes a piece of work spans a few of your repos but not all of them, and you
don’t want it tangled up with your main checkouts. A feature handles that.
multirepo feature create auth api web # short alias: multirepo feat …
That checks out api and web as their own git worktrees on a shared
feature/auth branch under .multirepo/feature/auth/ (each based on the repo’s
latest origin default branch), writes an auth.code-workspace you can open in
VSCode/Cursor, and drops you in. Name the repos or pick them from a checklist.
A feature is a first-class context: once you’re in it, the everyday commands act
on its worktrees, not your main checkouts. multirepo status shows the
worktrees’ state and multirepo sync fetches and fast-forwards them. To change
which repos are in the feature, run multirepo feature edit <name> from the
parent — check one to add its worktree, uncheck one to remove it. Your main
checkouts stay where they were.
When the work has landed, tear it down:
multirepo feature rm auth
This won’t throw away work: it checks every worktree first and, if anything is
dirty, unpushed, or unmerged (a squash-merged branch counts as merged), lists
what and stops — pass --force, or confirm, to override. The worktrees go; the
branches stay, to clean up later with multirepo prune.
To see the lay of the land, multirepo workspace ls -a nests each workspace’s
repos under a Primary node plus one node per feature. To step into a feature
later, cd into its directory (.multirepo/feature/<name>/) — the shell hook
activates it, the same way it does for a workspace.
The feature lives in the parent workspace’s .code-workspace (a new features
block); the per-feature auth.code-workspace is a generated file you open, never
something you hand-edit. As always, every command is safe to re-run.
focus merged into select; new feature edit
focus and select both shaped a workspace, so they’re now one command.
multirepo select switches workspace and curates its repos.
The no-arg screen is where repo curation happens. Space toggles a repo’s enabled
state, d drops a managed repo from the workspace (the clone on disk stays), and
any untracked git repo sitting in the workspace dir shows up as a (new) row —
check it to adopt it, with its source read from origin. Edits across every
workspace tab are kept; Enter saves them and drops you into the highlighted one.
For scripts, select takes the old focus flags against the active workspace:
multirepo select --enable api,web # turn repos on
multirepo select --disable infra # turn one off
multirepo select --set api,web # set the enabled list exactly
multirepo select --rm old-repo # drop a repo (clone kept on disk)
Adoption is interactive-only now — check the (new) row instead of --add.
Reconfiguring a feature’s repos moved to its own command, multirepo feature edit <name>, run from the parent workspace. It lists the parent’s repos with the
feature’s current members checked: check one to add its worktree, uncheck to
remove it through the same safe-removal gate as feature rm. --set/--add/
--rm cover the non-interactive case. Branches are kept.
multirepo focus no longer exists.
feature list, and workspace ls → workspace list
multirepo feature list (alias ls) shows the workspace’s features as a nested
list. Each feature gives its shared branch and the directory you cd into; under
it, one row per repo shows the worktree (• present, ⚠ missing — re-create with
sync) and the branch that worktree is actually on, flagging any that have
drifted off the feature branch. The current feature is marked when you run it from
inside one. So at a glance you see every feature, its repos, their worktrees, and
their branches.
multirepo workspace ls is now multirepo workspace list, with ls kept as an
alias, so the two listing commands read the same: workspace list, feature list. (Tidy-up under the hood: only feature create is eval-wrapped by the
shell shim now — feature list/edit/rm are plain commands, so their output
is never mistaken for shell code to run.)
status points at your features
status already switches context — inside a feature it reports that feature’s
worktrees under a Feature: header. But from your main checkouts there was no
sign features even existed. Now multirepo status in a workspace that has
features prints a one-line note (2 features here — see multirepo feature list),
so the worktree-backed features stay discoverable from the parent. It’s a stderr
note, like the untracked-repo nudge, so piped status output stays clean.
A curl | sh install is now complete: binary plus shims
The remote installer used to drop only the binary, so after curl … | sh you
still had to track down the shell shim yourself before cd-activation and
@repo aliases worked. The release tarball now carries the shims too, and
install.sh lays them down next to the binary under
${XDG_DATA_HOME:-~/.local/share}/multirepo.
It then offers to add the source line to your shell rc (zsh, bash, or fish). Say
no, or run it where there’s no terminal, and it prints the exact line to add
instead. Re-running never duplicates the entry.
New flags: --no-shim for the binary only, --modify-rc / --no-modify-rc to
force or skip the rc edit, and --shim-dir to choose where the shims go.
macOS downloads are signed and notarized
The macOS release binaries are now signed with an Apple Developer ID and
notarized, so Gatekeeper recognizes them as from a known developer. Installing is
unchanged.