## Summary
Permanently stops the recurring *"release published with zero assets →
install/upgrade 404s"* outage
(https://github.com/ComposioHQ/composio/issues/3408,
https://github.com/ComposioHQ/composio/issues/3269; regressions of
https://github.com/ComposioHQ/composio/issues/2625 and
https://github.com/ComposioHQ/composio/issues/1820 — 3 of the last 5
stable releases shipped empty).
**Root cause:** a concurrent-writer race. On a CLI version bump,
`changesets/action` creates an empty `@composio/cli@x.y.z` GitHub
Release in seconds, then the slower `build-cli-binaries.yml` fails its
`gh release create` because the release already exists — so binaries
never attach.
> 🥞 **Stacked on #3415** (`pi/exclude-cli-ts-release-42161920`), which
removes the *second writer* (changesets no longer creates CLI releases).
Review/merge #3415 first; this PR targets that branch. This PR hardens
the now-sole writer so a *partial* build can't publish either, and fixes
the monitoring that hid the failure.
## What changed (`build-cli-binaries.yml` + canary)
- **Draft → verify → publish.** The release is built as a **draft**,
then a gate asserts all 6 canonical assets are present **and** `state ==
"uploaded"` (loud `::error::` + fail otherwise), and only the final step
flips it to published. Drafts fire no `release: published` event and are
excluded from `/releases/latest`, so no install.sh / Homebrew / redirect
consumer can observe an incomplete release.
- **`fail-fast: false`** on the build matrix → a single platform failure
can never publish a partial set (`needs.build.result` is `success` only
if all legs pass).
- **Per-tag job-level `concurrency`** so re-runs / quick pushes can't
interleave uploads on the same tag, without serializing unrelated betas.
- **Beta-safe:** `--prerelease` is set on the draft so betas stay
prereleases through the publish flip.
- **`promote-stable` guard** uses `gh release view --json isDraft` (the
REST tags endpoint 404s on drafts) to resume an existing draft but
refuse an already-published tag.
- **Least privilege:** workflow defaults to `contents: read`; only the
release job opts up to `contents: write`.
- **Canary fix** (`cli.install-health-check.yml`): install the newest
stable **pinned** tag (`npm view @composio/cli version`) instead of the
asset-aware no-arg flow, which self-heals to the last good release and
kept the canary green through every outage.
## Idempotency note
Re-running a run that failed **before publish** is safe (reuse draft +
`--clobber`). An already-**published** tag is refused, not mutated — by
design.
## Testing
- Extended `test/release-workflow.test.ts` (run via `pnpm
test:release-workflow`) to lock in: draft→verify→publish ordering,
`fail-fast: false`, per-tag concurrency, preserved `--prerelease`, and
the pinned-tag canary. ✅ passes.
- `shellcheck` clean on the new `run:` scripts; YAML validated.
`actionlint` runs in CI.
- Runtime verification of the full green path happens on the next
release CI run.
## Out of scope (deferred to their own PRs)
Per reviewer consensus, these are real but *not this bug*: a per-release
npm↔GitHub asset auditor (needs a grace window), the Homebrew trigger
constraint (folds into #3355), `composio upgrade` missing-asset back-off
(https://github.com/ComposioHQ/composio/issues/3269), and a rollback
runbook.
---------
Co-authored-by: Rahul Tarak <cryogenicplanet@gmail.com>
## Summary
Depends on #3492.
This completes the Phase 2 migration by removing the transitional
version-file layer and making `mise.toml` plus `mise.lock` the
repository toolchain source of truth. It also moves runtime test
matrices into `toolchain-versions.json`, so CI matrix changes are
explicit and reviewable without reintroducing `.nvmrc`, `.dvmrc`,
`.bun-version`, or `.python-version`.
The Node.js e2e matrix now starts at the latest Node 22 LTS line and
also covers the latest Node 24 and Node 25 lines. That removes Node 20
from the well-known e2e versions while keeping us covered on the
runtimes SDK users are moving toward.
## Rationale
Phase 1 introduced mise side by side with the existing version files to
keep the first PR low-risk. Phase 2 removes that compatibility layer so
there is one place to update tool versions. That avoids silent drift
between local setup, GitHub Actions, Docker E2E images, release docs,
and install-time checks.
The composite setup actions now install Node, Bun, Python, and uv
through mise by default, with explicit version overrides only where a
matrix needs them. New GitHub actions added in this PR are pinned by
release commit SHA and include the release version comment.
## What changed
- Deleted the transitional root/version files: `.nvmrc`, `.bun-version`,
`.dvmrc`, root `.python-version`, and `python/.python-version`.
- Removed `idiomatic_version_file_enable_tools` from `mise.toml` and
added a committed `mise.lock` for linux/macOS x64/arm64 tool resolution.
- Replaced `BYPASS_BUN_VERSION_CHECK` with `BYPASS_TOOLCHAIN_CHECK`, and
made Docker E2E image installs use that bypass because they receive
explicit build args instead of installing mise.
- Updated Node/Bun and Python/uv composite actions to default to mise,
remove `*-version-file` inputs, report resolved versions, and cache pnpm
after `corepack enable`.
- Centralized CI runtime matrices in `toolchain-versions.json` for TS
E2E, Python tests, and CLI npm fallback coverage.
- Updated the Node E2E matrix to `22.22.3`, `24.16.0`, and `25.9.0`,
removing Node 20 from the well-known runtime versions.
- Updated workflows, docs, E2E helpers, Dockerfiles, and release
guidance to reference `mise.toml` / `mise.lock`.
## Verification
- Verified latest Node 22/24/25 releases from the official Node dist
index: `22.22.3`, `24.16.0`, `25.9.0`
(https://nodejs.org/dist/index.json).
- `pnpm install --frozen-lockfile`
- `pnpm --filter @e2e-tests/utils typecheck`
- `pnpm --filter @e2e-tests/utils exec tsc --noEmit --target es2022
--module esnext --moduleResolution bundler --types bun
--resolveJsonModule --skipLibCheck --strict scripts/docker-build.ts`
- `bash -n ts/scripts/pre-install.sh && bun run
ts/scripts/pre-install/check-toolchain.ts && BYPASS_TOOLCHAIN_CHECK=1
bash ts/scripts/pre-install.sh`
- `pnpm exec prettier --check ...` on touched YAML/Markdown/TS/JSON
files
- `ruby -e "require \"yaml\"; ARGV.each { |f| YAML.load_file(f) }" ...`
on touched actions/workflows
- `mise lock --platform linux-x64,linux-arm64,macos-arm64,macos-x64 &&
git diff --exit-code mise.lock`
- `mise exec node@22.22.3 -- pnpm --filter @e2e-tests/utils typecheck`
- `mise exec node@22.22.3 -- pnpm --filter @e2e-tests/node-esm-basic
typecheck`
- `mise exec node@22.22.3 -- pnpm --filter @e2e-tests/node-cjs-basic
typecheck`
- `docker manifest inspect node:24.16.0-slim`
- `docker manifest inspect node:25.9.0-slim`
- `git diff --check`
## Summary
- Add a generated `composio-cli` skill source that can render stable and
beta variants from a single channel-aware definition.
- Introduce build and validation scripts to generate the skill output
and verify channel-specific content, references, and reproducibility.
- Update the CLI packaging workflow to validate skills and package the
correct release-channel build for beta vs stable releases.
- Expand the skill content with clearer top-level CLI guidance,
troubleshooting, developer-project workflows, and beta-only power-user
examples.
- Tighten CLI install/upgrade behavior and add tests covering skill
installation behavior.
- Add example validation to the repo test flow and align example package
metadata with workspace expectations.
## Testing
- Not run locally.
- Added `ts/packages/cli/scripts/validate-skills.ts` checks for
stable/beta markers, channel-specific content, and required reference
files.
- Added `ts/packages/cli/test/src/effects/install-skill.test.ts`
coverage for skill installation behavior.
- Added `ts/scripts/validate-examples.ts` to validate example package
manifests during `pnpm test`.
- CI workflow now runs `pnpm run validate:skills` before packaging CLI
skill files.