axctl releases are designed for dev/staging co-promotion and automatic PyPI
publication.
- Merge feature work into
dev/staging. - Validate
dev/stagingwith automated tests, package build when needed, and the operator QA sequence in Operator QA Runbook. - Promote
dev/stagingtomainwith a reviewed PR. - Release Please opens or updates a release PR on
mainwith:pyproject.tomlversion bump.release-please-manifest.jsonversion bumpCHANGELOG.mdentries generated from conventional commits
- Merge the Release Please PR when the changelog/version are acceptable.
- The GitHub release publication triggers the PyPI publish workflow.
- PyPI publishes the package version. If that version already exists, publish is skipped.
Before MCP Jam, widget, Playwright, release, or production-facing promotion work moves forward, run the sequence below:
axctl auth doctorexplains identity and config resolution.axctl qa preflightis the required single-environment API gate.axctl qa matrixcompares environment drift across dev, next, prod, or customer targets.- Only after those pass should MCP Jam, widget, Playwright, or manual release QA continue.
Copy-paste dev gate:
axctl auth doctor --env dev --space-id <dev-space-id> --json
axctl qa preflight --env dev --space-id <dev-space-id> --for release --artifact .ax/qa/dev-preflight.json --jsonCopy-paste next gate:
axctl auth doctor --env next --space-id <next-space-id> --json
axctl qa preflight --env next --space-id <next-space-id> --for release --artifact .ax/qa/next-preflight.json --jsonCopy-paste promotion drift check:
axctl qa matrix \
--env dev \
--env next \
--space dev=<dev-space-id> \
--space next=<next-space-id> \
--for release \
--artifact-dir .ax/qa/promotion \
--jsonAttach or summarize the generated artifacts in the promotion PR when the change touches auth, profiles, messages, uploads, listeners, MCP, UI validation, or release behavior.
CI also calls the reusable .github/workflows/operator-qa.yml workflow for PRs
targeting main. It skips safely when no complete QA environment variables and
secrets are configured, uploads artifacts when it runs, and fails the promotion
path when a configured matrix returns ok: false.
The operator QA commands use stable exit codes: 0 for pass, 2 for a failed
gate, 3 for skipped/no config, and 1 for crashes or command usage failures.
Use Conventional Commit prefixes so Release Please can choose the version bump:
fix:creates a patch release.feat:creates a minor release.feat!:orfix!:creates a major release.docs:,test:,ci:,chore:, andstyle:are tracked but do not normally create a package release by themselves.
The PyPI workflow also supports manual dispatch as a break-glass fallback. The
normal path is release PR merge to main, followed by Release Please creating
the GitHub release.
The current automation is directionally right: version bumps and changelog generation should be boring, reviewable, and mostly automated. The important boundary is that publishing must remain tied to an explicit release artifact, not to arbitrary commits.
Current steady-state:
- Feature work lands in
dev/staging. - A reviewed promotion PR lands on
main. - Release Please opens a release PR that only changes release metadata.
- A human reviews and merges the release PR.
- Release Please creates the GitHub tag/release.
- The PyPI publish workflow runs from the GitHub release/tag.
Do not publish directly from every main push. Push-triggered publishing can
publish a package even if GitHub release creation fails. Release-triggered
publishing keeps PyPI, git tags, GitHub Releases, and changelog state aligned.
Use SemVer, with normal 0.x pre-1.0 semantics:
fix:creates a patch release for compatible bug fixes.feat:creates a minor release for user-visible CLI capability.- Breaking CLI changes should be rare; if needed before 1.0, document them clearly in the release notes and prefer a minor bump.
- Batch related
dev/stagingwork into coherent releases instead of publishing every small commit independently.
For axctl, a good release is one that an operator can understand from the
changelog: what changed, why it matters, and whether any setup or credential
behavior changed.
Release Please needs permission to open and update pull requests.
Required setup:
- Add a repository secret named
RELEASE_PLEASE_TOKENcontaining a bot PAT with repository Contents: write, Pull requests: write, and Issues: write access.
The workflow intentionally does not fall back to GITHUB_TOKEN. Repository and
organization Actions settings can make that token behave differently across
environments. A dedicated bot token gives us an explicit release identity and a
clear failure mode when the secret is missing.
- Keep release-sensitive files covered by CODEOWNERS:
.github/workflows/,pyproject.toml,release-please-config.json,.release-please-manifest.json,CHANGELOG.md, and this document. - If Release Please fails after a release PR merge, verify PyPI, create the missing GitHub release/tag if needed, and delete any stale generated release-please branch before the next release cycle.