πŸš€ Spawning Parallel Agents Across Multiple Repos

🧬 Each spawn creates
a fully isolated copy
of every repo via
git clone --local
(copy-on-write, near
instant on macOS).

The biggest friction in modern AI-assisted development isn’t the models β€” it’s the workspace problem. You’re shipping a feature that touches a backend service, a client library, and an infrastructure repo. You need the agent to reason across all three simultaneously, make consistent changes, and open PRs that actually cohere.

The usual answer? Open three terminal windows, manually create matching branches, context-switch constantly. It works, but it doesn’t flow.

This post is about a small script I wrote called spawn that solves exactly this. It creates a clean, isolated workspace with all your repos cloned and pre-branched, then opens everything in a single Cursor window. One command, zero context-switching.


The idea

git clone --local
uses hard-links on
the same filesystem,
so the clone is
nearly instantaneous
and uses minimal
extra disk space.

Every agent gets its own sandbox directory β€” a folder that contains one git clone --local of each repo you care about. All clones are put on the same branch. A .code-workspace file stitches them into a single Cursor multi-root workspace so the AI can see across repo boundaries as if they were one project.

Think of it like spawning a new process: isolated state, clean branch, no side-effects on your main working copies.


Installation

The script lives at ~/gitlab.com/angi/anchor/spawn. Drop a symlink so it’s on your PATH:

ln -s ~/gitlab.com/angi/anchor/spawn ~/.local/bin/spawn
chmod +x ~/.local/bin/spawn

Dependencies: bash β‰₯ 5, git, python3 (stdlib only), and cursor on your PATH.


Configuration

πŸ’‘ The config file is
created with sensible
defaults on first use
if it doesn’t exist.

On first run spawn creates ~/.config/spawn/config.json. You can also pass a custom path via SPAWN_CONFIG=/path/to/file.json.

Build your config interactively below β€” then copy the JSON into ~/.config/spawn/config.json.

The keys:

Key Required Description
workspace_root βœ“ Parent directory for all agent workspaces
primary_repos βœ“ Always cloned (your core services)
secondary_repos – Only cloned with --all flag

Usage

spawn without args
prints the full help
text β€” good habit
to check after updates.

Hit Run below to watch a simulated spawn session:

The four commands you’ll actually use:

# create a new isolated workspace on branch feat/my-feature
spawn feat/my-feature

# same, but also clone secondary repos (docs, infra, etc.)
spawn --all feat/my-feature

# list all your agents and their current branches
spawn --list

# open an existing agent in Cursor
spawn --open feat-my-feature__a3f9c21b

# delete a finished agent (asks for confirmation)
spawn --remove feat-my-feature__a3f9c21b

Watching agents work across repos

πŸ€– In practice I run
2–4 agents in parallel
on separate branches.
Each has its own
Cursor window with
the branch name in
the title bar.

Once Cursor opens the workspace file, the agent sees every repo as a top-level folder in the Explorer. You can:

  • Ask it to trace a type across backend/ β†’ client-lib/ β†’ infra/ in one message
  • Have it create matching migration + schema + client changes atomically
  • Review all diffs in one git status across all roots

The simulation below shows three parallel agents running on separate spawned workspaces. Toggle them on/off to see what each is doing:


How the workspace file works

The window.title
setting embeds the
branch name so you
always know which
agent is in which
Cursor window.

spawn writes two files into each agent directory:

agent.code-workspace

{
  "folders": [
    { "path": ".", "name": "feat/payments-v2" }
  ],
  "settings": {
    "window.title": "${dirty}${separator}feat/payments-v2${separator}${activeEditorShort}${separator}${appName}"
  }
}

.vscode/settings.json (same window.title β€” Cursor reads both).

When you cursor agent.code-workspace, Cursor opens all subdirectories as workspace roots and shows the branch in the title bar, so you always know which agent is which at a glance.


Tips & tricks

πŸ”‘ SPAWN_FORCE=1
skips the confirmation
prompt for --remove.
Useful in scripts.


The mental model

🎯 One branch per task.
One Cursor window
per branch. Let the
agent run. Review
the diff. Merge.
Delete the workspace.

A useful way to think about spawn is as git worktree with superpowers. Regular worktrees let you check out a different branch into a second directory β€” spawn does the same but for N repos at once, wires them into a Cursor workspace, and adds metadata so you can manage the lifecycle (--list, --open, --remove).

The workflow:

  1. spawn feat/my-feature β€” agent opens in Cursor
  2. Describe the cross-repo feature in Cursor’s Composer
  3. Agent edits files across all repos
  4. git diff in each repo, review, push
  5. spawn --remove feat-my-feature__<id> β€” clean up

Each task is a clean slate. No lingering uncommitted changes. No branch confusion. Just: spawn, build, ship, remove.