> For AI agents: the complete documentation index is at [llms.txt](https://reflex.dev/docs/llms.txt). Markdown versions are available by appending `.md` or sending `Accept: text/markdown`.

## v0.1.0 (2026-08-27)

### Features

- New package: `reflex-release` extracts Reflex's changelog-driven release pipeline — the towncrier news-fragment workflow, the changelog-as-source-of-truth publish detection, and the human-gated PyPI upload — into a reusable tool other repositories can adopt with `uvx reflex-release init`. It scaffolds the GitHub Actions workflows into the consuming repository (required for PyPI trusted publishing, which validates the workflow's own repository) and keeps them in step with `reflex-release sync --check`. Repository shape lives in a `[tool.reflex-release]` table: single package or monorepo, branch policy, lockstep groups that release together at one version, and internal packages that release without a changelog. Every upload waits on an approval from the `pypi` environment's required reviewers, and the artifacts it covers are named by SHA-256 in the run summary and in a manifest attached to the GitHub release. See `packages/reflex-release/README.md` for setup, configuration and the security model. ([#6868](https://github.com/reflex-dev/reflex/issues/6868))
- `reflex-release` can now delegate a package's build to a workflow the consuming repository owns, for packages whose artifacts cannot come from a single `uv build` — a matrix of platform-specific wheels, say. A `[[tool.reflex-release.custom-build]]` entry names the packages and the workflow file, and the generated `publish.yml` calls it in place of its own build job, passing the package, version, tag, build directory and the artifact-name prefix to upload under. Everything either side of the build is unchanged: the whole matrix runs before the approval gate, in the same unprivileged trust boundary (`contents: read`, no secrets, no OIDC — a called workflow cannot hold more than its caller grants), and every file it produces is verified against the release, hashed into the manifest the approver sees, and published only after that approval. A failed leg fails the release rather than uploading a partial set, and `expect-artifacts` can additionally require the built set to match a list of filename patterns so a leg that silently produced nothing is caught too. `reflex-release sync` fails when a configured build workflow is missing or declares no `workflow_call` trigger, so a renamed file is a red pull request instead of a failed release. ([#6891](https://github.com/reflex-dev/reflex/issues/6891))
- Add `post-release-workflow` to `[tool.reflex-release]`: the named workflow is dispatched once per published tag, on the tag itself, after the upload, the tag and the GitHub release exist — with `tag`, `package` and `version` as `workflow_dispatch` inputs. The dispatch step and the `actions: write` grant it needs are only scaffolded into `publish.yml` (and the workflows that call it) when the setting is present, so a repository that runs nothing after a release keeps the narrower permissions.
- Materializing a changelog now names leftover orphan news fragments (`+something.feature.md`) after the pull request whose commit added them, so their entries get the usual `#`-link instead of shipping unlinked.
- Materialization now lifts dependency pins a release cannot ship. A `*.dev` floor — and, for a final version, a prerelease floor on a sibling package — is rewritten to the earliest published version that satisfies the requirement, `uv.lock` is re-resolved, and both land in the release commit alongside the changelog bump. "Published" means tagged, which is this pipeline's record of what reached PyPI, so a prerelease satisfies a floor only when the version being materialized is itself a prerelease. A floor no published version satisfies has nowhere to go, so the package is held back at plan time — dropped from an auto-selection (a lockstep group whole), an error for an explicit one — rather than materialized into a version that could never be published. ([#6889](https://github.com/reflex-dev/reflex/issues/6889))
- Add `uv-version` and `python-version` to `[tool.reflex-release]`: every generated workflow now installs uv and Python at those exact versions instead of whatever `setup-uv` resolves at run time. Both default to versions this tool pins, so upgrading reflex-release moves the release toolchain with it and `sync --check` reports that as drift until the workflows are regenerated — the same signal a template change gives. Set either key to keep your own cadence, or to `""` to leave that version to the setup action. ([#6941](https://github.com/reflex-dev/reflex/issues/6941))
- Add `never-publish-packages` to `[tool.reflex-release]`, for the packages a repository builds but never releases — an application, a docs bundle, a fixture. A listed package gets no *Dispatch release* checkbox, is never auto-selected, is skipped by changelog detection even if it has a `CHANGELOG.md`, needs no news fragment, and is refused by `prepare-publish`, so a manual publish dispatch fails in the first unprivileged job instead of at `verify-dist`. It cannot also be a lockstep member, a `custom-build` package, `latest-release-package` or internal; each combination is rejected when the configuration loads. `changelog-exempt-packages` was the closest thing before, and it only waives the news-fragment requirement. ([#6941](https://github.com/reflex-dev/reflex/issues/6941))

### Bug Fixes

- A release using a `[[tool.reflex-release.custom-build]]` entry no longer publishes nothing while reporting success. Exactly one of the built-in `build` job and a custom-build job runs for any given package, so the other is always skipped — and GitHub evaluates the implicit `success()` a job gets when its `if` names no status function over the whole transitive dependency closure, not just the direct `needs`. The skipped build therefore reached `publish` straight through the `collect` written to absorb it, and `tag-and-release` behind it: every build succeeded, the artifacts were verified and checksummed, and then the upload silently never happened. Both jobs now carry an explicit `needs.<job>.result == 'success'` guard. `release_from_changelog.yml`'s `report` job, the canonical failure signal for a partial release, was blind to the same shape because it accepted any skipped leg; it now accepts a skipped leg only when detection found nothing for that leg to publish, so a release that publishes nothing — or holds a lockstep package back — is red.
- The generated `changelog.yml` now re-runs when a pull request's labels change, and reads the labels back from the API instead of the event payload. `skip-changelog` and `changelog-version-edit` waive parts of the check, so a verdict is only valid for the label set it was computed under: applying a label after the last push previously started no run at all, removing one left the green run that label produced standing, and re-running a failed run replayed the original payload — where the new label does not exist — so the check kept failing until someone pushed again. The job itself stays ungated so every run computes the real verdict, because a job skipped by `if` reports a check that branch protection counts as passing. ([#6941](https://github.com/reflex-dev/reflex/issues/6941))
- A release using a `[[tool.reflex-release.custom-build]]` entry no longer publishes nothing while reporting success. Exactly one of the built-in `build` job and a custom-build job runs for any given package, so the other is always skipped — and GitHub evaluates the implicit `success()` a job gets when its `if` names no status function over the whole transitive dependency closure, not just the direct `needs`. The skipped build therefore reached `publish` straight through the `collect` written to absorb it, and `tag-and-release` behind it: every build succeeded, the artifacts were verified and checksummed, and then the upload silently never happened. Both jobs now carry an explicit `needs.<job>.result == 'success'` guard. `release_from_changelog.yml`'s `report` job, the canonical failure signal for a partial release, was blind to the same shape because it accepted any skipped leg; it now accepts a skipped leg only when detection found nothing for that leg to publish, so a release that publishes nothing — or holds a lockstep package back — is red. ([#6950](https://github.com/reflex-dev/reflex/issues/6950))

### Miscellaneous

- Every `run:` step in the generated release workflows now declares `shell: bash`, so a `defaults.run.shell` added to one of those files — or a runner whose default shell is not bash — cannot change how a release-critical script is interpreted, or silently drop the `-e`/`-o pipefail` a failing step relies on. ([#6926](https://github.com/reflex-dev/reflex/issues/6926))
- Property docstrings are now noun phrases rather than "Get the ..." / "Return the ..." (ruff 0.16's new `D421`).
- Append new `Config` fields after the existing ones. `Config` is exported, so its generated `__init__` has a positional contract that inserting a field in the middle would break for any caller that does not pass every argument by keyword; a test now pins the historical field order as a prefix. ([#6941](https://github.com/reflex-dev/reflex/issues/6941))
- Pin `hatchling` and `uv-dynamic-versioning` exactly in this package's `[build-system] requires`. Build requirements are resolved fresh rather than locked, so a repository that vendors the tool — running it from its own lockfile rather than PyPI — no longer has the backend that builds its release tooling move underneath it. ([#6941](https://github.com/reflex-dev/reflex/issues/6941))
- Raise the package-checkbox limit on the Dispatch release form from ten to twenty, matching GitHub's actual `workflow_dispatch` input limit. Repositories with between nine and nineteen releasable packages (or lockstep groups) keep the checkboxes under `dispatch-package-inputs = "auto"` instead of falling back to the comma-separated field. ([#6941](https://github.com/reflex-dev/reflex/issues/6941))
