Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
# Releasing Patternflow
Patternflow uses one unified semantic version for the public project.
The project version covers firmware, PCB, case files, web, and docs together. Use tags like `v2.0.0`, not separate public `fw-*`, `hw-*`, or `web-*` release tags.
## Version rules
- **PATCH** (`v2.0.1`) -- documentation fixes, small firmware/web bug fixes, no user-facing build change.
- **MINOR** (`v2.1.0`) -- new patterns, new web features, compatible case or PCB improvements.
- **MAJOR** (`v3.0.0`) -- hardware-incompatible changes, major interaction changes, or a new build path.
## Two commands
Since 3.9.3 the checklist below is a script. On `dev`, with a clean tree and
the `[Unreleased]` section of `CHANGELOG.md` written:
```bash
python firmware/toolchain/release.py cut v3.9.4 --audio v0.5.4 --performance v0.2.4
```
bumps the versions, dates the changelog section, updates `AGENTS.md`, runs
`shelf.sh` for the core and each named edition, points the flasher manifest
and the `/editions` cards at the new images, runs the web checks, commits
`release: v3.9.4` and tags it. Name only the editions that should be re-cut;
the others keep their image. Then write the release notes and
```bash
python firmware/toolchain/release.py publish v3.9.4 --notes notes.md
```
pushes, opens the dev → main pull request from the changelog section, waits
for its checks, merges, creates the GitHub release from the notes, attaches
the edition images under their release names, and waits for the workflow
that attaches the core images. `README.md`'s *Moving fast* note is prose and
stays yours. `cut --no-build --no-commit` is the dry run.
## An edition on its own
An edition's maintainer ships between core releases, from a pull request,
with one command on a clean tree:
```bash
python firmware/toolchain/release.py edition performance v0.2.8
```
It bumps that edition's `PF_VARIANT_VERSION`, runs `shelf.sh` for it (a clean
build — the image is refused if it carries credentials or the wrong version),
points its `/editions` card at the new folder, updates its clause in
`AGENTS.md` and commits `release: performance v0.2.8`. No tag, no changelog
section, no manifest — those are the core's. Push and open the pull request;
CI checks that the six places agree and compiles every composition, and the
shelf serves the image once `main` deploys. The core's maintainer merges and
does nothing else. `--no-build --no-commit` is the dry run.
Only editions in `release.py`'s `EDITIONS` tuple are on the shelf. A bundle in
the tree that is not there (`clock`, `midi`) is a composition CI keeps
compiling, and nothing more; there is no card to point and nothing to cut.
## Release checklist
What the two commands do, step by step - and the way to do it by hand.
1. Make sure all intended changes are committed, and `./firmware/bundles/build.sh all` is green if anything under `firmware/` moved.
2. Bump the version the firmware reports: `PF_IMPROV_FW_VERSION` in `firmware/patternflow/net_config.h` (written `X.Y.Z`, no `v`). `shelf.sh` refuses a core image whose define disagrees with the version it is being shelved as.
3. Turn `CHANGELOG.md`'s `[Unreleased]` into `## [X.Y.Z] - YYYY-MM-DD` and open a fresh `[Unreleased]` above it.
4. Update the version the docs claim: the "current" line in `AGENTS.md`, the *Moving fast* note in `README.md`, and any guide that names a release.
5. If hardware changed: confirm `BUILD_GUIDE.md`'s parts table, `hardware/bom/bom_v*.csv` and the schematic agree; regenerate the Gerber zip, renders and schematic exports with the recipe in `hardware/pcb/README.md`; add a `### Hardware` entry to the changelog section; update the board table in `hardware/README.md` and the version line in `docs/assembly/README.md`; attach the Gerber zip, the BOM CSV and the STLs to the release.
6. Stage the images the site serves:
```bash
./firmware/bundles/shelf.sh core vX.Y.Z
```
then point `web/public/flash/manifest.json` at the new folder. An edition that also moved gets its own `shelf.sh <edition> vA.B.C` and a card update in `web/src/app/editions/editions-data.ts`. The shelf retires the previous folder of the same name — older images stay on their tags. Try-out images (`clock-v0.1.5`, `midi-v0.1.0`, the ones the features page installs) are not part of a release and stay as they are; a fresh one is its own `shelf.sh <name> vA.B.C` and a row update in `web/src/app/features/features-data.ts`, done when somebody wants a newer one, not because the core moved.
7. Run the web checks from `web/`: `npm run lint && npm run typecheck && npm run check:ci && npm run build`.
8. Commit and tag:
```bash
git commit -m "release: vX.Y.Z"
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin dev && git push --tags
```
9. Create the GitHub Release from the tag. Publishing it triggers **Firmware release assets**, which attaches the four flash images from the tag plus a generated `FLASHING.md` with offsets and hashes.
10. Confirm it went green before announcing; re-run it with `workflow_dispatch` if it did not fire.
## Branches
Work happens on `dev`, then lands on `main` through a pull request. `main` is protected: nobody pushes to it directly, the maintainer included.
- **Commit freely on `dev`.** Commits are cheap save points; small and frequent is good. Throwaway `wip:` commits belong here rather than on `main`.
- **Bigger or riskier work** gets its own branch (`feat/...`, `fix/...`) off `dev`.
- **Outside pull requests target `main`.** After one merges, pull `main` back into `dev` so the branches don't drift:
```
git checkout dev && git merge origin/main && git push origin dev
```
- **A release** is `dev` → `main` as one pull request, opened by `release.py publish` from the changelog section; merging it posts the dev-log to Discord.
## Current release line
`CHANGELOG.md` is the record — one section per release, newest first — and the [releases page](https://github.com/engmung/Patternflow/releases) carries the notes and the flashable images. The shape of the line, for orientation:
- `v1.x` -- first public buildable release, then the multi-pattern firmware and browser flasher.
- `v2.x` -- the v2.0 board (GPIO0 cold-boot fix, cleaned silkscreen), custom pattern workflow, the web platform. `v2.1.0` is the last release for v2.x hardware.
- `v3.0.0` -- the v3.0 board; `v3.9` (2026-09, unreleased as a tag) removed its USB-C footprint and changed nothing else. Every later `v3.x` is firmware/web on that hardware: `.pfm` modules over Wi-Fi (3.2), shows and the Director (3.6), the feature seam (3.7), editions (3.8).
- Editions on the shelf (`audio`, `performance`) carry their own version lines, independent of the project version — see `docs/EDITIONS.md`. `clock` and `midi` are bundles CI builds but the shelf does not carry.
3230db654This file is pinned to the selected release. Download the original to open it in your design tool.