Changelog

What we
shipped.

Every feature, fix and improvement to FerrFlow, the versioning CLI and the site around it.

RSS
── SEPTEMBER 2026 ──

FerrFlow: the documentation is now open to pull requests

The pages behind ferrflow.com/docs moved to a public repo. A wrong flag name, a stale example or a paragraph that never quite landed can now be fixed by anyone, and the fix goes live when it merges.

FerrFlow: Ansible Galaxy collections get a version file format

`galaxy.yml` carries a top-level `version:` like `Chart.yaml` and `pubspec.yaml` do, but versioning one meant falling back to the plain-text format and a hand-written regex. It is a first-class format now.

FerrFlow: your own commits set the floor for a bump, not the answer

A package with a fix of its own shipped as a patch even when a dependency in the same release took a minor. It now takes the stronger of the two. Expect larger bumps where a shared package and its consumers are released together.

FerrFlow: a dependent now takes the strongest bump reaching it

A package fed by two dependency edges of different strength took whichever arrived first, so it could ship as a patch while a package it depends on moved a minor. Expect larger bumps if your graph has a diamond in it.

FerrFlow: a changelog your hook rewrote is now what gets published

A `postBump` hook could already rewrite CHANGELOG.md and have it committed, but the tag, the release body and the release commit kept the text generated before the hook ran. They now agree.

FerrFlow: doctor now catches a lockfile that disagrees with its manifest

A package whose manifest and lockfile record different versions cannot build with `--locked`, and `ferrflow doctor` used to report it as healthy. It now says so, and warns before the drift happens.

FerrFlow: see what a release drags along before you run it

In a monorepo, releasing a widely depended-on package pulls others out with it. `ferrflow graph --impact` names them, with the version each would get, before anything is tagged.

── AUGUST 2026 ──

FerrFlow: a package release no longer carries other packages' commits

In a monorepo, each package collected every commit since its own last tag, whatever those commits touched. That padded the changelog with other packages' work and, less visibly, let their commits decide the version bump.

FerrFlow: calver-short-seq, and a warning when a release is held back

A date-only version scheme can only publish once a day, and the second attempt was indistinguishable from having nothing to release. FerrFlow now says so out loud, and calver-short-seq gives the compact year a sequence counter.

FerrFlow: a crash no longer leaves the release lock or a registry token behind

The release binary is built to abort on panic, which skips the cleanup that runs when a release ends normally. A crash left the lock file in place, blocking the repository for half an hour, and could leave a scoped npm token on disk.

FerrFlow: check no longer serves a stale plan after an uncommitted edit

The cache behind ferrflow check keyed on the commit, the tags and the config, but not on the version files it actually reads. Editing a version without committing returned the previous answer for up to five minutes. Interrupted runs also left temp files that nothing ever cleaned up.

FerrFlow: the crates.io link after a publish points at your crate again

FerrFlow built the crates.io link from the package name in its own config rather than the one in Cargo.toml. A workspace routinely uses short names against prefixed crates, and short crate names are long since taken, so the link led to an unrelated crate instead of yours.

FerrFlow: the npm link after a publish points at your package again

FerrFlow built the npmjs.com link from the package name in its own config rather than the one in package.json. In a monorepo those differ by default, and the short names are all taken on npm, so the link led to a stranger's package instead of yours.

FerrFlow: an annotated tag already on the remote no longer blocks the push

FerrFlow compared the commit a tag points at against the tag object itself, so any annotated tag already on the remote looked like it had moved. The push failed with a message about a difference that was not there, telling you to delete a perfectly healthy tag.

FerrFlow: undo a release that failed partway

A release that dies after pushing tags used to leave you reconstructing what it did from a job log, then deleting refs by hand. ferrflow rollback reads the checkpoint that run left behind and undoes exactly what it did, refusing the parts that cannot be undone.

FerrFlow: a config without a workspace block now keeps its defaults

Omitting the workspace block from a config file silently dropped every workspace default. The remote became an empty string and the release failed at the push; the target branch became empty and said nothing at all.

FerrFlow: release commits from the bot now show as verified

Commits authored by ferrflow[bot] showed as unverified, and no signing key could fix it because a GitHub App cannot register one. With bot: true on GitHub, the release commit is now authored through GitHub itself, which signs it.

FerrFlow: a failed push now says what actually went wrong

Every push failure was reported as "pushed onto a stale branch" and answered by regenerating the release commit three times, whatever the real cause. Transient server errors are now retried where they belong, real races are detected by their actual wording, and permanent failures surface immediately.

FerrFlow: release PRs are tagged when they merge, not when they open

In pr mode FerrFlow tagged and published the moment it opened the release PR, on the commit before the version bump. The PR then reported nothing left to release and was never updated again. Tagging now happens after the merge, on the commit that carries the bump.

FerrFlow: one config file per package

A monorepo no longer has to declare every package in a single root config. The new include key points at per-package files, each owning its own settings, and a package path inside one of those files defaults to its directory.

FerrFlow · choose whether the tag or the file is the source of truth

When a package has both a git tag and a version in a versioned file, FerrFlow took whichever was higher. That is still the default, and versionSource now lets a repo say the tags are the record, or that the file is.

FerrFlow · release output says where the current version came from

The version FerrFlow starts from is resolved from a tag, a versioned file, or neither. The release and check output now names the source, so a package whose tag was never pushed is distinguishable from one that has no tags yet.

FerrFlow: lockfiles no longer go stale after a release

updateLockfiles could leave Cargo.lock at the previous version while the release still reported success. Both causes are fixed: the crate name is read from the manifest, and a cold registry cache no longer defeats the update.

FerrFlow: commit formats are configurable, and the defaults are more permissive

workspace.commitFormats lets you declare which commit subjects map to which bump level. The defaults now also recognise Feat:, Fix/, feature: and friends. Which is why this ships as v7.

FerrFlow: now MIT licensed

FerrFlow moves from MPL-2.0 to MIT. Fewer obligations for everyone using it; the change ships as v6, so Action pins move from @v5 to @v6.

FerrFlow: the Action verifies the binary it downloads

Releases now ship a signed SHA256SUMS, and the GitHub Action checks the archive against it: and its build provenance: before extracting anything.

FerrFlow: the Action no longer interpolates its inputs into shell

force_version, package and version reached the Action’s run scripts as raw shell source. They now arrive as environment variables and are validated before use.

FerrFlow: the hosted API moves to api.ferrflow.com

The FerrFlow API and the hosted bot token exchange now answer on api.ferrflow.com. The old api.ferrlabs.com host keeps working indefinitely.

FerrFlow: `diff` now shows only the package you asked about

In a monorepo, `ferrflow diff <package> <from>..<to>` filters the range to commits that touched that package, so its commit list and changelog match what a release would actually produce.

── JULY 2026 ──

FerrFlow: Migrating from changesets now finds your packages

`ferrflow migrate --from changesets` reads your workspace globs and scaffolds one package entry per workspace package, instead of a single root package you had to expand by hand.

FerrFlow: Releases are signed with a single Sigstore bundle

From v5.48.0 each release artifact ships one `.bundle` instead of a separate `.sig` and `.crt`. Verification is one flag shorter; older releases keep working as before.

FerrFlow: Cabal and CMake version files

FerrFlow now bumps the version in Haskell `*.cabal` files and in the `project()` call of a `CMakeLists.txt`, bringing the supported formats to 16.

FerrFlow: Tags are pushed before releases are published

A release run now pushes its tags to the remote before creating the GitHub or Gitea release, so a failure in between can no longer leave a published release pointing at a tag that never landed: and annotated tag messages are no longer silently replaced.

FerrFlow: Concurrent releases no longer fail with E2006

When two release runs race, the losing run now replans against the version the winner published instead of aborting with E2006. And no longer silently drops the other packages it was about to release.

FerrFlow: Hosted API for validate, preview, schema and releases

A new hosted API at api.ferrlabs.com/v1/ferrflow/* lets you validate a config, preview version bumps and changelog, fetch the config JSON Schema, and resolve the latest release: over HTTP, with results identical to the CLI.

FerrFlow: Compare two versions with `diff`

A new `ferrflow diff v1.4.0..v1.6.0` command shows exactly what went into a version range: the commits and their bumps, the breaking changes, the files touched, and the changelog FerrFlow would generate for the range.

FerrFlow: Migrate reads JS and YAML configs

`ferrflow migrate` now imports JavaScript and YAML release configs directly: `.releaserc.js`, `release.config.js`, `.releaserc.yaml`, `.versionrc.js`, and friends: not just JSON, so you no longer have to hand-convert your config before migrating.

FerrFlow: Migrate from changesets, release-please & standard-version

`ferrflow migrate` now imports configs from changesets, release-please, and standard-version too: not just semantic-release: generating an equivalent `ferrflow.json` and a report of what mapped, what was ignored, and what needs a look.

FerrFlow: One persistent release PR

In `releaseCommitMode: pr`, FerrFlow now keeps a single long-lived release pull request and updates it on each new commit, instead of opening a fresh PR: and leaving a stale one. Every time the version changes.

FerrFlow: Post-publish hooks get the release URL

`postPublish` hooks now receive `releaseUrl`: the URL of the GitHub/GitLab release FerrFlow just created: so you can link to it from a Slack notification, a dashboard, or a downstream job.

FerrFlow: Hooks see the whole release batch

Release hooks now receive `allPackages`. Every package the run bumps, with its new version and bump type: so a monorepo hook can act on the batch, not just its own package.

FerrFlow: Richer context for release hooks

Release hooks now receive the rendered changelog, the parsed commits, the list of bumped files, and whether the run is a monorepo or pre-release. Both as `FERRFLOW_*` env vars and on the JS/TS `ctx` object.

FerrFlow: Auto-detect self-hosted forges

FerrFlow now recognises self-hosted GitLab, GitHub Enterprise, and Gitea/Forgejo instances automatically. No need to set `forge` by hand for a git host on your own domain.

FerrFlow: Bitbucket support

FerrFlow now recognises Bitbucket Cloud repositories and handles their releases. No more scripting a hook to get automatic release tagging on Bitbucket.

FerrFlow: Faster repeat runs via commit-graph

On large repositories, FerrFlow now writes a git commit-graph on the first run so that later `check` and `release` walks are materially faster: a benefit that repeat users (pre-commit hooks, local dev, warm CI runners) get for free.

FerrFlow: Robust BREAKING CHANGE detection

FerrFlow now recognises mixed-case, hyphenated, and lowercase `BREAKING CHANGE` footers: and a `!` typed inside the scope (`feat(api!):`): so a real breaking change no longer slips through and skips the major bump.

FerrFlow: ferrflow schema

A new `ferrflow schema` subcommand prints the config JSON schema that is now bundled into the binary: so editor tooling and pre-commit hooks can validate `.ferrflow.json` completely offline.

FerrFlow: ferrflow doctor

A new `ferrflow doctor` subcommand runs read-only diagnostics on your repo, config, and forge setup and prints a categorised report: so "is my setup sane?" has a first-class answer instead of grepping `--verbose` logs.

FerrFlow: Telemetry removed. The CLI no longer phones home

FerrFlow no longer collects any usage telemetry. The module is gone from the binary entirely, along with the network calls it made on every command: which also makes monorepo commands dramatically faster.

FerrFlow: Linked and fixed package version groups

New `linked` and `fixed` workspace options let a set of monorepo packages share a version: when one bumps, the whole group moves to the same version, the way changesets and lerna do it.

FerrFlow: Migrate from semantic-release in one command

A new `ferrflow migrate` command reads your existing `.releaserc` and generates the equivalent FerrFlow config: mapping tag format, branches, and the common plugins, and surfacing anything without an equivalent instead of guessing.

FerrFlow: Six new release hook points: post-commit, pre-tag, post-tag, pre-release, on-success, on-error

The release lifecycle gains six new hook points so you can run commands at the exact commit/tag/push boundaries: publish between tag and push, notify once when a release finishes, or react to a failure with the error code in hand.

── JUNE 2026 ──

FerrFlow: Windows arm64 and Linux armv7 prebuilt binaries

FerrFlow now ships prebuilt, signed binaries: and matching npm packages: for Windows on ARM (aarch64) and 32-bit ARM Linux (armv7). The release matrix grows from 5 targets to 7, so `npm i ferrflow` and direct downloads now work on Surface/Snapdragon Windows laptops and 32-bit Raspberry Pi / SBCs.

FerrFlow: ferrflow publish auto-scopes to the triggering tag

ferrflow publish now figures out which package to publish from the tag that triggered the run: so one workflow publishes each package on its own tag, no per-package wiring. It also takes multiple package names, and a --all flag to force everything.

FerrFlow: control parallelism with --jobs / FERRFLOW_JOBS

FerrFlow now exposes a global --jobs <N> flag (and FERRFLOW_JOBS env var) to cap how many threads it uses for CPU-parallel work. Default stays all logical cores; --jobs 1 forces single-threaded: handy for constrained CI runners and reproducible benchmarks.

FerrFlow: declarative publishers: publish to cargo, npm, docker, helm & more on release

FerrFlow can now publish your packages to registries declaratively from ferrflow.json: cargo, npm, docker (multi-arch + Sigstore), helm, GitHub release assets and webhooks: replacing hand-rolled postPublish shell hooks. Shipped across FerrFlow v5.4–v5.7.

FerrFlow: bot releases now work under branch rulesets (v5.2.2)

The FerrFlow bot identity pushes releases correctly even when the release branch is protected by a ruleset that bypasses ferrflow[bot]. Shipped in FerrFlow v5.2.2.