Common Issues When Using different-ai/openwork and How to Fix Them

The most common problems with OpenWork involve development profile lock contention on Windows, UI glitches in the in-app browser, stuck loading indicators, and monorepo dependency mismatches across its Electron-MCP-Den architecture.

OpenWork is a local-first, cloud-ready desktop app that unifies AI agents, skills, and MCPs behind a single control surface. Its three-layer architecture—Electron desktop runtime, remote MCP service, and cloud-hosted Den console—creates multiple failure points where platform-specific behaviors and configuration drift cause friction. Understanding how these layers interact, and where the open-source codebase handles state and events, is essential for troubleshooting effectively.

Development Profile Locking and Port Contention

The most frequently reported startup failure occurs when pnpm dev or pnpm dev:worktree aborts with a profile lock error or CDP port conflict. OpenWork uses profile-based isolation via the OPENWORK_DEV_PROFILE environment variable to separate credentials, ports, and runtime state between development contexts.

Root Cause: Stale Lock Files

Each profile creates a lock file to prevent multiple Electron instances from sharing state. When a process crashes or exits uncleanly, the lock persists and blocks subsequent launches. The lock location defaults to ~/.openwork/dev-profile-lock unless overridden.

Solution: Force a Fresh Profile


# Remove stale lock and start with isolated profile

rm -rf ~/.openwork/dev-profile-lock
OPENWORK_DEV_PROFILE=my-feature \
OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 \
pnpm dev

The OPENWORK_DEV_PROFILE=my-feature parameter forces allocation of a new CDP port and lock file. Setting OPENWORK_ELECTRON_USE_MOCK_KEYCHAIN=1 prevents macOS keychain authorization dialogs from blocking startup—particularly useful in CI or headless environments.

Platform-Specific Runtime Issues

Windows and macOS exhibit distinct failure modes due to how Electron handles STDIO, sandboxing, and native system integrations.

Windows: Dev Server Blocking and Task Abortion

Issue #3457 documents npm run dev blocking the agent process on Windows, causing tasks to abort when the terminal remains in the foreground. This stems from Windows command-line buffering interfering with Electron's STDIO pipe handling.

Workaround: Launch through a detached console or force new process group:


# Force new console window on Windows

cmd /c start pnpm dev

# Or use cross-env to isolate environment

npx cross-env OPENWORK_DEV_PROFILE=win-dev pnpm dev

Adding --max-old-space-size=4096 to Node flags also prevents long GC pauses that compound the blocking behavior.

In-App Browser: Right-Click and Passkey Hangs

Issue #3459 reports non-functional right-click menus and multi-minute passkey prompt hangs in the embedded Chromium browser. The root cause lies in contextIsolation settings and missing contextmenu event registration in the renderer preload.

Fix in preload script (apps/desktop/src/electron/preload.ts):

const { contextBridge, ipcRenderer } = require('electron');

// Expose safe API to renderer
contextBridge.exposeInMainWorld('openwork', {
  showContextMenu: (x: number, y: number) => 
    ipcRenderer.send('show-context-menu', { x, y })
});

Fix in renderer (apps/desktop/src/renderer/browser.ts):

window.addEventListener('contextmenu', (e) => {
  e.preventDefault();
  // Forward to main process for native menu
  window.openwork.showContextMenu(e.clientX, e.clientY);
});

For passkey hangs, ensure navigator.credentials polyfills are loaded before WebAuthn requests, or disable passkey auto-prompt via OPENWORK_SKIP_PASSKEY=1.

Stuck Session Loading Indicator

Issue #3462 describes the loading spinner persisting after task completion. The bug resides in apps/desktop/src/renderer/loading.tsx where the runTask promise lacks guaranteed cleanup.

Correct pattern:

// loading.tsx
async function runTask(task: () => Promise<void>): Promise<void> {
  setLoading(true);
  try {
    await task();
  } catch (err) {
    setError(err);
    throw err;
  } finally {
    setLoading(false); // Guaranteed execution
  }
}

The finally block ensures setLoading(false) runs regardless of success or failure, eliminating the stuck spinner state.

MCP and Remote Service Connectivity

OpenWork's Model-Control-Plane exposes search_capabilities and execute_capability tools via https://api.openworklabs.com/mcp/agent. Failures here typically manifest as "MCP tool not found" or timeout errors in Claude Code, Codex, or Cursor integrations.

Common Causes

  • Stale API key in dev profile credentials
  • CORS rejection from custom Den deployments
  • Version mismatch between local client and remote MCP schema

Debugging Steps


# Verify MCP endpoint health

curl -H "Authorization: Bearer $OPENWORK_API_KEY" \
  https://api.openworklabs.com/mcp/agent/health

# Test capability search locally

npx openwork-cli mcp search --query "file-ops"

The CLI source in packages/mcp/src/index.ts implements the client-side protocol; check MCPClient.searchCapabilities() and executeCapability() method signatures when building custom integrations.

Dependency and Build Tool Conflicts

OpenWork uses pnpm workspaces with Turborepo for build orchestration. Dependency bumps—especially in postcss, vite, or turbo—frequently break builds when lock files desynchronize across packages.

Symptoms

  • Module not found errors after pulling main
  • turbo cache corruption causing stale builds
  • Type conflicts between workspace package versions

Resolution Workflow


# From repository root

rm -rf node_modules **/node_modules pnpm-lock.yaml
pnpm install          # Regenerate unified lock

pnpm run build        # Verify full build

pnpm turbo run dev --filter=@openwork/desktop

Critical: Always run pnpm install at the monorepo root, never in individual package directories. The pnpm-workspace.yaml defines workspace boundaries; violating this causes phantom dependency resolution.

Per-Session Agent Selection Drift

A subtle configuration issue occurs when the per-session agent selector fails to persist across window reloads. This relates to how apps/desktop/src/electron/main.ts serializes session state to the profile's session.json.

Ensure your dev profile has write permissions:


# Check profile directory permissions

ls -la ~/.openwork/profiles/$OPENWORK_DEV_PROFILE/

# Reset session state if corrupted

rm ~/.openwork/profiles/$OPENWORK_DEV_PROFILE/session.json

Summary

  • Profile locks: Delete ~/.openwork/dev-profile-lock and use unique OPENWORK_DEV_PROFILE values to isolate development contexts
  • Windows blocking: Launch via cmd /c or detached process to prevent STDIO deadlock
  • Browser UI: Register contextmenu listeners in renderer and preload; disable passkey auto-prompt if needed
  • Loading states: Always place setLoading(false) in finally blocks of async task runners
  • Dependencies: Run pnpm install exclusively from repository root after any version bumps

Frequently Asked Questions

Why does OpenWork hang on startup with "profile locked" error?

The previous Electron instance did not shut down cleanly, leaving a stale lock file in ~/.openwork/dev-profile-lock. Remove this file or specify a new OPENWORK_DEV_PROFILE environment variable to force creation of a fresh lock and CDP port allocation.

How do I fix right-click menus in the embedded browser?

The in-app browser requires explicit contextmenu event handling. Register a listener in your renderer process that prevents the default chromium menu and communicates with the main process via contextBridge to display native menus. Ensure contextIsolation is properly configured in the preload script.

What causes the loading spinner to stay active after tasks complete?

The async task runner in loading.tsx lacks guaranteed cleanup. Move setLoading(false) into a finally block so it executes regardless of whether the task succeeds, fails, or throws—matching the pattern shown in the fixed implementation above.

How should I update dependencies in the OpenWork monorepo?

Always run pnpm install from the repository root, never in individual package directories. This ensures pnpm-lock.yaml stays synchronized across all workspaces defined in pnpm-workspace.yaml. After major bumps, clear node_modules and the lock file entirely before reinstalling.

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 →