# How OpenWork Manages Multi-Profile Development with Worktree Isolation

> Learn how OpenWork uses Git worktrees and profiles for isolated development sandboxes. Discover the dev:worktree command for clean branches and dedicated ports without touching your main checkout.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: how-to-guide
- Published: 2026-08-06

---

**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`](https://github.com/different-ai/openwork/blob/main/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`](https://github.com/different-ai/openwork/blob/main/.opencode/skills/voiceover/SKILL.md) (lines 34-38), the underlying Git command creates a fresh worktree from the `dev` branch:

```bash
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`](https://github.com/different-ai/openwork/blob/main/package.json):

```bash
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`](https://github.com/different-ai/openwork/blob/main/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:

```bash
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`](https://github.com/different-ai/openwork/blob/main/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:

```bash
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`](https://github.com/different-ai/openwork/blob/main/.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:

```bash

# 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`](https://github.com/different-ai/openwork/blob/main/.opencode/skills/voiceover/SKILL.md) and keeps the main repository's parent directory organized while maintaining Git's worktree linkage.