Create a focused workspace from directories scattered across your filesystem.
vp links them into one disposable folder without moving or copying anything.
Cross-repository work is awkward when your coding agent expects a single working directory. Opening a broad parent folder exposes unrelated code, which can send the agent exploring in the wrong direction and waste both time and tokens. Copying or moving projects can disrupt your layout and configuration; it also doesn't scale when the same repository needs to appear in multiple groups.
What you really want is one workspace containing only the projects relevant to the task.
vp creates that workspace as a directory of absolute symlinks. Your tools get
one focused root while every repository, Git history, and local configuration
stays exactly where it is.
cross-service-fix/
├── api -> /Users/you/projects/api
├── web -> /Users/you/projects/web
└── shared -> /Users/you/libraries/shared
The workspace can be moved, renamed, or deleted without affecting the source directories.
npm install -g @connectionloops/virtual-project
# or
bun add -g @connectionloops/virtual-projectvp has no external runtime dependencies.
Pass a name and one or more directories:
vp -n "monorepoX" ./backend ./frontend ../sharedPaths may be absolute or relative to the current directory.
vp # interactive browser (create)
vp -n <name> <path>... # create directly
vp edit [<name>] [<path>...] # add links to an existing project
vp edit [<name>] --remove <link>... # remove links by name
vp ls [<name>] # list a project's links
vp -h, --help # help
vp -v, --version # version
Run vp from the directory where you want to create the workspace:
vpThe built-in browser lets you navigate, filter, and mark directories:
| Key | Action |
|---|---|
| Up/Down | Move the selection |
| Type / Backspace | Filter the current view |
| Tab | Enter a directory |
| Shift+Tab | Go to the parent directory |
| Return | Mark or unmark |
| Esc | Finish and name the project |
| Ctrl+C | Cancel |
The browser shows the current path and selected projects. Hidden directories and common dependency/build directories are omitted.
vp edit modifies the symlinks inside a project folder that already exists.
The project folder is resolved as:
vp edit <name> ...—<cwd>/<name>(run from the parent), orvp edit ...—cwditself (run from inside the project).
Add links by passing paths; remove links by name with --remove (repeatable,
or pass the link path):
vp edit monorepoX ../api # add ../api to ./monorepoX
vp edit monorepoX --remove frontend # remove the "frontend" link
vp edit monorepoX ../api --remove frontend # add and remove in one pass
cd monorepoX && vp edit ../api # add to the project at cwd
cd monorepoX && vp edit --remove frontend # remove from the project at cwdThe first positional is treated as a project name only when it contains no
/ and <cwd>/<name> exists as a directory; otherwise every positional is an
add path against the project at cwd. To add a directory whose bare name
collides with an existing subdirectory of cwd, prefix it with ./
(e.g. vp edit ./src).
Adding a path that is already linked (same resolved target) is a no-op.
Basenames that collide with an existing link get a -2, -3, ... suffix,
just like at create time. Removing a name that isn't linked is reported but
non-fatal.
Run vp edit (or vp edit <name>) with no add paths and no --remove:
vp edit # edit the project at cwd
vp edit monorepoX # edit <cwd>/monorepoXThe same directory browser opens, but the project's current links are
pre-marked. Toggle a mark off (with Return) to remove that
link on finish; mark new directories to add them. Broken links are not
pre-marked, so finishing the browser cleans them up. When editing the project
at cwd, the browser roots at cwd's parent so you can find sibling repos
to add.
vp ls # list links in the project at cwd
vp ls monorepoX # list links in <cwd>/monorepoXBroken targets (the linked directory no longer exists) are flagged
[broken]. Clear them with vp edit --remove <name>.
vp validates each directory, creates the named workspace in the current
directory, and adds one symlink per selection. Duplicate directory names
receive a numeric suffix such as shared-2.
vp edit reads the existing project folder, unlinks the names you ask to
remove, and adds one symlink per add path using the same dedup rules as
create. A project's state is reconstructed from the folder itself (the
symlinks and their readlink targets), so there is no manifest to keep in
sync.
To remove a workspace:
rm -rf monorepoXOnly the workspace and its symlinks are removed. The linked directories remain untouched.
Bun is required only when building from source.
git clone https://github.com/connectionloops/virtual-project.git
cd virtual-project
bun install
bun run build
bun linkRun the type check and tests:
bun run typecheck
bun testThe build produces a standalone Node.js CLI in dist/index.js.
Releases are published through GitHub Actions with npm trusted publishing:
bump the version in package.json, commit, and push to main.
MIT