Releases are fully automated with
release-please. Versions,
CHANGELOG.md, git tags, and GitHub Releases are derived from commit
messages — none are edited or run by hand.
This project is a local CLI (not published to PyPI or npm). A release is the git tag + GitHub Release notes only.
-
A branch is created and changes are committed.
-
A PR is opened with a Conventional Commit title. The title determines the next version when the PR is squash-merged into
main:PR title prefix Example Version bump fix:fix: handle offline device timeoutpatch (1.1.0 → 1.1.1) feat:feat: add group volume commandminor (1.1.0 → 1.2.0) feat!:/fix!:or aBREAKING CHANGE:footerfeat!: require Python 3.12major (1.1.0 → 2.0.0) chore:,docs:,refactor:,test:,ci:docs: fix typono release -
The Tests workflow runs on the PR. The PR is squash-merged to
main. -
release-please opens or updates a Release PR titled
chore(main): release X.Y.Z. It bumps the version inpyproject.toml,constants.py, and.release-please-manifest.json, and appends toCHANGELOG.md. Multiple code PRs merged before a release are batched into one Release PR. -
Merging the Release PR triggers
release.ymlagain, which:- creates the
vX.Y.Zgit tag, - publishes a GitHub Release with the changelog notes.
- creates the
A release therefore reduces to: merge the code PR(s), approve the Release PR's checks, then merge the Release PR.
The Release PR is authored by github-actions[bot], because release.yml passes github.token to release-please. GitHub creates its checks but holds them until a user with write access approves.
Open the Release PR's Checks tab and click "Approve and run" before merging.
- There is no CLI for this.
POST /actions/runs/{run_id}/approveis documented for forks from first-time contributors and does not cover this gate. - The approval does not stick. It is needed on every release, and again whenever release-please updates an open Release PR.
- Merging without approving turns the runs red. They finalise as
failurewith zero jobs and no logs. That means nobody approved them, not that anything broke.
This gate arrived with GitHub's bot-created pull requests change and reached these repos in late August 2026. It applies to same-repo branches, not just forks, and has no repository-level opt-out. The only way to remove the step is to author the Release PR as a different identity, which needs a GitHub App or a PAT. Neither is set up here, and the click is cheaper.
main should stay compatible with this flow:
- Require a pull request before merging (0 required approvals is fine for a solo maintainer).
- Block force-pushes and deletions.
- No required status checks on the Release PR. The Release PR's own checks are held for approval, so a required check there would sit unresolved until someone approves it. Code PRs still run Tests; review those before merging.
Under Settings → Actions → General → Workflow permissions:
- Read and write permissions
- Allow GitHub Actions to create and approve pull requests
Without (2), release-please can update its branch but cannot open the Release PR
(GitHub Actions is not permitted to create or approve pull requests).
- PR titles drive releases. With squash merges, the PR title becomes the
commit release-please reads.
chore:/docs:/ci:titles intentionally produce no release. - Version source of truth is
.release-please-manifest.json.pyproject.tomlandconstants.__version__are kept in sync — do not hand-edit them for routine releases. - Behavior is configured in
release-please-config.json.
Manual tagging bypasses changelog automation and manifest sync. Prefer the Release PR flow. If unavoidable:
git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z
gh release create vX.Y.Z --generate-notes