Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release
on:
workflow_dispatch:
inputs:
ref:
description: Version tag, or commit for a dry run
type: string
required: true
publish:
description: Publish the verified release
type: boolean
default: false
permissions: {}
jobs:
release:
permissions:
contents: write
actions: read
uses: computer-mcp/.github/.github/workflows/plugin-release.yml@35766b350427ed900b456aa3c39098e97d9d3aa1 # master
with:
ref: ${{ inputs.ref }}
publish: ${{ inputs.publish }}
build: Scripts/build-package.sh
ci_artifact: computer-use-plugin-${commit}
notify-catalog:
needs: release
if: inputs.publish && needs.release.outputs.published == 'true'
permissions: {}
uses: ./.github/workflows/notify-catalog.yml
secrets:
CATALOG_APP_PRIVATE_KEY: ${{ secrets.CATALOG_APP_PRIVATE_KEY }}
67 changes: 33 additions & 34 deletions Documentation/Architecture/VersioningAndRelease.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
# Versioning and Release

Release status: partly manual. CI builds and checks candidate archives on every
pull request and `master` push; tagging, acceptance and publication are manual
steps described in [Release](../Reference/Release.md).

This document owns the current version and release rules for
plugin-computer-use.
plugin-computer-use. Shared versioning, plugin compatibility, tags, release
contents and recovery rules belong to the organization's
[VERSIONING.md](https://github.com/computer-mcp/.github/blob/master/VERSIONING.md).
The [release guide](../Reference/Release.md) describes this repository's
acceptance and workflow procedure.

## Components and Version Authority

| Shipped component | Version meaning | Authoritative source | Derived fields | Update and read-only check |
| --- | --- | --- | --- | --- |
| `computer-use.zip` plugin package | SemVer 2.0.0 package version | `version` in `computer-mcp-plugin.toml` | builder receipt, tag `vX.Y.Z`, catalog entry, the App's bundled index | Edit the manifest; agreement with the tag is checked manually |

Compatible fixes advance the patch number, compatible features the minor number,
and incompatible changes the major number. Compatibility is established by
review and tests, not by comparing version numbers.
| `computer-use.zip` plugin package | Package version | `version` in `computer-mcp-plugin.toml` | builder and release receipts, version tag, catalog entry, the App's bundled index | Edit the manifest; `release.yml` checks agreement with the tag |
| Manifest and host runtime contract | Plugin API version | `plugin_api` in `computer-mcp-plugin.toml` | release receipt and host compatibility evaluation | Package tests check the declaration; `release.yml` verifies it |

The archive contains the README, contribution guide, manifest, license, notices,
`skills/` and `Documentation/`. Any change to those files ships only under a new
version; a published version is never rebuilt from different bytes. Changes to
tests, scripts or workflows alone do not change the archive and do not require a
release.
`skills/` and `Documentation/`. Changes to tests, scripts or workflows alone do
not change the archive.

## Dependencies and Verified Combinations

Expand All @@ -30,9 +25,9 @@ client and ships no runtime code. The manifest locates that client by command
name or application bundle, and the vendor owns its installation and caller
authentication.

`minimum_host` in `[compatibility]` declares the oldest Computer MCP host that
reads every manifest field this package uses. Raise it only when the package
needs a newer host contract, after validating against that host.
The manifest owns this package's plugin API declaration and host compatibility
bounds. A host-version constraint is changed only after validating the package
against the required host.

The builder needs only the Python 3.11 standard library. CI runs the tests and
build on Python 3.11 and 3.13.
Expand All @@ -41,26 +36,30 @@ build on Python 3.11 and 3.13.

`Scripts/build_package.py` verifies the plugin ID, skips hidden files and Python
caches, rejects links and special files, and produces the same archive bytes
from the same source. `Tests/test_build_package.py` pins the exact archive file
set. The builder receipt prints the ID, version and SHA-256.
from the same source. `Tests/test_build_package.py` checks the plugin API
declaration and pins the exact archive file set. The builder receipt prints the
ID, version and SHA-256.

## Candidate, Acceptance and Publication

The candidate is the CI artifact for a reviewed `master` commit. Acceptance
requires a byte-identical local rebuild, host package validation and
installation of that exact archive, and native catalog discovery with the
installed vendor client. Native actions remain subject to the vendor's caller
authentication and system permissions; acceptance records what was observed and
does not assume a working action path.
The candidate is the `computer-use-plugin-<commit>` artifact from a successful
`master` push run of `ci.yml` for a reviewed commit. Acceptance requires a
byte-identical local rebuild, host package validation and installation of that
exact archive, and native catalog discovery with the installed vendor client.
Native actions remain subject to the vendor's caller authentication and system
permissions; acceptance records what was observed and does not assume a working
action path.

A signed annotated `vX.Y.Z` tag binds the accepted commit, and the GitHub
Release publishes that exact archive with its builder receipt. Published tags
and archives are immutable; a defect is fixed in a new version. Publishing
triggers the catalog notification.
`release.yml` calls the shared release workflow with `Scripts/build-package.sh`
and this repository's exact CI artifact name. Manual acceptance results belong
in the Release notes. After verified publication, its dependent notifier calls
`notify-catalog.yml`.

The Computer MCP App bundles a copy of this package, pinned by version and
SHA-256 in the App repository's `Resources/PluginArchives/index.json`. Updating
the bundled copy is an App change made after the release is public.
SHA-256 in the App repository's `Resources/PluginArchives/index.json`. Before
the first release, the host may bundle an archive reproducibly built from an
accepted commit before that plugin version is published. A host release
requires the plugin release with the same archive digest to be public first.

## Evidence Reuse and Invalidation

Expand All @@ -74,9 +73,9 @@ affected checks again.
| Operation | Existing command or explicit manual procedure | Required access |
| --- | --- | --- |
| Version update and check | Edit `computer-mcp-plugin.toml`; `python3 -m unittest discover -s Tests -p 'test_*.py'` | Local checkout |
| Candidate validation and build | `ci.yml`; locally `Scripts/build-package.sh <new directory>` | CI or local checkout |
| Status and interrupted-run recovery | Rerun the failed CI job or check; outputs go to new directories | Repository Actions |
| Acceptance and publication | Manual steps in [Release](../Reference/Release.md) | Signing key and release write access |
| Candidate validation and build | `ci.yml`; locally `Scripts/build-package.sh <output-directory>` | CI or local checkout |
| Release verification and publication | Dispatch `release.yml`, dry run first; manual acceptance in [Release](../Reference/Release.md) | Repository Actions; publication also needs a signed tag and release write access |
| Status and interrupted-run recovery | Rerun failed workflow jobs; follow the shared recovery rules | Repository Actions |
| Cleanup | Delete local output and evidence directories | Local checkout |

CI keeps candidate artifacts for 14 days. The builder refuses to overwrite a
Expand Down
85 changes: 54 additions & 31 deletions Documentation/Reference/Release.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,64 @@
# Release

This guide covers publishing an accepted package and notifying the official
This guide covers publishing an accepted package through
[`release.yml`](../../.github/workflows/release.yml) and notifying the official
plugin catalog. [Versioning and Release](../Architecture/VersioningAndRelease.md)
owns the version, acceptance and immutability rules.
owns this repository's version and acceptance rules. The organization's
[VERSIONING.md](https://github.com/computer-mcp/.github/blob/master/VERSIONING.md)
and [release workflow guide](https://github.com/computer-mcp/.github/blob/master/Documentation/Reference/PluginRelease.md)
own the shared release contents, immutability and recovery contract.

## Prerequisite

Before the first release, the repository owner must enable GitHub release
immutability in repository settings. The release workflow checks that setting
before any Release write and refuses publication if it is disabled or cannot
be verified. Enabling it does not lock previously published releases; an
existing public release must itself be immutable to be accepted by the workflow.

## Publish

1. Confirm that `version` in `computer-mcp-plugin.toml` has not been released
and that the reviewed `master` commit has a successful CI run.
2. Download that run's `computer-use-plugin-<commit>` artifact. Rebuild the same
commit with `Scripts/build-package.sh <new directory>` and confirm the two
`computer-use.zip` files are byte-identical.
3. Validate and install that exact archive with the selected Computer MCP host,
and confirm native catalog discovery with the installed vendor client. GUI
checks use a disposable, explicitly authorized target.
and that the reviewed `master` commit has a successful `push` run of
`ci.yml`, including its `computer-use-plugin-<commit>` artifact.
2. Dispatch `release.yml` with `ref` set to that full commit SHA and `publish`
set to `false` (the default). The workflow rebuilds with
`Scripts/build-package.sh` and compares the archive bytes with the exact CI
artifact. Inspect the `plugin-release-<run-id>-<attempt>` Actions artifact:
`assets/` contains `computer-use.zip`, `release-receipt.json` and `SHA256SUMS`.
An untagged dry run reports the signed annotated tag still required for
publication.
3. Rebuild the same commit with `Scripts/build-package.sh <output-directory>`
and confirm it matches the dry-run archive. Validate and install that exact
archive with the selected Computer MCP host, and confirm native catalog
discovery with the installed vendor client. GUI checks use a disposable,
explicitly authorized target.
4. Create a signed annotated tag `vX.Y.Z` on the accepted commit and push it.
5. Create the GitHub Release for the tag with `computer-use.zip` and the CI
run's `package-receipt.json`, then publish it.
Create a draft GitHub Release for that tag, targeting the full commit SHA,
and record the manual acceptance results and their limits in its notes.
5. Dispatch `release.yml` with `ref` set to that version tag and `publish` set
to `true`. The workflow verifies the tag, manifest, CI source and archive
bytes, completes the draft's assets and publishes the verified release.
Confirm the public release is immutable and its archive digest matches the
accepted archive.

`package-receipt.json` is the builder's receipt: the plugin ID, version, archive
path and SHA-256.
The public assets are `computer-use.zip`, the shared `release-receipt.json` and
`SHA256SUMS`. CI's `package-receipt.json` remains builder evidence in the CI
artifact.

## Catalog notification

`notify-catalog.yml` runs when a release is published, edited, released,
unpublished or deleted, and on manual dispatch. It asks the website to reconcile
the complete catalog. The website verifies the actual GitHub releases rather
than the event payload, keeps verified history, and applies its own withdrawal
policy; an event never withdraws a release by itself.
`release.yml` calls `notify-catalog.yml` only when `publish` is `true` and the
shared release workflow reports `published: true`. Only the notifier job
receives the catalog App private key; the shared release workflow receives no
secret inputs. This explicit call handles publication through `GITHUB_TOKEN`,
which does not trigger release-event workflows.

`notify-catalog.yml` also runs when a release is published, edited, released,
unpublished or deleted, and on manual dispatch. It asks the website to
reconcile the complete catalog. The website verifies the actual GitHub
releases rather than the event payload, keeps verified history, and applies
its own withdrawal policy; an event never withdraws a release by itself.

The workflow authenticates as the receiver-scoped catalog GitHub App through
the `CATALOG_APP_CLIENT_ID` variable and the `CATALOG_APP_PRIVATE_KEY` secret.
Expand All @@ -40,21 +71,13 @@ The website's notification action is pinned to a reviewed full commit. Publish
that website commit first, then update the pin here when adopting a change to
the notification contract.

A release published with a repository `GITHUB_TOKEN` does not trigger
release-event workflows. Automation that publishes that way calls the workflow
as a dependent of the job that makes the release public:

```yaml
notify-catalog:
needs: publish
uses: ./.github/workflows/notify-catalog.yml
secrets:
CATALOG_APP_PRIVATE_KEY: ${{ secrets.CATALOG_APP_PRIVATE_KEY }}
```

## Retry

For an operator-driven publication or a missed or failed notification, dispatch:
For an interrupted publication, use **Re-run failed jobs** and follow the shared
workflow guide's recovery rules. If verification already succeeded, the publish
job reuses its verified bundle and digest outputs.

For a missed or failed notification, rerun only the notifier job or dispatch:

```sh
gh workflow run notify-catalog.yml --repo computer-mcp/plugin-computer-use --ref master
Expand Down
3 changes: 3 additions & 0 deletions Tests/test_build_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ def test_reproducible_owned_contents(self):
second, _ = BUILDER.package_bytes(ROOT)
self.assertEqual(first, second)
self.assertEqual(manifest["id"], "computer-use")
self.assertIs(type(manifest["plugin_api"]), int)
self.assertEqual(manifest["plugin_api"], 1)
self.assertEqual(manifest["compatibility"]["minimum_host"], "0.1.0")
with zipfile.ZipFile(io.BytesIO(first)) as archive:
self.assertEqual(set(archive.namelist()), {
"README.md", "computer-mcp-plugin.toml",
Expand Down
1 change: 1 addition & 0 deletions computer-mcp-plugin.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
id = 'computer-use'
name = 'Computer Use'
version = '0.1.0'
plugin_api = 1
description = 'Native Computer Use MCP registration and observe–act–verify guidance.'

[[dependencies]]
Expand Down
Loading