docs/reference/RELEASING.md
OpenClaw has three public release lanes:
beta by default, or to npm latest when explicitly requestedbetamainYYYY.M.D
vYYYY.M.DYYYY.M.D-N
vYYYY.M.D-NYYYY.M.D-beta.N
vYYYY.M.D-beta.Nlatest means the current promoted stable npm releasebeta means the current beta install targetbeta by default; release operators can target latest explicitly, or promote a vetted beta build laterrelease/YYYY.M.D branch created
from current main, so release validation and fixes do not block new
development on main-beta.N tag instead of deleting or recreating the old beta tagThis checklist is the public shape of the release flow. Private credentials, signing, notarization, dist-tag recovery, and emergency rollback details stay in the maintainer-only release runbook.
main: pull latest, confirm the target commit is pushed,
and confirm current main CI is green enough to branch from it.CHANGELOG.md section from real commit history with
/changelog, keep entries user-facing, commit it, push it, and rebase/pull
once more before branching.src/plugins/compat/registry.ts and
src/commands/doctor/shared/deprecation-compat.ts. Remove expired
compatibility only when the upgrade path stays covered, or record why it is
intentionally carried.release/YYYY.M.D from current main; do not do normal release work
directly on main.pnpm plugins:sync so publishable plugin packages share the release
version and compatibility metadata, then run the local deterministic preflight:
pnpm check:test-types, pnpm check:architecture,
pnpm build && pnpm ui:build, pnpm plugins:sync:check, and
pnpm release:check.OpenClaw NPM Release with preflight_only=true. Before a tag exists,
a full 40-character release-branch SHA is allowed for validation-only
preflight. Save the successful preflight_run_id.Full Release Validation for the
release branch, tag, or full commit SHA. This is the one manual entrypoint
for the four big release test boxes: Vitest, Docker, QA Lab, and Package.vYYYY.M.D-beta.N, then run OpenClaw Release Publish from
the matching release/YYYY.M.D branch. It verifies pnpm plugins:sync:check,
dispatches all publishable plugin packages to npm and the same set to
ClawHub in parallel, and then promotes the prepared OpenClaw npm preflight
artifact with the matching dist-tag as soon as plugin npm publish succeeds.
ClawHub publishing may still be running while OpenClaw npm publishes, but the
release publish workflow does not finish until both plugin publish paths and
the OpenClaw npm publish path have completed successfully. After publish, run
the post-publish package
acceptance against the published [email protected] or
openclaw@beta package. If a pushed or published prerelease needs a fix,
cut the next matching prerelease number; do not delete or rewrite the old
prerelease.OpenClaw Release Publish, reusing the successful preflight artifact via
preflight_run_id; stable macOS release readiness also requires the
packaged .zip, .dmg, .dSYM.zip, and updated appcast.xml on main.CHANGELOG.md section, and the release announcement
steps.pnpm check:test-types before release preflight so test TypeScript stays
covered outside the faster local pnpm check gatepnpm check:architecture before release preflight so the broader import
cycle and architecture boundary checks are green outside the faster local gatepnpm build && pnpm ui:build before pnpm release:check so the expected
dist/* release artifacts and Control UI bundle exist for the pack
validation steppnpm plugins:sync after the root version bump and before tagging. It
updates publishable plugin package versions, OpenClaw peer/API compatibility
metadata, build metadata, and plugin changelog stubs to match the core
release version. pnpm plugins:sync:check is the non-mutating release guard;
the publish workflow fails before any registry mutation if this step was
forgotten.Full Release Validation workflow before release approval to
kick off all pre-release test boxes from one entrypoint. It accepts a branch,
tag, or full commit SHA, dispatches manual CI, and dispatches
OpenClaw Release Checks for install smoke, package acceptance, cross-OS
package checks, QA Lab parity, Matrix, and Telegram lanes. Stable/default runs
keep exhaustive live/E2E and Docker release-path soak behind
run_release_soak=true; release_profile=full forces soak on. With
release_profile=full and rerun_group=all, it also runs package Telegram
E2E against the release-package-under-test artifact from release checks.
Provide npm_telegram_package_spec after publishing when the same
Telegram E2E should prove the published npm package too. Provide
package_acceptance_package_spec after publishing when Package Acceptance
should run its package/update matrix against the shipped npm package instead
of the SHA-built artifact. Provide
evidence_package_spec when the private evidence report should prove that the
validation matches a published npm package without forcing Telegram E2E.
Example:
gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.DPackage Acceptance workflow when you want side-channel proof
for a package candidate while release work continues. Use source=npm for
openclaw@beta, openclaw@latest, or an exact release version; source=ref
to pack a trusted package_ref branch/tag/SHA with the current
workflow_ref harness; source=url for an HTTPS tarball with a required
SHA-256; or source=artifact for a tarball uploaded by another GitHub
Actions run. The workflow resolves the candidate to
package-under-test, reuses the Docker E2E release scheduler against that
tarball, and can run Telegram QA against the same tarball with
telegram_mode=mock-openai or telegram_mode=live-frontier. When the
selected Docker lanes include published-upgrade-survivor, the package
artifact is the candidate and published_upgrade_survivor_baseline selects
the published baseline.
Example: gh workflow run package-acceptance.yml --ref main -f workflow_ref=main -f source=npm -f package_spec=openclaw@beta -f suite_profile=product -f [email protected] -f telegram_mode=mock-openai
Common profiles:
smoke: install/channel/agent, gateway network, and config reload lanespackage: artifact-native package/update/plugin lanes without OpenWebUI or live ClawHubproduct: package profile plus MCP channels, cron/subagent cleanup,
OpenAI web search, and OpenWebUIfull: Docker release-path chunks with OpenWebUIcustom: exact docker_lanes selection for a focused rerunCI workflow directly when you only need full normal CI
coverage for the release candidate. Manual CI dispatches bypass changed
scoping and force the Linux Node shards, bundled-plugin shards, channel
contracts, Node 22 compatibility, check, check-additional, build smoke,
docs checks, Python skills, Windows, macOS, Android, and Control UI i18n
lanes.
Example: gh workflow run ci.yml --ref release/YYYY.M.Dpnpm qa:otel:smoke when validating release telemetry. It exercises
QA-lab through a local OTLP/HTTP receiver and verifies the exported trace
span names, bounded attributes, and content/identifier redaction without
requiring Opik, Langfuse, or another external collector.pnpm release:check before every tagged releaseOpenClaw Release Publish for the mutating publish sequence after the
tag exists. Dispatch it from release/YYYY.M.D (or main when publishing a
main-reachable tag), pass the release tag and successful OpenClaw npm
preflight_run_id, and keep the default plugin publish scope
all-publishable unless you are deliberately running a focused repair. The
workflow serializes plugin npm publish, plugin ClawHub publish, and OpenClaw
npm publish so the core package is not published before its externalized
plugins.OpenClaw Release ChecksOpenClaw Release Checks also runs the QA Lab mock parity lane plus the fast
live Matrix profile and Telegram QA lane before release approval. The live
lanes use the qa-live-shared environment; Telegram also uses Convex CI
credential leases. Run the manual QA-Lab - All Lanes workflow with
matrix_profile=all and matrix_shards=true when you want full Matrix
transport, media, and E2EE inventory in parallel.OpenClaw Release Checks and Full Release Validation, which call the
reusable workflow
.github/workflows/openclaw-cross-os-release-checks-reusable.yml directlyFull Release Validation or from the main/release workflow ref so workflow logic and
secrets stay controlledOpenClaw Release Checks accepts a branch, tag, or full commit SHA as long
as the resolved commit is reachable from an OpenClaw branch or release tagOpenClaw NPM Release validation-only preflight also accepts the current
full 40-character workflow-branch commit SHA without requiring a pushed tagv<package.json version> only for the
package metadata check; real publish still requires a real release tagOPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache
using both OPENAI_API_KEY and ANTHROPIC_API_KEY workflow secretsRELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts
(or the matching beta/correction tag) before approvalnode --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D
(or the matching beta/correction version) to verify the published registry
install path in a fresh temp prefix[email protected] OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live
to verify installed-package onboarding, Telegram setup, and real Telegram E2E
against the published npm package using the shared leased Telegram credential
pool. Local maintainer one-offs may omit the Convex vars and pass the three
OPENCLAW_QA_TELEGRAM_* env credentials directly.pnpm release:beta-smoke -- --beta betaN. The helper runs Parallels npm update/fresh-target validation, dispatches NPM Telegram Beta E2E, polls the exact workflow run, downloads the artifact, and prints the Telegram report.NPM Telegram Beta E2E workflow. It is intentionally manual-only and
does not run on every merge.preflight_run_idmain or
release/YYYY.M.D branch as the successful preflight runbetalatest explicitly via workflow inputopenclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml
for security, because npm dist-tag add still needs NPM_TOKEN while the
public repo keeps OIDC-only publishmacOS Release is validation-only; when a tag lives only on a
release branch but the workflow is dispatched from main, set
public_release_branch=release/YYYY.M.Dpreflight_run_id and validate_run_idYYYY.M.D-N, the post-publish verifier
also checks the same temp-prefix upgrade path from YYYY.M.D to YYYY.M.D-N
so release corrections cannot silently leave older global installs on the
base stable payloaddist/control-ui/index.html and a non-empty dist/control-ui/assets/ payload
so we do not ship an empty browser dashboard againlatest.pnpm test:install:smoke also enforces the npm pack unpackedSize budget on
the candidate update tarball, so installer e2e catches accidental pack bloat
before the release publish pathplugin-prerelease-extension-shard matrix outputs from
.github/workflows/plugin-prerelease.yml before approval so release notes do
not describe a stale CI layout.zip, .dmg, and .dSYM.zipappcast.xml on main must point at the new stable zip after publishCFBundleVersion at or above the canonical Sparkle build floor
for that release versionFull Release Validation is how operators kick off all pre-release tests from
one entrypoint. For a pinned commit proof on a fast-moving branch, use the
helper so every child workflow runs from a temporary branch fixed at the target
SHA:
pnpm ci:full-release --sha <full-sha>
The helper pushes release-ci/<sha>-..., dispatches Full Release Validation
from that branch with ref=<sha>, verifies every child workflow headSha
matches the target, then deletes the temporary branch. This avoids proving a
newer main child run by accident.
For release branch or tag validation, run it from the trusted main workflow
ref and pass the release branch or tag as ref:
gh workflow run full-release-validation.yml \
--ref main \
-f ref=release/YYYY.M.D \
-f provider=openai \
-f mode=both \
-f release_profile=stable \
-f [email protected]
The workflow resolves the target ref, dispatches manual CI with
target_ref=<release-ref>, dispatches OpenClaw Release Checks, prepares a
parent release-package-under-test artifact for package-facing checks, and
dispatches standalone package Telegram E2E when release_profile=full with
rerun_group=all or when npm_telegram_package_spec is set. OpenClaw Release Checks then fans out install smoke, cross-OS release checks, live/E2E Docker
release-path coverage when soak is enabled, Package Acceptance with Telegram
package QA, QA Lab parity, live Matrix, and live Telegram. A full run is only acceptable when the
Full Release Validation
summary shows normal_ci and release_checks as successful. In full/all mode,
the npm_telegram child must also be successful; outside full/all it is skipped
unless a published npm_telegram_package_spec was provided. The final
verifier summary includes slowest-job tables for each child run, so the release
manager can see the current critical path without downloading logs.
See Full release validation for the
complete stage matrix, exact workflow job names, stable versus full profile
differences, artifacts, and focused rerun handles.
Child workflows are dispatched from the trusted ref that runs Full Release Validation, normally --ref main, even when the target ref points at an
older release branch or tag. There is no separate Full Release Validation
workflow-ref input; choose the trusted harness by choosing the workflow run ref.
Do not use --ref main -f ref=<sha> for exact commit proof on moving main;
raw commit SHAs cannot be workflow dispatch refs, so use
pnpm ci:full-release --sha <sha> to create the pinned temporary branch.
Use release_profile to select live/provider breadth:
minimum: fastest release-critical OpenAI/core live and Docker pathstable: minimum plus stable provider/backend coverage for release approvalfull: stable plus broad advisory provider/media coverageUse run_release_soak=true with stable when the release-blocking lanes are
green and you want the exhaustive live/E2E, Docker release-path, and
all-since-2026.4.23 upgrade-survivor sweep before promotion. full implies
run_release_soak=true.
OpenClaw Release Checks uses the trusted workflow ref to resolve the target
ref once as release-package-under-test and reuses that artifact in cross-OS,
Package Acceptance, and release-path Docker checks when soak runs. This keeps
all package-facing boxes on the same bytes and avoids repeated package builds.
The cross-OS OpenAI install smoke uses OPENCLAW_CROSS_OS_OPENAI_MODEL when the
repo/org variable is set, otherwise openai/gpt-5.4, because this lane is
proving package install, onboarding, gateway startup, and one live agent turn
rather than benchmarking the slowest default model. The broader live provider
matrix remains the place for model-specific coverage.
Use these variants depending on release stage:
# Validate an unpublished release candidate branch.
gh workflow run full-release-validation.yml \
--ref main \
-f ref=release/YYYY.M.D \
-f provider=openai \
-f mode=both \
-f release_profile=stable
# Validate an exact pushed commit.
gh workflow run full-release-validation.yml \
--ref main \
-f ref=<40-char-sha> \
-f provider=openai \
-f mode=both
# After publishing a beta, add published-package Telegram E2E.
gh workflow run full-release-validation.yml \
--ref main \
-f ref=release/YYYY.M.D \
-f provider=openai \
-f mode=both \
-f release_profile=full \
-f [email protected] \
-f [email protected] \
-f npm_telegram_provider_mode=mock-openai
Do not use the full umbrella as the first rerun after a focused fix. If one box
fails, use the failed child workflow, job, Docker lane, package profile, model
provider, or QA lane for the next proof. Run the full umbrella again only when
the fix changed shared release orchestration or made earlier all-box evidence
stale. The umbrella's final verifier re-checks the recorded child workflow run
ids, so after a child workflow is rerun successfully, rerun only the failed
Verify full validation parent job.
For bounded recovery, pass rerun_group to the umbrella. all is the real
release-candidate run, ci runs only the normal CI child, plugin-prerelease
runs only the release-only plugin child, release-checks runs every release
box, and the narrower release groups are install-smoke, cross-os,
live-e2e, package, qa, qa-parity, qa-live, and npm-telegram.
Focused npm-telegram reruns require npm_telegram_package_spec; full/all runs
with release_profile=full use the release-checks package artifact. Focused
cross-OS reruns can add cross_os_suite_filter=windows/packaged-upgrade or
another OS/suite filter. QA release-check failures are advisory; a QA-only
failure does not block release validation.
The Vitest box is the manual CI child workflow. Manual CI intentionally
bypasses changed scoping and forces the normal test graph for the release
candidate: Linux Node shards, bundled-plugin shards, channel contracts, Node 22
compatibility, check, check-additional, build smoke, docs checks, Python
skills, Windows, macOS, Android, and Control UI i18n.
Use this box to answer "did the source tree pass the full normal test suite?" It is not the same as release-path product validation. Evidence to keep:
Full Release Validation summary showing the dispatched CI run URLCI run green on the exact target SHA.artifacts/vitest-shard-timings.json when
a run needs performance analysisRun manual CI directly only when the release needs deterministic normal CI but not the Docker, QA Lab, live, cross-OS, or package boxes:
gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D
The Docker box lives in OpenClaw Release Checks through
openclaw-live-and-e2e-checks-reusable.yml, plus the release-mode
install-smoke workflow. It validates the release candidate through packaged
Docker environments instead of only source-level tests.
Release Docker coverage includes:
core, package-update-openai,
package-update-anthropic, package-update-core, plugins-runtime-plugins,
plugins-runtime-services,
plugins-runtime-install-a, plugins-runtime-install-b,
plugins-runtime-install-c, plugins-runtime-install-d,
plugins-runtime-install-e, plugins-runtime-install-f,
plugins-runtime-install-g, and plugins-runtime-install-hplugins-runtime-services chunk when requestedbundled-plugin-install-uninstall-0 through
bundled-plugin-install-uninstall-23Use Docker artifacts before rerunning. The release-path scheduler uploads
.artifacts/docker-tests/ with lane logs, summary.json, failures.json,
phase timings, scheduler plan JSON, and rerun commands. For focused recovery,
use docker_lanes=<lane[,lane]> on the reusable live/E2E workflow instead of
rerunning all release chunks. Generated rerun commands include prior
package_artifact_run_id and prepared Docker image inputs when available, so a
failed lane can reuse the same tarball and GHCR images.
The QA Lab box is also part of OpenClaw Release Checks. It is the agentic
behavior and channel-level release gate, separate from Vitest and Docker
package mechanics.
Release QA Lab coverage includes:
qa-live-shared environmentpnpm qa:otel:smoke when release telemetry needs explicit local proofUse this box to answer "does the release behave correctly in QA scenarios and live channel flows?" Keep the artifact URLs for parity, Matrix, and Telegram lanes when approving the release. Full Matrix coverage remains available as a manual sharded QA-Lab run rather than the default release-critical lane.
The Package box is the installable-product gate. It is backed by
Package Acceptance and the resolver
scripts/resolve-openclaw-package-candidate.mjs. The resolver normalizes a
candidate into the package-under-test tarball consumed by Docker E2E, validates
the package inventory, records the package version and SHA-256, and keeps the
workflow harness ref separate from the package source ref.
Supported candidate sources:
source=npm: openclaw@beta, openclaw@latest, or an exact OpenClaw release
versionsource=ref: pack a trusted package_ref branch, tag, or full commit SHA
with the selected workflow_ref harnesssource=url: download an HTTPS .tgz with required package_sha256source=artifact: reuse a .tgz uploaded by another GitHub Actions runOpenClaw Release Checks runs Package Acceptance with source=artifact, the
prepared release package artifact, suite_profile=custom,
docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update,
telegram_mode=mock-openai. Package Acceptance keeps migration, update, stale
plugin dependency cleanup, offline plugin fixtures, plugin update, and Telegram
package QA against the same resolved tarball. Blocking release checks use the
default latest published package baseline; run_release_soak=true or
release_profile=full expands to every stable npm-published baseline from
2026.4.23 through latest plus reported-issue fixtures. Use
Package Acceptance with source=npm for an already shipped candidate, or
source=ref/source=artifact for a SHA-backed local npm tarball before
publish. It is the GitHub-native
replacement for most of the package/update coverage that previously required
Parallels. Cross-OS release checks still matter for OS-specific onboarding,
installer, and platform behavior, but package/update product validation should
prefer Package Acceptance.
The canonical checklist for update and plugin validation is
Testing updates and plugins. Use it when
deciding which local, Docker, Package Acceptance, or release-check lane proves a
plugin install/update, doctor cleanup, or published-package migration change.
Exhaustive published update migration from every stable 2026.4.23+ package is
a separate manual Update Migration workflow, not part of Full Release CI.
Legacy package-acceptance leniency is intentionally time boxed. Packages through
2026.4.25 may use the compatibility path for metadata gaps already published
to npm: private QA inventory entries missing from the tarball, missing
gateway install --wrapper, missing patch files in the tarball-derived git
fixture, missing persisted update.channel, legacy plugin install-record
locations, missing marketplace install-record persistence, and config metadata
migration during plugins update. The published 2026.4.26 package may warn
for local build metadata stamp files that were already shipped. Later packages
must satisfy the modern package contracts; those same gaps fail release
validation.
Use broader Package Acceptance profiles when the release question is about an actual installable package:
gh workflow run package-acceptance.yml \
--ref main \
-f workflow_ref=main \
-f source=npm \
-f package_spec=openclaw@beta \
-f suite_profile=product \
-f [email protected]
Common package profiles:
smoke: quick package install/channel/agent, gateway network, and config
reload lanespackage: install/update/plugin package contracts without live ClawHub; this is the release-check
defaultproduct: package plus MCP channels, cron/subagent cleanup, OpenAI web
search, and OpenWebUIfull: Docker release-path chunks with OpenWebUIcustom: exact docker_lanes list for focused rerunsFor package-candidate Telegram proof, enable telegram_mode=mock-openai or
telegram_mode=live-frontier on Package Acceptance. The workflow passes the
resolved package-under-test tarball into the Telegram lane; the standalone
Telegram workflow still accepts a published npm spec for post-publish checks.
OpenClaw Release Publish is the normal mutating publish entrypoint. It
orchestrates the trusted-publisher workflows in the order the release needs:
main or release/*.pnpm plugins:sync:check.Plugin NPM Release with publish_scope=all-publishable and
ref=<release-sha>.Plugin ClawHub Release with the same scope and SHA.OpenClaw NPM Release with the release tag, npm dist-tag, and
saved preflight_run_id.Beta publish example:
gh workflow run openclaw-release-publish.yml \
--ref release/YYYY.M.D \
-f tag=vYYYY.M.D-beta.N \
-f preflight_run_id=<successful-openclaw-npm-preflight-run-id> \
-f npm_dist_tag=beta
Stable publish to the default beta dist-tag:
gh workflow run openclaw-release-publish.yml \
--ref release/YYYY.M.D \
-f tag=vYYYY.M.D \
-f preflight_run_id=<successful-openclaw-npm-preflight-run-id> \
-f npm_dist_tag=beta
Stable promotion directly to latest is explicit:
gh workflow run openclaw-release-publish.yml \
--ref release/YYYY.M.D \
-f tag=vYYYY.M.D \
-f preflight_run_id=<successful-openclaw-npm-preflight-run-id> \
-f npm_dist_tag=latest
Use the lower-level Plugin NPM Release and Plugin ClawHub Release workflows
only for focused repair or republish work. For a selected plugin repair, pass
plugin_publish_scope=selected and plugins=@openclaw/name to
OpenClaw Release Publish, or dispatch the child workflow directly when the
OpenClaw package must not be published.
OpenClaw NPM Release accepts these operator-controlled inputs:
tag: required release tag such as v2026.4.2, v2026.4.2-1, or
v2026.4.2-beta.1; when preflight_only=true, it may also be the current
full 40-character workflow-branch commit SHA for validation-only preflightpreflight_only: true for validation/build/package only, false for the
real publish pathpreflight_run_id: required on the real publish path so the workflow reuses
the prepared tarball from the successful preflight runnpm_dist_tag: npm target tag for the publish path; defaults to betaOpenClaw Release Publish accepts these operator-controlled inputs:
tag: required release tag; must already existpreflight_run_id: successful OpenClaw NPM Release preflight run id;
required when publish_openclaw_npm=truenpm_dist_tag: npm target tag for the OpenClaw packageplugin_publish_scope: defaults to all-publishable; use selected only
for focused repair workplugins: comma-separated @openclaw/* package names when
plugin_publish_scope=selectedpublish_openclaw_npm: defaults to true; set false only when using the
workflow as a plugin-only repair orchestratorOpenClaw Release Checks accepts these operator-controlled inputs:
ref: branch, tag, or full commit SHA to validate. Secret-bearing checks
require the resolved commit to be reachable from an OpenClaw branch or
release tag.run_release_soak: opt into exhaustive live/E2E, Docker release-path, and
all-since upgrade-survivor soak on stable/default release checks. It is forced
on by release_profile=full.Rules:
beta or latestbetaOpenClaw NPM Release, full commit SHA input is allowed only when
preflight_only=trueOpenClaw Release Checks and Full Release Validation are always
validation-onlynpm_dist_tag used during preflight;
the workflow verifies that metadata before publish continuesWhen cutting a stable npm release:
OpenClaw NPM Release with preflight_only=true
npm_dist_tag=beta for the normal beta-first flow, or latest only
when you intentionally want a direct stable publishFull Release Validation on the release branch, release tag, or full
commit SHA when you want normal CI plus live prompt cache, Docker, QA Lab,
Matrix, and Telegram coverage from one manual workflowCI workflow on the release ref insteadpreflight_run_idOpenClaw Release Publish with the same tag, the same npm_dist_tag,
and the saved preflight_run_id; it publishes externalized plugins to npm
and ClawHub before promoting the OpenClaw npm packagebeta, use the private
openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml
workflow to promote that stable version from beta to latestlatest and beta
should follow the same stable build immediately, use that same private
workflow to point both dist-tags at the stable version, or let its scheduled
self-healing sync move beta laterThe dist-tag mutation lives in the private repo for security because it still
requires NPM_TOKEN, while the public repo keeps OIDC-only publish.
That keeps the direct publish path and the beta-first promotion path both documented and operator-visible.
If a maintainer must fall back to local npm authentication, run any 1Password
CLI (op) commands only inside a dedicated tmux session. Do not call op
directly from the main agent shell; keeping it inside tmux makes prompts,
alerts, and OTP handling observable and prevents repeated host alerts.
.github/workflows/full-release-validation.yml.github/workflows/package-acceptance.yml.github/workflows/openclaw-npm-release.yml.github/workflows/openclaw-release-checks.yml.github/workflows/openclaw-cross-os-release-checks-reusable.ymlscripts/resolve-openclaw-package-candidate.mjsscripts/openclaw-npm-release-check.tsscripts/package-mac-dist.shscripts/make_appcast.shMaintainers use the private release docs in
openclaw/maintainers/release/README.md
for the actual runbook.