How OpenWork Manages Multi-Profile Development with Worktree Isolation

OpenWork couples Git worktrees with environment variable profiles to create isolated development sandboxes, using the dev:worktree command to spawn fresh branches with dedicated ports and mock keychains while keeping the main checkout untouched.

OpenWork, an open-source project maintained by different-ai, solves the friction of parallel development by treating each feature branch as a self-contained profile backed by a Git worktree. This architecture ensures that developers can run multiple Electron instances simultaneously without port conflicts or credential leakage.

The Profile-Worktree Architecture

OpenWork isolates each development session by binding a Git worktree to a unique profile identifier. When you invoke the dev:worktree script defined in package.json, the system executes a sequence that keeps your main repository clean while spinning up a fully configured development environment.

According to the source code in .opencode/skills/voiceover/SKILL.md (lines 34-38), the underlying Git command creates a fresh worktree from the dev branch:

git worktree add ../_worktrees/openwork-<slug> -b feat/<slug> origin/dev

This places the new worktree in a sibling directory to your main repository, naming the branch feat/<slug> while tracking origin/dev. The result is a pristine checkout where you can build, test, or demo without affecting your primary working directory.

Setting Up an Isolated Development Profile

You have two pathways to initialize a profile: using the automated helper or manually configuring the environment.

Using the dev:worktree Command

The simplest method leverages the NPM script defined in package.json:

pnpm dev:worktree

This command automatically creates the worktree, derives a profile name, and launches the Electron application with isolated resources. By default, OpenWork sets OPENWORK_DEV_PROFILE=auto, which computes a deterministic name based on the worktree directory path, as documented in README.md (lines 88-95).

Manual Worktree Creation with Custom Profiles

For explicit control over the profile name and ports, set the environment variables before running the standard dev command:

OPENWORK_DEV_PROFILE=my-feature \
OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0 \
PORT=0 pnpm dev

The value 0 tells OpenWork to auto-assign free ports, preventing collisions with other running instances.

Resource Isolation Mechanisms

Each profile receives its own sandboxed resources, ensuring that concurrent development sessions remain independent.

Port Assignment and CDP Endpoints

OpenWork automatically allocates dedicated ports for each profile through three key environment variables defined in README.md (lines 94-100):

  • OPENWORK_ELECTRON_REMOTE_DEBUG_PORT – The Chrome DevTools Protocol (CDP) port for debugging the Electron renderer
  • PORT – The Vite development server port
  • OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN – Forces the use of an in-memory keychain rather than macOS Keychain

When the application starts, it prints a banner to the console showing the profile name and CDP endpoint:


[openwork] dev profile=my-feature cdp=http://127.0.0.1:9223

This makes it trivial to attach external debugging tools to the correct instance.

Keychain and Credential Isolation

By default, new profiles activate the mock keychain (OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1), starting with an empty credential store. This prevents cross-contamination between features that require authentication and ensures that macOS system keychain prompts only appear when explicitly requested.

To disable the mock and use the real macOS keychain for a specific profile:

OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=0 pnpm dev:worktree

Profile Name Resolution

The OPENWORK_DEV_PROFILE variable accepts either explicit strings or the special value auto. When set to auto, OpenWork analyzes the worktree directory path to generate a stable, deterministic identifier. This guarantees that returning to the same worktree directory always resumes the same logical profile, preserving port assignments and keychain state across sessions.

If a second instance attempts to acquire a profile lock already held by another process, OpenWork aborts immediately rather than leaving orphaned ports open, ensuring graceful handling of resource contention.

Under the Hood: Worktree Creation

The orchestration logic in .opencode/agents/orchestrator.md coordinates the worktree lifecycle. When triggered for demo-driven development, the orchestrator ensures that the target worktree exists and is synchronized with origin/dev before launching the application stack.

This integration means you can run the following workflow repeatedly without manual cleanup:


# Create and enter a new worktree manually

git worktree add ../_worktrees/openwork-feature -b feat/feature origin/dev
cd ../_worktrees/openwork-feature

# Launch with auto-profile detection

OPENWORK_DEV_PROFILE=auto pnpm dev

Inside this worktree, all standard OpenWork commands respect the isolated environment, allowing you to build the demo or run tests from a known baseline without touching your main checkout.

Summary

  • Git worktrees provide filesystem isolation by creating linked working trees from the dev branch in sibling directories like ../_worktrees/openwork-<slug>.
  • Environment profiles derive stable names from worktree paths when OPENWORK_DEV_PROFILE=auto, ensuring consistent resource allocation across sessions.
  • Port safety is enforced through OPENWORK_ELECTRON_REMOTE_DEBUG_PORT and PORT variables, with each profile receiving dedicated CDP and Vite endpoints.
  • Credential isolation uses OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 by default, keeping the macOS keychain clean until explicitly requested.
  • Contention handling prevents port collisions by aborting duplicate profile acquisitions rather than spawning orphaned processes.

Frequently Asked Questions

What happens if two instances try to use the same profile?

OpenWork detects profile lock contention and aborts the second instance immediately. This prevents orphaned ports and ensures that only one process controls a given profile's resources at a time, maintaining the integrity of the isolation boundary.

Can I use the real macOS keychain instead of the mock?

Yes. Set OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=0 when launching your profile. By default, the dev:worktree command enables the mock keychain for safety, but you can override this to test credential flows against the actual macOS Keychain.

How does OpenWork determine port numbers for each profile?

When you set PORT=0 or OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0, OpenWork automatically discovers available free ports on your system. The specific port numbers are then tied to the profile name, ensuring that returning to the same worktree always reconnects to the same ports.

Where are the worktree directories created?

By convention, OpenWork creates worktrees in a sibling directory to your main repository, specifically at ../_worktrees/openwork-<slug>. This path is referenced in .opencode/skills/voiceover/SKILL.md and keeps the main repository's parent directory organized while maintaining Git's worktree linkage.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →