Every merge to main should already be releasable.
GitHub Actions owns npm publishing, GitHub Releases, release assets, and Homebrew tap updates. ci.yml runs vp run verify (which includes smoke:pack) on the secretless job, then vp run build and semantic-release on the release job.
The verify job ends with the shared links and scan actions: an offline check of relative Markdown links and anchors on every event, and Actionlint and Zizmor when a push to main changes .github/. GitHub secret scanning and push protection cover secrets in this public repository. Dispatch CI without a tag to verify and lint every workflow without touching a release.
semantic-release publishes npm, writes the version tag, and creates a draft GitHub Release. Binary jobs build from that exact tag and upload all six archive and checksum assets while the Release is mutable. A final job verifies the exact asset manifest before publishing, then reconciles the Homebrew formula to the same tag.
Release jobs declare the protected GitHub Environment named release.
Environment entries:
- secrets:
PUTIO_CI_APP_PRIVATE_KEY - variables:
PUTIO_CI_APP_CLIENT_ID,PUTIO_CLI_SENTRY_DSN - approval: none; releases are continuous after the
maingate passes - refs: only
maincan use it - deployment records: disabled with
deployment: falsebecause this is package publishing, not an app deploy
PUTIO_CLI_SENTRY_DSN is a public routing key rather than an administration secret. The workflow
validates and injects it into npm and standalone artifacts at build time, and release builds fail if
it is absent or invalid. Local and pull-request builds intentionally omit it so verification cannot
send crash reports.
Release GitHub writes use putio-ci for version sync commits, v* tags, GitHub Releases, binary asset uploads, and Homebrew tap formula commits. The app installation grants Contents read and write access to putio-cli and homebrew-tap; the Homebrew job mints an installation token scoped to those two repositories.
The npm package uses Trusted Publishing from GitHub Actions. On npm, configure owner putdotio, repository putio-cli, workflow ci.yml, and Environment named release for the package.
During the @semantic-release/npm publish step, npm detects the GitHub OIDC identity, mints short-lived publish credentials, and publishes provenance for the release job.
The workflow keeps dependency caches only on the secretless verify job. Secret-bearing release, binary asset, and Homebrew publish jobs use fresh installs or release tooling with package-manager caching disabled.
The release-bot remote is configured only after dependencies are installed and the package build completes.
After a partial release failure, dispatch CI from current main with the
exact existing tag. Before it mints the release bot token, the release job
checks that the tag is on main and not older than the newest stable release,
so recovery cannot roll the Homebrew formula back. It then reads the tag's exact
GitHub Release state:
- a draft rebuilds and replaces its binary assets, verifies all six names, and publishes once
- a published Release skips asset mutation, verifies the complete manifest, and reruns the idempotent Homebrew reconciliation
- a push with no new semantic-release output remains a no-op
An unavailable expected Release fails closed. Use the manual Backfill Release Assets workflow only for an older published release created before draft-first
publication. It shares CI's concurrency group on main, so it never runs
alongside a push or dispatch run there.
The files list in package.json sets the npm package
contents. skills/putio-cli ships in it on purpose: consuming repos and agents
install the same guidance maintainers use from git.
The build bundles the pinned put.io SDK into dist.
Effect remains a package dependency so the CLI and its bundled SDK execute on
the same installed Effect runtime.