Skill v1.0.0
currentAutomated scan100/100name: react-native-worktree description: Manage git worktrees for parallel React Native / Expo development. Covers creating worktrees (excluding native dirs), registering them with react-native-worktree, switching the device between Metro servers, and coordinating runtime access via per-platform mutex locks. user_invocable: true metadata: version: "1.0.0"
react-native-worktree — Multi-Agent Worktree Guide
You are an AI agent working on a React Native / Expo project alongside other agents. Each agent works in its own git worktree with its own Metro server. Only one agent can use the device/simulator at a time per platform. react-native-worktree handles port switching and runtime coordination.
Creating a Worktree (Lightweight)
Git worktrees share the .git object store, so they're cheap — but you should still exclude heavy generated directories that each worktree can regenerate on its own.
Expo projects with Continuous Native Generation (CNG)
If ios/ and android/ are in .gitignore (standard for CNG projects), worktrees are already lightweight — those dirs won't be copied. Just create normally:
git worktree add ../my-feature -b my-feature
Projects with tracked native directories
If ios/ and android/ are tracked in git, use sparse checkout to skip them:
# Create worktree without checking out filesgit worktree add --no-checkout ../my-feature -b my-feature# Configure sparse checkout to exclude native dirscd ../my-featuregit sparse-checkout set --no-cone '/*' '!ios/' '!android/'git checkout
This saves significant disk space and creation time. The agent can run npx expo prebuild later if it specifically needs native files.
Always exclude node_modules
node_modules/ is gitignored and never copied by worktrees. Each worktree needs its own install:
cd ../my-featurenpm install # or: yarn / bun install
Registering and Using react-native-worktree
Registering your worktree
On first run, add auto-detects the bundle ID and platforms from app.json / app.config.js and creates the config automatically. No separate init step needed.
react-native-worktree add my-feature --path /path/to/my-feature# Output: Added 'my-feature' on port 8083 (app: com.myapp)# Output: Start Metro: cd /path/to/my-feature && npx expo start --port 8083
The port is auto-assigned. If a previously registered worktree's Metro is dead, its port is reclaimed and the stale worktree entry is removed from config.
IMPORTANT: Start Metro immediately after `add`, before registering any other worktrees. Port reclamation detects dead Metro servers — if you register multiple worktrees without starting Metro, they may all get the same port. Always do add then start sequentially for each worktree:
react-native-worktree add my-feature --path /path/to/my-featurecd /path/to/my-featurenpx expo start --port 8083 # start BEFORE adding the next worktree
If Metro reports "port busy", re-run add with the same worktree name — it will reassign a new available port:
react-native-worktree add my-feature --path /path/to/my-feature# got port 8082, but Metro says it's busy:# Error: port 8082 already in usereact-native-worktree add my-feature --path /path/to/my-feature # re-add → gets port 8083npx expo start --port 8083
Multi-app projects
If you have multiple apps configured, specify which one:
react-native-worktree add my-feature --app com.myapp --path /path/to/my-feature
If only one app is configured, --app is auto-detected.
Switching the device to your worktree
react-native-worktree switch my-feature # uses first configured platformreact-native-worktree switch my-feature --platform ios # explicit platformreact-native-worktree switch my-feature --platform android # independent Android lock
This does three things atomically:
- Acquires the mutex lock for that platform (waits if another agent holds it)
- Reconfigures the device to connect to your Metro port
- Kills and relaunches the app
iOS and Android locks are independent — one agent can hold the iOS lock while another holds Android. If another agent holds the lock for your platform, the command blocks and prints Waiting for 'other-agent' to release... until the lock is freed or goes stale.
The --timeout flag controls the inactivity threshold — how long a lock can sit without a heartbeat before another agent can reclaim it. It does NOT limit how long the waiting agent will poll.
Heartbeat — keeping the lock alive
While you are actively using the device, periodically call switch again:
react-native-worktree switch my-feature --platform ios # refreshes timestamp, no app restart
This updates the lock timestamp so other agents know you're still active. If you stop calling, the lock goes stale after 60s and another agent can take over.
Releasing the device
When done testing:
react-native-worktree release --platform iosreact-native-worktree release --platform android
Always release when you're finished so other agents don't have to wait for the stale timeout. Each platform is released independently.
Checking status
react-native-worktree status # all platform locksreact-native-worktree status --platform ios # just iOSreact-native-worktree list # all apps and worktreesreact-native-worktree list --app com.myapp # filter by app
Typical Agent Workflow
# 1. Create worktree, register, and start Metro (do these sequentially — don't add another worktree until Metro is running)git worktree add ../feat-auth -b feat-authcd ../feat-authnpm installreact-native-worktree add feat-auth --path $(pwd)# note the assigned port from outputnpx expo start --port <assigned-port> # start Metro IMMEDIATELY after add# 2. When you need the device to preview your workreact-native-worktree switch feat-auth --platform ios# device restarts connected to your Metro# 4. Keep the lock alive while user is testingreact-native-worktree switch feat-auth --platform ios # heartbeat every ~20s# 5. Release when donereact-native-worktree release --platform ios# 6. Clean up when branch is mergedcd /path/to/maingit worktree remove ../feat-auth
CRITICAL: Lock Before Any Device Operation
You MUST call `react-native-worktree switch <name> --platform <platform>` and hold the lock BEFORE any operation that touches the simulator or emulator. This includes:
- Taking screenshots of the app
- Reading simulator/emulator logs
- Running
xcrun simctlcommands - Running
adbcommands against the device - Any UI testing or visual inspection
- Launching or restarting the app
If you do not hold the lock, another agent may switch the device out from under you at any moment, causing your operation to hit the wrong app state or fail entirely. Always acquire first, then interact with the device.
Important Rules
- Never use Expo Go. Always build and use the actual development client with the correct bundle ID. Expo Go does not support
RCT_jsLocationswitching or custom native modules. Only use Expo Go if the user explicitly asks for it. - Build and install the app if needed. If the app is not already installed on the simulator/emulator, build and install it first:
- iOS:
npx expo run:ios(builds with the correct bundle ID and installs on the simulator) - Android:
npx expo run:android(builds with the correct package name and installs on the emulator) - Only one worktree needs to build — the binary is shared across all worktrees since only the Metro port changes.
- Lock before touching the device. Every
xcrun simctl,adb, screenshot, or log read requires you to hold the lock for that platform. No exceptions. - Always release the lock when you're done with the device. Don't hog it.
- Start Metro before switching.
react-native-worktree switchwarns if Metro isn't running on your port, but it still acquires the lock. - Don't force-take the lock. If another agent holds it, wait. The mutex exists to prevent app thrashing.
- Heartbeat if holding long. If you hold the lock for more than a few seconds, call
switchagain periodically to avoid the inactivity timeout (default 60s). - One port per worktree. Don't change ports after registration. Other agents rely on the mapping.
- `--timeout` is the inactivity threshold, not a wait limit. It controls how long a lock survives without heartbeats. The waiting agent polls forever until the lock is free.
- iOS and Android are independent. You can hold both platform locks simultaneously if needed, and two different agents can hold different platform locks at the same time.
- Port reuse is automatic. When adding a worktree without
--port, dead Metro ports are reclaimed. You don't need to manage port numbers manually.