# OpenWork Release Process: Complete Workflow Guide

> Master the OpenWork release process with this complete workflow guide. Learn how pnpm scripts manage review, prepare, and ship phases for seamless versioning and distribution.

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

---

**OpenWork’s release workflow follows a three-phase process—review, prepare, and ship—controlled by pnpm scripts in `scripts/release/` that validate workspace consistency, bump versions, create lightweight Git tags, and trigger GitHub Actions builds for cross-platform desktop app distribution.**

The [different-ai/openwork](https://github.com/different-ai/openwork) repository manages its deployment pipeline through a sophisticated CLI-driven workflow designed for reliability and team coordination. Understanding the **release process for OpenWork** requires examining the three root scripts located under `scripts/release/` that orchestrate everything from version validation to GitHub release publication.

## The Three-Phase Release Workflow

The entire release process for OpenWork is driven by three distinct phases executed through pnpm commands. Each phase is implemented as a Node.js script in the `scripts/release/` directory.

### Phase 1: Review (`pnpm release:review`)

The **review phase** validates that the workspace is ready for a version bump. Running `pnpm release:review` executes the `scripts/release/review.mjs` script to perform two critical checks:

- Verifies that version numbers across the workspace are consistent
- Confirms that the `opencode` pin is present in the repository

This step must succeed before proceeding to the prepare phase. It acts as a gatekeeper to prevent releasing from an inconsistent state.

### Phase 2: Prepare (`pnpm release:prepare`)

The **prepare phase** handles version bumping, commit creation, and tag generation. Implemented in `scripts/release/prepare.mjs`, this script performs several validation and mutation steps:

1. **Tool-chain validation** – Ensures the pinned pnpm version matches [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json)’s `packageManager` field
2. **Git state checks** – Verifies you are on the `dev` branch with a clean working tree
3. **Synchronization** – Executes a pull-rebase against `origin/dev` to ensure the latest changes are present
4. **Version bump** – Runs `pnpm bump:<patch|minor|major>` to increment version numbers and regenerate the lockfile
5. **Commit and tag** – Creates a commit with the message `chore: bump version to …` and generates a **lightweight** tag `vX.Y.Z`

The script temporarily disables global `tag.gpgsign` settings to avoid annotation problems during tag creation. Importantly, this phase is **idempotent**—if a bump commit already exists but the tag is missing, rerunning `pnpm release:prepare` resumes directly at the tagging step without duplicating work.

For testing changes without mutation, use the dry-run variant:

```bash
pnpm release:prepare:dry

```

All actions in this phase occur locally; no pushes occur to the remote repository at this stage.

### Phase 3: Ship (`pnpm release:ship`)

The **ship phase** pushes artifacts to the remote and triggers the CI/CD pipeline. The `scripts/release/ship.mjs` script executes:

- Pushes the newly created tag to `origin`
- Attempts to synchronize the `dev` branch (which is protected)
- If direct push is rejected due to branch protection, creates a temporary branch `release/<tag>-dev-sync` and opens a **back-fill PR** for team approval
- Prints the URL to the "Release App" GitHub Actions workflow and the GitHub release page

To monitor the workflow execution in real-time:

```bash
pnpm release:ship:watch

```

## GitHub Actions Automation

Once the ship phase pushes a tag, the [`.github/workflows/release-macos-aarch64.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/release-macos-aarch64.yml) workflow automatically triggers. This workflow:

- Builds the Electron desktop application for macOS, Windows, and Linux
- Publishes the build assets to GitHub
- Executes the "Publish GitHub Release" step to transition the release from draft to public

The release is considered **complete** only when this workflow succeeds and the GitHub release is no longer in draft state. The full documentation for this automation resides in [`docs/RELEASING.md`](https://github.com/different-ai/openwork/blob/main/docs/RELEASING.md).

## Branch Protection and Release Strategies

The **release process for OpenWork** accommodates two distinct strategies based on team permissions and urgency.

**Tag-First (Admin Shortcut)**

Administrators can execute `pnpm release:prepare` followed immediately by `pnpm release:ship` to create and push a tag directly, bypassing the normal PR merge workflow. This works because tags matching `v*` are admin-bypassable in the repository settings.

**PR-First (Standard Flow)**

The standard approach merges a bump PR into `dev` before shipping. The `dev` branch enforces strict protection rules:
- Pull-request-only updates
- Required approvals from a different person than the pusher
- Signed commit requirements
- Linear history enforcement

These guarantees ensure only reviewed code reaches subsequent releases.

## Idempotency and Recovery

The release scripts are designed for resilience. If `pnpm release:prepare` crashes after committing but before tagging, rerunning the command resumes at the tagging step without creating duplicate commits.

If a defective tag is created, recovery involves:

1. Deleting the draft release on GitHub
2. Removing the local tag: `git tag -d vX.Y.Z`
3. Rerunning the prepare and ship commands

To manually retry a failed workflow without creating a new tag:

```bash
gh workflow run "Release App" --repo different-ai/openwork -f tag=v0.18.15

```

## Summary

- OpenWork uses three pnpm commands (`release:review`, `release:prepare`, `release:ship`) orchestrated by scripts in `scripts/release/`
- The prepare phase in `scripts/release/prepare.mjs` creates lightweight tags and is idempotent, resuming at tagging if interrupted
- The ship phase in `scripts/release/ship.mjs` handles protected branch constraints by creating temporary `release/<tag>-dev-sync` branches and back-fill PRs when direct pushes fail
- Releases trigger via the [`.github/workflows/release-macos-aarch64.yml`](https://github.com/different-ai/openwork/blob/main/.github/workflows/release-macos-aarch64.yml) workflow only after tag push, building cross-platform Electron assets
- Complete release documentation exists in [`docs/RELEASING.md`](https://github.com/different-ai/openwork/blob/main/docs/RELEASING.md)

## Frequently Asked Questions

### What is the release process for OpenWork?

The release process for OpenWork consists of three phases: review (validation), prepare (bump and tag), and ship (push and sync). These are executed via `pnpm release:review`, `pnpm release:prepare`, and `pnpm release:ship` commands that validate workspace state, create lightweight Git tags, and trigger GitHub Actions builds.

### How does OpenWork handle version bumping and tagging?

Version bumping occurs in `scripts/release/prepare.mjs`, which validates the toolchain, checks git state, performs the bump, regenerates lockfiles, commits changes, and creates a lightweight tag named `vX.Y.Z`. The script disables `tag.gpgsign` temporarily to ensure lightweight tags are created correctly and is idempotent to allow recovery from interruptions.

### What happens if the dev branch is protected during release?

If `pnpm release:ship` cannot push directly to the protected `dev` branch, it automatically creates a temporary branch named `release/<tag>-dev-sync` and opens a back-fill pull request. This allows a teammate to approve the synchronization, ensuring compliance with branch protection rules requiring reviews and signed commits.

### How can I retry a failed release without creating a new version?

You can manually trigger the release workflow for an existing tag using the GitHub CLI: `gh workflow run "Release App" --repo different-ai/openwork -f tag=vX.Y.Z`. This avoids unnecessary version bumps when the issue was with the CI/CD pipeline rather than the code itself.