Docs menu

Example: a fleet of agents

.md

End to end: several agents on one big repo, each on its own mounted branch, then review and merge.

This is the end-to-end shape the rest of the docs assume: one large repo, several agents working on it at once โ€” each on its own mounted branch โ€” and one person reviewing and merging what comes back.

The shape of it#

Five lines, before any commands:

  1. A branch is a task โ€” one unit of work, usually one agent session.
  2. A mount is a working copy of that branch. Files arrive as they're read, so a 20 GB monorepo is editable in seconds, and N tasks means N mounts, not N clones.
  3. Commits are checkpoints; the branch description is the message.
  4. Publishing isn't merging. Each agent pushes its branch and stops. Nothing reaches main until a person merges it.
  5. Merging squashes. main gets one commit per task, however many checkpoints the agent made.

If you're coming from Git: mounts do what worktrees do, minus the clone behind each one; the branch description does what a PR title and body do, minus the PR; and the squash merge is what "Squash and merge" does, except it's the only merge there is.

1. Set up a space#

Mounts need a one-time per-machine step first โ€” the Oak Mount app on macOS, fuse3 on Linux, ProjFS on Windows. See Setting up mounts.

curl -fsSL https://oak.space/install | sh
oak login

oak space new acme        # scaffolding only โ€” nothing is cloned
cd acme
oak space repos           # which repos can this space see?
# acme/monorepo
# acme/infra
# acme/docs

That leaves:

acme/
โ”œโ”€โ”€ AGENTS.md              # the workflow, written for the agent
โ”œโ”€โ”€ CLAUDE.md              # one-line @AGENTS.md import
โ”œโ”€โ”€ .oak-space             # marker recording the org
โ””โ”€โ”€ .claude/settings.json  # pre-approves the oak commands agents need

The AGENTS.md isn't a stub. It's the agent's full operating manual for a space: how to pick a task slug, mount per repo, that oak commit takes no message, how to finalize a task, and the mount-specific traps (keep CARGO_TARGET_DIR and node_modules off the mount, don't run whole-tree formatters across it, how to recover a wedged mount). An agent that follows it does the right thing without further prompting. It's a plain file โ€” add your team's conventions and every agent opened in the space picks them up.

2. Fan out#

One task = one subdirectory = one mount per repo it touches = one branch per mount. Tasks are isolated by construction: separate directories, separate overlays, separate branches, and none of them can touch main.

# From the space root. Each returns in seconds.
oak mount acme/monorepo ./fix-auth-redirect/monorepo
oak mount acme/monorepo ./add-search-index/monorepo
oak mount acme/monorepo ./bump-tokio/monorepo

oak mount list
#   ./fix-auth-redirect/monorepo
#     -> acme/monorepo@8fcf5aed1b2c (virtual branch: fix-auth-redirect--a1b2c3d4)
#   ./add-search-index/monorepo
#     -> acme/monorepo@8fcf5aed1b2c (virtual branch: add-search-index--e5f6a7b8)
#   ./bump-tokio/monorepo
#     -> acme/monorepo@8fcf5aed1b2c (virtual branch: bump-tokio--c9d0e1f2)

Branch names come from the task directory, so they read as work rather than as repo names. A cross-repo task gets one branch per repo โ€” mount ./unify-errors/monorepo and ./unify-errors/infra side by side and they share the slug.

Now launch one agent per task, from the space root so each reads AGENTS.md. With Claude Code:

claude -p "Task slug fix-auth-redirect, mounted at ./fix-auth-redirect/monorepo.
The OAuth callback drops the ?next= param. Fix it, then finalize per AGENTS.md." &

claude -p "Task slug add-search-index, mounted at ./add-search-index/monorepo.
Add a trigram index behind the search-index flag. Finalize per AGENTS.md." &

claude -p "Task slug bump-tokio, mounted at ./bump-tokio/monorepo.
Bump tokio to 1.42 across the workspace and fix the fallout. Finalize per AGENTS.md." &

wait

You can also skip pre-mounting and just name a slug โ€” AGENTS.md tells the agent to mount what it needs. Pre-mounting is worth it when you're scripting the fan-out and want mount failures to surface up front rather than inside a transcript.

3. Each agent finishes its own branch#

Per AGENTS.md, each agent ends with:

cd ./fix-auth-redirect/monorepo
oak finish --desc-file /tmp/desc.md --json

One command that checks it can publish, sets the branch description from the file, checkpoints anything uncommitted, pushes, and tears the mount down โ€” only after the push succeeds. If a step fails, the mount stays intact and the JSON names the next command.

Watch the fleet with oak mount list --json (dirty and unpushed counts per mount). Pushed branches appear live on the repo's Branches page.

4. Review what came back#

Three branches, no checkouts, and you don't want to switch your working tree three times. Start with triage:

oak branch triage --remote                     # every open branch, scored
oak branch triage --remote --only mergeable
oak branch triage --remote --only ambiguous

Then read the ones that need you:

oak branch review fix-auth-redirect--a1b2c3d4 --remote --merge-preview
oak diff fix-auth-redirect--a1b2c3d4                       # full-screen, no checkout
oak branch diff add-search-index--e5f6a7b8 --remote --diff-mode net-merge

Or do it in the browser: the Branches page lists every open branch with its CI status, and each one opens to its diff with a Merge button. Reviewing branches has the details.

5. Land them#

Merging is a decision, so it happens from somewhere you control โ€” the web UI or a real checkout, not a mount:

# In a clone of the repo (a sparse one is fine)
oak switch fix-auth-redirect--a1b2c3d4
oak merge --wait                    # wait for CI, then squash onto main

Or check off the clean branches on the Branches page and click Merge selected.

When a branch conflicts, don't re-run the agent from scratch โ€” mount the branch itself and fix it in place:

oak mount acme/monorepo ./fix-auth-redirect/monorepo --branch fix-auth-redirect--a1b2c3d4
cd ./fix-auth-redirect/monorepo
oak pull                     # merge the new main in; conflicts surface here
# resolve, or hand this mount to an agent
oak pull --continue
oak commit && oak push

A plain oak mount starts a fresh branch; --branch continues an existing one. That's also how a follow-up prompt keeps working on a branch an agent already pushed.

6. Clean up#

oak space clean                  # tear down every mount with nothing in flight
oak space clean ./bump-tokio     # or just one task

Mounts with uncommitted or unpushed work are left alone unless you pass --force, so a sweep can't eat a session you forgot about.

All of it at once#

# once per machine
curl -fsSL https://oak.space/install | sh && oak login

# once per org
oak space new acme && cd acme

# fan out
oak mount acme/monorepo ./fix-auth-redirect/monorepo
oak mount acme/monorepo ./add-search-index/monorepo
claude -p "task fix-auth-redirect โ€ฆ" &
claude -p "task add-search-index โ€ฆ" &
wait
oak mount list --json

# review, checkout-free
oak branch triage --remote --json
oak branch review <branch> --remote --merge-preview

# land
oak switch <branch> && oak merge --wait      # or Merge in the web UI

# sweep
oak space clean

Scaling up is more of the same: more task directories, more mounts, more agents. The two limits worth knowing are the mount's โ€” keep build output and node_modules off it โ€” and your own review throughput, which is what oak branch triage exists to protect.

Something here wrong or missing? Run oak feedback -m "โ€ฆ" or email [email protected].