-_Black_ has had a lot of work automating its release process. This document sets out to
-explain what everything does and how to release _Black_ using said automation.
-
-## Cutting a Release
-
-To cut a release, you must be a _Black_ maintainer with `GitHub Release` creation
-access. Using this access, the release process is:
-
-1. Cut a new PR editing `CHANGES.md` and the docs to version the latest changes
- 1. Example PR: [#2616](https://github.com/psf/black/pull/2616)
- 2. Example title: `Update CHANGES.md for XX.X release`
-2. Once the release PR is merged ensure all CI passes
- 1. If not, ensure there is an Issue open for the cause of failing CI (generally we'd
- want this fixed before cutting a release)
-3. Open `CHANGES.md` and copy the _raw markdown_ of the latest changes to use in the
- description of the GitHub Release.
-4. Go and [cut a release](https://github.com/psf/black/releases) using the GitHub UI so
- that all workflows noted below are triggered.
- 1. The release version and tag should be the [CalVer](https://calver.org) version
- _Black_ used for the current release e.g. `21.6` / `21.5b1`
- 2. _Black_ uses [setuptools scm](https://pypi.org/project/setuptools-scm/) to pull
- the current version for the package builds and release.
-5. Once the release is cut, you're basically done. It's a good practice to go and watch
- to make sure all the [GitHub Actions](https://github.com/psf/black/actions) pass,
- although you should receive an email to your registered GitHub email address should
- one fail.
- 1. You should see all the release workflows and lint/unittests workflows running on
- the new tag in the Actions UI
-
-If anything fails, please go read the respective action's log output and configuration
-file to reverse engineer your way to a fix/soluton.
+_Black_ has had a lot of work done into standardizing and automating its release
+process. This document sets out to explain how everything works and how to release
+_Black_ using said automation.
+
+## Release cadence
+
+**We aim to release whatever is on `main` every 1-2 months.** This ensures merged
+improvements and bugfixes are shipped to users reasonably quickly, while not massively
+fracturing the user-base with too many versions. This also keeps the workload on
+maintainers consistent and predictable.
+
+If there's not much new on `main` to justify a release, it's acceptable to skip a
+month's release. Ideally January releases should not be skipped because as per our
+[stability policy](labels/stability-policy), the first release in a new calendar year
+may make changes to the _stable_ style. While the policy applies to the first release
+(instead of only January releases), confining changes to the stable style to January
+will keep things predictable (and nicer) for users.
+
+Unless there is a serious regression or bug that requires immediate patching, **there
+should not be more than one release per month**. While version numbers are cheap,
+releases require a maintainer to both commit to do the actual cutting of a release, but
+also to be able to deal with the potential fallout post-release. Releasing more
+frequently than monthly nets rapidly diminishing returns.
+
+## Cutting a release
+
+**You must have `write` permissions for the _Black_ repository to cut a release.**
+
+The 10,000 foot view of the release process is that you prepare a release PR and then
+publish a [GitHub Release]. This triggers [release automation](#release-workflows) that
+builds all release artifacts and publishes them to the various platforms we publish to.
+
+To cut a release:
+
+1. Determine the release's version number
+ - **_Black_ follows the [CalVer] versioning standard using the `YY.M.N` format**
+ - So unless there already has been a release during this month, `N` should be `0`
+ - Example: the first release in January, 2022 → `22.1.0`
+1. File a PR editing `CHANGES.md` and the docs to version the latest changes
+ 1. Replace the `## Unreleased` header with the version number
+ 1. Remove any empty sections for the current release
+ 1. (_optional_) Read through and copy-edit the changelog (eg. by moving entries,
+ fixing typos, or rephrasing entries)
+ 1. Add a new empty template for the next release above
+ ([template below](#changelog-template))
+ 1. Update references to the latest version in
+ {doc}`/integrations/source_version_control` and
+ {doc}`/usage_and_configuration/the_basics`
+ - Example PR: [GH-3139]
+1. Once the release PR is merged, wait until all CI passes
+ - If CI does not pass, **stop** and investigate the failure(s) as generally we'd want
+ to fix failing CI before cutting a release
+1. [Draft a new GitHub Release][new-release]
+ 1. Click `Choose a tag` and type in the version number, then select the
+ `Create new tag: YY.M.N on publish` option that appears
+ 1. Verify that the new tag targets the `main` branch
+ 1. You can leave the release title blank, GitHub will default to the tag name
+ 1. Copy and paste the _raw changelog Markdown_ for the current release into the
+ description box
+1. Publish the GitHub Release, triggering [release automation](#release-workflows) that
+ will handle the rest
+1. At this point, you're basically done. It's good practice to go and [watch and verify
+ that all the release workflows pass][black-actions], although you will receive a
+ GitHub notification should something fail.
+ - If something fails, don't panic. Please go read the respective workflow's logs and
+ configuration file to reverse-engineer your way to a fix/solution.
+
+Congratulations! You've successfully cut a new release of _Black_. Go and stand up and
+take a break, you deserve it.
+
+```{important}
+Once the release artifacts reach PyPI, you may see new issues being filed indicating
+regressions. While regressions are not great, they don't automatically mean a hotfix
+release is warranted. Unless the regressions are serious and impact many users, a hotfix
+release is probably unnecessary.
+
+In the end, use your best judgement and ask other maintainers for their thoughts.
+```
+
+### Changelog template
+
+Use the following template for a clean changelog after the release:
+
+```
+## Unreleased
+
+### Highlights
+
+<!-- Include any especially major or disruptive changes here -->
+
+### Stable style
+
+<!-- Changes that affect Black's stable style -->
+
+### Preview style
+
+<!-- Changes that affect Black's preview style -->
+
+### Configuration
+
+<!-- Changes to how Black can be configured -->
+
+### Packaging
+
+<!-- Changes to how Black is packaged, such as dependency requirements -->
+
+### Parser
+
+<!-- Changes to the parser or to version autodetection -->
+
+### Performance
+
+<!-- Changes that improve Black's performance. -->
+
+### Output
+
+<!-- Changes to Black's terminal output and error messages -->
+
+### _Blackd_
+
+<!-- Changes to blackd -->
+
+### Integrations
+
+<!-- For example, Docker, GitHub Actions, pre-commit, editors -->
+
+### Documentation
+
+<!-- Major changes to documentation and policies. Small docs changes
+ don't need a changelog entry. -->
+```