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.