pi-dev-flow 0.0.0-stage → 0.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +651 -0
- package/LICENSE +21 -0
- package/README.md +186 -2
- package/docs/concurrency.md +18 -0
- package/docs/development.md +37 -0
- package/docs/gates.md +29 -0
- package/docs/guardrails.md +27 -0
- package/docs/headless.md +42 -0
- package/docs/playbook.md +141 -0
- package/extensions/dev-flow.ts +1502 -0
- package/package.json +37 -4
- package/skills/dev-flow/SKILL.md +378 -0
- package/src/core.ts +1320 -0
- package/src/detect.ts +103 -0
- package/src/projectmd.ts +394 -0
- package/src/timeouts.ts +79 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Format: newest first. `Unreleased` collects what's merged but not yet tagged.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.52.0] - 2026-10-21
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **The release publishes the package.** `pi-dev-flow` is on npm, and `.github/workflows/release.yml` is what puts it there: the `v*` tag `flow release` pushes triggers a job that checks the tag against the manifest version, proves the tag is on the default branch (an npm version is immutable — a tag cut from a feature branch would burn the number and ship code main never had), runs `npm ci && npm run build && npm test`, and publishes with `--provenance`. Authorization is npm **trusted publishing**: the job's OIDC identity is the credential, so there is no token in the repo to leak or rotate. Nothing publishes from a developer machine, and a failed publish is re-run on the same tag rather than re-tagged. The published manifest finally says what it ships (`files`), carries the `LICENSE` it had only claimed, states `engines.node`, and names the renamed repository; a new guard test refuses a pi-discoverable resource directory that `files` would silently drop, since that break is invisible to the author and fatal to whoever installs the package.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **`flow reflect` sends updates to npm.** The session-reflection protocol probed `git ls-remote` tags and recommended `pi install git:github.com/<upstream>`, because git was the only channel. It now compares the running version with `npm view pi-dev-flow version` and recommends `pi install npm:pi-dev-flow` then `/reload`, with the git probe kept as the fallback for git-installed copies (an installed fork still carries the same package name, so the probe stays correct). The README install section leads with the npm source and names the update path (`pi update --extensions`), and the publish workflow is documented for maintainers.
|
|
16
|
+
|
|
17
|
+
## [0.51.2] - 2026-10-21
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **`release-done` proves the forge release exists instead of trusting the attempt.** A repository carried an annotated tag, published images and a **completely empty Releases page** — the playbook had the forge-release key off, `release-done` verified the registry artifact, printed `release recorded as complete`, and nobody looked at the web page. Three earlier failures (#51, #60, #63 — quoting that shipped a shell error as the body, quoting that killed `gh release create`, and a create whose failure was stamped as a note the release rode past) are the same shape: recorded, nothing published. The gate now asks the forge (`gh release view <tag>` / `glab release view <tag>`) and refuses when nothing is there, naming both ways out: create it, or say publication is manual with `release.releases = false`. Skipping stays deliberate and loud — `--no-release-create`, `release.releases = false` and `forge = self` each print that no release was created, and the proof is skipped for them. This replaces #63's advisory note: a failed create is no longer something a release can ride past, so `finish`'s "the forge release was not created" warning can only fire for flows released by an older build.
|
|
22
|
+
|
|
23
|
+
## [0.51.1] - 2026-10-21
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`flow verify` runs the checks it gates on.** Entering a stage — and every edit of the worktree since — clears the recorded results, so the gate answered "check `test` has not passed — run flow check" and made the agent run it and come back: three round trips to say what one could, and the operator answering **Verified?** about a state the gate had never seen that round. A check with no passing record is now run by `flow verify` itself, the PASS is recorded like `flow check` records it, and the line says `checks ran at the gate (test)`. A check that fails there refuses the gate with its output instead of a pointer. `health` is left to the post-deploy probe when there is a deploy to prove — probing twice only waits twice.
|
|
28
|
+
|
|
29
|
+
## [0.51.0] - 2026-10-21
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`protect`/`forbid` can name a sibling set: `protect docker/.env*`.** A playbook guarded `docker/.env`, a session flipped a variable by copying the file aside to `docker/.env.bak-<date>`, and the backup went into a commit and out to a public repository. The guard never spoke: the path rule was prefix-only, so `.env*` was not expressible, and no `deny` regex could have caught it either — the commit (`git add -A`) never names the file. A glob in the **last** segment now matches the basenames in that directory (realpath'd like every other path rule, so a symlinked or `..`-reached directory cannot dodge it); a glob anywhere else in the pattern still means one literal path, and `flow init` / `flow doctor` now say so instead of letting a rule silently guard nothing.
|
|
34
|
+
|
|
35
|
+
## [0.50.0] - 2026-10-21
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **A forced push asks the operator instead of being someone's regex problem.** A secret reached a pushed branch and the only way back was a rewrite of that branch — which the guard chain refused with no authorised path: the playbook's own deny rule is unconditional, and the refusal's advice ("update it by merging main into it") is exactly the option that cannot be taken when the commits are the leak. The workaround the session found (scrub locally, push `-v2`, second PR, close the first) split one feature's audit trail and left the blob reachable on the old branch anyway. dev-flow now confirms `git push` carrying `--force`, `--force-with-lease…` or `-f` with the operator itself, and the refusal prints the one prefix that answers for it — `DEV_FLOW_ALLOW_REWRITE=1`, the same "the operator said so" contract as `DEV_FLOW_ALLOW_MAIN`, so it works headless too.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- **Playbook guidance anchors a guard rule on the verb, not on a flag.** The documented example was `deny \bgit\b[^\n]*--force`, which also refuses `git filter-branch --force` (a purely local rewrite) and `git show -f` — and a rule that blocks unrelated commands gets routed around until it means nothing. The example now reads `\bgit\b[^\n]*\bpush\b[^\n]*--force`, and the docs say plainly that a project needs no force-push rule of its own now that dev-flow confirms it.
|
|
44
|
+
|
|
45
|
+
## [0.49.1] - 2026-10-21
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- **A `cd ~/<worktree> && git commit` was judged from the session cwd and refused as a commit on the default branch.** The git guard took the `cd` / `git -C` target verbatim, and `path.resolve` treats `~/wt` as a relative path — it became `<session cwd>/~/wt`, where the branch probe could not answer. The probe then fell back to the session's own branch, so a legal worktree commit was blocked with "direct commits to main are forbidden": a message about a rule the command was never near. `~`, `$HOME` and `${HOME}` are now expanded where the directory is captured (any other `$VAR` stays literal — resolving it needs a shell, and guessing is how the wrong path appeared), the silent session-cwd fallback is gone (a directory git cannot answer for yields no verdict, and git itself fails there), and the commit refusal names the directory it judged so a future misjudgment reads as one.
|
|
50
|
+
|
|
51
|
+
## [0.49.0] - 2026-10-21
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- **The operator answers words; the agent runs the gates.** The stage hints injected into the model's context every minute ended with "ask the operator to run `/flow approve`" / `/flow verify`", which trained exactly the hand-off the skill forbids — the operator reading a command line instead of a question. The plan and implement hints now end with the checkpoint word and the gate the agent runs itself (`ask the operator Approve? in chat and run flow approve --confirmed`), and the every-turn rules line says outright that gates run through the flow tool, that the operator never types commands, and that `/flow` is their manual override. Same for the stage-context header's `/flow init` pointer.
|
|
56
|
+
- **README rewritten human-first, reference detail split into `docs/`.** It now leads with the idea (spec before code, gated phases, git hygiene, parallel worktrees) and a stage/gate diagram with what each gate refuses, one table of stage → what the agent does → the word it asks you, your checkpoint answers (`yes`/`no`/`yolo`/`no version`), what reflections are and what you do with them, and a short enforcement list. The gate table, playbook reference, full guardrail list, concurrency, headless contract and development notes moved to `docs/{gates,playbook,guardrails,concurrency,headless,development}.md` — moved, not rewritten, so nothing was lost in the move.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **A bash segment whose head is `flow` is refused.** There is no `flow` CLI — gates live inside the session — but agents kept calling `flow status` in a shell, collecting an exit 127 with no pointer, and repeating the mistake. The refusal names the call that works (`flow {args:["status"]}`), the same shape as the `bashTimeout` hint. Matching is the head token of a masked segment: `grep flow status`, a `skills/dev-flow/SKILL.md` path and a commit message quoting a gate are arguments, not invocations; a project that really ships a `flow` binary calls it by path or through `npx` (see Limitations).
|
|
61
|
+
|
|
62
|
+
## [0.48.0] - 2026-10-21
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
|
|
66
|
+
- **`flow verify` refuses a branch with nothing committed.** Checks describe the working tree, so an agent that committed nothing could ask **Verified?** about a state no gate had ever seen — the first hard commit wall was `flow finish`, long after the answer. The gate now counts the branch's commits over its merge base with the default branch (local refs only, so it stays offline-safe) and refuses at zero **before** build / `dev` / health spend minutes on a deploy; a branch whose merge base cannot be resolved prints `commits: unknown` and is never blocked on a measurement failure. Every verify line now names `commits: N ahead of <default>, M uncommitted path(s)` alongside what it ran, so the operator sees what they are approving — uncommitted paths are reported, not gated, so fixing something the operator spotted still costs a re-verify and not a commit ceremony. `--docs` features follow the same rule.
|
|
67
|
+
|
|
68
|
+
## [0.47.0] - 2026-10-21
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- **`release --no-version` now ships merge + changelog instead of skipping both.** The flow still cuts no version, tag or forge release, but the Release? gate refuses until the branch changes the changelog — the entry rides under `Unreleased` until the next versioned release folds it. The versioned gate grew the matching rule: it refuses while the `Unreleased` section (`## Unreleased` / `## [Unreleased]`, nested `###` sub-headings included) still holds entries — several `--no-version` flows accumulate there and a full release must gather them under its new version heading. `release.changelog` defaults to `CHANGELOG.md` (set it empty in project.md to opt out); with no changelog file at all an unversioned release is refused, since its changelog line is all it ships.
|
|
73
|
+
|
|
74
|
+
## [0.46.3] - 2026-10-21
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- **Skill release step now forbids `gh pr merge --delete-branch`** — it aborts with "'main' is already used by worktree" whenever the default branch is checked out in the main checkout (hit in two consecutive flows), and `flow finish` deletes the merged feature branch on proof anyway.
|
|
79
|
+
|
|
80
|
+
## [0.46.2] - 2026-10-20
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
|
|
84
|
+
- **Reflection is now part of every finish.** Before `flow finish` deletes `.dev-flow/<slug>/` and the session context with it, the agent runs the end-of-session reflection and parks real issues via `flow reflect`. With issues parked the closing question becomes **Fold? Fix? Drop?** (fold = queue them in `reflections.md`, fix = route them now via `flow doctor`, drop = discard) and its answer replaces **Finish?** — no second question; with nothing parked, Finish? stays as before.
|
|
85
|
+
|
|
86
|
+
## [0.46.1] - 2026-10-20
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- **The skill now states the rules the plugin only enforced silently.** Every shell call must pass an explicit `timeout` (the `bashTimeout = require` guard, shipped in 0.45.0, was undocumented in the skill). Checkpoint grammar is enforced: the agent asks the one-verb question (Approve?/Verified?/Release?/Finish?) in plain chat, mentions that **yolo** is an available answer, and runs the gate when the operator answers — it never routes the operator to a `/flow` command at a checkpoint. `skills/dev-flow/SKILL.md` was also compacted ~18% with every rule kept: the checkpoint/`--confirmed`/mode-grant grammar that was stated up to four times now lives once in the ground rules, and rationale prose was trimmed.
|
|
91
|
+
|
|
92
|
+
## [0.46.0] - 2026-10-20
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- **A type error shipped in 0.45.2 because nothing typechecked.** The compaction takeover passed pi's `ProviderHeaders` (values may be `null`) into `compact()`, which takes plain string headers — `npx tsc --noEmit` failed on main and every gate stayed green, because tier-1 was only `npm test`. Null headers are dropped at the call site and `npm run build` (`tsc --noEmit`) is now a script; add `build = npm run build` under `## implement` in your playbook to gate on it.
|
|
97
|
+
- **Deleting flow state was not blocked; reading it was.** The state guard matched one path shape plus a loose verb list: `rm -rf .dev-flow/<slug>` (state *and* plan, gitignored, unrecoverable) and `cd .dev-flow/<slug> && mv state.json /tmp/bak` passed it, while `jq -e .stage .dev-flow/x/state.json` — a read — was refused for a `-e`. Both tamper checks now share one per-segment, target-based verdict (the same shape the playbook check learned in #53): the folder, the feature directory and `state.json` are owned, reads and backups stay free, and the block message names what was actually touched. Writing state files is now atomic (tmp + rename), so a kill mid-write no longer truncates a feature out of existence.
|
|
98
|
+
- **`flow init --force` overwrote the operator playbook with no confirmation and no backup** — an agent that misread a doctor finding could replace every `flow-guard` rule, checklist item and piece of guidance with a detection draft. It now needs the operator's word (`--confirmed`, or one confirm dialog for a human) and every sanctioned playbook overwrite keeps the previous file as `project.md.bak`.
|
|
99
|
+
- **A release could be recorded from tags that never left the laptop.** When `git ls-remote` failed (offline, no ssh agent) the tag list silently fell back to local tags, so `release-done` declared a release whose tag had not been pushed. An origin that exists but cannot be asked now refuses both release gates.
|
|
100
|
+
- **`mdDigest` skipped `## pre-release` entirely** — `buildDraft` writes `versionFile`/`versionTag` there, so the init dialog never showed the version rules, the tag pattern or that stage's checklist items. Pre-release now renders like release.
|
|
101
|
+
- **`<!-- operator notes -->` in project.md were injected as stage guidance** on every turn of every session (this repo's own `<!-- tier-3: standing guidance -->` placeholder included). HTML comments are inert again; real prose still injects.
|
|
102
|
+
- **`flow test` / `flow health` pointed at `.dev-flow/project.json`** — a file the plugin no longer reads and the guard refuses to create. Both messages now name `## implement` in project.md.
|
|
103
|
+
- **A failed `ctx.compact()` left the in-flight mark set**, switching off flow-aware self-compaction (and the takeover) for the rest of the session.
|
|
104
|
+
|
|
105
|
+
### Changed
|
|
106
|
+
|
|
107
|
+
- **Gates follow the session claim.** Passing another live session's slug to `flow approve`/`verify`/`finish` is refused with "flow use <slug> takes it over explicitly" — before, two sessions drove one feature and clobbered each other's state file, which is exactly what claims exist to prevent.
|
|
108
|
+
- **`deny`/`confirm` rules now see write-capable read-only heads**: `find -delete`, `find -exec …`, `sort -o FILE` and `awk 'BEGIN{system(…)}'` no longer slip past the read-only skip list, while `grep "git push --force" docs/` stays a search.
|
|
109
|
+
- A plan-stage session may only write inside **its own** `.dev-flow/<slug>/` — it can no longer edit another feature's plan and let that feature's approval gate accept text it never wrote.
|
|
110
|
+
- The bash guard parses each git segment once instead of four times, and `featureRefs` is built once per call.
|
|
111
|
+
|
|
112
|
+
### Removed
|
|
113
|
+
|
|
114
|
+
- The duplicate `StageCheck` interface in `projectmd.ts` (core's is imported) and the always-empty `findings` field of `loadProject`, which nothing read.
|
|
115
|
+
|
|
116
|
+
## [0.45.2] - 2026-10-20
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- **A flow-bound threshold compaction deadlocked the session instead of compacting it.** The takeover awaited `ctx.compact()` from inside `session_before_compact` — but pi's `compact()` opens with `abort()` + `waitForIdle()`, and the run awaiting the hook can only go idle once the hook returns: a full cycle. The summarize request was never issued (nothing ever reached the provider), no compaction entry landed, the UI spun on "Compacting…" forever, and Stop could not free it — the takeover ignored the very abort signal compaction events carry. The unit test mocked the exact `ctx.compact` call that deadlocked, which is how a 100%-deadlocking takeover shipped. The takeover now never re-enters `compact()`: it calls the same `compact()` pi itself calls — same split-turn merge, file lists and structured prompts — with the flow-aware instructions and the event's signal, and returns the summary through the event's custom-compaction channel, which pi appends itself (no cancel dance; Stop now really cancels the summarize call). Any takeover failure returns `undefined` and pi's own compaction proceeds — a broken takeover can no longer block compaction at all. The rewritten test drives the real path through a one-line seam and asserts auth and signal forwarding, the fallback, and that a failed takeover releases the in-flight mark.
|
|
121
|
+
|
|
122
|
+
## [0.45.1] - 2026-10-20
|
|
123
|
+
|
|
124
|
+
### Fixed
|
|
125
|
+
|
|
126
|
+
- **A redirect to somewhere else is not a write to the playbook.** The playbook guard's loose fallback tested a verb list whose first term was a bare `>`, so *any* segment that merely mentioned `.dev-flow/project.md` was refused the moment it contained any redirect at all — it blocked `gh pr create --title … --body "…prose about the playbook…" 2>&1 | tail -1` during the 0.45.0 release, and would have refused `> /tmp/out.log` just as happily. The dangerous form was never the problem: a redirect whose target *is* the playbook (plain, quoted, or inside a `sh -c` payload) is caught by the dedicated check two lines earlier, so the fallback now looks for write **tools** only (`tee rm mv cp sed -i truncate dd python node`) and ignores redirection. Reads, backups and heredocs that discuss the path keep passing exactly as before; `> .dev-flow/project.md`, `>> '.dev-flow/project.md'`, `sh -c "echo x > .dev-flow/project.md"`, `tee` and `truncate` into it still refuse — and the new test fails against the old pattern, so the fix is pinned from both sides.
|
|
127
|
+
|
|
128
|
+
## [0.45.0] - 2026-10-20
|
|
129
|
+
|
|
130
|
+
### Changed
|
|
131
|
+
|
|
132
|
+
- **BREAKING: a shell call must state its own timeout** — `bashTimeout = require` is the new default. v0.43.0 started arming a deterministic class default whenever a call arrived without one, which ended the hangs but left the call line looking unarmed: the value is written into `event.input` by the `tool_call` handler *after* the transcript recorded the call, so neither operator nor model ever saw a `timeout` on it — a bare call read as "nothing will kill this". Now the call is **refused** until the model states one, and the refusal quotes the exact number the class table would have armed (`pass an explicit timeout on shell calls — the class default here is 900s …`), so the retry is a one-token fix and every shell call in the transcript shows the timer that is really running. The silent injection stays in place underneath both modes and is what protects a project that opts back — `bashTimeout = inject` in `## global` restores the 0.43.0 behaviour exactly. A session with no `.dev-flow/project.md` cannot opt out (no playbook to put the key in), so it applies to every agent loading this build; for that reason the guard is judged **after** the project's own `flow-guard` deny/confirm rules — an operator deny still answers with the operator's reason even on a call that forgot the timeout. The injected value also finally has a test asserting it lands on `input.timeout`: the smoke suite drove this handler for guard verdicts for two releases without ever checking the injection reached the call.
|
|
133
|
+
|
|
134
|
+
## [0.44.0] - 2026-10-20
|
|
135
|
+
|
|
136
|
+
### Added
|
|
137
|
+
|
|
138
|
+
- **The plan stage now teaches the mockup harness, not just the gate** (#70). Step 4 of the plan stage said "build mockups, render them, embed them" — correct as a gate, silent about the tool, and an agent mocking *stateful* UI paid for the gap: ~20 render attempts in one session, a List-view shot showing a control the real code hides, an "after" shot of a stale teardown state, renders written as bare filenames (prose, not `![]()` — broken links the operator flagged twice), a shared chromium profile leaking localStorage between shots, and below-the-fold regions coming back blank because a headless shot always captures from the page's top-left. Step 4 now carries the checklist that makes those impossible to hit blind: an embed is the image syntax and every tag is re-checked against the filesystem before Approve?; a component question gets a **static strip** against the project's real stylesheet instead of driving the app's state machine through the harness; nothing scrolls, so hide what is above the region or render a strip; one fresh profile dir per intended UI state; a shot of planned behavior must show it and be captioned as such; freeze the app's own repaint to catch a transient state (an inline editor); and when the harness fights the same shot twice, verify that state via DOM/code and move on — screenshots are a spot-check, not a test loop. Step 4's first sub-bullet, which rendered inside its sentence, is fixed on the way.
|
|
139
|
+
|
|
140
|
+
## [0.43.1] - 2026-10-20
|
|
141
|
+
|
|
142
|
+
### Fixed
|
|
143
|
+
|
|
144
|
+
- **`flow reflect` files notes where it says it does** (#69). `appendReflection` rebuilt `reflections.md` from two buckets and re-derived the bucket of **every existing line** from an inline `(plugin)` marker — which new-style items never carry, because the `## playbook` / `## plugin` heading above them is the only information. So each write re-moved the whole `## plugin` section into `## playbook` (a both-sections note then showed up twice under `## playbook`, and a checked-off plugin item wandered off too), and a file whose playbook section was empty lost its plugin items on the next reflect — while the printed `reflected (plugin)` line was the only feedback the agent got, and it was wrong. A heading is now authoritative for the lines under it, order is preserved and nothing relocates; an identical note already open in a section is not written there again (the call reports `already reflected (duplicate)` instead, and a checked-off note may be reported again when it comes back). Items above every heading keep the inline-marker reading, so the legacy flat-file migration is untouched. An unbound session also stopped signing notes `— - <date>` — no slug now means no slug, `— <date>`.
|
|
145
|
+
|
|
146
|
+
## [0.43.0] - 2026-10-20
|
|
147
|
+
|
|
148
|
+
### Added
|
|
149
|
+
|
|
150
|
+
- **Shell calls can no longer hang a session forever** (operator request). pi arms its kill timer only when the model passed a `timeout`, and it omits one in ~75% of calls — this host's session logs showed hangs of hours (`gh pr merge` waiting on a prompt, `curl` to a dead port, `git push` on a credential prompt, foreground watchers). The `tool_call` handler now injects a **deterministic class default** whenever a shell call has no timeout, and clamps explicit ones to 1,800s: 30s quick inspection (ls/grep/`git status`) · 120s local git and anything unrecognized · 180s network (`git push`, curl, gh) · 300s containers/services (docker, systemctl) · 900s builds/tests/installs · 1,200s watchers (`gh run watch`, `logs -f`, `compose up` without `-d`). Compound commands split on `&&`/`;`/`|` and the slowest class wins; wrappers (`cd`, `export`, `sudo`) don't count. The numbers come from the measured duration distribution (99% of no-timeout calls end under ~70s; real builds under ~400s), so a premature kill is rare and self-correcting — the model sees `timeout:` and reruns with an explicit value. Sensible explicit timeouts pass through untouched. The policy applies to every session that loads the package, flow-bound or not.
|
|
151
|
+
|
|
152
|
+
## [0.42.0] - 2026-10-19
|
|
153
|
+
|
|
154
|
+
### Added
|
|
155
|
+
|
|
156
|
+
- **Machine surfaces for headless orchestrators** (driving dev-flow from a remote agent via a Pi SDK session). `flow status --json` answers the prose view as stable JSON — bound slug plus per-feature stage, mode flags, branch, worktree, approvals, checks (name→ok) and the next hint — parseable in every case, an empty repo included; `flow help --json` returns the gate contract as data (the command list split from the one `GATE_HELP` source, the checkpoint questions, the flag names) so an orchestrator learns the interface without grepping prose. Both are additive: the human views are unchanged.
|
|
157
|
+
- **`NEEDS-OPERATOR` refusal marker.** Every no-UI refusal that needs the operator's word now starts with the stable token `NEEDS-OPERATOR <Question?> — …` (the four checkpoint gates, and a project flow-guard `confirm` rule met without UI). A remote driver routes on the token — relay the question, then re-run the gate with `--confirmed` — instead of string-matching prose that is free to drift. The human-readable sentence follows the marker unchanged.
|
|
158
|
+
- **README: “Driving dev-flow from an orchestrator (headless)”** — the refuse → relay → `--confirmed` loop, the honor-system trust of `--confirmed`, one-session-one-feature binding for reconnecting drivers, long-gate timeouts, check invalidation and version skew, and the read-only-safe command set.
|
|
159
|
+
|
|
160
|
+
## [0.41.0] - 2026-10-19
|
|
161
|
+
|
|
162
|
+
### Added
|
|
163
|
+
|
|
164
|
+
- **yolo works at any gate** (operator request). Until now `“you said yolo” could only be recorded at Approve? (`approve --yolo`); saying yolo later meant answering every remaining checkpoint one by one. Now **every state gate accepts `--yolo`** — `verify --yolo --confirmed`, `release --yolo --confirmed`, `finish --yolo --confirmed` answer that question and pre-confirm all later ones, so “yolo” at Verified? runs verify → release → release-done → finish to the end with no further questions. `--yolo` without `--confirmed` is refused — the flag is the operator's word, never self-granted. Guidance attached to the yolo word (“yolo, create a patch version release”) is a binding directive for the gate chain, and the YOLO stage guidance now spells the chaining rule out to the agent. Checks and guardrails stay fully enforced: tier-1 gates, version/changelog validation and flow-guard `confirm` rules are untouched by yolo.
|
|
165
|
+
|
|
166
|
+
## [0.40.0] - 2026-10-19
|
|
167
|
+
|
|
168
|
+
### Added
|
|
169
|
+
|
|
170
|
+
- **Roadmap: a flow-aware backlog of future features** (operator request). `.dev-flow/roadmap.md` is a gitignored `- [ ]` checklist of features to build later — advisory like `reflections.md`, it never gates. `flow roadmap` lists the open items numbered; `add "<feature>"` appends one; `pick <n> <slug>` stamps open item *n* with the slug and prints the `flow start` line (one verb — it starts nothing itself), and when a flow with that slug reaches `finish`, **the stamped item checks itself off** (`— done: <date>`) — a picked feature closes its backlog line with no extra ceremony; `done <n>` checks off by hand for items shipped outside a flow, `tidy` drops the checked lines. The open count is surfaced in `flow status` (including the no-features answer — a backlog is most useful before a flow exists) and in the per-turn session context, bound and unbound; direct edits of the file are equally fine.
|
|
171
|
+
|
|
172
|
+
## [0.39.2] - 2026-10-19
|
|
173
|
+
|
|
174
|
+
### Fixed
|
|
175
|
+
|
|
176
|
+
- **A failed forge release can no longer slip past the flow** (#63). `release-done` created the forge release *advisory* — a failed `gh`/`glab release create` printed `github release skipped: <error>` and the release was recorded anyway; an operator who skimmed the line finished the feature with a tag but no release page. A failed create now **stamps the flow state** (`forgeReleaseSkipped`, cleared by a successful re-run of `release-done`) and **`finish` names it in the Finish? question**, in the no-UI refusal and in the `--confirmed` output — intentional skips (`--no-release-create`, `release.releases = false`, `forge = self`) stay silent, because declining is the operator's call, a failure never is.
|
|
177
|
+
|
|
178
|
+
## [0.39.1] - 2026-10-18
|
|
179
|
+
|
|
180
|
+
### Fixed
|
|
181
|
+
|
|
182
|
+
- **Every argument that reaches `/bin/sh` is now a real shell literal** (the #51 leftover, from an open reflection). Gates built commands with `${JSON.stringify(x)}` — JavaScript quoting, which `/bin/sh` strips before expanding what is inside: an annotated tag whose body held backticks had its code spans *executed* by `gh release create` (v0.37.1), a semicolon killed it outright (v0.38.0); the #51 fix had quoted the notes on the way in, not the way out. A `sq()` helper (POSIX single quotes, `'\''` for embedded quotes) now escapes all 19 such embeddings — release commands, tag lookups, worktree and branch paths, remote refs — and the smoke round-trip runs a tag body full of backticks, `$()` and `;` through real `/bin/sh`, asserting it prints verbatim and nothing runs.
|
|
183
|
+
|
|
184
|
+
## [0.39.0] - 2026-10-18
|
|
185
|
+
|
|
186
|
+
### Fixed
|
|
187
|
+
|
|
188
|
+
- **The compaction pacing now counts the way pi counts** (operator report). The 0.35 safe-point compaction compared against the *built-in* `reserveTokens` default while pi compares against the effective one — settings and per-model overrides included. Any reserve above 16384 ate the 16 KiB margin directly; above 32768 pi's threshold sat *below* dev-flow's and always won. The trigger now reads the effective reserve through pi's own `SettingsManager`, and a `compaction.enabled = false` in settings is honored — dev-flow no longer compacts behind an operator who turned auto-compaction off. A malformed compaction setting bails the check instead of crashing every turn end.
|
|
189
|
+
- **Safe points at pi's frequency.** pi checks its threshold between *every* turn, after tool results land; dev-flow only checked after a gate and when a run settled — a long implement run without a `flow` call got no check, and one fat tool batch (two 50 KB-capped reads already approach 16 KiB) jumped past the margin mid-run. `turn_end` is now a safe point too.
|
|
190
|
+
- **A forced threshold compaction gets taken over.** The chat-only states (open tier-2 dialog, undigested plan discussion) deliberately never self-compact — but pi force-compacted that same transcript blind, and the plan dialog is the most token-hungry state there is. `session_before_compact` now redoes a threshold compaction with the flow-aware instructions (awaited before cancelling pi's, so it never races `prepareNextTurn`; if ours fails, pi's proceeds). Overflow recovery is left alone — cancelling it would drop pi's compact-and-retry.
|
|
191
|
+
|
|
192
|
+
## [0.38.0] - 2026-10-18
|
|
193
|
+
|
|
194
|
+
### Fixed
|
|
195
|
+
|
|
196
|
+
- **The guards read commands, not prose.** `bashSegments` split on `;`, `|`, `&` and newlines without respecting quotes, so every line inside a quoted argument became a segment of its own: a `gh pr create --body "…"` whose body discussed a commit was refused as a main-branch commit, and `playbookTamper` — matching a write verb anywhere in a segment against the playbook path anywhere else — refused a PR body that quoted a copy of the playbook. Both fired during the v0.37.0 release, on the text describing the fix. Splitting now respects quotes, and quoted argument contents are masked before the playbook check, so the operator's words about a command are data.
|
|
197
|
+
- **A wrapper cannot carry a git command past the guard.** `sh -c "git push origin main"` used to slip through: the guard only recognised `git` as the first word of a segment. Segments whose head executes its argument (`sh`, `bash`, `node`, `python`, `env`, `xargs`, `sudo`, …) are now judged on their payload, and their quoted text stays code rather than being masked. Unbalanced quoting keeps the old plain split, so a stray quote cannot be used to hide a command either.
|
|
198
|
+
|
|
199
|
+
## [0.37.1] - 2026-10-18
|
|
200
|
+
|
|
201
|
+
### Fixed
|
|
202
|
+
|
|
203
|
+
- **`flow version` says which build is running.** A session keeps the code it loaded at start while the manifest on disk moves past it after a release, so a long-lived session reported the new version while executing the old gates — twice in a row that meant shipping release notes generated by the previous session's broken code. `flow version` now names both when they disagree (`dev-flow 0.37.0 … — but this session runs 0.36.0; /reload to run 0.37.0`), `flow release-done` prints the same warning before it publishes anything, and the skill tells the agent to stop and ask for `/reload` instead of releasing from behind.
|
|
204
|
+
- **Release-stage checklist items are no longer uncatchable.** No gate records a `release`-stage confirmation, so a release-stage item nagged from `release-done` to `finish` with nothing able to mark it handled, and the checklist itself vanished at the last objective gate. `release-done` now lists the still-open release-stage items, and the nag says plainly that the operator's **Finish?** answer is what closes them.
|
|
205
|
+
|
|
206
|
+
## [0.37.0] - 2026-10-18
|
|
207
|
+
|
|
208
|
+
### Fixed
|
|
209
|
+
|
|
210
|
+
- **The playbook-tracking chore finally has a legal path** (#53). `flow doctor` said *`.dev-flow/project.md is not tracked in git — git add -f .dev-flow/project.md`* while every route to doing it was closed: commits on the default branch are forbidden with no flow bound, and a docs flow's worktree cannot contain a file that is untracked in the checkout it was cut from. A commit whose **only** change in that checkout is the playbook is now allowed — tracking the operator's playbook is setup, not feature work — and any other dirty path closes the lane (`--amend` never uses it: that rewrites the default branch's history). Doctor, `flow init` and the skill now print the command that works: `git add -f .dev-flow/project.md && DEV_FLOW_ALLOW_MAIN=1 git commit -m "track project.md"` (the env prefix is for the installed hook only).
|
|
211
|
+
- **The playbook guard no longer blocks reads and backups** (#53). `playbookTamper` matched a write verb *anywhere* in the command against the path *anywhere else*, so `cp .dev-flow/project.md /tmp/project.md.bak` — the safety copy to make before a write — was refused, along with `grep -e health .dev-flow/project.md`, `git ls-files --error-unmatch .dev-flow/project.md` (a bare `-e` in the verb list), `sed -n 1,10p …` and a `cat > /tmp/issue.md` heredoc that merely mentions the path. Writes are now decided per segment and by target: redirect into the playbook, a copy/replace verb whose destination is the playbook, or a real write tool (`python -c`, `node -e`, `sed -i`) — everything else reads.
|
|
212
|
+
|
|
213
|
+
## [0.36.0] - 2026-10-18
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
|
|
217
|
+
- **`release-done` publishes the version the release gate approved** (#52). The `release` gate read the manifest under the feature worktree, `release-done` read it from the main checkout — so a main checkout whose default branch was still behind republished the *previous* version, its `release.artifact` probe verified the previous artifact, and the gate reported `Artifact verified.` while nothing new shipped (this happened in the wild: a `v0.9.0` release came out as `v0.8.1`). The gate now stamps its validated version into the flow state (`releaseVersion`) and `release-done` publishes exactly that; the artifact line names what it probed (`Artifact verified for 0.9.0.`).
|
|
218
|
+
- **Tags are judged by what origin holds, not by one clone** (#52): "already tagged" and "the tag exists" now come from `git ls-remote --tags origin` (local tags only when there is no remote), and a release older than the newest matching tag on origin is refused outright — `v9.9.9 is already tagged — refusing to release v9.9.8 behind it`.
|
|
219
|
+
- **Forge release bodies stopped being shell errors** (#51). `git tag -l --format=%(contents)` is a `/bin/sh` syntax error (the unquoted `(`), and `sh()` folds stderr into its output, so `/bin/sh: 1: Syntax error: "(" unexpected` became the stored release notes — on two repos, including dev-flow's own `v0.34.0` and `v0.35.0`. The format is now quoted, notes are taken only from a *successful* tag command, and a body that looks like a shell complaint is dropped and reported instead of published. When a tag carries no annotation (a lightweight tag silently produced an empty body), the body falls back to that version's `release.changelog` entry, and if there is none the gate says so: `no release notes (tag v0.9.0 carries no annotation … — tag with git tag -a)`.
|
|
220
|
+
|
|
221
|
+
## [0.35.0] - 2026-10-18
|
|
222
|
+
|
|
223
|
+
### Added
|
|
224
|
+
|
|
225
|
+
- **`healthWait` in playbook `## implement`** (#42): the seconds the post-deploy health probe may keep retrying — one immediate shot plus a retry every 2s, default 30, `healthWait = 0` restores the single shot. A service whose readiness lags its container start (a BFF answering `/readyz` only after its upstream connects) no longer needs a poll loop hand-written into the playbook, and the gate says how it tried: `health: PASS (curl … , 3 attempts)` / `gave up after 16 attempt(s), healthWait 30s`. `flow health` waits the same way; `flow check` stays single-shot — before any deploy there is nothing to wait for.
|
|
226
|
+
|
|
227
|
+
### Fixed
|
|
228
|
+
|
|
229
|
+
- **`approve` retries a setup that never succeeded** (#49). A failed `commands.setup` left the worktree behind and the next `approve` reused it in silence — "fix it and run approve again" was a no-op, and the damage (no `.env`, no `node_modules`) only surfaced later as an unrelated-looking `flow check` failure. Setup now stamps `setupAt` when it first exits 0 and reruns until it does.
|
|
230
|
+
- **A `--docs` feature runs no project command** (#49 #43). Docs mode's contract was always "no tier-1 checks", but `approve` still copied `.env` and installed dependencies and `verify` still built, deployed and probed. Now: `setup skipped (docs mode)`, `docs mode: project commands skipped (build/dev/health)` — and the verify prompt no longer claims a dev deploy is up for review when none ran.
|
|
231
|
+
- **`flow reflect "<note>" --confirmed` no longer pastes `--confirmed` into the note** (#43) — the flag belonged to the state gates and made the operator's own sentence in `reflections.md` read like a command line. A flags-only `reflect` is a bare reflect.
|
|
232
|
+
|
|
233
|
+
## [0.34.0] - 2026-10-17
|
|
234
|
+
|
|
235
|
+
### Changed
|
|
236
|
+
|
|
237
|
+
- **Status bar is emoji-only: `<stage glyph> <slug>` plus markers.** Stages render as 📝 plan, 🔨 implement, 🔍 pre-release, 🚀 release, with ⚡ patch, 📚 docs, 🎱 yolo and ⚠️ while a check fails — no `◆` anchor, no stage word, no theme stage color (color-emoji ignore `theme.fg`). `flow status` is now the spelled-out surface (`stage=implement`, the `[ui]`/`[yolo]`/`[no-version]` tags, the `flow=<ver>` stamp).
|
|
238
|
+
|
|
239
|
+
### Removed
|
|
240
|
+
|
|
241
|
+
- **The `ctrl+,` detail panel is gone** (overlay, shortcut, `STAGE_COLORS`). It needed a real terminal — `ui.custom()` is a no-op in RPC/web mode — so the footer and `flow status` are the only status surfaces now. README's Status bar line is the glyph legend.
|
|
242
|
+
|
|
243
|
+
## [0.33.3] - 2026-10-17
|
|
244
|
+
|
|
245
|
+
### Fixed
|
|
246
|
+
|
|
247
|
+
- **Stale section headers in `reflections.md` no longer duplicate.** Everything above the first item is the verbatim preamble, so empty `## playbook` / `## plugin` headers left there by an older rewrite were copied back on every append — headers multiplied with each `flow reflect "<note>"`. `appendReflection` now drops bare section headers from the preamble; the rebuilt sections below are the only headers.
|
|
248
|
+
- **Bare `/flow reflect` now executes instead of just rendering.** The command bar sends gate output as a display-only box with no model turn — for `reflect`, whose entire output is a work instruction for the agent, that meant the protocol printed and nothing happened. Bare `reflect` from the bar now triggers a model turn so the agent runs the protocol; every other command keeps the display-only behavior.
|
|
249
|
+
|
|
250
|
+
## [0.33.2] - 2026-10-16
|
|
251
|
+
|
|
252
|
+
### Fixed
|
|
253
|
+
|
|
254
|
+
- **`flow reflect`'s output now says so in the first line: it is a work instruction, execute it.** The protocol listed the steps but never told the agent to run them — an agent that only echoed the printed protocol looked like "the command did nothing". The preamble now opens with "this output is your work instruction: execute these steps now — do not echo the protocol and do not ask to begin."
|
|
255
|
+
|
|
256
|
+
## [0.33.1] - 2026-10-16
|
|
257
|
+
|
|
258
|
+
### Fixed
|
|
259
|
+
|
|
260
|
+
- **Release chores finally have a lane in the main checkout.** The bash guard blocked `git commit` on the default branch at **every** stage — including `release`, where the stage hint tells the agent to "commit and push the release chores in the main checkout" and pushing to the default branch is explicitly allowed: a dead allowance, since the commit to push could never be created. Commits on the default branch now carry the same stage exception as push and merge — only at stage `release` — and the release hint names the `DEV_FLOW_ALLOW_MAIN=1` prefix the installed pre-commit hook requires.
|
|
261
|
+
|
|
262
|
+
## [0.33.0] - 2026-10-16
|
|
263
|
+
|
|
264
|
+
### Added
|
|
265
|
+
|
|
266
|
+
- **`flow reflect` — the full session-reflection protocol.** Bare `flow reflect` prints what the agent must do at the end of a session and the facts it cannot guess: running plugin version, upstream repo, and the open `reflections.md` items with their routes. The protocol: review the session log in full (messages, tool calls, results); re-check every open item against the current playbook and **newer dev-flow versions** — dev-flow ships from git, so the probe is `git ls-remote --tags --sort=-v:refname <upstream> | head -1` against the running version, and a newer tag covering an item means recommending the operator update (`pi install git:github.com/<upstream>` + `/reload`) — check items off in reflections.md (gitignored, agent-editable); dedupe new findings against open items before queueing them; report playbook vs plugin items to the operator structurally; ask whether to fix now — yes: plugin items search upstream first (`gh issue list --repo <upstream> --state all --search …`, an author-addressed match is reported back, never re-filed; no match → `gh issue create` with a detailed description, session evidence and a suggested fix), playbook items go through `flow doctor` to their docs flow. The command writes nothing and runs no network calls — the protocol is the agent's, the facts are the plugin's. `pluginVersion` now also reports the manifest's upstream `owner/slug` (package.json carries a `repository` field).
|
|
267
|
+
|
|
268
|
+
### Removed
|
|
269
|
+
|
|
270
|
+
- **`flow doctor reflect "<note>"` — queue notes with `flow reflect "<note>"`** (same section routing by wording; plain `flow doctor` still reviews and routes open reflections). The old form lost its special case: `flow doctor reflect x` now prints a fresh-note investigation brief for an observation literally named "reflect x" and touches nothing.
|
|
271
|
+
|
|
272
|
+
## [0.32.0] - 2026-10-17
|
|
273
|
+
|
|
274
|
+
### Added
|
|
275
|
+
|
|
276
|
+
- **Guided setup on `flow init`.** A first init no longer writes a detection draft silently: it prints a **setup brief** — the detection report plus one question per knob detection cannot decide (git forge, version manifest and tag convention, automatic forge releases, registry artifacts like Docker Hub, the real test/build/lint/health commands, tier-2 items and prose). The agent relays the questions to the operator and applies the answers through the validated `flow init --write`; an interactive init can review the draft with one confirm dialog and write it there. Nothing touches disk before the operator confirms.
|
|
277
|
+
- **Forge support end-to-end.** New global key `forge = github | gitlab | self` (auto-detected from the `origin` URL at the moment of use when unset). `flow release-done` creates the forge release from the verified tag via `gh` or `glab release create` — and stays hands-off for `self`, where publication is manual. `flow finish` proves a squash-merged branch via `gh pr list`, or the GitLab API via `glab api projects/:id/merge_requests?source_branch=…&state=merged`, or ancestry alone — an unverifiable branch is still never deleted.
|
|
278
|
+
- **`flow doctor` reviews reflections and routes the fixes.** Bare doctor now lists every open `reflections.md` item with its section and a fix route: playbook item → a docs flow (`flow start fold-<topic> --docs --confirmed`), plugin item → an upstream issue in your repo or a patch/normal flow inside the dev-flow repo. It still never writes, never asks — CI-safe. `flow doctor "<observation>"` (new form) prints an investigation brief and a fix route for a fresh note without queueing it; `flow doctor reflect "<note>"` still parks raw notes.
|
|
279
|
+
|
|
280
|
+
### Changed
|
|
281
|
+
|
|
282
|
+
- **`.dev-flow/project.md` now lives in git** — the one tracked file under `.dev-flow/`. The self-ignoring `.gitignore` heals to `*` + `!project.md`, doctor finds an untracked playbook (tracking is `git add -f` — a root `.gitignore` may exclude `.dev-flow/` wholesale, and a tracked file outranks the ignore), and write discipline is enforced instead of conventional: the main-checkout playbook is blocked for agent edits and bash writes outright, and the worktree copy is writable only inside an operator-granted **docs or patch flow** — playbook updates go through the docs flow, with its gates as the confirmation.
|
|
283
|
+
- **`release.github` is renamed `release.releases`** (operator's call): the old key still parses, with a rename warning from doctor.
|
|
284
|
+
|
|
285
|
+
### Removed
|
|
286
|
+
|
|
287
|
+
- **`project.json` is gone.** It is no longer read at all (`loadConfig`/`mergeConfig` deleted); a leftover file is a doctor finding — fold the values into `project.md` and delete it. `flow init --write` was already the only sanctioned write path and stays it.
|
|
288
|
+
|
|
289
|
+
## [0.31.0] - 2026-10-15
|
|
290
|
+
|
|
291
|
+
### Added
|
|
292
|
+
|
|
293
|
+
- **`flow verify` re-probes the deploy it just made.** `flow check` records `health` PASS *before* the deploy, so a `commands.dev` that failed to restart the container, brought it back unhealthy, or left it serving the previous image used to walk through the gate on evidence about a container that no longer exists. Verify now runs the project's own probe — `commands.health`, or a `flow-check` block named `health` (`seedData` first when set) — right after a successful dev deploy, in the worktree, records it, and **refuses the gate** when it fails: `post-deploy probe FAILED (<cmd>):` plus the output tail. What "healthy and serving the expected version" means stays project knowledge, not plugin knowledge: the probe runs with the worktree as cwd, so the project's script waits for readiness and compares the served build stamp with `git rev-parse HEAD`. No new config key.
|
|
294
|
+
- **Success output names it**: `dev ran (bun run build:bff && docker compose -f docker/compose.yml up -d); health: PASS (./scripts/probe-dev.sh)`, or `health: none configured` — a missing probe is a notice, never a block (the gate must stay walkable for playbooks that deploy without a probe).
|
|
295
|
+
- **doctor finding**: `dev` deploy configured with no health check — verify cannot prove the deploy came back serving this build.
|
|
296
|
+
|
|
297
|
+
## [0.30.2] - 2026-10-15
|
|
298
|
+
|
|
299
|
+
### Fixed
|
|
300
|
+
|
|
301
|
+
- **`flow init --write` no longer claims `.dev-flow/ created` in a repo that already had it** (#39). The recursive mkdir cannot tell the two apart, so every init path — worst the agent-only `--write` path — printed a creation that never happened, and the agent went off to diff its own playbook for damage that had not been done. Creation is now reported only when the folder was really created; otherwise `--write` prints just `project.md written (operator-owned playbook)`.
|
|
302
|
+
- **`flow verify` says which commands it ran** (#38). `commands.dev` can rebuild an image and recreate a live container — minutes of work and a real side effect — while the only output was `verified … — entering pre-release stage.`, which read as if nothing had run. The gate now prints `build ran (<cmd>)` / `dev ran (<cmd>)`, or `dev: none configured`, on success and on the "verification needs the operator" path alike, and names the command in the Verified? prompt. Same precedent as `setup ran in the worktree (<cmd>)`; checks, guardrails and prompts are unchanged.
|
|
303
|
+
|
|
304
|
+
## [0.30.1] - 2026-10-14
|
|
305
|
+
|
|
306
|
+
### Fixed
|
|
307
|
+
|
|
308
|
+
- Documentation consistency: the extension header's stale stage/gate lists (missing `pre-release`, missing the `release` gate, "merged worktree" criterion), the skill playbook's operator-config rule now names `project.md` (legacy `project.json` noted as superseded), `flow help`/command description now show `start --force` and the `release-done` opt-out flags, the README status-bar bullet documents the mode markers (⚡/📄/🎱) and the `flow status` mode tags + `flow=<ver>` stamp; a dead v0.5.0 limitations line was dropped. No behavior change.
|
|
309
|
+
|
|
310
|
+
## [0.30.0] - 2026-10-14
|
|
311
|
+
|
|
312
|
+
### Added
|
|
313
|
+
|
|
314
|
+
- **`flow help`** (aliases `--help`, `-h`) prints the gate usage — answerable in any repo, at any stage, with no `.dev-flow/` (where `flow --help` used to fall into an unknown-subcommand error).
|
|
315
|
+
- **Version stamp at `flow start`.** Start prints the dev-flow build that created the feature and persists it (`state.flowVersion`); `flow status` shows `flow=<ver>` per feature — a stuck flow can now be read against the tooling that started it.
|
|
316
|
+
- **Unversioned release: `flow release --no-version`.** Default stays versioned (bump + tag). When the operator chooses it at the Release? step, the gate skips the manifest-bump and changelog requirements and `release-done` skips the whole version/tag/artifact machinery for that flow, recording the release with an `unversioned` note; status marks it `[no-version]`.
|
|
317
|
+
- **Yolo mode: `flow approve --yolo`.** The operator's word at Approve? pre-confirms every later gate question (Verified?/Release?/Finish?) so the agent drives the flow through without stopping. Tier-1 checks still block gates, and guardrails stay fully enforced — a flow-guard `confirm` rule still asks the operator. Status marks it 🎱; the stage context tells the agent not to re-ask.
|
|
318
|
+
|
|
319
|
+
### Docs
|
|
320
|
+
|
|
321
|
+
- README command table and the dev-flow skill playbook cover when "yolo" / "no version" in chat license the flags.
|
|
322
|
+
|
|
323
|
+
## [0.29.0] - 2026-10-15
|
|
324
|
+
|
|
325
|
+
### Added
|
|
326
|
+
|
|
327
|
+
- **`--docs` mode — the most relaxed release lane.** For docs-only work: no plan file (like `--patch`) **and no tier-1 checks** (build/lint/test skipped at verify and the release gate); worktree/branch discipline and the full release (version bump, changelog, tag, gate questions) stay untouched. Status marks it `📄` (patch keeps `⚡`).
|
|
328
|
+
|
|
329
|
+
### Changed
|
|
330
|
+
|
|
331
|
+
- **Relaxed modes are operator-granted, mechanically.** `flow start` refuses `--patch` or `--docs` without `--confirmed` — reusing the convention that `--confirmed` may only anchor a literal operator chat answer, self-selection is impossible: the agent proposes a mode, the operator grants it in chat, the gate enforces the grant. `--patch --docs` together is refused (exclusive). The skill playbook's checkpoint rule now names the failure it prevents: gate verbs and mode grants are plain chat only — a structured question-tool dialog is not an operator answer and never licenses `--confirmed`.
|
|
332
|
+
- **Clarify before drafting.** The plan stage opens with investigation, a preliminary direction presented to the operator in chat, a mode proposal with reasoning, and clarifying Q&A — only then is the plan drafted. Encoded in the skill playbook and the plan-stage hints; normal mode keeps enforcing the written `plan/*.md` at approve (it always did — this is what `--patch` used to skip, by operator grant only).
|
|
333
|
+
|
|
334
|
+
## [0.28.0] - 2026-10-14
|
|
335
|
+
|
|
336
|
+
### Changed
|
|
337
|
+
|
|
338
|
+
- **`/flow` output is a conversation message, not a popup.** Gate output (the command handler, the panel-mode hint, the no-feature notice) used to arrive as a `ui.notify` toast — easy to miss, gone on scroll, and colored severity nobody saw in time. It now goes through `pi.sendMessage({customType: "flow", display: true})`, rendering as a persistent `[flow]` box in the transcript in both the TUI and the web UI, with no model turn triggered. The gate confirmations, the `flow init` editor and the `ctrl+,` panel stay dialogs — they are operator input, not output.
|
|
339
|
+
|
|
340
|
+
## [0.27.0] - 2026-10-14
|
|
341
|
+
|
|
342
|
+
### Added
|
|
343
|
+
|
|
344
|
+
- **`flow finish` cleans the remote too.** Every release used to leave `origin/feat/<slug>` behind (a squash-merged repo accumulated one stale branch per release, each keeping the pre-squash commit line alive in every contributor's graph and making released work look unmerged). Finish now deletes the feature's remote branch — but **only on proof it was merged**: the branch is an ancestor of `origin/<default>` (merge-commit merges, repo-local), or `gh pr list --state merged` confirms a merged PR (squash merges, same advisory-gh posture as the GitHub release). Unverifiable branches are kept with the reason and the manual command in the output — never a silent delete, never a block on the release. No new config: the verification is the safety.
|
|
345
|
+
|
|
346
|
+
## [0.26.0] - 2026-10-14
|
|
347
|
+
|
|
348
|
+
### Changed
|
|
349
|
+
|
|
350
|
+
- **One release question.** The release stage asked the operator twice — `Release?` (pre-release → release) and `Ship?` (`release-done`) — but by the time `Ship?` came the PR was merged and the tag pushed: the answer ratified a fait accompli and could still only skip the advisory GitHub release. `flow release-done` is now **check-only**: it re-verifies (tag rendered from the manifest version, reachable from the default branch, present on origin, artifact check when configured), records the release and creates the GitHub release without a checkpoint; the surviving `Release?` dialog names its coverage ("Publishing starts: PR, merge, tag — release-done afterwards needs no further answer"). `--confirmed` is still accepted by `release-done` as a silent no-op; `--no-github-release` / `--no-artifact-check` stay operator-instructed-only, anchored on the chat answer. Checkpoints per release drop from five to four: Approve? / Verified? / Release? / Finish?.
|
|
351
|
+
|
|
352
|
+
## [0.25.0] - 2026-10-14
|
|
353
|
+
|
|
354
|
+
### Added
|
|
355
|
+
|
|
356
|
+
- **Session claims — auto-bind no longer silently joins a live session's feature.** A second pi session on the same checkout used to auto-bind onto the one unfinished feature and become its unwitting caretaker — a stray verification run could commit that worktree's work as its own. Every bind (`start`, `use`, auto-bind) now leaves a claim in the feature directory (`claim.json`: session key + pi pid). Auto-bind refuses a feature whose claim is held by a **live** process (pid probe; a claim from a dead process is void and gets replaced), and the unbound-session context names the blocked feature and its `flow use <slug>` takeover. An explicit `flow use` always wins and says so when it takes over from a still-running holder. Liveness is pid-only: pid reuse can at worst force an explicit `flow use` instead of an auto-bind — friction, never a wrong commit.
|
|
357
|
+
|
|
358
|
+
## [0.24.0] - 2026-10-14
|
|
359
|
+
|
|
360
|
+
### Added
|
|
361
|
+
|
|
362
|
+
- **`flow version` — which dev-flow is this session running?** Prints the plugin's own version and the directory it was loaded from, e.g. `dev-flow 0.24.0 (pi-dev-flow at /home/me/.pi/agent/npm/node_modules/pi-dev-flow)`. The number comes from the nearest `package.json` named `pi-dev-flow` above the loaded extension module, so a session dogfooding a checkout and a session on an installed release can be told apart at a glance — previously the only way was digging through pi settings. Read-only like `doctor`: no stage, no `.dev-flow/` required, nothing written. It reports the **plugin's** version, never the project's `versioning.file` version the release gates use.
|
|
363
|
+
|
|
364
|
+
## [0.23.0] - 2026-10-14
|
|
365
|
+
|
|
366
|
+
### Added
|
|
367
|
+
|
|
368
|
+
- **The `pre-release` stage — a checkpoint before anything publishes.** `flow verify` now lands in `pre-release`, where the release preparation happens as worktree work: `/ponytail-review` + fixes, docs, the version bump, the changelog. The new **`flow release`** gate — the one **Release?** question — hands over to `release` only when the tier-1 checks are re-greened after those prep edits, the manifest version parses and is **ahead of the last tag**, and the changelog (when configured) mentions the version. The operator sees the PR summary, the version and the changelog entry *before* the PR, merge and tag start; the `release` stage now only publishes.
|
|
369
|
+
- **`flow finish` asks Finish?** — one unconditional operator question before the cleanup, called after every safety check so it is never wasted; commits that look unmerged (squash merges) are called out inside that same question.
|
|
370
|
+
|
|
371
|
+
### Changed
|
|
372
|
+
|
|
373
|
+
- The machine is now `plan → implement → pre-release → release → done`. The guards confine `pre-release` to the feature worktree exactly like `implement`; pushing to or merging into the default branch still requires stage `release`.
|
|
374
|
+
- project.md gains `## pre-release` (prose, checklist items, and the `versionFile`/`versionTag` keys; existing `## release` keys keep parsing unchanged so old playbooks are untouched), and `flow init --draft` generates the new section.
|
|
375
|
+
|
|
376
|
+
## [0.22.0] - 2026-10-14
|
|
377
|
+
|
|
378
|
+
### Removed
|
|
379
|
+
|
|
380
|
+
- **`flow exempt` — there is no bypass any more.** In a repo with a `.dev-flow/`, every request goes through `flow start`/`flow use`: the command, the `◆ exempt` status marker and the write-guard hole it opened are gone. The `flow-guard` rules in project.md `## global` remain the operator's valve, and they now run **ahead of** dev-flow's own verdicts on edit paths too (they already did on bash) — so a `protect`/`forbid` rule reports the reason you wrote instead of a stage complaint.
|
|
381
|
+
- **The `cleanup` and `deploy` commands, and their stages.** The machine is now `plan → implement → release → done`: `flow finish` closes a released feature in one step, so the flow has one closing door instead of three that had to be walked in order. `release-done` records the release and no longer auto-removes the worktree, branch and feature dir.
|
|
382
|
+
- **`init --yes`** — documented as the CI fast path, never read by the code: a non-interactive session already is the CI path.
|
|
383
|
+
- **`commands.deployNote`** — it lived in the `## deploy` playbook section, which went with the stage. Production deployment stays manual, out of scope and never asked about.
|
|
384
|
+
|
|
385
|
+
### Added
|
|
386
|
+
|
|
387
|
+
- **`flow finish [slug]` — the closer.** It refuses until `flow release-done` has recorded a release, then requires the main checkout to be **clean and pushed** to `origin/<default>` (an uncommitted changelog or a local-only release commit is exactly what it protects against), removes the worktree and branch — asking only when commits look unmerged, e.g. after a squash merge — and deletes `.dev-flow/<slug>/`. Abandoning an unreleased feature is still `flow abort`.
|
|
388
|
+
- **`flow doctor reflect "<note>"` — the suggestion queue, filed by target.** `reflections.md` is now a document with up to two sections: `## playbook` (what to change in your playbook) and `## plugin` (what to change in dev-flow). The note's wording decides where it lands, a note about both goes to both, legacy flat `- [ ] (plugin) …` lines are bucketed and their inline marker dropped on the next write, and whatever the operator wrote above the first item is kept verbatim.
|
|
389
|
+
|
|
390
|
+
### Changed
|
|
391
|
+
|
|
392
|
+
- Advice is parked where it is reported: the top-level `flow reflect … [--to playbook|plugin|doctor]` is gone, `flow doctor reflect "<note>"` is the one form (`flow doctor` on its own still only reports and never writes).
|
|
393
|
+
|
|
394
|
+
## [0.21.0] - 2026-10-14
|
|
395
|
+
|
|
396
|
+
### Changed
|
|
397
|
+
|
|
398
|
+
- **This checkout now loads its own working extension, and always will.** `.pi/extensions/dev-flow.ts` is a committed one-line re-export of `extensions/dev-flow.ts` instead of an untracked hard link that a `git pull` silently left behind. A fresh clone of dev-flow needs no setup to dogfood itself, and after any merge or pull new sessions run main's current code — nothing to re-run. (A symlink cannot be used here: pi resolves a module's relative imports from the link's own directory, so the extension's `../src/core.ts` would not resolve.)
|
|
399
|
+
|
|
400
|
+
### Added
|
|
401
|
+
|
|
402
|
+
- **`flow doctor` now flags broken dogfood wiring**: in a `pi-dev-flow` checkout, a missing `.pi/extensions/dev-flow.ts` — or one that no longer re-exports `../../extensions/dev-flow.ts` — is a finding, because sessions in that checkout would silently load nothing (or stale code).
|
|
403
|
+
|
|
404
|
+
## [0.20.0] - 2026-10-14
|
|
405
|
+
|
|
406
|
+
### Added
|
|
407
|
+
|
|
408
|
+
- **`flow doctor` — the doctor as an endpoint, not a side effect of `flow init`.** Findings on demand: playbook drift and dead commands/scripts, ghost feature dirs, orphan worktrees and branches, open reflections — printed as `doctor: N finding(s)` plus one line each, or `doctor: no findings — playbook, flow state and git layout are consistent`. It writes nothing, asks nothing and deletes nothing, so an agent or a CI job can run it at any stage with no flow bound; `flow init` stays the fix path, the one that can write.
|
|
409
|
+
|
|
410
|
+
### Changed
|
|
411
|
+
|
|
412
|
+
- `flow init` **without a UI prints the findings it computed** (the `--yes`/CI path said "the doctor ran" and showed nothing).
|
|
413
|
+
- `flow status` runs the cheap probes even when no feature is unfinished — it used to return `no features` before reaching them — and points at `flow doctor` for the full list.
|
|
414
|
+
- The git consistency probe no longer flags an active feature's own branch as an orphan: `git branch --list` marks worktree-checked-out branches with `+ ` and only `* ` was stripped, so the marked name never matched the owned set.
|
|
415
|
+
|
|
416
|
+
## [0.19.1] - 2026-10-14
|
|
417
|
+
|
|
418
|
+
### Added
|
|
419
|
+
|
|
420
|
+
- **The doctor finds ghost feature dirs and offers to remove them.** A `.dev-flow/<slug>/` holding a `plan/` with no `state.json` — a feature closed by hand before auto-close existed, or an interrupted `flow start` — was invisible: `flow status`, the guards and auto-bind all key off `state.json`, so the clutter was only findable by eye. `flow status` now counts it as a doctor finding and `flow init` offers to delete exactly those directories, one confirm, with the plan files called out as unrecoverable; decline keeps them, and with no UI nothing is deleted (the finding says how to do it by hand). Live features, `cleanup`/`deploy` leftovers and `project.md` are untouched by construction.
|
|
421
|
+
|
|
422
|
+
### Changed
|
|
423
|
+
|
|
424
|
+
- The status warning reads `⚠ doctor: N finding(s) — run flow init` instead of `⚠ project.md:`, since findings now cover flow state as well as the playbook.
|
|
425
|
+
- Internal: `loadProject(dfDir)` dropped its never-read `root` parameter.
|
|
426
|
+
|
|
427
|
+
## [0.19.0] - 2026-10-14
|
|
428
|
+
|
|
429
|
+
### Added
|
|
430
|
+
|
|
431
|
+
- **`flow-guard` — the playbook carries the project's own safety rules**, so an adopting project can delete its own guard extension. A ` ```flow-guard ` block in `## global` of project.md holds `deny`/`confirm` rules (JS regex over one shell segment of a bash command) and `protect`/`forbid` rules (a repo-relative edit/write path; a directory covers its subtree, files that do not exist yet included). `deny`/`forbid` block outright; `confirm`/`protect` ask the operator and block when no UI is present — a hidden confirmation is not a confirmation. Every rule carries a ` :: <why>` reason that shows up verbatim in the block, and a bad regex is a hard finding so `flow init --write` refuses the file. Enforcement reuses the existing tool-call guards (rules cover `docker`/`gh`/everything, not only git), runs at every stage, and is not lifted by `flow exempt`. Read-only segments are skipped, so `grep "git push --force" docs/` searches instead of pushing.
|
|
432
|
+
|
|
433
|
+
### Fixed
|
|
434
|
+
|
|
435
|
+
- **`flow init` no longer destroys a hand-written project.md.** The doctor's refresh regenerated the file from detection + config, which silently reverted hand-set keys (`versionTag = {version}` → `v{version}`) and deleted every tier-3 prose line and extra checklist item — and its confirm could be answered by an agent driving `flow init` through the `flow` tool. The refresh is now refused outright when the current file has lines a regenerated draft cannot reproduce: it prints the findings plus the lines it would drop. `--force` stays the deliberate overwrite.
|
|
436
|
+
- **`commands.setup` now runs** — once, inside a freshly created worktree at `approve`, which is where `cp docker/.env` + `bun install` belong; a failing setup fails the gate instead of approving an unusable worktree. `commands.run` was documented as if executed and never is: it is now documented as advisory (the agent starts the app with it for the running-and-healthy walk).
|
|
437
|
+
- **Doctor stopped flagging worktree-relative paths forever**: command arguments are only probed as repo-root paths, so `cp -n ../../docker/.env` — correct relative to the worktree the check runs in — is no longer reported as a missing file.
|
|
438
|
+
|
|
439
|
+
## [0.18.0] - 2026-10-13
|
|
440
|
+
|
|
441
|
+
### Added
|
|
442
|
+
|
|
443
|
+
- **Compact-aware**: when context nears pi's auto-compaction threshold, dev-flow now compacts *itself* at a safe point — right after a gate wrote state to disk, or when a run settles — with flow-aware summary instructions (slug/stage-aware; keeps operator answers, uncommitted-change rationale and next action verbatim). It never self-compacts while chat is the state: an open tier-2 dialog or a plan discussion not yet in `plan/` blocks it. If pi force-compacts anyway (threshold/overflow while a feature is bound), a pacing note lands in `reflections.md` for the operator — advisory, never a gate.
|
|
444
|
+
|
|
445
|
+
## [0.17.0] - 2026-10-14
|
|
446
|
+
|
|
447
|
+
### Changed
|
|
448
|
+
|
|
449
|
+
- First `flow init` writes `.dev-flow/project.md` immediately — the pre-write editor/confirm dialogs are gone. The review loop moved onto the file: confirm as-is, or say what to change; the skill tells the agent to ask one short question per knob, apply answers via `flow init --write`, and re-present until confirmed
|
|
450
|
+
|
|
451
|
+
### Kept
|
|
452
|
+
|
|
453
|
+
- Doctor mode (existing playbook) still confirms before refreshing — it must never silently overwrite hand edits; `--draft` prints without writing; `--force` remains the deliberate overwrite
|
|
454
|
+
|
|
455
|
+
## [0.16.1] - 2026-10-14
|
|
456
|
+
|
|
457
|
+
### Fixed
|
|
458
|
+
|
|
459
|
+
- `flow init` confirm dialog is now human: one line per phase with real values (commands quoted, checklist items and guidance verbatim, rendered tag pattern, whether a GitHub release is created, which artifact check runs) instead of parser notation (`set: file, pattern · prose`); states plainly what Cancel does and where to read the full file first
|
|
460
|
+
- `flow init --draft` — referenced by the docs since v0.9 but never implemented — now prints the draft (or the current file in doctor mode) and writes nothing; tool help lists `--draft` and `--patch`
|
|
461
|
+
|
|
462
|
+
## [0.16.0] - 2026-10-14
|
|
463
|
+
|
|
464
|
+
### Added
|
|
465
|
+
|
|
466
|
+
- `flow start <slug> --patch` — chore releases with reduced paperwork: no plan document (the one-line start description is the plan); approve, worktree discipline, tier-1 checks, verify, tagged release and audit trail unchanged. Status marks patch features with an amber marker. (Folded reflection: release-patch shortcut)
|
|
467
|
+
|
|
468
|
+
## [0.15.2] - 2026-10-14
|
|
469
|
+
|
|
470
|
+
### Changed
|
|
471
|
+
|
|
472
|
+
- `flow abort` at plan stage (nothing approved) removes the feature dir outright — a kept-over plan-stage state dir stayed "unfinished" forever and the one-unfinished-feature auto-bind resurrected the ghost into every unbound session
|
|
473
|
+
|
|
474
|
+
### Fixed
|
|
475
|
+
|
|
476
|
+
- Per-segment git guard: each git command in a chain is judged by the branch of the directory it actually runs in (incl. its own `git -C`); previously the last `cd` in a compound command set the verdict for all git calls, blocking legitimate worktree commits (hit two real releases) and weakening mixed-chain checks symmetrically
|
|
477
|
+
- `git checkout -b feat/x` in the main checkout is now blocked like a plain checkout of a feature branch
|
|
478
|
+
- `flow init` reports when an existing pre-commit hook prevents installing the dev-flow hook (main commits outside Pi are then unguarded)
|
|
479
|
+
- `flow` tool description matches its actual subcommands (shared const with the help line)
|
|
480
|
+
- Docs: the `dev` command must background and exit — `flow verify` waits for it (15-min cap)
|
|
481
|
+
|
|
482
|
+
## [0.15.1] - 2026-10-14
|
|
483
|
+
|
|
484
|
+
### Changed
|
|
485
|
+
|
|
486
|
+
- One-word checkpoints: gates ask **Approve? / Verified? / Ship?** — the verb doubles as the operator's answer; dialogs carry the same verb with just enough context, cleanup still asks only when unsafe, deploy stays silent
|
|
487
|
+
|
|
488
|
+
## [0.15.0] - 2026-10-14
|
|
489
|
+
|
|
490
|
+
### Added
|
|
491
|
+
|
|
492
|
+
- `release.artifact` playbook key: `release-done` verifies the published artifact (any command — `docker manifest inspect`, registry `curl` — with `{version}`/`{tag}` placeholders) after the tag lands on origin; failure blocks the release; `--no-artifact-check` skips once (operator's call, audited). Set = every tag must show its artifact; unset = none
|
|
493
|
+
|
|
494
|
+
### Changed
|
|
495
|
+
|
|
496
|
+
- `release-done` refuses local-only tags: the tag ref must exist on `origin` (`git ls-remote`) when a remote is configured — `git push --follow-tags` silently skipping lightweight tags was producing releases that never existed upstream
|
|
497
|
+
- Doctor flags an implement stage whose tier-1 gates nothing (no test, no health, no `flow-check`)
|
|
498
|
+
- SKILL: annotated tags with explicit `git push origin v<ver>` (never `--follow-tags`); incremental worktree commits instead of a monolith at review time; plan-stage check for local-only default-branch commits that would fall out of the worktree base
|
|
499
|
+
|
|
500
|
+
## [0.14.2] - 2026-10-12
|
|
501
|
+
|
|
502
|
+
### Added
|
|
503
|
+
|
|
504
|
+
- GitHub release opt-out valves: playbook key `release.github = false` never attempts `gh release create` (self-hosted or Releases-unused repos); `flow release-done --no-github-release` skips it once, recorded in the audit line; the single release question states whether a GitHub release will be created; SKILL restricts skipping to explicit operator decisions
|
|
505
|
+
|
|
506
|
+
## [0.14.1] - 2026-10-12
|
|
507
|
+
|
|
508
|
+
### Changed
|
|
509
|
+
|
|
510
|
+
- SKILL: handling additions mid-implement — same-feature scope grows in place (plan.md amended with an "Added mid-stage:" line, stay at implement; edit invalidation makes verify re-cover it); a different problem becomes a new flow instead of a folded second feature; formal re-review of an amended plan is a chat re-approval — no reopen gate by design
|
|
511
|
+
|
|
512
|
+
## [0.14.0] - 2026-10-12
|
|
513
|
+
|
|
514
|
+
### Changed
|
|
515
|
+
|
|
516
|
+
- `flow release-done` creates the GitHub release for the verified tag (title = tag, notes = tag annotation) — advisory: missing gh, no GitHub remote or an existing release prints a note and never blocks
|
|
517
|
+
- A clean release now closes itself: when the worktree has no uncommitted changes and nothing unmerged, `release-done` removes worktree, branch and feature dir in one step — zero operator actions after merge; dirty or unmerged-looking worktrees still stop at `flow cleanup` and ask
|
|
518
|
+
- `flow cleanup`/`flow deploy` remain as the not-clean / manual path
|
|
519
|
+
|
|
520
|
+
## [0.13.0] - 2026-10-12
|
|
521
|
+
|
|
522
|
+
### Changed
|
|
523
|
+
|
|
524
|
+
- One crisp question per checkpoint: gate confirms are single-line questions (multi-line markdown blobs rendered unreadably where clients collapse newlines); plan and checklist detail live in files
|
|
525
|
+
- Tier-2 checklist items support a `(ui)` marker in project.md — UI-only items vanish entirely (dialog, injection, confirmation hash) for non-UI features; non-UI work is no longer asked about mockups or visual passes
|
|
526
|
+
- `--confirmed` operator-presence flag (approve/verify/release-done/cleanup): when the operator answered the stage question in chat, gates proceed without a second dialog and record the audit line — one checkpoint per stage
|
|
527
|
+
- New `dev` implement-stage command: `flow verify` deploys to dev first (recorded tier-1 check) so the operator reviews the running app; unconfigured verify says nothing about dev (the dead "no run command configured" text is gone)
|
|
528
|
+
- `flow release-done` asks the single release question (changelog, tag and merged PR covered by one answer)
|
|
529
|
+
- `flow cleanup` is silent when the worktree is safe and asks only when commits look unmerged; `flow deploy` never asks — production deploy is manual and out of scope
|
|
530
|
+
|
|
531
|
+
### Fixed
|
|
532
|
+
|
|
533
|
+
- Approve/verify dialogs no longer present UI checklist items to non-UI features
|
|
534
|
+
|
|
535
|
+
## [0.12.0] - 2026-10-12
|
|
536
|
+
|
|
537
|
+
### Added
|
|
538
|
+
|
|
539
|
+
- `reflect` — the agent's suggestion queue: `flow reflect "<note>" [--to playbook|plugin|doctor]` appends one line to `.dev-flow/reflections.md` (drifted commands, gate friction, plugin bugs), `flow reflect` lists open items. The open count surfaces in `flow status`, stage injections and the init doctor; fold-in goes through the existing validated `playbook --write` path and items are checked off with a normal edit. Advisory by design — reflections never gate anything, and `project.md` keeps its operator-only contract
|
|
540
|
+
|
|
541
|
+
## [0.11.0] - 2026-10-12
|
|
542
|
+
|
|
543
|
+
### Changed
|
|
544
|
+
|
|
545
|
+
- Push guard is now ref-aware: each push's refspec is parsed (deletes judged by source, `HEAD` = current branch, `--mirror` worst-case) and bare names resolved against `refs/tags` — only pushes that write the default branch require stage `release`; tag pushes and feature-branch pushes pass from any stage. The old substring heuristic (which blocked `git push origin v1.0` and anything mentioning `main` in a chained command) and the park-`.dev-flow` tag-push workaround are gone
|
|
546
|
+
|
|
547
|
+
### Fixed
|
|
548
|
+
|
|
549
|
+
- Draft playbooks no longer inject a placeholder health check (`curl localhost:3000/healthz`) — in repos without a server it was an always-red tier-1 gate blocking verify forever
|
|
550
|
+
- Doctor refresh no longer drops explicit `flow-check` blocks — every tier-1 check is carried through regeneration (previously the refreshed playbook silently lost teeth)
|
|
551
|
+
- `.gitignore` entry `node_modules` matches symlinked `node_modules` (trailing-slash pattern didn't)
|
|
552
|
+
|
|
553
|
+
## [0.10.0] - 2026-10-12
|
|
554
|
+
|
|
555
|
+
### Added
|
|
556
|
+
|
|
557
|
+
- **Flow by default**: in a repo with `.dev-flow/`, an unbound session can no longer touch source files — every request goes through `flow start`/`flow use` unless the operator exempts the session with `/flow exempt <reason>` (session-scoped, survives resume, `flow exempt off` clears, `◆ exempt` shown in the status bar; `project.md`/`state.json` stay protected even when exempt). Unbound sessions get the posture injected at turn start, including a flag when the main checkout isn't on the default branch
|
|
558
|
+
- Doctor (init) git-consistency findings: orphan worktrees, orphan feature branches, and features whose worktree vanished; `flow abort` now prints the exact commands to remove worktree + branch
|
|
559
|
+
|
|
560
|
+
### Changed
|
|
561
|
+
|
|
562
|
+
- `flow start` refuses when the main checkout is on another branch (`--force` to override) — features must base on the default branch
|
|
563
|
+
- Worktrees are created from `origin/<default>` explicitly (fallback `<default>`) — never from whatever HEAD the main checkout happened to sit on
|
|
564
|
+
- The agent cannot check feature-pattern branches out in the main checkout; feature branches are only usable inside their own worktree
|
|
565
|
+
- `flow use` prints the bound feature's worktree path
|
|
566
|
+
|
|
567
|
+
## [0.9.0] - 2026-10-12
|
|
568
|
+
|
|
569
|
+
### Added
|
|
570
|
+
|
|
571
|
+
- `project.md` — the operator playbook in Markdown, three tiers by notation: ` ```flow key = value ` blocks and named ` ```flow-check <name> ` blocks are tier 1 (gates run every check via `flow check`, record pass/fail, worktree edits invalidate); `- [ ]` checklist items are tier 2 (confirmed as a hashed set in gate confirms — edits reset the confirmation); stage prose is tier 3 (injected to the agent at stage entry). Unknown stages/keys warn, never fail; broken syntax rejects with line numbers. `project.json` remains as legacy base (project.md overrides; doctor flags having both)
|
|
572
|
+
- `flow init` v2 — advisory dialogue instead of the scripted wizard: fresh repos draft from detection and confirm once; `--draft` / `--write "<content>"` is the validated agent path (line-pointed rejection); on an existing file init becomes the **doctor** (command drift, dead script files, missing/unparseable version manifest, dual configs, missing health check — file probes only, never runs project commands) offering a refresh that keeps configured values
|
|
573
|
+
- Init review UX: TUI opens the draft in a multi-line editor (review *and* edit before anything is written); elsewhere a per-stage digest confirms instead of a raw markdown dump; every write prints how to change the playbook afterwards
|
|
574
|
+
- `flow check` runs the whole tier-1 set (auto-includes configured test/health commands) and records each result
|
|
575
|
+
|
|
576
|
+
### Changed
|
|
577
|
+
|
|
578
|
+
- Gates generalize to named checks: `flow verify` demands every tier-1 check green plus the tier-2 confirmation before asking the operator; `flow status` flags pending doctor findings
|
|
579
|
+
- Git ops in bash gates are judged by the branch of the directory git actually runs in (`git -C`, preceding `cd`), so worktree work no longer misjudges against the session root; cleanup unstuck for worktree-hosted releases
|
|
580
|
+
|
|
581
|
+
### Removed
|
|
582
|
+
|
|
583
|
+
- The interactive init wizard (`--step` machinery) — replaced by draft/discuss/write; `flow init --yes` and `--force` keep the scripted fast paths
|
|
584
|
+
|
|
585
|
+
## [0.8.0] - 2026-08-05
|
|
586
|
+
|
|
587
|
+
### Added
|
|
588
|
+
|
|
589
|
+
- `flow init --force`: overwrite an existing `project.json` with fresh detection (silent fast path; destructive reset for a misconfigured repo)
|
|
590
|
+
|
|
591
|
+
### Changed
|
|
592
|
+
|
|
593
|
+
- `flow init --yes` never overwrites an existing config, even headless; the "already exists" note now advertises `--force`
|
|
594
|
+
|
|
595
|
+
## [0.7.0] - 2026-08-04
|
|
596
|
+
|
|
597
|
+
### Added
|
|
598
|
+
|
|
599
|
+
- Interactive `flow init` wizard: walks the operator through every setting (default branch, commands, version manifest + tag pattern, worktree dir, main-hook) showing `value [configured|detected|default]` — keep/change/remove per item, pick manifest from candidates; nothing writes before a final diff confirm, Esc aborts unchanged
|
|
600
|
+
- Re-running `flow init` on an initialized project is a review-and-edit flow (existing config wins over re-detection); `flow init --yes` and headless sessions keep the silent fast path
|
|
601
|
+
|
|
602
|
+
### Fixed
|
|
603
|
+
|
|
604
|
+
- Default branch is never proposed from a feature branch (origin/HEAD → current branch only if it looks default-like → "main"), preventing a hooked-up repo from blocking its own feature branches
|
|
605
|
+
|
|
606
|
+
## [0.6.0] - 2026-08-04
|
|
607
|
+
|
|
608
|
+
### Added
|
|
609
|
+
|
|
610
|
+
- Healthy local run as implementation-complete criteria: optional `commands.seedData` (ensure pre-existing data) and `commands.health` (must exit 0 only when the app is up locally with real data); new `flow health` gate records the check; `flow verify` now requires green test AND health (when configured) checks plus build; worktree edits invalidate both checks — "running and healthy" is enforced, not honor-system
|
|
611
|
+
- Versioning approach: `flow init` detects the version manifest (`VERSION` → `package.json` → `Cargo.toml` → `pyproject.toml`) into `versioning.file`, with an explicit "clarify with the operator" report line when none exists; `versioning.pattern` (default `v{version}`) derives the release tag from the manifest; `flow release-done` refuses unless that tag exists and is reachable from the default branch — manifest, changelog and tag must agree
|
|
612
|
+
|
|
613
|
+
### Changed
|
|
614
|
+
|
|
615
|
+
- Release playbook and status hints now derive the tag from the version manifest (`flow next` shows the exact bump + tag to perform)
|
|
616
|
+
|
|
617
|
+
## [0.5.0]
|
|
618
|
+
### Added
|
|
619
|
+
- Session-scoped flows: a pi session binds to one feature (persisted per session branch, restored on resume/fork). `flow start` binds, new `flow use <slug>` switches; a lone unfinished feature binds automatically, ambiguous sessions must bind or pass explicit slugs. One feature per session, many sessions per repo, is now the supported concurrency model.
|
|
620
|
+
- Write enforcement is by path attribution: every write is judged by the stage of the feature owning that worktree, whichever session attempts it — parallel sessions cannot clobber each other or write into plan-stage features.
|
|
621
|
+
- Release playbook requires the project's version manifest (`package.json`/`pyproject`/`Cargo.toml`/`VERSION`) to be bumped to the exact tagged version in the same release; dev-flow's own manifest (drifting at 0.1.0) is re-synced here.
|
|
622
|
+
|
|
623
|
+
### Removed
|
|
624
|
+
- `.dev-flow/.current` (repo-global pointer) — superseded by session bindings; `flow init` migrates it away.
|
|
625
|
+
|
|
626
|
+
## [0.4.1]
|
|
627
|
+
### Fixed
|
|
628
|
+
- Detail panel check timestamps now show local time instead of UTC.
|
|
629
|
+
|
|
630
|
+
## [0.4.0]
|
|
631
|
+
### Added
|
|
632
|
+
- Flow status in the pi status bar: `◆ <slug> ▸ <stage>` in the footer, stage-colored, `✗` when a recorded check is failing; cleared when no feature is active. Refreshed at session start, every turn end, and after each gate.
|
|
633
|
+
- `ctrl+,` opens a detail panel (slug, stage, branch/worktree, approvals, checks with timestamps, next step); Esc closes. Non-TUI modes degrade to notifications.
|
|
634
|
+
|
|
635
|
+
## [0.3.0]
|
|
636
|
+
### Changed
|
|
637
|
+
- UI features now gate on **rendered mockup screenshots**: default `mockupGlobs` is `["*.png"]`, and an `--ui` plan without renders under `plan/` cannot be approved. HTML sources stay encouraged but ungated.
|
|
638
|
+
|
|
639
|
+
### Added
|
|
640
|
+
- The `dev-flow` skill documents the mockup workflow: HTML sources + renders in `plan/mockups/`, headless chromium probe (system chrome → playwright `chrome-headless-shell`), per-width renders embedded in plan.md (``) so approval is one browsable document, and an explicit no-chromium fallback that never fakes a screenshot.
|
|
641
|
+
|
|
642
|
+
## [0.2.0]
|
|
643
|
+
### Added
|
|
644
|
+
- `flow init` analyzes the project and writes a starter `.dev-flow/project.json` — default branch from git, package manager from `packageManager`/lockfiles, `test`/`build`/`run` from npm scripts, or cargo/go/python (uv/poetry/pytest) conventions. Existing config is never overwritten; the report shows what was guessed and what was left empty.
|
|
645
|
+
- `.dev-flow/` now ignores itself and everything under it via a folder-local `.gitignore` containing `*`.
|
|
646
|
+
|
|
647
|
+
### Changed
|
|
648
|
+
- `flow init` no longer edits the tracked root `.gitignore`.
|
|
649
|
+
|
|
650
|
+
## [0.1.0]
|
|
651
|
+
- Initial release: stage gates (`start`/`approve`/`test`/`verify`/`release-done`/`cleanup`/`deploy`) over a per-feature state machine, tool-call guardrails (main-branch protection, worktree confinement, untouchable state), per-turn stage context, the `dev-flow` agent skill, and the main-branch `pre-commit` hook.
|