# How to Set Up Continuous Integration for OpenWork: A Complete GitHub Actions Guide

> Learn to set up continuous integration for OpenWork using GitHub Actions. Automate your testing across Linux and macOS with this complete guide.

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

---

**OpenWork uses GitHub Actions to automatically run its full test suite on every push and pull request to the `dev` branch, with workflows defined in `.github/workflows/` that support cross-platform testing on Linux and macOS.**

Setting up continuous integration for the OpenWork repository ensures that code changes are validated across multiple platforms before merging. According to the different-ai/openwork source code, the CI pipeline is entirely self-contained within workflow files, making it easy to replicate or extend for forks and custom deployments.

## The Core CI Architecture: [`.github/workflows/ci-tests.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-tests.yml)

The main test matrix lives in [[`.github/workflows/ci-tests.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-tests.yml)](https://github.com/different-ai/openwork/blob/dev/.github/workflows/ci-tests.yml). This file orchestrates the entire validation process through a **matrix execution strategy** that runs on both `blacksmith-4vcpu-ubuntu-2204` and `macos-14` runners.

### Cross-Platform Matrix Configuration

The matrix is declared under `strategy.matrix.os` and ensures OpenWork functions correctly on both Linux and macOS environments. This catches platform-specific issues early, particularly important for the Electron desktop application and native binary dependencies.

## Toolchain Bootstrap Process

Each CI job performs a consistent toolchain setup in four stages:

1. **Node.js 24** via `actions/setup-node`

2. **pnpm 11.4.0** via `pnpm/action-setup`

3. **OpenCode CLI** fetched dynamically based on [`constants.json`](https://github.com/different-ai/openwork/blob/main/constants.json) — the CI reads `require('./constants.json').opencodeVersion`, downloads the matching release binary for the runner OS/architecture, extracts it, and adds it to `$PATH`

4. **Bun** via `oven-sh/setup-bun`

### OpenCode CLI Installation (Self-Contained)

The CI includes a custom step to fetch the correct OpenCode binary without hardcoding versions:

```yaml
- name: Install OpenCode CLI
  run: |
    version=$(node -p "require('./constants.json').opencodeVersion")
    curl -L "https://github.com/anomalyco/opencode/releases/download/v${version}/opencode-linux-x64-baseline.tar.gz" | tar -xz -C $HOME/.opencode
    echo "$HOME/.opencode" >> $GITHUB_PATH

```

This pattern keeps the CLI version synchronized across all CI runs and local development environments.

## Cache Management for Fast CI Runs

The pipeline aggressively caches dependencies using `actions/cache` with keys derived from both [`pnpm-lock.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-lock.yaml) and [`evals/pnpm-lock.yaml`](https://github.com/different-ai/openwork/blob/main/evals/pnpm-lock.yaml). This eliminates redundant network requests and reduces typical install times from minutes to seconds on cache hits.

Dependency installation uses strict reproducibility flags:

```bash
pnpm install --frozen-lockfile --prefer-offline

```

The `evals` workspace is installed separately after the main monorepo dependencies resolve.

## The Full Test Execution Pipeline

The CI runs eight distinct validation stages in sequence:

- **Eval specs** — `pnpm --dir evals run test:pr` validates end-to-end specifications

- **Unit tests** — `pnpm --filter @openwork/app test`, `pnpm --filter @openwork/server test`, and `pnpm --filter @openwork/desktop test` cover each package

- **Release script tests** — `node --test scripts/release/*.test.mjs` verifies automation logic

- **Eval runner tests** — `pnpm test:eval-runner` checks the evaluation infrastructure

- **Outbound-access manifest check** — `pnpm check:outbound-access` validates network permissions

- **Server plugin bundling** — Mirrors production builds with `--target node`

- **Electron IPC type-checking** — `pnpm --filter @openwork/desktop typecheck:electron` catches contract mismatches

- **E2E UI tests** — `pnpm --filter @openwork/app test:e2e` exercises the full application

## Result Aggregation with Required Checks

A sentinel job named `openwork-tests-required` depends on the matrix job and runs `if: always()` to guarantee execution. It fails the workflow if any matrix leg failed, providing a single required check that branch protection rules can target. This abstraction hides matrix complexity from repository settings.

## Additional Specialized Workflows

Beyond the main test matrix, OpenWork includes focused workflows for specific concerns:

- **[`.github/workflows/ci-openwork-ui-mcp.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-openwork-ui-mcp.yml)** — Validates MCP UI integration

- **[`.github/workflows/ci-no-new-eval-flows.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-no-new-eval-flows.yml)** — Prevents accidental addition of new evaluation flows

- **[`.github/workflows/ci-i18n.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-i18n.yml)** — Runs localization validation

These execute in parallel to the main matrix and add targeted guards without slowing the critical path.

## Minimal CI Setup for Forks or New Projects

To set up continuous integration for OpenWork in your own repository, commit the workflow files to `.github/workflows/`. GitHub Actions automatically discovers and executes them—no additional configuration required.

### Copy-Pasteable Minimal Workflow

```yaml
name: OpenWork CI – Minimal Example
on:
  push:
    branches: [dev]
  pull_request:
    branches: [dev]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 24

      - uses: pnpm/action-setup@v4
        with:
          version: 11.4.0

      - name: Install OpenCode CLI
        run: |
          version=$(node -p "require('./constants.json').opencodeVersion")
          curl -L "https://github.com/anomalyco/opencode/releases/download/v${version}/opencode-linux-x64-baseline.tar.gz" | tar -xz -C $HOME/.opencode
          echo "$HOME/.opencode" >> $GITHUB_PATH

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Run unit tests
        run: pnpm test

```

## Running OpenWork CI Locally

Execute the same validation scripts used in CI on your development machine:

```bash

# Clone and enter repository

git clone https://github.com/different-ai/openwork.git
cd openwork

# Install pnpm if needed

npm i -g pnpm

# Reproduce CI install exactly

pnpm install --frozen-lockfile

# Run key validation stages

pnpm --filter @openwork/app test:e2e
pnpm --filter @openwork/desktop typecheck:electron
pnpm test:eval-runner

```

Local execution uses identical tooling versions and lockfile constraints, minimizing "works on my machine" failures.

## Key Files for CI Maintenance

| File | Purpose |
|------|---------|
| [`.github/workflows/ci-tests.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-tests.yml) | Core test matrix with platform matrix and aggregation |
| [`.github/workflows/ci-openwork-ui-mcp.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-openwork-ui-mcp.yml) | MCP UI integration validation |
| [`.github/workflows/ci-no-new-eval-flows.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-no-new-eval-flows.yml) | Eval flow addition guards |
| [`.github/workflows/ci-i18n.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-i18n.yml) | Localization checks |
| [`constants.json`](https://github.com/different-ai/openwork/blob/main/constants.json) | Single source of truth for OpenCode CLI version |
| [`pnpm-lock.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-lock.yaml) | Monorepo dependency lock for cache keys |
| [`evals/pnpm-lock.yaml`](https://github.com/different-ai/openwork/blob/main/evals/pnpm-lock.yaml) | Eval workspace dependency lock |
| `scripts/release/*.test.mjs` | Release automation test suite |

## Summary

- **Primary entry point**: [`.github/workflows/ci-tests.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/ci-tests.yml) defines the complete OpenWork CI pipeline
- **Platform coverage**: Matrix runs on Ubuntu 22.04 and macOS 14 via `strategy.matrix.os`
- **Toolchain**: Node 24, pnpm 11.4.0, Bun, and dynamically-fetched OpenCode CLI
- **Caching**: Lockfile-based pnpm store caching accelerates repeat runs
- **Validation stages**: Eight distinct test phases from unit tests through E2E UI automation
- **Required checks**: `openwork-tests-required` sentinel job enables simple branch protection
- **Zero configuration**: Workflow files alone enable full CI—no external services needed

## Frequently Asked Questions

### Does OpenWork CI require any external services beyond GitHub Actions?

No. The OpenWork continuous integration pipeline is entirely self-contained within GitHub Actions workflows. The only external dependency is the OpenCode CLI, which the CI fetches automatically from GitHub releases based on the version stored in [`constants.json`](https://github.com/different-ai/openwork/blob/main/constants.json). No third-party CI services, secrets, or infrastructure are required.

### How does OpenWork handle cross-platform testing in CI?

The [`ci-tests.yml`](https://github.com/different-ai/openwork/blob/main/ci-tests.yml) workflow uses a matrix strategy with `strategy.matrix.os` set to `[blacksmith-4vcpu-ubuntu-2204, macos-14]`. This runs all tests on both Linux and macOS runners in parallel. The OpenCode CLI installation step automatically selects the correct binary architecture for each runner platform.

### Can I run the OpenWork test suite locally without CI?

Yes. Install pnpm globally, run `pnpm install --frozen-lockfile`, then execute individual test commands like `pnpm test`, `pnpm --filter @openwork/app test:e2e`, or `pnpm test:eval-runner`. These commands use the same scripts and configuration as the CI pipeline, though local execution won't include the platform matrix coverage.

### What prevents the CI from passing if one matrix job fails?

The `openwork-tests-required` job in [`ci-tests.yml`](https://github.com/different-ai/openwork/blob/main/ci-tests.yml) runs `if: always()` and aggregates results from all matrix legs. It fails explicitly when any dependency failed, creating a single required status check that branch protection rules can enforce. This ensures partial platform success never masks comprehensive failure.