How to Set Up CI/CD for OpenWork Development: A Complete Guide
To set up CI/CD for OpenWork development, configure the GitHub Actions workflows under .github/workflows/, install the exact toolchain—Node 24, pnpm 11.4, Bun, and the OpenCode CLI—and run the same test, build, and publish commands defined in ci-tests.yml and the specialized package pipelines.
This guide explains how to set up CI/CD for OpenWork development using the existing automation in the different-ai/openwork repository. The project defines its entire delivery cycle under .github/workflows/, ensuring every push or pull request to the dev branch is linted, tested, and built before it reaches production.
How OpenWork CI/CD Is Structured
All workflow definitions live in the .github/workflows/ directory on the dev branch. The primary entry point for continuous integration is .github/workflows/ci-tests.yml, which triggers on every push and pull request.
Several focused workflows complement the main pipeline:
ci-tests.yml— Installs Node 24, pnpm 11.4, Bun, and the OpenCode CLI; caches the pnpm store; and executes unit, integration, and end-to-end tests across workspace packages.ci-openwork-ui-mcp.yml— Lints, type-checks, and performs a dry-run publish for theopenwork-ui-mcppackage.ci-i18n.yml— Extracts and validates internationalization strings.ci-no-new-eval-flows.yml— Blocks accidental additions of new eval flow files.ci-enterprise-mcp-mock.yml— Verifies the enterprise-MCP mock implementation when present.release-macos-aarch64.ymlandrelease-daytona-snapshot.yml— Build and sign production binaries or Docker images.
Together these files provide a complete CI/CD cycle for OpenWork development.
The Core Test Pipeline in ci-tests.yml
The primary workflow triggers on every push or pull request to the dev branch. It begins by installing the required toolchain, including the OpenCode CLI whose version is read from constants.json. The job then caches the pnpm store using keys derived from pnpm-lock.yaml and evals/pnpm-lock.yaml before executing tests.
Build, Test, and Packaging Stages
The CI run follows a strict five-stage sequence:
- Build and lint — Verify syntax and run static analysis.
- Unit tests — Run package-level suites for
@openwork/app,openwork-server,@openwork/desktop, and the eval runner. - Integration and end-to-end tests — Execute
pnpm --filter @openwork/app test:e2e. - Packaging — Build server plugins exactly as the production bundle does via
pnpm --filter openwork-server build. - Publish readiness — When a Git tag matching
openwork-ui-mcp-v*is pushed, the corresponding workflow publishes to npm using theNPM_TOKENsecret.
This sequence ensures that code merged into dev is linted, tested, and buildable before it reaches users.
Specialized and Release Workflows
Beyond the main pipeline, dedicated workflows enforce quality gates and manage releases.
Lint and Publish Checks for openwork-ui-mcp
The .github/workflows/ci-openwork-ui-mcp.yml file targets the openwork-ui-mcp package specifically. It runs node --check, performs a type-check, and executes npm publish --dry-run on every relevant change. If the commit is tagged with a version string like openwork-ui-mcp-v*, the workflow performs a real publish to the npm registry.
Guardrails and i18n Validation
The .github/workflows/ci-i18n.yml workflow extracts translation keys and fails if i18n rules are violated. Meanwhile, .github/workflows/ci-no-new-eval-flows.yml acts as a guardrail by ensuring no eval flow files are added unintentionally, keeping the repository’s evaluation surface stable.
Production Release Automation
Release workflows such as .github/workflows/release-macos-aarch64.yml handle signing and packaging for macOS on Apple Silicon, while .github/workflows/release-daytona-snapshot.yml produces Docker snapshots. These jobs run outside the standard dev branch PR flow and are triggered by release tags or manual dispatch.
Mirror the OpenWork CI Environment Locally
To reproduce the exact environment used by the GitHub Actions runners, run the same installation and verification steps locally. This is the fastest way to debug a failing job before pushing to the dev branch.
# 1. Clone the repository and checkout the dev branch
git clone https://github.com/different-ai/openwork.git
cd openwork
git checkout dev
# 2. Install the exact Node version (24) – you can use nvm or asdf
nvm install 24 && nvm use 24
# 3. Install pnpm (matches the CI version)
npm i -g pnpm@11.4.0
# 4. Install the OpenCode CLI (the same binary the CI downloads)
# The version is read from constants.json; the script below mirrors the CI logic.
OPENCODE_GITHUB_REPO=${OPENCODE_GITHUB_REPO:-anomalyco/opencode}
VERSION=$(node -p "require('./constants.json').opencodeVersion.replace(/^v/, '')")
ARCH=$(uname -m)
case "$(uname -s)" in
Linux) [[ $ARCH == aarch64 || $ARCH == arm64 ]] && ASSET=opencode-linux-arm64.tar.gz || ASSET=opencode-linux-x64-baseline.tar.gz ;;
Darwin) [[ $ARCH == arm64 ]] && ASSET=opencode-darwin-arm64.zip || ASSET=opencode-darwin-x64-baseline.zip ;;
*) echo "Unsupported OS"; exit 1 ;;
esac
curl -L -o opencode.$ASSET "https://github.com/${OPENCODE_GITHUB_REPO}/releases/download/v${VERSION}/${ASSET}"
# Extract and put the binary on PATH (same as CI)
mkdir -p $HOME/.opencode/bin
if [[ $ASSET == *.tar.gz ]]; then tar -xzf opencode.$ASSET -C $HOME/.opencode/bin; else unzip -q opencode.$ASSET -d $HOME/.opencode/bin; fi
export PATH=$HOME/.opencode/bin:$PATH
# 5. Verify the CLI
opencode --version
# 6. Install Bun (used by some scripts)
curl -fsSL https://bun.sh/install | bash
export PATH=$HOME/.bun/bin:$PATH
bun --version
# 7. Install project dependencies (cached in CI)
pnpm install --frozen-lockfile --prefer-offline
# 8. Install the eval workspace (same as CI)
pnpm --dir evals install --frozen-lockfile --prefer-offline
# 9. Run the same test lanes as CI
pnpm --dir evals run spec # eval specs
pnpm --filter @openwork/app test # app unit tests
pnpm --filter openwork-server test # server unit tests
pnpm --filter @openwork/desktop test # desktop unit tests
pnpm test:eval-runner # eval-runner unit tests
pnpm check:outbound-access # outbound-access manifest check
pnpm --filter openwork-server build # build server plugins (type-check)
pnpm --filter @openwork/desktop typecheck:electron
pnpm --filter @openwork/app test:e2e # e2e tests
Running these commands reproduces the same environment and verification steps executed on GitHub Actions. If a test fails locally, it will fail in CI, allowing you to fix issues before opening a pull request.
Customize and Extend Your OpenWork CI/CD
You can tune the pipeline to match evolving project needs without breaking the existing flow.
- Update Node or pnpm versions — Edit the
node-versionfields in.github/workflows/ci-tests.yml,.github/workflows/ci-openwork-ui-mcp.yml, and related files, then bump your local environment withnvmorasdf. - Add a new workspace package to CI — Append a
pnpm --filter <pkg>command to the job steps inci-tests.yml, or create a new workflow that follows the pattern of.github/workflows/ci-openwork-ui-mcp.yml. - Adjust caching logic — The pnpm store cache key is based on
pnpm-lock.yamlandevals/pnpm-lock.yaml. If you introduce a new lock file, include it in the cache key hash in the workflow YAML. - Trigger an npm release — Push a Git tag that matches the
openwork-ui-mcp-v*pattern. Theci-openwork-ui-mcp.ymlworkflow will detect the tag and publish the package using the repository secretNPM_TOKEN.
Summary
- OpenWork CI/CD is orchestrated through GitHub Actions under
.github/workflows/, with.github/workflows/ci-tests.ymlserving as the main pipeline for thedevbranch. - The CI toolchain requires Node 24, pnpm 11.4, Bun, and the OpenCode CLI, whose version is pinned in
constants.json. - The pipeline covers build, unit tests, integration tests, end-to-end tests (
pnpm --filter @openwork/app test:e2e), server plugin builds (pnpm --filter openwork-server build), and npm publishing. - Specialized workflows enforce i18n compliance, prevent new eval flows, and handle macOS and snapshot releases.
- You can replicate the entire CI environment locally by running the installation and test commands exactly as defined in the workflows.
Frequently Asked Questions
What versions of Node, pnpm, and Bun does the OpenWork CI use?
The OpenWork CI runners currently use Node 24, pnpm 11.4, and the latest Bun release installed via the official install script. These versions are hard-coded in .github/workflows/ci-tests.yml and .github/workflows/ci-openwork-ui-mcp.yml, so local development should match them exactly to avoid lock file or runtime discrepancies.
How can I reproduce a failing OpenWork CI job on my machine?
Clone the dev branch, install the toolchain using the same commands found in .github/workflows/ci-tests.yml, and run the test lane that failed. The bash script above downloads the identical OpenCode CLI binary and executes pnpm install --frozen-lockfile --prefer-offline followed by the relevant pnpm --filter test and build commands.
Which Git tag format triggers npm publishing in OpenWork?
Pushing a tag that matches the pattern openwork-ui-mcp-v* triggers the publish job inside .github/workflows/ci-openwork-ui-mcp.yml. The workflow first runs npm publish --dry-run on every commit, but only performs the live publish to npm when it detects a matching tag and the NPM_TOKEN secret is available.
Where does OpenWork CI store its cache keys?
The pnpm store is cached using keys derived from the contents of pnpm-lock.yaml and evals/pnpm-lock.yaml. If either lock file changes, the cache is invalidated and dependencies are reinstalled. Adjust the actions/cache step in the workflow files if you add additional lock files to the repository.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →