How to Configure Multiple Dev Profiles for Parallel Git Worktree Development in OpenWork
OpenWork supports isolated development instances by pairing each git worktree with its own dev profile, automatically managing Electron user-data directories, ports, and app identifiers.
The OpenWork desktop application enables sophisticated parallel development workflows through environment-driven dev profiles. Each profile isolates Electron's user-data storage, Vite dev-server ports, and CDP debug endpoints—allowing multiple worktrees to run simultaneously without conflicts. This article explains how to configure these profiles using the OPENWORK_DEV_PROFILE environment variable and the built-in auto-detection system.
Understanding Dev Profiles in OpenWork
A dev profile determines three critical isolation boundaries:
- User-data directory: Where Electron stores cookies, keychain entries, and caches
- Vite development server port:
PORTenvironment variable - Chrome DevTools Protocol port:
OPENWORK_ELECTRON_REMOTE_DEBUG_PORT
According to the OpenWork source code, profiles are resolved in apps/desktop/electron/dev-profile.mjs through the resolveUserDataPath function (line 41), which constructs the path as ${appDataPath}/${appIdentifier}.
Automatic Profile Detection with auto Mode
When you run pnpm dev:worktree, the script (defined in package.json line 7) automatically configures:
OPENWORK_DEV_MODE=1
OPENWORK_DEV_PROFILE=auto # derives stable profile from worktree path
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1
OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0 # dynamic CDP port selection
PORT=0 # dynamic Vite port selection
The auto mode uses deriveAutoDevProfileName (line 18 of dev-profile.mjs) to hash the absolute worktree path, producing a deterministic name in the format <hint>-<hash>. The resolveAppIdentifier function (line 31) then builds the final app identifier from this value.
Manual Profile Configuration
For explicit control, supply a custom profile name:
OPENWORK_DEV_PROFILE=my-feature pnpm dev
This bypasses auto-detection and uses your chosen identifier directly. The profile name propagates through:
process.env.OPENWORK_DEV_PROFILE— read inmain.mjs(line 134) asdevProfileresolveAppIdentifier— constructsAPP_IDENTIFIERas${BASE_APP_IDENTIFIER}.dev.${profileName}- Electron app initialization — applies the identifier to window titles, dock icons, and user-data paths
Step-by-Step: Running Parallel Worktrees
Follow this workflow to develop multiple features simultaneously:
- Create worktrees from your repository:
git worktree add ../_worktrees/feat-a feat/a
git worktree add ../_worktrees/feat-b feat/b
- Launch first instance with auto-profile:
cd ../_worktrees/feat-a
OPENWORK_DEV_PROFILE=auto pnpm dev
- Launch second instance with custom profile:
cd ../_worktrees/feat-b
OPENWORK_DEV_PROFILE=feat-b pnpm dev
Each instance starts with isolated state. The console banner (printed near line 202 of main.mjs) confirms the active profile:
[openwork] dev profile=feat-b cdp=http://127.0.0.1:9223
Technical Implementation Details
| Component | Source Location | Function |
|---|---|---|
| Environment setup | package.json line 7 |
dev:worktree script sets base variables |
| Profile derivation | apps/desktop/electron/dev-profile.mjs |
deriveAutoDevProfileName, resolveAppIdentifier |
| App initialization | apps/desktop/electron/main.mjs line 134 |
Reads devProfile, configures mock keychain |
| Port allocation | main.mjs lines 261-263 |
Dynamic port selection with use-mock-keychain |
| Worktree exclusion | .gitignore lines 22-24 |
Excludes _worktrees/ and .worktrees/ directories |
Key Security and Isolation Features
Mock keychain enforcement: OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 prevents macOS credential dialogs by substituting an in-memory keychain implementation—critical for automated testing and parallel instances.
Deterministic auto-naming: The hash-based profile generation ensures the same worktree path always receives the same profile, preserving cookies and cache across restarts while remaining distinct from other worktrees.
Dynamic port binding: Both PORT=0 and OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0 trigger automatic free-port selection, eliminating manual port management.
Summary
- Environment variable:
OPENWORK_DEV_PROFILEcontrols profile selection—useautofor path-based hashing or any custom string - Auto-detection: Hashes absolute worktree path to produce stable, unique profile names via
deriveAutoDevProfileName - Isolation guarantees: Separate user-data directories, ports, and app identifiers prevent cross-contamination between instances
- Mock keychain: Automatically enabled in dev mode to avoid system credential prompts
- Source files: Configuration flows through
package.json→dev-profile.mjs→main.mjs
Frequently Asked Questions
What happens if I don't set OPENWORK_DEV_PROFILE?
The application may use a default profile that shares user-data with other instances, causing session conflicts and port collisions. Always use auto or an explicit name when running parallel worktrees.
Can I use the same profile name across different worktrees?
Avoid this—identical profile names result in shared Electron user-data directories (${appDataPath}/${appIdentifier}), which causes cookie leakage and state corruption between your development contexts.
How does OpenWork handle keychain access on macOS?
In dev mode, OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 enables a mock keychain via Electron's use-mock-keychain command-line switch (implemented in main.mjs lines 261-263). This prevents system security dialogs while maintaining credential storage functionality.
Where is profile data stored on my system?
resolveUserDataPath in dev-profile.mjs (line 41) constructs the path as ${appDataPath}/${appIdentifier}, where appIdentifier incorporates your profile name. On macOS this typically resolves to ~/Library/Application Support/openwork.dev.<profile>/.
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 →