How to Configure OpenWork Environment Variables and Dev Profiles: A Complete Guide

Set OPENWORK_DEV_MODE=1 and use OPENWORK_DEV_PROFILE to isolate Electron user data, CDP ports, and credentials across worktrees.

OpenWork uses a purpose-built environment variable system to manage local development workflows, particularly when running multiple Git worktrees or isolating sensitive credentials. This article explains every variable, how the dev profile system works under the hood, and the exact commands for common scenarios based on the different-ai/openwork source code.

Core Environment Variables

OpenWork recognizes six primary environment variables that control development behavior. These are defined across .env.dev, package.json scripts, and the Electron main process.

Variable Purpose Default Defined In
OPENWORK_DEV_MODE Enables built-in dev mode with profile logic 1 .env.dev
OPENWORK_DEV_PROFILE Selects the dev profile (auto, custom name, or unset) unset (legacy fallback) [package.json](https://github.com/different-ai/openwork/blob/dev/package.json#L7)
OPENWORK_ELECTRON_REMOTE_DEBUG_PORT CDP port for Chrome DevTools Protocol 0 (auto-select) [package.json](https://github.com/different-ai/openwork/blob/dev/package.json#L7)
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN Uses isolated mock keychain instead of OS keychain 1 (dev worktrees) [package.json](https://github.com/different-ai/openwork/blob/dev/package.json#L7)
OPENWORK_ELECTRON_DISABLE_PROTOCOL_REGISTRATION Prevents custom URL protocol registration 1 (tests) dev-profile.test.mjs
OPENWORK_ELECTRON_USERDATA Direct override for Electron user-data directory unset dev-profile.test.mjs

In apps/desktop/electron/main.mjs, the Electron main process reads process.env.OPENWORK_DEV_PROFILE and logs the resolved profile path at startup. The OPENWORK_ELECTRON_USERDATA variable takes precedence over profile-based paths when explicitly set.

How the Dev Profile System Works

When you launch pnpm dev, OpenWork prints a diagnostic banner:

[openwork] dev profile=/Users/you/.openwork/dev-<hash> cdp=http://127.0.0.1:9223

The profile directory stores isolated Chromium data: cookies, localStorage, IndexedDB, and credential caches. This isolation prevents collisions between developers or branches.

The CDP endpoint (9223 in the example) exposes Chrome DevTools Protocol for remote debugging, automated browser testing, or external tooling like browser_navigate and browser_snapshot.

Profile Naming Modes

  • auto: Hashes the current Git worktree path to generate a stable, unique directory per checkout. Ideal for parallel worktree development.
  • Custom name (e.g., my-feature): Creates a deterministic, reusable profile. Useful for CI pipelines or persistent debugging sessions.
  • Unset: Falls back to a legacy identifier derived from the project name. Not recommended for multi-worktree setups.

The mock keychain (OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1) prevents macOS keychain authorization prompts during development. Disable it only when testing real OAuth flows that require OS credential storage.

Common Development Workflows

Single Checkout Development

Run the standard dev server with shared profile state:

pnpm dev

No additional environment configuration required. Uses legacy profile fallback.

Parallel Worktree Development

Run multiple worktrees simultaneously with fully isolated profiles and auto-assigned ports:

pnpm dev:worktree

This script in package.json automatically sets:

OPENWORK_DEV_PROFILE=auto
OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1

Named Profile with Custom Settings

Create a deterministic profile for reproducible paths or CI:

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

Setting PORT=0 allows Vite to select a free port, preventing collisions with other instances.

Real System Keychain for OAuth Testing

When authenticating against live providers that require OS-level credential storage:

OPENWORK_DEV_PROFILE=auth-test \
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=0 \
pnpm dev

Capturing the CDP Endpoint Programmatically

Extract the Chrome DevTools URL for external tooling:


# Start dev server and capture CDP URL

export CDP_URL=$(pnpm run -s print-cdp 2>/dev/null || echo "http://127.0.0.1:9223")

# Use in Node.js script

node -e "
const CDP = require('chrome-remote-interface');
CDP({ target: '$CDP_URL' })
  .then(client => {
    const { Network, Page } = client;
    return Page.navigate({ url: 'https://example.com' });
  })
  .catch(console.error);
"

Key Source Files

File Role
.env.dev Base environment values including OPENWORK_DEV_MODE and placeholder secrets
[package.json](https://github.com/different-ai/openwork/blob/dev/package.json#L7) dev:worktree script definition with auto-profile environment setup
apps/desktop/electron/main.mjs Profile resolution and startup logging
apps/desktop/electron/dev-profile.test.mjs Test suite validating profile selection, mock keychain, and protocol registration flags
[scripts/dev-web-local.sh](https://github.com/different-ai/openwork/blob/dev/scripts/dev-web-local.sh) Web-only dev server with environment propagation to Vite

Summary

  • Set OPENWORK_DEV_MODE=1 to enable the development profile system (typically pre-configured in .env.dev).
  • Use OPENWORK_DEV_PROFILE=auto for automatic isolation across Git worktrees, or assign custom names for reproducible environments.
  • The mock keychain (OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1) prevents OS prompts but must be disabled for real OAuth flows.
  • Override OPENWORK_ELECTRON_USERDATA directly when you need complete control over the Electron data directory.
  • Reference apps/desktop/electron/main.mjs for the runtime implementation and dev-profile.test.mjs for expected behavior.

Frequently Asked Questions

What happens if I don't set OPENWORK_DEV_PROFILE?

OpenWork falls back to a legacy identifier derived from the project name. This works for single-checkout development but causes state collisions when running multiple worktrees simultaneously. As implemented in different-ai/openwork, the fallback is intentionally simple to maintain backward compatibility.

Why does pnpm dev:worktree set CDP port to 0?

Setting OPENWORK_ELECTRON_REMOTE_DEBUG_PORT=0 instructs Electron to bind to any free port, preventing conflicts when multiple dev servers run concurrently. The actual port is logged in the startup banner and can be captured via the print-cdp helper or parsed from stdout.

Can I use the real macOS keychain in development?

Yes. Set OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=0 before starting the dev server. This is necessary for testing OAuth flows that require OS-level credential persistence, but expect authorization prompts and potential state sharing between profiles.

How do I completely override the profile directory?

Set OPENWORK_ELECTRON_USERDATA to an absolute path. This bypasses all OPENWORK_DEV_PROFILE logic and directs Electron to use your specified directory for all user data. According to dev-profile.test.mjs, this is primarily used in test suites for temporary directory injection.

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 →