# How to Contribute to the Openwork Project: A Complete Developer Guide

> Learn how to contribute to the Openwork project with this developer guide. Fork the repo, set up the dev environment, implement features, add tests, and submit your pull request.

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

---

**To contribute to Openwork, fork the repository on GitHub, install dependencies with `pnpm install`, launch the dev environment using `pnpm dev`, implement your feature in the relevant package, write end-to-end tests in `evals/specs/`, and submit a pull request against the `dev` branch.**

Openwork is a modular, open-source platform maintained by different-ai that combines an Electron desktop client, a Node.js/TypeScript backend, and a cloud control plane called **Den**. This guide walks you through the exact steps to set up your local environment, navigate the monorepo architecture, and submit contributions that meet the project's quality standards.

## Understanding the Openwork Architecture

Before writing code, familiarize yourself with the three-tier **client-server-control-plane** pattern. The codebase is organized as a monorepo using **pnpm workspaces** to share type-safe TypeScript utilities across packages.

**Desktop UI (Electron + React):** The user interface lives in `packages/ui/` and renders inside an Electron shell. Key entry points include [`packages/ui/src/react/platform-detect.ts`](https://github.com/different-ai/openwork/blob/main/packages/ui/src/react/platform-detect.ts) for OS/architecture detection and [`apps/ui-demo/vite.config.ts`](https://github.com/different-ai/openwork/blob/main/apps/ui-demo/vite.config.ts) for the Vite development server configuration.

**Server API (Node.js):** The local backend in `apps/server/src/` persists workspace data, manages plugins, and exposes the MCP (Multi-Capability Protocol). Critical files include [`apps/server/src/server.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/server.ts) for booting the HTTP server and [`apps/server/src/workspaces.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspaces.ts) for workspace CRUD operations.

**Den (Control Plane):** This cloud-hosted layer handles model provisioning, team management, and policy enforcement. The bridge between your local server and Den is implemented in [`apps/server/src/cloud-plugins.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/cloud-plugins.ts), which forwards MCP calls to the remote endpoint at `https://api.openworklabs.com/mcp/agent`.

## Setting Up Your Development Environment

Start by forking the repository and cloning your fork locally. Openwork requires **pnpm** for dependency management.

Install all dependencies from the repository root:

```bash
pnpm install

```

This command automatically links workspace packages between the UI and server, ensuring a single source of truth for shared types.

## Running the Development Environment

Openwork provides two commands for local development. For standard development, run:

```bash
pnpm dev

```

This starts the Vite UI dev server on `http://localhost:5173` and launches Electron with Chrome DevTools Protocol (CDP) access available on `http://127.0.0.1:9223`.

For isolated feature branch development, use:

```bash
pnpm dev:worktree

```

This creates a separate dev profile with isolated state, useful when working on parallel features without conflicts. For CI environments, the project also provides [`scripts/dev-headless-web.ts`](https://github.com/different-ai/openwork/blob/main/scripts/dev-headless-web.ts) to launch a headless Electron instance.

## Contributing Code: Step-by-Step Workflow

### 1. Implement UI Changes

Modify React components under `packages/ui/src/`. Reference [`packages/ui/src/react/platform-detect.ts`](https://github.com/different-ai/openwork/blob/main/packages/ui/src/react/platform-detect.ts) for examples of cross-platform TypeScript patterns that detect OS and CPU architecture.

### 2. Extend Server Capabilities

Add routes or database models under `apps/server/src/`. The main entry point is [`apps/server/src/server.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/server.ts), where you wire new HTTP routes and MCP registrations.

### 3. Add New MCP Skills

To expose new capabilities to AI agents, define your skill in [`apps/server/src/skills.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/skills.ts):

```typescript
// apps/server/src/skills.ts
export const myNewSkill = {
  name: "my-new-skill",
  description: "Does something useful",
  execute: async (input: any) => {
    // your logic here
    return { result: "done" };
  },
};

```

Register the skill in the server entry point:

```typescript
// apps/server/src/server.ts
import { myNewSkill } from "./skills";

mcp.registerSkill(myNewSkill);

```

### 4. Write End-to-End Tests

Openwork requires **slow specs**—full-stack tests using `@openwork/testkit`—to validate complete user scenarios. Place these in `evals/specs/` using the [`.slow.test.ts`](https://github.com/different-ai/openwork/blob/main/.slow.test.ts) suffix. This ensures the CI stays green and guarantees that hidden tests will pass.

Example test structure:

```typescript
// evals/specs/my-new-skill.slow.test.ts
import { test, expect } from "@openwork/testkit";

test("my-new-skill works end-to-end", async ({ client }) => {
  const result = await client.executeCapability("my-new-skill", { foo: "bar" });
  expect(result).toMatchObject({ result: "done" });
});

```

Reference [`evals/specs/first-run-local.slow.test.ts`](https://github.com/different-ai/openwork/blob/main/evals/specs/first-run-local.slow.test.ts) for a complete example validating a fresh local installation.

### 5. Run the Test Suite

Verify your changes locally before submitting:

```bash
pnpm test        # Runs unit tests

pnpm test:slow   # Executes full-stack specs (uses Daytona when available)

```

All tests must pass before opening a pull request.

### 6. Submit Your Pull Request

Push your branch to your fork and open a PR against the `dev` branch. The CI automatically runs the test suite and generates a **testkit evidence tape**; ensure this tape is attached to your PR for human verification.

## Key Source Files Reference

Keep these entry points bookmarked when navigating the codebase:

- **[`apps/server/src/server.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/server.ts)** – Backend entry point for HTTP routes and MCP registration
- **[`apps/server/src/skills.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/skills.ts)** – Central registry for MCP-exposed capabilities
- **[`apps/server/src/workspaces.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspaces.ts)** – Workspace CRUD operations and data models
- **[`apps/server/src/cloud-plugins.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/cloud-plugins.ts)** – Bridge to the Den control plane
- **[`packages/ui/src/react/platform-detect.ts`](https://github.com/different-ai/openwork/blob/main/packages/ui/src/react/platform-detect.ts)** – Cross-platform detection utilities
- **[`evals/specs/first-run-local.slow.test.ts`](https://github.com/different-ai/openwork/blob/main/evals/specs/first-run-local.slow.test.ts)** – Example end-to-end test implementation

## Summary

- Openwork uses a monorepo structure with pnpm workspaces linking the Electron UI, Node server, and shared types
- Run `pnpm dev` for standard development or `pnpm dev:worktree` for isolated profiles
- Implement UI changes in `packages/ui/src` and server logic in `apps/server/src`
- Register new MCP skills in [`apps/server/src/skills.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/skills.ts) and expose them via [`server.ts`](https://github.com/different-ai/openwork/blob/main/server.ts)
- Write slow specs in `evals/specs/` to validate full-stack functionality and satisfy hidden test requirements
- Execute `pnpm test` and `pnpm test:slow` locally before submitting PRs to the `dev` branch

## Frequently Asked Questions

### What is the Openwork Den?

The **Den** is Openwork's cloud-hosted control plane that manages organization-wide settings, model provider credentials, and marketplace content. According to the different-ai/openwork source code, it exposes a single MCP endpoint at `https://api.openworklabs.com/mcp/agent` that local servers communicate with via [`apps/server/src/cloud-plugins.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/cloud-plugins.ts) when remote capabilities are required.

### Do I need to write tests for every contribution?

Yes. The project requires end-to-end coverage using `@openwork/testkit`. You must add slow specs in `evals/specs/` that exercise the complete flow of your changes. This practice ensures the CI remains green and verifies that your code satisfies hidden tests not visible in the local test runner.

### What is the difference between pnpm dev and pnpm dev:worktree?

`pnpm dev` starts the UI and server in a shared development profile suitable for most changes, accessible at `http://localhost:5173` with CDP debugging on port `9223`. `pnpm dev:worktree` creates an isolated profile with separate state, which is essential when working on parallel features or long-running branches that might conflict with each other.

### How do I debug the Electron client?

When running `pnpm dev`, the console prints a banner like `[openwork] dev profile=… cdp=http://127.0.0.1:9223`. Navigate to this URL in Chrome to attach DevTools and debug the Electron process directly, or use the headless script at [`scripts/dev-headless-web.ts`](https://github.com/different-ai/openwork/blob/main/scripts/dev-headless-web.ts) for CI debugging.