This document explains how to create Git worktrees for parallel agent work without
copying a full Chromium engine/ checkout for every worker.
Dao Browser keeps Chromium in engine/, which is very large and gitignored. The
worktree helper supports two engine modes:
shared: the worktree'senginesymlink points at the primary checkout'sengine/, so rebuilds reuse the exact existingout/dao-debugstate.private: the worktree gets its own writableenginesymlink backed by a copy-on-write clone of the warm cache under.dao/engine/.
Use this flow when multiple agents need to work on different branches at the same time:
dao-browser/ # primary checkout
dao-browser-feature-a/ # git worktree for agent A
dao-browser-feature-b/ # git worktree for agent B
Use shared mode when one agent needs fast local iteration from the primary
checkout's hot build cache. Use private mode when multiple agents need to
import or rebuild at the same time without touching the same engine/src or
engine/src/out/dao-debug state.
From the primary checkout:
npm run setup
npm run rebuild
npm run engine:cache:refreshThen create a worker worktree:
npm run worktree:create -- feature/little-dao \
--base main \
--path ../dao-browser-feature-little-daoThe new worktree can use normal project commands. If the worktree was created by an external agent system, run the setup script from inside that worktree first:
cd ../dao-browser-feature-little-dao
npm run setup:worktree
npm run rebuildsetup:worktree uses shared engine mode by default. That is the fastest path
when the primary checkout already has a complete warm build.
Refreshes the warm engine cache from the current checkout's engine/.
The cache path is:
.dao/engine/cache/warm/<cache-key>/engine
The cache key includes:
- Chromium version from
dao.json - build flavor, default
dao-debug - contents of
configs/
Dao-owned source files, patch files, and branding assets are intentionally not
part of the warm cache key. A worker worktree reuses a compatible Chromium build
cache first, then npm run import applies that worktree's current Dao-owned
sources and patches into its private engine/.
If the exact cache key is missing, the helper reuses the primary checkout's
recorded lastWarmCacheKey when it matches the same Chromium version and build
flavor. This keeps agent worktrees warm across ordinary Dao source changes.
Run npm run rebuild before refreshing the cache if you want workers to inherit
hot out/dao-debug build state.
Use --force to replace an existing cache for the current key:
npm run engine:cache:refresh -- --forceCreates a Git worktree and attaches a private engine to it.
Example:
npm run worktree:create -- feature/sidebar-cleanup \
--base main \
--path ../dao-browser-feature-sidebar-cleanupThis runs:
git worktree add -b feature/sidebar-cleanup ../dao-browser-feature-sidebar-cleanup mainThen it creates:
.dao/engine/worktrees/feature-sidebar-cleanup/engine
Finally, it links that private engine into the Git worktree:
../dao-browser-feature-sidebar-cleanup/engine
-> ../dao-browser/.dao/engine/worktrees/feature-sidebar-cleanup/engine
Useful options:
--branch <branch> # branch to create, defaults to <name>
--base <ref> # base ref, defaults to HEAD
--path <path> # checkout path, defaults to ../dao-browser-<name>
--refresh-cache # rebuild the warm cache before cloning it
--allow-full-copy # allow a slow full copy if CoW clone is unavailableThe command currently creates a new branch with git worktree add -b. If the
branch already exists, Git will fail before the engine is attached.
Initializes a Git worktree that was created outside the Dao helper. This package script uses shared engine mode:
npm install
npm run worktree:setup
npm run importRun it from inside the new worktree:
cd ../dao-browser-feature-from-agent
npm run setup:worktreenpm run worktree:setup auto-detects the primary checkout with:
git worktree list --porcelainIt then attaches the primary checkout engine to the current worktree:
engine -> ../dao-browser/engine
This keeps the engine path and out/dao-debug build state unchanged, so
Chromium rebuilds can reuse the primary checkout's existing cache.
If you need isolation for parallel agent builds, run the lower-level setup with
--private-engine. That reuses the primary checkout's .dao/engine warm cache
and attaches a private engine to the current worktree:
engine -> ../dao-browser/.dao/engine/worktrees/<worktree-id>/engine
Use this as the agent initialization command when the agent platform creates the Git worktree for you:
npm run setup:worktreeIf auto-detection fails, run the lower-level setup command with an explicit primary checkout:
npm install
npm run worktree:setup -- --primary /Users/moonrailgun/Develop/dao-browser
npm run importTo reattach an existing worktree to a specific warm cache, pass its cache key and explicitly recreate that worktree's private engine:
npm run worktree:setup -- \
--private-engine \
--cache-key 148.0.7778.217-dao-debug-<cache-id> \
--recreate-engine
npm run import--recreate-engine replaces only the private engine for the current worktree.
It does not delete the warm cache.
Archives private worktree engine copies. The default behavior depends on where the command is run:
- from a linked worktree, it deletes that worktree's private engine copy and
local
enginesymlink - from the primary checkout, it dry-runs stale
.dao/engine/worktrees/*directories
The command compares:
- active worktrees from
git worktree list --porcelain - each
.dao/engine/worktrees/<worktree-id>/manifest.json - active worktree
enginesymlink targets
From a linked worktree, run:
npm run archive:worktreeFrom the primary checkout, the same command is a dry run. After reviewing the
output, pass --delete to remove the stale private engine directories:
npm run archive:worktree -- --deleteFrom a non-primary worktree, pass the primary checkout explicitly if auto-detection cannot find it:
npm run archive:worktree -- --primary /Users/moonrailgun/Develop/dao-browserThe helper keeps all cache state inside the primary checkout:
dao-browser/
engine/ # primary checkout engine
.dao/
engine/
manifest.json
cache/
warm/
<cache-key>/
engine/ # warm cache cloned from engine/
worktrees/
<worktree-id>/
manifest.json
engine/ # private engine for one git worktree
.dao/ is gitignored.
The primary checkout still uses the normal root engine/. The helper does not
move it into .dao/engine/.
On macOS, the helper uses:
cp -cR <source-engine> <destination-engine>That asks APFS to create a copy-on-write clone. The clone has independent paths and can be written safely, but unchanged file data still points at the same physical disk blocks. Only blocks changed by a worker consume new space.
Copy-on-write clones save disk. They do not guarantee perfect Chromium build
cache reuse after the engine path changes. Siso and Ninja keep path-sensitive
state in out/dao-debug, so a private clone can still need broad revalidation.
Use shared engine mode when avoiding that revalidation matters more than
parallel build isolation.
On Linux, the helper uses:
cp -a --reflink=always <source-engine> <destination-engine>This requires a filesystem with reflink support, such as btrfs or supported XFS configurations.
Windows ReFS block clone is not wired yet. On Windows, the helper fails instead
of silently copying the whole engine/.
Refresh the cache when any Dao-owned build input changes and you want new workers to start from a hot engine:
npm run rebuild
npm run engine:cache:refresh -- --forceYou can also refresh during worktree creation:
npm run worktree:create -- feature/new-flow --base main --refresh-cacheExisting worktrees keep their own private engines. Refreshing the warm cache does not mutate engines already attached to worktrees.
Remove the Git worktree first:
git worktree remove ../dao-browser-feature-sidebar-cleanupThen list stale private engine copies:
npm run archive:worktreeIf you are in the primary checkout and the output looks correct, delete them:
npm run archive:worktree -- --deleteIf you are inside the linked worktree being retired, npm run archive:worktree
deletes that worktree's private engine copy immediately.
Warm caches live under .dao/engine/cache/warm/. Remove old cache-key
directories only when no active worker was cloned from them and you no longer
need that warm build state.
- Do not share one writable
engine/between multiple agents that may runnpm run importornpm run rebuildconcurrently. setup:worktreeintentionally shares the primary checkout engine for one active local agent, because it reuses the exact hot build cache.- Do not symlink every worktree to the same engine cache.
- Do not pass
--allow-full-copyunless you intentionally want a full disk copy. - Run Chromium compile confirmation through
npm run rebuild, not directautoninja,ninja,siso, orgn gen. - Keep deliverable source changes in tracked files under the Git worktree, not
only inside
engine/.