> ## Documentation Index
> Fetch the complete documentation index at: https://browser-mcp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Build, release, and documentation

> Verify both editions, publish immutable artifacts, and configure documentation hosting deliberately.

## Publication status

The source repository remains **private**. The Helm chart is intended for public distribution through a dedicated Cloudflare R2 bucket; publishing the chart must not make the source repository public. The repository contains release automation, not evidence of an already-live product. An operator must configure permissions, actual upstream URLs, and hosting before publishing. Chrome Web Store registration/submission and Mintlify account setup are separate owner-controlled actions, not performed by these workflows.

## Checks

`.github/workflows/ci.yml` runs on pull requests and main, and is reused by releases:

* Independently installs root and frontend dependencies with frozen Bun lockfiles.
* Type-checks, migrates an isolated PostgreSQL database, and tests **both** build-time editions.
* Builds both server artifacts and smoke-tests the bundled migration entrypoint, health/readiness endpoints, and selected `/api/config` edition.
* Builds both Docker editions without pushing.
* Builds the MV3 extension, validates its ZIP/manifest, and uploads a short-lived CI artifact configured for localhost.
* Runs strict Helm lint and render contract tests for bundled/external databases, managed secrets, migration startup gating, namespaces, Ceph storage, and unsafe-value rejection.
* Tests the exact R2 publish script with fake AWS/GitHub endpoints: historical retention, index-last upload, repeatability, immutable-version rejection, and fail-closed storage errors.

Run chart tests locally:

```bash theme={null}
python3 -m venv /tmp/browser-mcp-chart-tests
/tmp/browser-mcp-chart-tests/bin/pip install -r charts/browser-mcp/tests/requirements.txt
/tmp/browser-mcp-chart-tests/bin/python charts/browser-mcp/tests/render_test.py
/tmp/browser-mcp-chart-tests/bin/python .github/tests/r2_publish_test.py
```

These tests do not create a namespace or deploy workloads. Server-side admission dry-runs require an already-existing dedicated namespace and explicit cluster access; they are separate from CI render tests.

## Release images and extension

Before creating a stable `vX.Y.Z` tag:

1. Keep `package.json` version, chart version, chart `appVersion`, and extension manifest version aligned.
2. Require green checks and protect release tags from mutation.
3. Set the repository Actions variable `EXTENSION_MANAGED_URL` to the actual canonical HTTPS managed upstream origin. The release workflow rejects missing/local origins. This value is public build configuration, not an OAuth secret.
4. Permit `GITHUB_TOKEN` to publish packages and releases. No separate GHCR personal token is required.

The release workflow produces separate community/managed images under `ghcr.io/<owner>/<repository>` with version tags such as `0.1.0-community`, `0.1.0-managed`, and full commit tags `sha-<commit>-<edition>`. It refuses to overwrite tags that already exist, and fails closed on registry errors other than a missing manifest. There are no mutable `latest` aliases. Pin the resulting digest in production.

Images target Linux amd64 and arm64 and include provenance/SBOM attestations. After image publication, the workflow builds the extension using the configured upstream, uploads its ZIP/checksum as an Actions artifact, and attaches them to a GitHub release. It does not submit to the Chrome Web Store. Protect against partial failures: if an image tag already published but a later job failed, do not overwrite the image; inspect the run and rerun only the uncompleted downstream job or issue a new version.

## Public Helm repository on Cloudflare R2

An authorized owner creates a dedicated R2 chart bucket, configures its public HTTPS endpoint/custom domain, and grants a bucket-scoped read/write S3 API credential. The source repository remains private. There is no GitHub Pages configuration and no branch switching.

Configure these Actions secrets (repository-wide or in the `helm-repository` environment):

| Secret                  | Purpose                                  |
| ----------------------- | ---------------------------------------- |
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account owning the R2 bucket. |
| `R2_ACCESS_KEY_ID`      | Bucket-scoped R2 S3 API access key ID.   |
| `R2_SECRET_ACCESS_KEY`  | Corresponding secret access key.         |

Configure Actions variables `R2_CHART_BUCKET` (bucket name) and `R2_CHART_PUBLIC_URL` (actual public HTTPS base URL). These are not Cloudflare global API tokens; use R2's S3-compatible credentials. Restrict publishing to trusted release refs and, preferably, require approval on the `helm-repository` environment.

The release workflow packages the chart once and attaches its archive/checksum to the private stable release. `.github/workflows/publish-chart.yml` downloads and verifies those exact archives, downloads the existing public chart packages/index through the authenticated S3 API, rejects changed bytes for an existing version, and merges the index. It uploads **only chart archives and `index.yaml`**, packages first and index last. No `--delete` is used, so historical packages are retained even if a private release is removed. Reusing archives preserves digests; do not replace assets or mutate tags.

A shared workflow concurrency group serializes chart publication. Do not run a separate writer against the same bucket: GitHub concurrency does not lock external tools. Credentials/network errors fail closed rather than being treated as an empty bucket. The owner must configure public bucket access; S3 API credentials do not themselves create a public endpoint.

The release workflow explicitly calls the chart workflow after publishing the release (events created with `GITHUB_TOKEN` do not trigger another workflow). Human-published releases and manual workflow dispatch are also supported. Once the public endpoint is verified:

```bash theme={null}
helm repo add browser-mcp <actual-r2-public-url>
helm repo update
helm search repo browser-mcp
```

No specific R2 endpoint or domain is presumed live. GitHub release assets remain private with the repository, and GHCR visibility must be deliberately configured by the owner or consumers need image pull credentials. A public chart does not automatically make its container image or extension ZIP public.

## Mintlify documentation

The docs configuration is `docs/docs.json`; content is local MDX with navigation links. Preview from that directory using Mintlify's CLI:

```bash theme={null}
cd docs
npx mint@latest dev
```

For validation:

```bash theme={null}
cd docs
npx mint@latest validate
npx mint@latest broken-links
```

To publish, an authorized owner must connect the GitHub repository in Mintlify and select `docs/` as the docs directory, then configure any domain in the provider's dashboard. A local preview does not publish a site. No paid plan or live documentation URL is assumed.

`docs/architecture.md` is the internal implementation contract and is not part of public navigation. Keep public documentation aligned with `shared/tools.ts`, the extension manifest, and the artifact actually released.

## Kubernetes deployment automation

These workflows publish images, extension release assets, and the public R2 Helm repository; they do **not** deploy Browser MCP to Kubernetes. If an operator later adds an r5d deployment workflow, it must use GitHub OIDC via `ricsam/r5d-cluster-auth@v1` with `contents: read` and `id-token: write`, register the exact trusted workflow, server-dry-run intended manifests, and verify rollouts. Do not introduce long-lived kubeconfig or R5D token secrets. Registry authentication remains separate.
