Releases: The01Geek/prflow
Release list
v2.30.0
[2.30.0] — 2026-07-31
Changed
Changed
- PRFlow rename Tier 2 (issue #1003) — the three consumer-visible brand identifiers move,
and every reader of a pre-rename artifact keeps resolving it.- The provenance label new runs stamp is now
PRFlow. Every selector accepts both
PRFlowand the supersededDevFlow(lib/scan.sh,lib/classify-pr-kind.jq,
lib/fetch-pr-context.sh), so no retrospective history is dropped. The API-side filter
now uses a single--search "… label:PRFlow,DevFlow"qualifier —gh pr list --label A --label Bis an AND and would have returned zero candidates silently. - The telemetry branch default is now
prflow-telemetry. Records already published on
devflow-telemetryare not migrated automatically; the unmigrated state is detected
with a breadcrumb naming the one-linegit push origin devflow-telemetry:prflow-telemetry
migration (seedocs/efficiency-trace.md). - Comment markers newly written carry
<!-- prflow:… -->. No existing issue or PR body
is rewritten. Readers of persisted GitHub artifacts accept both spellings per record,
so a workpad mutated in place across the rename boundary still discharges its pre-rename
deferred-filedrecords and binds its pre-renamescope-decision pr=pendingones.
In-tree reference boundaries (*-ref) and the in-rundispatch-scopefile-format marker
are renamed in place with no dual form. deferred.labelsdefaults toPRFlow,Deferred.
- The provenance label new runs stamp is now
Fixed
scripts/match-lint-adjudications.py's adjudication-sentinel tamper guard now counts the
union of both marker spellings. Counting each spelling independently would have let one
genuine new-form section sit beside one attacker-quoted old-form section, read as1and
1, raise no tamper flag, and honor the forged window. The review engine's producer-side
neutralization list names both spellings to match.- Every fail-open marker reader is fixed rather than documented: both trigger resolvers, the
#989review-backstop dedupe override, the stall-backstop lifetime attempt counter and the
review-backstop per-head attempt counter now match or count both spellings — a marker miss
in any of them was a duplicate-run or suppressed-resume bug, not a cosmetic gap. .prflow/config.schema.json'sdocs.labelsdefault wasDevFlow, disagreeing with the
shipped example config, the live config and the resolver default; it is nowDocumented.
Added
lib/rename-map.jsongains a top-levelidentifiersrename channel with per-entry match
semantics (token/prefix), andlib/test/pin-corpus-lint.pycompiles it. The alternation
is ordered longest-literal-first with frozen entries winning ties, and the builder now refuses
a name that is both frozen and mapped, an unrecognised top-level block, and an identifier
entry with no declared match — three edits that were previously silent no-ops.
v2.29.0
[2.29.0] — 2026-07-31
Changed
Rename everything PRFlow ships into a consumer repository from devflow to prflow, and make /prflow:init migrate an existing repository as a single atomic unit (#1002).
The plugin has been prflow for several releases, but everything it shipped into a consumer repository still carried the old brand at the structural layer. That is now migrated: the .devflow/ state directory becomes .prflow/, the vendored plugin path .devflow/vendor/devflow/ becomes .prflow/vendor/prflow/, the seven brand-named top-level config keys (devflow, devflow_implement, devflow_runner, devflow_review, devflow_review_and_fix, devflow_retrospective, devflow_version) become their prflow_* equivalents, the shipped workflow bodies name the new paths and keys, and the .gitignore rules follow the directory.
The migration is all-or-nothing. The shipped workflows invoke bundled helpers at the vendored path as repo-relative leading tokens and the cloud allowlist grants are per-literal-path, so a half-moved tree is not merely broken — it is silently denied, and the run ends with no verdict. scripts/migrate-consumer-tier1.sh therefore plans, validates every precondition for all four members, stages every new byte, and only then commits behind a rollback journal. A single unsatisfiable member refuses the whole set and leaves the repository byte-identical. /prflow:init runs it before the scaffolder, and install.sh runs it first inside its one apply path, where the shipped-workflow copy loop now shares its fate.
Detection where a migration has not happened yet. scripts/config-get.sh gained a superseded-key probe that distinguishes a genuinely absent key from one a consumer deliberately set to "", false, 0 or null — a distinction the resolver structurally could not make before — and breadcrumbs only on the first. The two shipped workflow config jobs gained a per-family fail-loud guard, because the trigger-time channel reads config through inline jq and never through the resolver, so no breadcrumb could reach it. scripts/scaffold-config.sh migrates the config keys behind a fail-closed shipped-workflow freshness gate, reports the version pin without gating on it, names any retained workflow no installer run can refresh, and its deep-merge backfill will not graft a prflow_* key while its devflow_* counterpart is still present.
The state directory has a transitional read-through, and the config keys deliberately do not. /prflow:init registers the marketplace with autoUpdate: true, so a consumer's plugin can update ahead of any migration run; without a fallback the next update would resolve an absent config and silently revert every defaulted read. Readers therefore resolve .prflow/ first and fall back to .devflow/ only when it alone is present, breadcrumbing the remedy every time. The key-level rule from #988 is unchanged — no read-through there, because a silent key fallback makes the migration unobservable and therefore permanent.
Unchanged, and deliberately so: devflow-marketplace, the workflows.devflow / workflows.devflow-review config sub-keys, every .github/workflows/ filename, the DevFlow provenance label, the devflow-telemetry branch, the <!-- devflow:* --> comment markers, the DEVFLOW_* environment variables, the devflow_module_pin_* harness functions, and the byte-contents of learnings/*.jsonl and logs/*.tsv — those files move with the directory but are never rewritten. The label, branch and marker rulings are tracked in #1003; the environment-variable advisory report in #1004.
v2.28.5
[2.28.5] — 2026-07-31
Fixed
- Renamed the PR-authoring GitHub App reference to its current slug. The App
was renameddevflow-autopilot→prflow-implementer(PRFlow (Implementer);
the app id is unchanged at3102164) and the old slug now 404s, so every
workflow comment, setup instruction, and architecture note naming it pointed at
an identity a reader could not look up. TheDEVFLOW_APP_IDvariable and
secret names are deliberately unchanged — they are configuration identifiers,
not App identity — as are the workspace-path grants in.devflow/config.json
(repo-name, re-anchored onto the live$GITHUB_WORKSPACE) and the dated
CHANGELOG.mdrecords.
v2.28.4
[2.28.4] — 2026-07-31
Fixed
- The frozen pin-corpus census can no longer silently disagree with its own adjudication
table.lib/test/pin-corpus-classifier.pyresolveslib/test/pin-corpus-adjudications.tsv
at the census's recorded revision, so the existing frozen-revision regeneration
re-derived whatever rationales the census already carried and could never notice a
working-tree table that had moved on — a table-only edit shipped a superseded rationale
behind a green suite, the#810gate and green CI. The frozen-revision test now repeats its
byte-comparison with the working tree's adjudications reconciled into the recorded
revision's table, so changing an adjudicated cell for a key the census already carries is RED,
with the drifting row and column named instead of a whole-file diff; a companion mutation
control drives the same reconcile-then-regenerate path with one working-tree rationale changed
each run, so the comparison cannot be satisfied vacuously. Only keys the two files share are
compared: a site that resolves a literal is keyed by a hash of that literal, so rewording a
pinned literal re-keys the same adjudication, and the census — a frozen snapshot whose lag is
fail-closed by design — is not thereby stale. The two-commit inventory-free protocol itself is unchanged.
(#967)
v2.28.3
[2.28.3] — 2026-07-30
Changed
Fixed
- Cloud setup docs no longer describe
devflow-review.yml, a workflow that is not in the
tree.docs/cloud-setup.mdhad named it among "the five consumer-shipped workflows" and
its workflow inventory gave an install instruction ("edit that list when installing") for
a file that does not exist. The true shipped set is two workflows —devflow.ymland
devflow-implement.yml— and the inventory now states which entriesinstall.shcopies,
which belong to this repository only, and which are the retained withheld-tier files.
docs/DEVFLOW_SYSTEM_OVERVIEW.mdcarried the same stale count and is reconciled. - README requirements no longer overstate the PyYAML dependency. It is a lazy import in a
single helper, reached only when a pull-request body already carries a deferred-findings
block, and the review engine logs and steps over its absence with all findings intact. - The withheld auto-review tier disclosure is reworded to state its actual disposition —
the feature was withdrawn rather than abandoned, and a fresh install is unaffected — and
moved below the fold, with the removal procedure spelled out.
Changed
- Skill descriptions shown in the skill picker use the current product name:
init,
receiving-code-reviewandrequesting-code-review. The/devflow:implementalias in
theimplementskill's description is retained deliberately — it is still a live trigger. docs/DEVFLOW_SYSTEM_OVERVIEW.mdno longer carries a hand-maintained version literal
(it read2.4.3against a shipped2.28.1); it points atplugin.jsoninstead.CHANGELOG.md's live header uses the current product name. Dated entries are unchanged.- The README gained an
installanchor so the published one-pager's call-to-action lands
on the install instructions rather than the top of the page.
v2.28.2
[2.28.2] — 2026-07-30
Fixed
- A new user's first command works again: the documented install identifier is now
prflow@devflow-marketplace. The plugin was renameddevflow→prflowand the rename
swept every executable surface, but the human-facing surfaces were left behind —README.md
anddocs/still told a reader to runclaude plugin install devflow@devflow-marketplace,
which fails on a clean install withPlugin "devflow" not found in marketplace "devflow-marketplace". The marketplacerenamesmap migrates an already-installed plugin;
it is not an install-time alias. All nine documented install sites acrossREADME.md,
docs/install.md,docs/cloud-setup.mdanddocs/DEVFLOW_SYSTEM_OVERVIEW.mdnow name
prflow@devflow-marketplace, and bothREADME.mdanddocs/install.mdexplain why the
marketplace keeps thedevflow-marketplacename (therenamesmap is scoped per
marketplace, so renaming it would strand every existing install). - Every documented command is now
/prflow:. README's quick start, the skills table, the
end-to-end workflow diagram and all ofdocs/used the retired/devflow:local-command
namespace. The README's namespacing note previously gave inverted advice — "always use the
/devflow:-prefixed form" — and now states the split correctly: local slash commands are
/prflow:only, because a skill's namespace is the plugin name, while cloud comment
triggers accept both namespaces during the alias window.docs/workflow-triggers.mdstates
that dual acceptance where the trigger surface is documented. - Two dead documentation links are repointed.
docs/external/release-notes.mdcited
issues #930 and #920 at the pre-renameThe01Geek/devflow-autopilotpath, which now returns
404; both point atThe01Geek/prflowand were re-verified live. - Product naming and scaffolded config.
README.md,CITATION.cff,CONTRIBUTING.md,
SECURITY.md,LICENSES/README.md, thedocs/corpus and the vendored agent descriptions
now say PRFlow..devflow/config.example.json— what/prflow:initscaffolds into a new
repository — and theconfig.schema.jsondescriptions an editor surfaces no longer seed the
staledevflow:agent namespace or document/devflow:commands. - Deliberately unchanged: the
devflow-marketplacemarketplace name, the.devflow/
directory,DEVFLOW_*environment variables,devflow_*config keys, the<!-- devflow:* -->
markers, the reservedDevFlowprovenance label, theDevflow Reflection/Devflow Review
markers, the workflow filenames, thelib + python testscheck name, and the
devflow-autopilotGitHub App, which is a separate identity that has not been renamed.
CHANGELOG.mdand.devflow/learnings/**are dated historical records and keep the old name.
v2.28.1
[2.28.1] — 2026-07-30
Changed
- Repository references now point at
The01Geek/prflow, the repository's new name. The
GitHub repository was renamed fromdevflow-autopilottoprflow; this updates every live
reference that names it — the installer'sDEVFLOW_REPOdefault, thevendor-plugin
composite action'sDEVFLOW_REPOdefault, theclaude plugin marketplace addinstructions,
theraw.githubusercontent.cominstaller pins, the plugin and marketplace manifests'
homepage/repositorymetadata, the config schema's$idand itsdevflow_version
description, the citation metadata, and the marketplace registration
scripts/provision-local-settings.shwrites into.claude/settings.json. GitHub redirects
the old repository path for git and API traffic, so existing installations keep working and
no consumer action is required; GitHub Pages does not redirect, which is why the
README's one-pager links had to move tohttps://the01geek.github.io/prflow/. Dated
historical records — the changelog, the external release notes, and the retrospective
learnings corpus — deliberately keep the old name, because rewriting them would falsify a
record of runs that happened under it. The plugin's own identity is untouched: the plugin is
still namedprflowwith thedevflowalias, and thedevflow-autopilotGitHub App keeps
its name, which is a separate thing from the repository. (#972)
v2.28.0
[2.28.0] — 2026-07-30
Changed
Changed
- The plugin identifier is now
prflow(displayName: PRFlow). The former
devflowidentifier is declared as a permanent alias in
lib/plugin-identity.jsonand as arenamesentry in the marketplace
manifest. The marketplace name itself (devflow-marketplace) is deliberately
unchanged: therenamesmap is per-marketplace, so renaming the marketplace
would put the migration map somewhere existing installs do not look. - Comment triggers accept both the
/prflow:and the transitional/devflow:
command namespaces. The detected command token is always emitted in the
canonical/prflow:form, because the consumers that compare it need one
spelling. A consumer that parses the token must accept every declared
namespace instead —scripts/prepare-harness-floor.shnow derives that set
rather than stripping a hardcoded prefix, and announces a token it cannot
classify instead of silently recording an empty command class.
Upgrading
renames is a real, documented platform mechanism, but it is not universal,
and the fallback is a one-time manual reinstall:
- It requires Claude Code v2.1.193 or later (the marketplace-manifest schema
documents the floor). Earlier versions ignorerenamesentirely and report
plugin-not-foundfor the old name. - DevFlow installs from a remote source, and the documented behaviour there
isplugin-cache-missafter the rename, so even a supported version needs one
/plugin installto fetch the plugin under its new name. - Third-party marketplaces have auto-update disabled by default, so the
renamesmap may not be fetched at all until/plugin marketplace updateis
run. (Installs provisioned byinitsetautoUpdate: trueand are unaffected.) - Managed/policy settings scopes are read-only and never auto-rewrite.
Fallback, sufficient in every case above: run /plugin marketplace update
followed by /plugin install prflow@devflow-marketplace. Local /devflow:*
slash commands do not survive the rename in any case — a skill's namespace is the
plugin name — so update local muscle memory to /prflow:*. The cloud
comment-trigger path and the agent_overrides config keys do keep accepting
the old namespace during the alias window.
v2.27.1
[2.27.1] — 2026-07-30
Changed
Changed
- Retire the throwaway
devflow-alias-probeplugin alias.lib/plugin-identity.json's
plugin_aliasesreturns to[]and every dependent region is regenerated, so the four
baked copies (.github/actions/vendor-plugin/vendor-slice.sh,
.github/workflows/devflow-runner.yml,install.sh,scripts/resolve-extra-plugins.sh)
accept the canonicaldevflowonly. The probe had already established what it was declared
for — that a second accepted identifier propagates to every baked region, that the
agent-namespace roster guards must be alias-agnostic, and that the canonical discriminator
still resolves with an alias declared — and its removal was a stated condition of the change
that introduced it: leaving it in ships a trust-discriminator widening for an identifier
nobody owns. The name-agnostic mechanism itself is untouched, as is the alias-agnostic
hardening of the roster guards. - Two comments that were corrected because an alias was declared —
lib/generate-plugin-identity.py'spayload_installdocstring andinstall.sh's
superseded-identifier gate comment — are reconciled with the tree they now ship in: each
states the conditional the code implements, names the current (empty) state as a property
of the manifest rather than of the function, and tells the reader to re-read the manifest
before asserting which way the gate falls.
v2.27.0
[2.27.0] — 2026-07-30
Changed
Added
-
install.shnow has a real consumer upgrade path. Re-running it in a repository that
already carries a DevFlow installation is dry-run by default: it prints the plan and a
unified diff of every byte it would change and writes nothing until you re-run with
--apply. A first-time install still applies immediately, so the documented one-liner is
unchanged;--dry-runforces the preview there too, andDEVFLOW_DRY_RUN=1/
DEVFLOW_APPLY=1select the same modes for acurl | bashinvocation that cannot pass a
flag. The preview is not a second implementation of the plan — it runs the real install
into a sandbox copy of the consumer's own tree and diffs it. -
Installed artifacts now carry provenance in
.devflow/install-manifest.json(a sha256 per
artifact). An upgrade updates an artifact whose bytes match the recorded digest, leaves an
already-identical one alone, recreates a deleted one, and preserves one that was
hand-edited — writing the new version to<path>.devflow-newfor a human merge instead of
overwriting. An installation with no manifest (predating it, or a skipped-version jump) is
treated as unverified rather than pristine: unknown is never collapsed onto "unmodified". -
The provenance layer fails safe whenever a digest cannot be established, and the blast
radius matches the cause:- No working
python3— stock Windows / Git-Bash before the shim provisioner has run.
Nothing can be digested, so the upgrade preserves every artifact it finds, offers each
new version as a<path>.devflow-newsidecar, and writes no manifest. - A read error on one artifact while
python3works — an unreadable file, or one
unreadable file inside a composite-action directory. Only that artifact is preserved
and offered as a sidecar; every other artifact is classified and written as usual, and the
manifest is still recorded — the preserved one simply keeps its previous entry rather than
being re-recorded against bytes nothing could read.
Each case reports the cause that actually applied and the remedy that matches it, rather
than naming a missing interpreter on a host whose interpreter works.Whether an artifact exists is decided without
python3in both cases, so a genuinely absent
artifact is still created and a first-time install on such a host is unaffected; what an
unreadable digest costs is the comparison, never the consumer's bytes. Both report distinctly
from "no recorded digest" (provenance UNESTABLISHED), and each names its own remedy. - No working
-
The upgrade path surfaces the withheld automatic-review tier (issue #936) when a
repository still carries it, naming the #930/#920 exposure, and offers removal behind the
explicit--remove-withheld-review-tieropt-in. The opt-in setsworkflows["devflow-review"]
tofalseand then deletes the three workflow files, and states that the branch-protection
context is a step no installer can perform. Deletion is guarded by a per-file signature
each withheld workflow actually carries — not by the mere presence of the stringdevflow,
which a consumer's owntelemetry-push.ymlmay legitimately contain (a.devflow/**path
filter, a comment) and which would otherwise have deleted their file. The config key is
turned off before the files are removed: that is the only order whose interrupted state
is self-healing, since once the files are gone no later run reaches the config edit. -
The dry-run diff covers
.claude/plugins/as well, so the recursive removal of a stale
pre-relocation.claude/plugins/devflowtree is shown rather than performed unpreviewed.
The consumer's wider.claude/is still neither written nor diffed. -
An artifact the installer replaces is staged beside its target and swapped into place, so a
failure mid-copy can no longer leave a half-written file or composite action behind. That
mattered more than a partial write usually does here: the aborted run never reaches the
manifest write, so the next upgrade would compare the half-copied bytes against the old
digest, call them a local edit, and preserve the corruption on every subsequent run. -
The upgrade path reports a
.claude/settings.jsonstill registering a superseded
plugin/marketplace identifier and routes the consumer to/devflow:init, which already owns
that migration throughscripts/provision-local-settings.sh.install.shstill writes no
.claude/settings.json. -
DEVFLOW_SRCskips the clone and installs from an already-materialized source tree — the
offline seam the test suite drives real end-to-end fixture upgrades through.
Changed
- The local
marketplace.jsoninstall.shwrites is now composed from the generated plugin
identity region rather than hand-spelled literals, and the region carries the canonical
plugin/marketplace pair plus the superseded identifier sets alongside the existing
discriminator ERE. Declaring an alias inlib/plugin-identity.jsonand regenerating is the
only edit an identifier change needs in the installer.