How OpenWork's `pnpm dev:worktree` Enables Git Worktree-Based Local Development
OpenWork's pnpm dev:worktree command uses Git worktrees with environment variables to spawn isolated Electron development instances from a single repository checkout, each with unique user-data directories, auto-allocated debug ports, and mock keychain isolation.
OpenWork's local development workflow centers on pnpm dev:worktree, a script that enables developers to run multiple independent desktop app instances without separate repository clones. This approach leverages Git worktrees to keep branches isolated while sharing a single .git history, then uses environment-driven profile isolation to prevent Electron state conflicts between parallel runs.
What pnpm dev:worktree Actually Does
The script is defined in the root package.json as follows:
"dev:worktree": "OPENWORK_DEV_MODE=1 OPENWORK_DEV_PROFILE=auto OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=${OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN:-1} OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0 PORT=0 pnpm --filter @openwork/desktop dev"
This single command sets up four key behaviors:
OPENWORK_DEV_MODE=1— Signals the Electron app to run in development build modeOPENWORK_DEV_PROFILE=auto— Triggers automatic profile name generation based on worktree path (implemented inapps/desktop/electron/dev-profile.mjs)OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1— Prevents macOS keychain dialogs during developmentOPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0&PORT=0— Requests dynamic port allocation for Chrome DevTools Protocol and Vite dev-server
How Profile Isolation Works
Automatic Profile Name Generation
In apps/desktop/electron/dev-profile.mjs, the deriveAutoDevProfileName function creates a stable profile identifier from the worktree's filesystem path. This ensures that returning to the same worktree directory always yields the same profile, while different worktrees get distinct profiles.
The resolveUserDataPath function then constructs an isolated directory:
~/.config/openwork/<profile-name>/
This directory houses Electron's storage, cookies, cache, and keychain state—completely separating parallel development instances.
Port Allocation for Debugging
Both debug and dev-server ports use zero-value placeholders that trigger probing logic in apps/desktop/electron/main.mjs. The findFreeCdpPort function (lines 215-236) scans from 9223 upward to locate an available port, then prints the result in the startup banner:
[openwork] dev profile=/home/user/.config/openwork/feature-xyz cdp=http://127.0.0.1:9224
Running Multiple Worktree Instances
Basic Worktree Setup
Create and enter a new worktree, then launch an isolated dev instance:
# Create worktree for a feature branch
git worktree add -b feature-xyz ../openwork-feature-xyz feature-xyz
cd ../openwork-feature-xyz
# Launch with auto-generated profile
pnpm dev:worktree
Custom Profile Names for Scripts
Override the automatic naming when you need deterministic paths for automation:
OPENWORK_DEV_PROFILE=my-demo pnpm dev:worktree
This creates ~/.config/openwork/my-demo/, making the profile easy to reference from CI pipelines or test scripts.
Preventing Conflicts Between Instances
The implementation includes safeguards against common development friction:
-
Mock keychain on macOS: When
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1, the startup code inmain.mjs(around line 92) appends--use-mock-keychainto Electron's command line, eliminating the "Login" keychain modal that would otherwise block headless or automated runs. -
Single-instance enforcement: If a second process attempts to use an already-active profile, the app detects the lock file and exits cleanly with an explanatory message. This prevents the confusing scenario where a CDP port remains open but no window is visible.
-
Parallel debugging: Each instance exposes its own CDP endpoint, enabling simultaneous Chrome DevTools or OpenCode agent connections to multiple running apps.
Attaching Debug Tools to a Worktree Instance
After pnpm dev:worktree starts, use the printed CDP URL to connect automation tools:
# Example: connect OpenCode agent to the running instance
pnpm exec -- openwork-agent --connect http://127.0.0.1:9224
This integration supports the fraimz proof workflow, where agents drive the Electron UI, execute automation tasks, and capture screenshots without interfering with other active development sessions.
Key Source Files
| File | Purpose |
|---|---|
package.json |
Defines the dev:worktree script with environment variable preset |
apps/desktop/electron/dev-profile.mjs |
Implements deriveAutoDevProfileName and resolveUserDataPath for stable profile derivation |
apps/desktop/electron/main.mjs |
Handles port probing (findFreeCdpPort, lines 215-236), mock keychain flags (line 92), and startup banner output (line 247) |
Summary
pnpm dev:worktreecombines Git worktrees with environment variables to enable parallel, isolated Electron development from one repository- Auto-generated profiles create stable, path-based user-data directories in
~/.config/openwork/ - Dynamic port allocation ensures each instance gets unique CDP and Vite ports without manual configuration
- Mock keychain and lock-file detection prevent macOS dialogs and duplicate-instance crashes
- Custom profile names via
OPENWORK_DEV_PROFILEsupport deterministic paths for CI and automation
Frequently Asked Questions
What is a Git worktree and why does OpenWork use it?
A Git worktree is a linked working directory that shares the same repository history but checks out a different branch. OpenWork uses worktrees so developers can keep multiple feature branches open simultaneously—each with its own filesystem state—without cloning the repository multiple times or constantly switching branches.
How does OpenWork prevent worktree instances from interfering with each other?
Each pnpm dev:worktree invocation generates or uses a unique profile name that determines Electron's user-data directory. Stored state—including cookies, local storage, and application cache—is written to ~/.config/openwork/<profile>/, ensuring complete isolation. Additionally, lock files prevent the same profile from running twice.
Can I use pnpm dev:worktree without creating an actual Git worktree?
Yes. The script functions in any directory; OPENWORK_DEV_PROFILE=auto derives a profile from the current path. However, the workflow is designed for worktrees—using it in the main repository checkout produces a profile based on that path, which may not provide meaningful isolation if you're not using separate directories.
Why does the mock keychain default to enabled in worktree mode?
macOS keychain access triggers a system modal dialog that blocks unattended or automated development sessions. Defaulting OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN to 1 ensures pnpm dev:worktree runs headlessly-friendly without manual intervention, critical for CI pipelines and agent-driven workflows like fraimz proof generation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →