Correct the v12 guides from agent-skills.md through lockfile.md against pnpm/crates, and fix the same wrong text on the v11 twins where pnpm11 confirms it. Part of pnpm/tasks#191. Wrong claims (both versions): - configuring: the global auth file is auth.ini, not rc; list the npm_config_* exceptions (workspace dir, userconfig, URL-scoped auth). - config-dependencies: the hook import used an invalid ESM specifier. - docker: Example 3 ran fetch --prod and built without an offline install or pnpm-workspace.yaml. - errors: drop MISMATCHED_RELEASE_CHANNEL, describe INVALID_NODE_VERSION through nodeVersion, PEER_DEP_ISSUES needs strictPeerDependencies. - faq: no lockfile deletion after a readPackage hook, default store order, junctions depend on symlink privilege. - filtering: `!./lib` matches one project; use `!./lib/**`. - git branch lockfiles: every non [A-Za-z0-9_.-] character becomes `!`, the name is lowercased, merging deletes branch lockfiles, "or" patterns. - git-worktrees: remove the nonexistent worktree:new and shell/wt.sh. - global-packages: orphaned dirs are cleaned by add -g (and update -g in v12), not store prune; document that add -g replaces every group that contains the package. - how-peers-are-resolved: current peer directory names. - completion: built-in completion already covers --filter and scripts. - feature-comparison: broken JSR anchor. Wrong claims (v12 only): - cargo: cargo.indexUrl fails the parse, overrides apply to adding only, merge the duplicated Cargo index section into Registries. - global-virtual-store: pnx keeps its own virtual store (dlx part only; the global-install claims are left for a separate decision). - installation: the npm package installs on Node.js 18, only get-pnpm needs 22.13; trim unverified compatibility rows. Missing facts (v12): agent-skills group filtering and naming, catalogs (catalogs.default, pnx, --save-catalog, error codes), cargo recursive add, build-std, resolution keys, completion zsh/pwsh setup, config dependency location and error codes, include error codes, CI opt-outs and pnpm ci, finders on list, filtering settings and --no-fail-if-no-match, global install refusals, trust for npm-registry package managers, Rust shims, overrides link from aliases. Stale history (v12): drop v11/v10 version markers and "since v11" narration in continuous-integration, filtering, finders, git-worktrees, global-packages, global-virtual-store, how-peers-are-resolved, lockfile, completion, configuring. Review follow-up: the Node.js compatibility table keeps the pnpm 10 column; Docker Example 3 builds with all dependencies in a build stage and ships only production dependencies, with the pnpm-workspace.yaml caveat (both versions); catalogs keep the bare-path form; v11 global packages name `pnpm update -g` as cleaning orphans too; the cargo build-std note says when rust-src must be listed. Second review: build-std needs a non-empty list; the Docker fetch layer also depends on the project settings; branch lockfile names keep only ASCII characters; the conflict merge needs both sides to parse; Rust shims and package managers are default globalShims participants; pnpm self-update also cleans orphaned global groups; v12 pnpm login writes tokens to config.yaml; legacyDirFiltering keeps the subtree wording (the v12 mismatch is pnpm/tasks#196); the v12 Docker example copies the files that `include` names before pnpm fetch.
6.4 KiB
id, title
| id | title |
|---|---|
| git-worktrees | pnpm + Git Worktrees for Multi-Agent Development |
When multiple AI agents need to work on the same monorepo simultaneously, they each need an isolated working copy with fully functional node_modules. Git worktrees combined with pnpm's global virtual store make this practical: each worktree gets its own checkout and its own node_modules, but dependencies are shared across all of them through a single content-addressable store on disk.
What is a git worktree?
Normally, a git repository has a single working directory tied to one branch at a time. If you want to look at another branch, you have to stash or commit your changes and switch. A git worktree lets you check out multiple branches simultaneously, each in its own directory. All worktrees share the same repository history and objects. They're just different views into the same repo.
git worktree add ../feature-branch feat/my-feature
This creates a new directory ../feature-branch with feat/my-feature checked out, while your original working directory stays on its current branch. You can work in both directories independently.
A common pattern is to use a bare repository (one with no working directory of its own) as the hub, and create all working directories as worktrees:
git clone --bare https://github.com/your-org/your-repo.git your-repo
cd your-repo
git worktree add ./main main
git worktree add ./feature feat/something
Why worktrees?
Even before AI agents, worktrees are useful for maintaining multiple major versions of a project. On my dev machine, I use a pnpm repository with at least two worktrees: one on main for pnpm v11, and another on the v10 branch for backports and maintenance releases. This way, I can fix a bug on v10 without stashing my in-progress v11 work. Both versions are always checked out and ready to go. In the past, 2 or 3 worktrees were usually enough for me in the pnpm repository. However, since I started using AI agents extensively, I need a lot more worktrees to let my agents work on many tasks in parallel.
Why this matters even more with AI agents
With AI coding agents, worktrees go from convenient to essential. Each agent needs its own working directory to edit files, run builds, and execute tests without interfering with other agents. Without worktrees, this means cloning the repository multiple times, duplicating git history for each copy.
Worktrees solve the git side. Every agent gets its own isolated checkout while sharing the underlying git objects. But each worktree still needs its own node_modules, which can be hundreds of megabytes. That's where pnpm's global virtual store comes in: with it enabled, each worktree's node_modules contains only symlinks into a single content-addressable store on disk. This means adding a new agent is fast and costs almost no extra disk space.
:::important
This setup assumes the worktrees and agents share the same trust boundary. Do not use one writable pnpm store for mutually untrusted agents or users.
:::
Setting it up
1. Create a bare repository
git clone --bare https://github.com/your-org/your-monorepo.git your-monorepo
cd your-monorepo
2. Create worktrees for each branch
# Main development worktree
git worktree add ./main main
# A feature branch for agent A
git worktree add ./feature-auth feat/auth
# A bugfix branch for agent B
git worktree add ./fix-api fix/api-error
Each worktree is a full checkout with its own files, but they all share the same .git object store.
3. Enable the global virtual store
Add virtualStoreType: global to the pnpm-workspace.yaml in your repository (before v11.23.0 this setting was spelled enableGlobalVirtualStore: true):
packages:
- 'packages/*'
virtualStoreType: global
4. Install dependencies in each worktree
cd main && pnpm install
cd ../feature-auth && pnpm install
cd ../fix-api && pnpm install
The first pnpm install downloads packages into the global store. Subsequent installs in other worktrees are nearly instant because they only create symlinks to the same store.
How it works
Without the global virtual store, each worktree would have its own .pnpm virtual store inside node_modules, with hardlinks or copies of every package. With virtualStoreType: global, pnpm keeps all package contents in a single shared directory (the global store, which you can find by running pnpm store path), and each worktree's node_modules contains symlinks pointing there:
your-monorepo/ (bare git repo)
├── main/ (worktree: main branch)
│ ├── packages/
│ └── node_modules/
│ ├── lodash → <global-store>/links/@/lodash/...
│ └── express → <global-store>/links/@/express/...
├── feature-auth/ (worktree: feat/auth branch)
│ └── node_modules/
│ ├── lodash → <global-store>/links/@/lodash/... ← same target
│ └── express → <global-store>/links/@/express/...
└── fix-api/ (worktree: fix/api-error branch)
└── node_modules/
├── lodash → <global-store>/links/@/lodash/... ← same target
└── express → <global-store>/links/@/express/...
This means:
- Near-zero per-worktree overhead: the local
node_modulescontains only symlinks to the shared global virtual store. Unlike pnpm's default behavior, which hardlinks files from the content-addressable store into a localnode_modules/.pnpmdirectory, the global virtual store means no files are copied or hardlinked into the worktree at all. - Instant installs for new worktrees: packages are already in the global store.
- No conflicts: each worktree has its own
node_modulestree, so agents can install different dependency versions on different branches without interference.
Tips
- Creating worktrees for agents: When launching an AI agent, create a dedicated worktree for it. The agent gets full isolation to edit files, run tests, and install packages without affecting other agents.
- Cleanup: Remove a worktree when it's no longer needed with
git worktree remove ./feature-auth. Leftover worktrees are cheap but can accumulate.