"Orchestrates the canonical 4-verb release pipeline introduced by SPEC-T9345: cleo release plan, then cleo release open, then PR + GHA tag workflow, then cleo release reconcile. The deprecated cleo release ship monolith was deleted in T10103 — do not invoke it. Use ship-e2e-smoke to validate the full pipeline end-to-end (dry-run by default). The full verb-to-state map is in docs/release/verb-matrix.md. Use when shipping a new version, validating the release pipeline end-to-end, or promoting a completed epic to released status."
Recursos
2Instal·la
npx skillscat add kryptobaseddev/cleo/ct-release-orchestrator Instal·la des del registre de SkillsCat.
Release Orchestrator
Overview
Independent opt-in canaries use --channel canary with a numberedvYYYY.MM.N-canary.N version. The OIDC workflow publishes this version only
to canary, verifies registry convergence and soaks the installed package.
It never continues to latest. Stable promotion is a separate normal release;
use --hooks-v1-promotion on the stable promotion plan; ordinary releases and
hotfixes are exempt. The promotion gate runs before GitHub Release creation.
That plan also makes scripts/mark-hotfix-release.mjs stampcleo.releasedFeatures: ["hooks-v1"] into @cleocode/core, which opens the
hooks-v1 runtime gate on the stable build (T13557); stable candidates without it
prove the runtime inert. hooks-v1 was promoted in v2026.10.17 and is released
in source since T13776 (UNRELEASED_HOOK_FEATURES is empty), so later releases
need neither the flag nor the stamp.cleo release plan refuses a stable plan whose source opens that gate since the
previous tag (hooks-v1 leaving the set, a changed hooksV1Released, a deleted
gate) with E_HOOKS_V1_PROMOTION_REQUIRED, unless it is the promotion or passes--hooks-v1-waiver "<reason>", which the plan and .cleo/audit/hooks-v1-waiver.jsonl
record (T13555). A release right after the promotion (its committed plan setshooksV1Promotion) is exempt, so the post-promotion removal needs no waiver.
The unified-hooks pilot must first supply hosted VidaPeps CI, read-only database
verification and live harness evidence bound to the exact canary source digest.
Source changes require fresh pilot evidence. Do not move npm tags manually.
Owns the canonical 4-verb release pipeline established by SPEC-T9345 and finalised when T9540 deleted the legacy start / verify / publish verbs (and the 12-step releaseShip monolith) plus T10103 deleted the deprecated ship shim. The current verb surface is documented in docs/release/verb-matrix.md — that file is the SSoT for verb-to-state mapping. This skill is the agent-facing entry point and references the matrix instead of redefining it.
Core Principle
Each verb owns exactly one state transition. No verb performs more than one mutation. Multi-step orchestration uses
ship-e2e-smoke(validator) — never compose the verbs into a custom script. The one sanctioned end-to-end runner isscripts/release-run.mjs(below).
Single release PR (T13825, owner choice 2026-10-16). node scripts/release-run.mjs <ver> --epic <id> --notes-review <file> [--execute] runs plan → independent notes review ({"reviewer","notesSha256","approved":true} by someone other than the operator, for the plan's exact meta.releaseNotes) → release/plan-<ver> (one commit, plan + CHANGELOG.md, on the default branch's HEAD, made through the GitHub API) → cleo release open <ver> --ref release/plan-<ver> → waits for release-prepare and the bump PR's dispatched CI on its exact head → version-only assert against the merge-base → gh pr merge --admin --merge --match-head-commit plus the .cleo/audit/force-bypass.jsonl line → explicit git tag -a on the merge commit and push. The bump PR carries the plan and the bump. Dry-run by default; every step resumes on re-run. --ref alone dispatches on any plan branch; preflight skips carry over only when it adds release-plan files alone.
Canonical Pipeline
| Step | Verb / Workflow | Owns transition | Notes |
|---|---|---|---|
| 1 | cleo release plan <ver> --epic <id> |
(none) → planned |
Builds the Release Plan envelope; auto-writes CHANGELOG.md (T10105 closes the silent-skip gap). stdout is the one envelope, and the readiness report goes to stderr (T13322). A --tasks plan records epicId: null, and each task keeps its own epicAncestor (T13323) |
| 2 | cleo release open <ver> |
planned → pr-opened |
Dispatches release-prepare.yml with the plan's sha256 once the plan is verified on the default branch, plus the verified preflight skips; the workflow cuts the branch + opens the PR |
| 3 | (GHA) release-prepare.yml → PR merge |
pr-opened → pr-merged |
Owned by CI; verify via cleo release pr-status <ver> |
| 4 | git tag -a v<ver> -m "Release v<ver>" && git push origin v<ver> |
pr-merged → tag-pushed |
Explicit tag after the release PR merges — auto-tag-on-release-merge.yml is retired (T10434, ADR-087); the tag push triggers release.yml |
| 5 | cleo release reconcile <ver> |
tag-pushed → published |
Backfills 11 provenance tables; idempotent |
| 6 | (GHA) release.yml Publish: release candidate gate |
<ver>-rc.ci.<n> on canary → <ver> on latest |
Automatic, OIDC only, no token (T13181). The candidate must install from npm and pass the sandbox soak (scripts/release-canary-soak.mjs) before the release publishes to latest; a failed gate leaves users on the previous release, and a re-run of the failed job continues. No dist-tag is ever moved by hand: a bad release is fixed forward with the next patch. Runbook: docs/release/merge-queue-runbook.md, "Release candidate gate" |
Optional validators (read-only / dry-run):
| Verb | Use |
|---|---|
cleo release ship-e2e-smoke <ver> --epic <id> |
One-shot end-to-end smoke. Dry-run by default; --execute performs real mutations. T10103. |
cleo release pr-status <ver> |
Poll release PR CI checks while waiting |
cleo release list / show <ver> |
Read-only inspection |
Immutable Constraints
| ID | Rule | Enforcement |
|---|---|---|
| RLSE-001 | Version MUST be CalVer (YYYY.MM.patch) per ADR-065 — never SemVer. |
cleo release plan rejects non-CalVer; exit 53. |
| RLSE-002 | CHANGELOG.md MUST be updated before the tag — always-write is the default behaviour of cleo release plan (T9784 deleted the manual changelog verb). |
Plan envelope refuses to advance to pr-opened if the changeset directory is unparseable (T10105). |
| RLSE-003 | All per-task evidence gates MUST be recorded via cleo verify <task> --gate <g> --evidence … BEFORE cleo complete. The legacy cleo release verify batch verb was deleted in T9540. |
ADR-051 per-task evidence ritual. |
| RLSE-004 | The release MUST be tagged explicitly (git tag -a v<ver> + git push origin v<ver>) after the release PR merges. |
Auto-tag was retired in T10434 / ADR-087: GITHUB_TOKEN tag pushes did not reliably trigger release.yml. |
| RLSE-005 | Direct pushes to main are prohibited. Every release ships via a PR cut by release-prepare.yml. |
ADR-065 + branch protection (see docs/release/branch-protection-setup.md). |
| RLSE-006 | Version MUST be consistent across all workspace targets resolved by resolveVersionBumpTargets (root package.json + every workspace package + Cargo workspace). |
Version-bump preflight in release-prepare.yml. |
| RLSE-007 | Provenance reconcile MUST run within the release-publish workflow — never as a manual followup. | Invoked by release-publish.yml. |
Integration
Use the explicit verbs. Do not invoke cleo release ship — it was deleted in T10103.
# 1. Plan — build the canonical Release Plan envelope.
cleo release plan v2026.6.0 --epic T10099
# 2. Open — dispatch release-prepare workflow. When the plan reached main
# through a release-plan PR (branch protection), open it with
# --no-commit-plan: the plan on main is verified (read from there if this
# checkout lacks it) and dispatched by its sha256 (T13050).
cleo release open v2026.6.0 --no-commit-plan
# 3. (Optional) Poll PR + CI status while the workflow runs.
cleo release pr-status v2026.6.0
# 4. After the release PR merges, tag explicitly (auto-tag is retired).
git tag -a v2026.6.0 -m "Release v2026.6.0"
git push origin v2026.6.0
# 5. Reconcile — runs automatically inside release-publish.yml.
# Run manually only if backfilling a historical release.
cleo release reconcile v2026.6.0To validate the whole pipeline end-to-end without shipping a real release:
# Dry-run preview — no side effects.
cleo release ship-e2e-smoke v2026.6.0 --epic T10099
# Execute mode — runs plan + open, then polls for PR merge, tag push,
# and npm publish (default 30-min wall-clock budget).
cleo release ship-e2e-smoke v2026.6.0 --epic T10099 --executeExit codes (canonical):
0— success.53— version validation failed (e.g. not CalVer).54— release-prepare workflow gate failed.56— tag creation failed.82—E_PLAN_NOT_FOUND(plan envelope missing for the requested version).83—E_IVTR_INCOMPLETE(per-task IVTR loops not released).88— artifact publish failed.
Anti-Patterns
| Pattern | Problem | Solution |
|---|---|---|
Running cleo release ship |
The verb was deleted in T10103 — the command will exit with Unknown command. |
Use cleo release plan + cleo release open. |
Manually invoking gh workflow run release-prepare.yml |
Bypasses the plan envelope; releases.status stays at planned; a hand dispatch also drops the verified skip-tests / verified-sha inputs, so the whole Linux and macOS suites run again (v2026.10.3 lost ~45 min). |
Always go through cleo release open <ver> (--no-commit-plan after a plan PR) — it tracks state in the releases table and forwards the preflight skips. |
Tagging before the release PR merges, or git push --tags |
Tags an unmerged commit, or pushes every local tag. | Tag the merged release commit and push that one tag: git push origin v<ver>. |
Hand-editing CHANGELOG.md for the new version |
Drift between the changeset directory and the changelog. | cleo release plan always auto-writes the section (T10105). Use cleo changeset add to author entries. |
| Pasting one verb into another's workflow file | Multi-step orchestration belongs in ship-e2e-smoke. |
Use cleo release ship-e2e-smoke … --execute for end-to-end validation. |
| Running the pipeline on a dirty worktree | Release commit scoops up unrelated changes. | The clean-tree gate refuses to advance. |
Skipping cleo release reconcile after a successful tag push |
11 provenance tables stay empty; canon drift. | release-publish.yml runs reconcile automatically — verify it ran via cleo release show <ver>. |
Critical Rules Summary
- The 4-verb pipeline —
plan,open,reconcile,rollback— is the ONLY way to ship. - The deprecated
cleo release shipshim was DELETED in T10103. Do not invoke it. - CalVer (
YYYY.MM.patch) is the only valid version scheme. cleo release planalways writes the CHANGELOG section unless--no-changelog.- The tag is created explicitly after the release PR merges;
auto-tag-on-release-merge.ymlis retired (T10434, ADR-087). - Provenance reconcile is invoked by
release-publish.yml, not manually (unless backfilling). - Per-task evidence gates use
cleo verify --gate --evidenceper ADR-051 — not the deleted batch verb. - Use
cleo release ship-e2e-smoketo validate the full pipeline before a real ship. - A stable release reaches
latestonly through release.yml's release candidate gate (T13181). If the gate fails, the release is not shipped to users: re-run the failed Publish job or fix forward; never movelatestby hand (there is no npm token).
CI Job Inventory
The authoritative reference for every job that runs in this repo's GitHub Actions pipeline — including which jobs run on PR-to-main vs push-to-main vs tag-push, branch-protection cross-check, and documented divergences — lives at:
- docs/release/job-inventory.md (T10106 · Saga T10099)
Consult the inventory whenever:
- A release verb fails CI and you need to know which gate is blocking.
- Branch-protection required status checks need to be reconciled against actual workflow jobs.
- A new workflow is added or an existing trigger changes — regenerate the matrix per the "How this document is maintained" section at the bottom of the inventory.
See also / References
This skill binds to the release LOOM lifecycle stage. Governing ADRs:
- ADR-053 — project-agnostic release pipeline — language-agnostic version bump → changelog → tag flow.
- ADR-063 — release pipeline — original 12-step pipeline (historical; superseded by SPEC-T9345 §4).
- ADR-065 — PR-required release flow — direct pushes to
mainare prohibited.
Live verb matrix: docs/release/verb-matrix.md — the single source of truth for verb-to-state mapping.
LOOM coverage matrix: docs/skills/loom-coverage-matrix.md.