Release Automation skill for Codex
Versions, changelogs and publishes nobody types. Codex picks a release tool from how the repo already works, then wires it so the next version comes from merged changes, the changelog is reviewable in a release PR, and publishing runs from CI through OIDC trusted publishing instead of stored tokens. It catches the GITHUB_TOKEN trap that leaves release PRs without checks and dry-runs everything before the first public release.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- release-automation Installs to ~/.agents/skills/release-automation/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install release-automation The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project release-automation Installs to .agents/skills/release-automation/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/release-automation.zipunzip -o release-automation.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) release-automation PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $release-automation, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Automates versioning, changelogs, tags, GitHub releases and package publishing with release-please, Changesets, semantic-release or GoReleaser - choosing the tool from repo shape and team habits, wiring CI with the right token and permissions, npm and PyPI trusted publishing over OIDC with provenance, monorepo package versioning, prereleases, and dry runs before the first real release. Use when setting up automated releases, replacing a manual version-bump script, publishing to npm, PyPI or GitHub Releases from CI, or fixing a release workflow that skipped or duplicated a version.
Use it when
- Versions and changelogs are bumped by hand before each release
- Packages are published from a developer laptop
- A monorepo needs per-package versions and release notes
- A release workflow skipped, duplicated or mis-numbered a version
Use something else when
- You need to decide what version number a change deserves: use semantic-versioning
- You are writing human release notes or announcements: use release-notes
How to check the result
A dry run shows the expected version, the release PR runs normal CI checks, and the first release's tag, GitHub release, registry version and changelog all agree.
The mistake it prevents
Opening release PRs with the default GITHUB_TOKEN, which does not trigger other workflows, so the release PR merges without CI having run.
A good release pipeline derives the next version from merged changes, writes the changelog entry from the same source, tags exactly once, publishes from CI with short-lived credentials and provenance, and gives a human one obvious place to approve the release. Nobody edits a version number by hand, and a dry run proves the setup before the first real publish.
Inspect first
- Read
AGENTS.md,CONTRIBUTING.mdand recent history:git log --oneline -30andgit tag --sort=-creatordate | head. Are commits Conventional Commits? Squash merges? - Find current version sources:
package.json,pyproject.toml,Cargo.toml,version.go, HelmChart.yaml, docs that mention the version. - Find the registry and how publishing works today (local
npm publish, a token in CI). - Monorepo? List packages and whether they version together or independently.
- Existing
CHANGELOG.mdformat; the new tool should continue it, not restart it.
Choose the tool
| Situation | Tool |
|---|---|
| Conventional commits already enforced, want a reviewable release PR | release-please |
| JS/TS monorepo, contributors describe changes per PR | Changesets |
| Fully automatic publish on every merge to main, conventional commits | semantic-release |
| Go binaries, cross-compiled archives, Homebrew taps, container images | GoReleaser (triggered by a tag; pair with release-please for the tag) |
| Python package | release-please (release-type: python) + PyPI trusted publishing |
Default recommendation: release-please. The release PR is the approval gate, the changelog is reviewable before it ships, and it works for most languages.
release-please
// release-please-config.json
{
"packages": {
".": { "release-type": "node", "changelog-path": "CHANGELOG.md" }
}
}
// .release-please-manifest.json
{ ".": "1.4.2" }
# .github/workflows/release.yml
on:
push:
branches: [main]
permissions: {}
jobs:
release-please:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
released: ${{ steps.rp.outputs.release_created }}
tag: ${{ steps.rp.outputs.tag_name }}
steps:
- id: rp
uses: googleapis/release-please-action@v4 # pin to a SHA in production
with:
token: ${{ secrets.RELEASE_BOT_TOKEN }}
publish:
needs: release-please
if: needs.release-please.outputs.released == 'true'
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
with: { persist-credentials: false }
- uses: actions/setup-node@v4
with: { node-version: 22, registry-url: https://registry.npmjs.org }
- run: npm ci && npm run build
- run: npm publish
- A PR opened with the default
GITHUB_TOKENdoes not trigger other workflows, so the release PR gets no CI checks. Use a GitHub App installation token (or fine-grained PAT) for the release-please step. - Monorepo: add each package path to both files; release-please opens one PR covering all
changed packages (or separate PRs with
separate-pull-requests: true). - Bootstrapping on an existing project: set the manifest to the current released version
and, if history is long,
bootstrap-shain the config so it does not parse every commit.
Changesets
npx @changesets/cli init
npx changeset # contributor picks packages + bump + summary
npx changeset status --since=origin/main # CI check that a PR includes a changeset
- uses: changesets/action@v1
with:
version: npx changeset version # opens "Version Packages" PR
publish: npx changeset publish # runs after that PR merges
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- Internal dependents get patch bumps automatically when a dependency bumps
(
updateInternalDependenciesin.changeset/config.json). - Prereleases:
npx changeset pre enter next, release, thenpre exit. Forgetting to exit keeps publishing-nextversions.
semantic-release
// .releaserc.json
{
"branches": ["main", { "name": "beta", "prerelease": true }],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
"@semantic-release/github"
]
}
- Checkout needs full history and tags:
fetch-depth: 0. npx semantic-release --dry-run --no-cilocally (needs network and a token with read access) shows the version it would cut without publishing.- Writing CHANGELOG.md back to the repo needs
@semantic-release/changelogand@semantic-release/git, which commit to main from CI; branch protection must allow the bot. Many teams skip this and keep notes only in GitHub Releases.
Trusted publishing
Prefer OIDC over long-lived registry tokens:
| Registry | Setup |
|---|---|
| npm | Configure a trusted publisher (repo, workflow file, environment) in the package settings on npmjs.com; job needs id-token: write and npm CLI 11.5.1 or later; provenance is generated automatically |
| PyPI | Add a trusted publisher on pypi.org; use pypa/gh-action-pypi-publish@release/v1 with id-token: write |
| crates.io | Trusted publishing via rust-lang/crates-io-auth-action on recent setups; otherwise a scoped token |
| Containers | Push to GHCR with packages: write; sign with cosign keyless |
After switching, delete the old NPM_TOKEN or PyPI token, with the user’s approval.
GoReleaser
goreleaser check
goreleaser release --snapshot --clean # local build of all artifacts, nothing published
Trigger the real goreleaser release --clean on tag push (on: push: tags: ['v*']) with
contents: write. Fetch full history so it can build the changelog.
Version rules
- Conventional commits map:
fix:patch,feat:minor,feat!:or aBREAKING CHANGE:footer major. Before 1.0.0, release-please bumps minor for breaking changes unless configured otherwise. - Squash merges make the PR title the commit message; lint PR titles in CI
(see
conventional-commits). - Never reuse or move a published tag. Fix forward with a new patch version.
Confirmation
Publishing a package, creating a GitHub release, pushing tags and merging the release PR are public and mostly irreversible (npm unpublish is limited to 72 hours and blocked when dependents exist). Run dry runs freely; ask the user before the first real release and before deleting old tokens.
Verification
- Dry run or snapshot shows the expected next version and changelog
- Release PR (or changeset PR) runs the normal CI checks
- First real release: tag, GitHub release, registry version and changelog agree
- Registry page shows provenance or trusted-publisher attestation
- A docs-only or chore commit does not trigger a release
Output
Report the tool chosen and why, files added, secrets or apps the user must create (GitHub App, trusted publisher entries), the dry-run version, and the steps that remain manual.
What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "Release Automation"
short_description: "Versions, changelogs and publishes nobody types"
default_prompt: "$release-automation Set up release-please so merging to main produces a release PR and publishes to npm" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.