flow-workflows 0.65.0 → 0.67.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/README.md +25 -4
- package/adapters/README.md +11 -3
- package/adapters/codex/CORE.md +31 -5
- package/adapters/codex/skills/flow-bug-fix/SKILL.md +5 -0
- package/adapters/codex/skills/flow-bug-review/SKILL.md +19 -6
- package/adapters/codex/skills/flow-bug-ship/SKILL.md +5 -3
- package/adapters/codex/skills/flow-feat-build/SKILL.md +16 -2
- package/adapters/codex/skills/flow-feat-review/SKILL.md +51 -47
- package/adapters/codex/skills/flow-feat-ship/SKILL.md +23 -4
- package/adapters/codex/skills/flow-feat-validate/SKILL.md +5 -1
- package/adapters/codex/skills/flow-init/SKILL.md +4 -3
- package/adapters/codex/skills/flow-work-README/SKILL.md +9 -2
- package/adapters/codex/skills/flow-work-respond/SKILL.md +1 -1
- package/adapters/gemini/CORE.md +31 -5
- package/adapters/gemini/commands/flow/bug/fix.toml +5 -0
- package/adapters/gemini/commands/flow/bug/review.toml +19 -6
- package/adapters/gemini/commands/flow/bug/ship.toml +5 -3
- package/adapters/gemini/commands/flow/feat/build.toml +16 -2
- package/adapters/gemini/commands/flow/feat/review.toml +51 -47
- package/adapters/gemini/commands/flow/feat/ship.toml +23 -4
- package/adapters/gemini/commands/flow/feat/validate.toml +5 -1
- package/adapters/gemini/commands/flow/init.toml +4 -3
- package/adapters/gemini/commands/flow/work/README.toml +9 -2
- package/adapters/gemini/commands/flow/work/respond.toml +1 -1
- package/adapters/hermes/CORE.md +31 -5
- package/adapters/hermes/skills/flow-bug-fix/SKILL.md +5 -0
- package/adapters/hermes/skills/flow-bug-review/SKILL.md +19 -6
- package/adapters/hermes/skills/flow-bug-ship/SKILL.md +5 -3
- package/adapters/hermes/skills/flow-feat-build/SKILL.md +16 -2
- package/adapters/hermes/skills/flow-feat-review/SKILL.md +51 -47
- package/adapters/hermes/skills/flow-feat-ship/SKILL.md +23 -4
- package/adapters/hermes/skills/flow-feat-validate/SKILL.md +5 -1
- package/adapters/hermes/skills/flow-init/SKILL.md +4 -3
- package/adapters/hermes/skills/flow-work-README/SKILL.md +9 -2
- package/adapters/hermes/skills/flow-work-respond/SKILL.md +1 -1
- package/adapters/opencode/CORE.md +31 -5
- package/adapters/opencode/commands/flow-bug-fix.md +5 -0
- package/adapters/opencode/commands/flow-bug-review.md +19 -6
- package/adapters/opencode/commands/flow-bug-ship.md +5 -3
- package/adapters/opencode/commands/flow-feat-build.md +16 -2
- package/adapters/opencode/commands/flow-feat-review.md +51 -47
- package/adapters/opencode/commands/flow-feat-ship.md +23 -4
- package/adapters/opencode/commands/flow-feat-validate.md +5 -1
- package/adapters/opencode/commands/flow-init.md +4 -3
- package/adapters/opencode/commands/flow-work-README.md +9 -2
- package/adapters/opencode/commands/flow-work-respond.md +1 -1
- package/bin/cli.mjs +330 -24
- package/package.json +2 -1
- package/plugins/flow/.claude-plugin/plugin.json +5 -2
- package/plugins/flow/CHANGELOG.md +227 -0
- package/plugins/flow/examples/FLOW.template.md +2 -2
|
@@ -27,12 +27,14 @@ Closes the feature: commit, push, MR/PR (assigned per `git.assignee`, squash per
|
|
|
27
27
|
- Read `meta.json` and `00-summary.md`; open in full only the `Brief MR/PR #N` of `05-implementation.md`, the `## Summary`/blockers of `06-review.md` and `07-validation.md`. (flow-core §5)
|
|
28
28
|
- Require `review` in `phases_done`; for `size` other than `XS`, also require `validate`. **In a multi-MR/PR work** (`meta.json.mrs` has >1 entry) check the **current `in_progress` MR/PR's** own `phases_done` (its `mrs[]` entry), NOT the work-level list — a previous MR/PR's `review`/`validate` does **not** satisfy this gate.
|
|
29
29
|
- Not met → refuse and send the user to the missing step (multi-MR/PR: `$flow-feat-review` or `$flow-feat-validate` **for this MR/PR**).
|
|
30
|
-
- **The review has to be about the tree you are about to push.** Compare `meta.json.reviewed_sha` and `validated_sha` (this MR/PR's `mrs[]` entry in a multi-MR/PR work) against `git rev-parse HEAD`:
|
|
31
|
-
- **Equal** → continue, nothing to report.
|
|
30
|
+
- **The review has to be about the tree you are about to push.** `reviewed_sha` is the revision the reviewers **read** (`$flow-feat-review §1.5` froze it), not the one that phase ended on, so the round's own fixes are a real delta here rather than a match. Compare `meta.json.reviewed_sha` and `validated_sha` (this MR/PR's `mrs[]` entry in a multi-MR/PR work) against `git rev-parse HEAD`:
|
|
31
|
+
- **Equal** → continue, nothing to report — **unless `fixed_sha` is set**, which says the review changed the tree after reading it and cannot then be equal to `HEAD`. That combination is a mismatch, not a match: the shas were recorded by two different mechanisms and one of them is wrong. Say so and treat it as Different below.
|
|
32
|
+
- **The tree is dirty at this end** (`git status --porcelain` non-empty, ignoring untracked) → both shas describe committed history and the bytes about to be pushed are not in either. Name the paths and ask, exactly as Different does; a comparison of two identical shas over two different trees is the case the old gate passed over in silence.
|
|
33
|
+
- **`reviewed_sha` does not resolve** (`git cat-file -e <sha>^{commit}`) — a candidate from a dirty tree whose anchor ref was deleted, or history rewritten since — → say so in one line and treat it as Absent. A gate that cannot read its own input must not report nothing wrong here.
|
|
32
34
|
- **Absent** (work started before the shas were recorded) → say so in one line and continue. Absence is not a mismatch.
|
|
33
|
-
- **Different** → read the delta (`git log --oneline <sha>..HEAD`, `git diff --stat <sha>..HEAD`) and judge it by **what it touches**, never by size.
|
|
35
|
+
- **Different** → read the delta (`git log --oneline <sha>..HEAD`, `git diff --stat <sha>..HEAD`) and judge it by **what it touches**, never by size. When `fixed_sha` is set, say in the same line that part of this delta is the review's own fixes: the user is judging what the reviewers never read, and where it came from is the first thing they need.
|
|
34
36
|
- Only test files (`tests/`, `test/`, `spec/`, `__tests__/`, `*_test.*`, `*Test.*`, `*.test.*`, `*.spec.*`) and this work's own folder under `.claude/work/` → append both shas and the file list to `06-review.md`, continue **without asking** (a test written by `validate` after the review is the normal order).
|
|
35
|
-
- **Anything else** → stop and ask, in **every** `autonomy.mode`, with a single `AskUserQuestion`: *re-review the delta* (`$flow-feat-review`, recommended default — it reads
|
|
37
|
+
- **Anything else** → stop and ask, in **every** `autonomy.mode`, with a single `AskUserQuestion`: *re-review the delta* (`$flow-feat-review`, recommended default — §1.5 resolves `reviewed_sha` as its base, so it reads the delta and nothing else, and resolves the tier on the delta too) · *ship it as it stands*, which first appends to `06-review.md` the two shas, the files, and that the user accepted them unreviewed. Never resolve this one silently.
|
|
36
38
|
- Check for blocking TODO/FIXME added on this branch (`git diff --unified=0 <git.default_base>...HEAD | grep -E '^\+.*(TODO|FIXME)'`). If any, list them and ask whether to continue.
|
|
37
39
|
|
|
38
40
|
## 2. Draft title and description (without sending anything yet)
|
|
@@ -228,6 +230,22 @@ Only if `knowledge.read_staging` or `knowledge.save` is set; neither → skip wi
|
|
|
228
230
|
3. **Combine staging + new findings** into a short list. Empty or only code-derivable → do not insist.
|
|
229
231
|
4. 1+ relevant findings → ask the user whether to consolidate. Yes → run the consolidation of flow-core §0 (`read_staging`, then one decision and one `knowledge.save` per finding). No → do not insist.
|
|
230
232
|
|
|
233
|
+
## 5.5 A worktree does not own the tree its tools wrote into
|
|
234
|
+
|
|
235
|
+
`meta.json.worktree` null → skip silently; there is nothing here that can go wrong.
|
|
236
|
+
|
|
237
|
+
Everything above this line ran in a worktree, and several of the tools it called had no way of knowing that. A configured tool — `knowledge.save` is the first one this caught, and no key is special — is started once per session, resolves the repo from the directory it was started in, and takes no root in its call. A worktree is the same repo with another tree, so its output can land in the **main checkout**, which is standing on another branch, while the branch §4 just pushed goes out without it. Nothing in the invocation could have corrected that: flow is the only party that knows `meta.json.worktree` is set, and this is the only place that knows the push already happened.
|
|
238
|
+
|
|
239
|
+
So, before the Close:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
git -C "$(git rev-parse --path-format=absolute --git-common-dir)/.." status --porcelain
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Empty → say nothing at all. Non-empty → **one line naming the paths**, and what it means in plain words: they are sitting in the main checkout, not in the branch that was pushed. Say it as a reading, never as an accusation — that checkout may have been dirty before this work started, and only the user can tell their own leftovers from what this run put there.
|
|
246
|
+
|
|
247
|
+
Then offer once, with `AskUserQuestion` **in every autonomy mode** (it edits two trees): **carry them over** — copy the paths the user confirms into this worktree, commit onto the branch, push, and the MR/PR from §4 updates itself — or **leave them**, which is the right answer whenever what is sitting there belongs to the other branch. Either way the Close reports what was decided: a `ship` that quietly repaired two checkouts is worse than one that named the problem and left it standing.
|
|
248
|
+
|
|
231
249
|
## 6. Close
|
|
232
250
|
|
|
233
251
|
### 6.1 Update `meta.json` per scenario
|
|
@@ -407,6 +425,7 @@ paste. Never a list here, and never a question: in `guided`/`auto` not asking is
|
|
|
407
425
|
### 6.5 Archive and cleanup
|
|
408
426
|
|
|
409
427
|
Only if `phase = "done"`:
|
|
428
|
+
- Delete the candidate anchor `$flow-feat-review §1.5` left behind: `git update-ref -d refs/flow/candidate/<TICKET>`. It existed to stop the object being collected while the gate still needed it; the gate has run. No question — it is local, it was never pushed, and nothing reads it after this. Absent already → nothing to do.
|
|
410
429
|
- Ask whether to keep `.claude/work/<TICKET>/` or archive it (move to `.claude/work/_archive/`).
|
|
411
430
|
- If `meta.json.worktree` is not null, offer to remove the worktree (from the main checkout) with `git worktree remove <worktree>` (`--force` only if it still has changes the user confirms discarding). Never without confirmation, never if the MR/PR is not yet merged.
|
|
412
431
|
|
|
@@ -30,10 +30,14 @@ Verify the feature is complete: test coverage, edge cases, performance, regressi
|
|
|
30
30
|
|
|
31
31
|
## 2. Work
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
One of the three below writes and two of them read, so they do not all go at once (flow-core §6, one writer of the working tree at a time). The testing agent's deliverable is **files on disk**; the performance agent and the suite both read the tree it is writing into. Run beside it, the suite reports on a tree that no longer exists by the time you read the result — and a red raised by a half-written test file is a red nobody can act on. Both briefs end with the report contract of flow-core §6 (`agents.report_max_words`, empty → 250; findings only, one line each).
|
|
34
|
+
|
|
35
|
+
**First, alone — the writer.** It is told the **test files are the deliverable**, saved as each one is finished, not at the end:
|
|
34
36
|
|
|
35
37
|
1. **Testing agent**: the `agents.testing` agent from the effective FLOW config; if empty, `Agent general-purpose` with this role. Brief: "Review the branch changes and complete the test suite where coverage is missing. Focus: the acceptance criteria in `03-design.md` marked `test` that no current test demonstrably asserts (see the §3 mapping), plus edge cases from `03-design.md`, error paths, input validations, emitted domain events. Do not rewrite tests that already pass. Read `.claude/work/<TICKET>/03-design.md` and `05-implementation.md`. Follow the project's effective test conventions from `FLOW.md` plus the active harness overlay."
|
|
36
38
|
|
|
39
|
+
**Then, in parallel — the readers**, once the testing agent has reported and its files are on disk. The suite runs here and not earlier for a second reason beyond the collision: run after the writer, it is the first thing that has ever executed the tests this phase just added.
|
|
40
|
+
|
|
37
41
|
2. **Performance agent** if the feature touches persistence, repositories, templates on hot paths, controllers with real traffic, or calls anything outside the process inside a loop: the `agents.performance` agent from `FLOW.md`; if empty, `Agent general-purpose` with this role. Brief: "Detect N+1, missing indexes, unbounded queries, flush in a loop, per-iteration calls that leave the process (external API, HTTP, cache, filesystem), and heavy synchronous work that should go to a queue. For any call inside a loop that can fail, follow what **each failed iteration** sets off downstream — what it publishes, enqueues, disables or logs — and whether N failures multiply it. Report only actionable findings."
|
|
38
42
|
|
|
39
43
|
**A green suite is not a performance result** — a tiny fixture database proves a query's **rows**, never its **plan**. If `$flow-feat-review §3.6` left any query verdict `unresolved`, or an acceptance criterion concerns speed or volume: run the measurement of **`$flow-work-query §4`** with the volumes in `data.volumes` (or a data set shaped like them — the distribution matters more than the total), record plan and timings, and gate on the result. No `data.*` configuration and the criterion cannot be measured → it is `unproven` with the reason, never silently `proven`.
|
|
@@ -20,9 +20,10 @@ description: "Assistant that generates FLOW.md and its optional harness overlay
|
|
|
20
20
|
|
|
21
21
|
Creates or updates the effective FLOW configuration at the repo root: shared values in `FLOW.md`
|
|
22
22
|
and optional harness-owned values in the active `FLOW.<harness>.md`. The active filename is
|
|
23
|
-
`FLOW.claude.md`, `FLOW.codex.md`, `FLOW.opencode.md`, `FLOW.gemini.md`,
|
|
24
|
-
identify it from the
|
|
25
|
-
product executing this command, never from the selected model
|
|
23
|
+
`FLOW.claude.md`, `FLOW.codex.md`, `FLOW.opencode.md`, `FLOW.gemini.md`, `FLOW.hermes.md`, or
|
|
24
|
+
`FLOW.zcode.md`; identify it from the
|
|
25
|
+
product executing this command, never from the selected model (zcode runs the Claude pages too, so
|
|
26
|
+
the page you are reading does not name the harness). Every other `$flow-*` command reads
|
|
26
27
|
the base and then that overlay. The user answers the **minimum**: what the repo can tell is
|
|
27
28
|
auto-detected and only confirmed.
|
|
28
29
|
|
|
@@ -25,7 +25,7 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
25
25
|
- `FLOW.md` at the repo root is the shared base: tracker, branch and MR/PR conventions, quality
|
|
26
26
|
commands, code conventions, and observability profile.
|
|
27
27
|
- The active `FLOW.<harness>.md` is an optional sparse overlay (`claude`, `codex`, `opencode`,
|
|
28
|
-
`gemini`, or `
|
|
28
|
+
`gemini`, `hermes`, or `zcode`) for model names, agents, skills, orchestration, knowledge tools, or any other value that
|
|
29
29
|
differs on that harness. Every command reads the base and then the active overlay in step 0;
|
|
30
30
|
existing repos with only `FLOW.md` behave exactly as before.
|
|
31
31
|
- An overlay key replaces the base even when explicitly empty; an absent key inherits it. Lists
|
|
@@ -87,9 +87,12 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
87
87
|
"phase": "context" | "design" | "plan" | "build" | "review" | "validate" | "ship" | "investigate" | "fix" | "postmortem" | "done" | "abandoned",
|
|
88
88
|
// retired in v0.53.0 and still read from older works: "brainstorm" → treat as "context", "diagnose" → as "investigate"
|
|
89
89
|
"phases_done": ["context", ...],
|
|
90
|
+
"candidate_sha": "40-char sha the current review froze before reading, or ''",
|
|
90
91
|
"reviewed_sha": "40-char sha the last passing review read, or ''",
|
|
92
|
+
"fixed_sha": "40-char sha after that review's own fixes, or '' when it applied none",
|
|
91
93
|
"validated_sha": "40-char sha the suite last went green on, or ''",
|
|
92
94
|
"respond_rounds": 0,
|
|
95
|
+
"review_findings": [{"round": 1, "origin": "security", "severity": "blocker", "file": "src/X.php", "discarded_by_skeptic": false}],
|
|
93
96
|
"mrs": [
|
|
94
97
|
{
|
|
95
98
|
"n": 1,
|
|
@@ -97,7 +100,9 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
97
100
|
"size": "S",
|
|
98
101
|
"status": "pending" | "in_progress" | "merged" | "closed" | "superseded",
|
|
99
102
|
"phases_done": ["build", "review", "validate"],
|
|
103
|
+
"candidate_sha": "",
|
|
100
104
|
"reviewed_sha": "",
|
|
105
|
+
"fixed_sha": "",
|
|
101
106
|
"validated_sha": "",
|
|
102
107
|
"respond_rounds": 0,
|
|
103
108
|
"wave": 1,
|
|
@@ -138,7 +143,9 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
138
143
|
}
|
|
139
144
|
```
|
|
140
145
|
|
|
141
|
-
- **`reviewed_sha` / `validated_sha`**: which code
|
|
146
|
+
- **`candidate_sha` / `reviewed_sha` / `fixed_sha` / `validated_sha`**: which code each verdict is about. `candidate_sha` is written by `review` in its **pre-flight** (§1.5) — the revision it froze before reading anything, `git rev-parse HEAD` over a clean tree and `git stash create` over a dirty one, anchored at `refs/flow/candidate/<TICKET>` so nothing collects it. The other three are written at `## Close`, **only when the phase actually advances**, work-level and in the current `mrs[]` entry: `reviewed_sha` is the candidate that was actually read, `fixed_sha` is `HEAD` after that round's own fixes (empty when it applied none), `validated_sha` is where the suite went green.
|
|
147
|
+
- **`review_findings[]`**: one entry per finding **per source** — `{ round, origin, severity, file, discarded_by_skeptic }`, no finding text (that stays in `06-review.md`). Written at `review`'s Close, and by `flow review --record` when the CLI ran the panel. `origin` is `built-in`, a panel role, or the pass that raised it. It exists so a pass can be retired on evidence: `flow cost` reports per origin how many findings each contributed, how many **only** it raised, and how many of those survived §6 — and a finding three sources raised says nothing about any of them, which is why dedup keeps every source rather than the first. The rule was written down before the data arrived: no exclusive surviving finding across twenty reviews and the pass comes out of the command.
|
|
148
|
+
Two fields for the review because they are two facts. `reviewed_sha` used to be `git rev-parse HEAD` at the end of the phase, which by then held the round's own fixes — so `ship` compared a sha against itself and reported a match over code no reviewer had read. Read by `ship` at pre-flight against `HEAD`: a delta of test files and this work's own folder passes with a note in `06-review.md`; anything else stops and asks in every autonomy mode. Empty is not a mismatch; `fixed_sha` set with `reviewed_sha == HEAD` is one. `review` also reads `reviewed_sha` back as **its own base** on a re-review, so the second round reads the delta instead of the whole branch.
|
|
142
149
|
- **`respond_rounds`**: rounds of `$flow-work-respond` on an MR/PR. `$flow-work-respond §1` reads it against `quality.respond_max_rounds` (empty = 3) and refuses the round that would exceed it, handing the open threads back to the user.
|
|
143
150
|
- **`related_repos`**: the **other repos a task touches**. Captured at `$flow-feat-start` / `$flow-bug-start` §cross-repo, refined at `design`/`plan`, reminded at `ship`, shown by `daily`/`resume`/`status`. flow only notes and reminds — never touches the other repo. `[]` for single-repo.
|
|
144
151
|
- **`contract_handoff`**: whether the sibling knows **what shape to build against** (`scope` is prose; distinct from `status`). `none` — consumes no contract declared here. `pending` — consumes one, not handed over yet. `published → <location>` — published where that side reads it (normally the tracker ticket; `$flow-feat-ship` §6.3), picked up by the sibling's `$flow-feat-start` §3.6.
|
|
@@ -138,7 +138,7 @@ Only the **code-change** bucket, with the flow's building mechanics and conventi
|
|
|
138
138
|
In-review edits are **not** exempt because they are "small": they are where a wrong primitive or over-engineered mechanism slips in, straight into an MR/PR already under human eyes. The round's diff passes the **same gate as `$flow-feat-review`**, scaled to the round:
|
|
139
139
|
|
|
140
140
|
- **Trivial rounds** — only nitpick/style edits, no new classes or wiring → a single built-in `code-review` pass over the round's diff; skip the rest of this subsection.
|
|
141
|
-
- **Non-trivial rounds** — anything beyond nitpicks, or new architectural pieces → run the review machinery of `$flow-feat-review`, **scoped to this round's diff** (not the whole feature),
|
|
141
|
+
- **Non-trivial rounds** — anything beyond nitpicks, or new architectural pieces → run the review machinery of `$flow-feat-review`, **scoped to this round's diff** (not the whole feature). Its **§1.5** is what now delivers that scope rather than leaving it a promise: the previous `reviewed_sha` is the base when it is an ancestor of the candidate, so the round's own diff is both what is read and what sets the tier. Then apply:
|
|
142
142
|
- Its **§2.0 depth ladder** — pick the built-in `code-review` effort from the round's diff size (proxying `meta.json.size` when the round is small) plus the **sensitive-surface bump**; launch the project panel (`quality.review_skill` / `quality.reviewers`) when the ladder selects it, **as defined**. Per its **§2.2**: the stance agreed in §4 goes to the reviewer as context, never as a scope exclusion in the prompt.
|
|
143
143
|
- Its **§4 over-engineering / YAGNI audit** and **§5.5 idiom / primitive audit (blind to the design's rationale)** — they catch extracting a class/interface/mechanism to "answer a comment". **§5.5's trigger — "introduces new architectural pieces" — always runs when that is true, regardless of round size.**
|
|
144
144
|
- Its **§3.6 data-access duel** whenever the round **added or changed a query** — including a one-line change to an order, a bound or a join, and a change made to satisfy a reviewer's comment. If §4.G already measured it this round, reuse that table.
|
package/adapters/gemini/CORE.md
CHANGED
|
@@ -16,7 +16,7 @@ Every `/flow:*` command assumes these rules. They are stated once, here, so a co
|
|
|
16
16
|
carries what is specific to its phase. Read this once per session; a command that says "load
|
|
17
17
|
`flow-core`" means this file.
|
|
18
18
|
|
|
19
|
-
**This file belongs to flow `0.
|
|
19
|
+
**This file belongs to flow `0.67.0`.** Compare it once, at the start of the session, against
|
|
20
20
|
`version` in `~/.claude/flow/.claude-plugin/plugin.json`. The two differing means the session
|
|
21
21
|
is running a **mixture** — the commands from one copy of the plugin, these shared rules from another
|
|
22
22
|
— which is exactly what happens when a branch or a release candidate is loaded over an installed
|
|
@@ -37,10 +37,14 @@ a command relies on is simply absent in that session, and nothing else will repo
|
|
|
37
37
|
them. **Name the files this listing found the first time a phase reports any configured value**,
|
|
38
38
|
so a missed overlay is visible in the artifact rather than invisible everywhere.
|
|
39
39
|
- Read `FLOW.md` at the repo root as the base, then the optional overlay for the harness running
|
|
40
|
-
this command: `FLOW.claude.md`, `FLOW.codex.md`, `FLOW.opencode.md`, `FLOW.gemini.md`,
|
|
41
|
-
`FLOW.hermes.md`. The
|
|
40
|
+
this command: `FLOW.claude.md`, `FLOW.codex.md`, `FLOW.opencode.md`, `FLOW.gemini.md`,
|
|
41
|
+
`FLOW.hermes.md`, or `FLOW.zcode.md`. The
|
|
42
42
|
harness is the product executing the command, never guessed from a model name. An overlay is
|
|
43
|
-
valid without a base file; unknown `FLOW.*.md` names are ignored.
|
|
43
|
+
valid without a base file; unknown `FLOW.*.md` names are ignored. **A page can outlive the product it
|
|
44
|
+
was written for**: zcode reads the plugin's Claude pages as well as its own `/flow:`-prefixed
|
|
45
|
+
mirror of them, so a `claude` in a path or in a `--harness` flag records where the page was
|
|
46
|
+
written, never who is running it. On zcode the overlay is `FLOW.zcode.md` and the flag is
|
|
47
|
+
`--harness zcode`, whichever of the two pages you were handed. Throughout every command,
|
|
44
48
|
**"FLOW.md" means this effective merged configuration** unless the command explicitly names a
|
|
45
49
|
file it will edit.
|
|
46
50
|
- **"The repo root" is the main checkout's, not the worktree's.** With `git.worktree` set, every
|
|
@@ -54,6 +58,12 @@ a command relies on is simply absent in that session, and nothing else will repo
|
|
|
54
58
|
differ — and otherwise read both files from the main checkout, which
|
|
55
59
|
`git rev-parse --path-format=absolute --git-common-dir` locates from anywhere (its parent
|
|
56
60
|
directory). Name the file you actually read when a stop reports configuration.
|
|
61
|
+
**This is a rule about reading a git-ignored config, and it inverts for anything a phase
|
|
62
|
+
writes into the repo.** A tracked file belongs to the branch, and the branch is the worktree:
|
|
63
|
+
written to the main checkout it lands on whatever that checkout is standing on — usually the
|
|
64
|
+
base branch — and goes out in no MR/PR at all. So a phase writing a tracked file writes it
|
|
65
|
+
**here**, in the directory it is running in, and `/flow:feat:ship §5.5` is what catches the
|
|
66
|
+
tools that could not be told.
|
|
57
67
|
- Merge by section and key. A key present in the active overlay replaces the base value; a key
|
|
58
68
|
absent there inherits the base. **A present-but-empty overlay key masks the base** and resolves
|
|
59
69
|
to the normal empty-key fallback — this is how Codex can inherit its session model while a legacy
|
|
@@ -114,7 +124,8 @@ worth a command of its own, which is why there is no longer one:
|
|
|
114
124
|
3. **Per finding**: `knowledge.search` set → query it with the topic and the finding's paths, then
|
|
115
125
|
decide *create* · *update* · *enrich with a new angle* · *conflict*. A conflict is asked
|
|
116
126
|
immediately (`AskUserQuestion`) and nothing is saved until it is resolved. Then `knowledge.save`,
|
|
117
|
-
one call per finding; the role empty → append to **`KNOWLEDGE.md` at the
|
|
127
|
+
one call per finding; the role empty → append to **`KNOWLEDGE.md` at the root of the checkout
|
|
128
|
+
you are in** (a tracked file belongs to the branch — the inversion above) under a
|
|
118
129
|
`## <topic>` heading — the finding, its evidence line, the date and the branch. Creating that file
|
|
119
130
|
the first time edits the tree, so it is asked once, in every mode; appending to an existing one is
|
|
120
131
|
recorded, not asked.
|
|
@@ -314,6 +325,21 @@ test suite, a migration, a batch of edits — name the **path it writes** and re
|
|
|
314
325
|
after each finished piece, not at the end**. Then verify the artifact instead of believing the
|
|
315
326
|
report: half a chunk on disk is recoverable, what lives only in the agent's context is not.
|
|
316
327
|
|
|
328
|
+
**One writer of the working tree at a time.** An agent whose deliverable is files on disk is not
|
|
329
|
+
another reader with a longer report: it is break, run, restore, and it composes with nothing else
|
|
330
|
+
looking at the same tree. Two of them at once — or one of them beside a reader — and every reading
|
|
331
|
+
taken in that window is of a tree somebody else was halfway through changing. That is how a suite
|
|
332
|
+
comes back red for an edit belonging to another agent, how a reviewer ends up running `git status`
|
|
333
|
+
around each of its own findings to work out which changes are its doing, and how a commit that
|
|
334
|
+
looks clean is clean by luck. **The parent thread is a writer too**: applying a round's fixes while
|
|
335
|
+
its agents are still reading is the same collision, from the side nobody counts.
|
|
336
|
+
|
|
337
|
+
So a round that contains a writer is not one round. Readers fan out freely, as they always did;
|
|
338
|
+
writers go one at a time, each either alone or in a worktree of its own, and the readers sit
|
|
339
|
+
entirely before them or entirely after them. The parent's own edits wait until the round is
|
|
340
|
+
consolidated. Ordering costs wall clock and the phase says so in one line — a reading nobody can
|
|
341
|
+
trust costs the phase twice, which is the trade this rule is making.
|
|
342
|
+
|
|
317
343
|
**A parallel round names a path too, however short the answer.** Not for volume — for arrival. A
|
|
318
344
|
round of four is four chances for a result to reach you as nothing: truncated in transit, delivered
|
|
319
345
|
as a notification while you were mid-turn, or an agent that went idle without replying at all. From
|
|
@@ -70,6 +70,8 @@ Save the brief at the top of `04-fix.md`. Any "also fix X while we're at it" dur
|
|
|
70
70
|
- **`guided`** — ask **once**, at the first step; apply that answer for the rest of the fix; record it in `04-fix.md`.
|
|
71
71
|
- **`auto`** — commit the WIP yourself (`git add <files> && git commit -m "WIP <TICKET>: <step>" --no-verify`) without asking. Invoking the command in `auto` is the authorization, and it covers **only** WIP commits on the work branch — push and MR/PR creation stay hard gates in every mode.
|
|
72
72
|
|
|
73
|
+
**Then write the step into the log, committed or not** — `/flow:feat:build §2.2`, unchanged, into a `## Steps` section of `04-fix.md`: `- <short sha> · <step name> · <n files, +a −b>`, with `—` in place of the sha for a step that was not committed. No question, in every mode. A fix is usually one step and one commit, which is exactly when the missing line costs least to add and the `06-review.md` delta is most likely to be that one sha.
|
|
74
|
+
|
|
73
75
|
## 2.2 The premise this fix rests on (any size)
|
|
74
76
|
|
|
75
77
|
Same instrument as `/flow:feat:build §2.1bis`: the four conditions, one round per fix, the same
|
|
@@ -118,6 +120,9 @@ A **product decision** the fix turns out to need is neither of these — not sco
|
|
|
118
120
|
## Changes by file
|
|
119
121
|
- <file> — what changed and why (1 line)
|
|
120
122
|
|
|
123
|
+
## Steps
|
|
124
|
+
<one line per step of §2.1, in order: `- <short sha> · <step name> · <n files, +a −b>`, and `—` in place of the sha where the step was not committed. This is what joins the log to the git history; a section with no holes is the point, so an uncommitted step still gets its line.>
|
|
125
|
+
|
|
121
126
|
## Premises the fix depends on
|
|
122
127
|
<one row per premise put through §2.2, plus any belief recorded as an assumption without a round: premise · what it rests on · verdict (holds / refuted / unsettled) · the evidence, or what would settle it. Omit the section when the fix depends on nothing outside its own diff.>
|
|
123
128
|
|
|
@@ -58,14 +58,24 @@ Read `~/.claude/flow/CORE.gemini.md` first (shared rules: `FLOW.md` step 0, mode
|
|
|
58
58
|
picks the model, so `models.agents`/`models.workers` do not reach those reviewers. A one-shot sweep
|
|
59
59
|
cannot pull a thread, so an ambiguous finding still goes to a real agent with tools, as below.
|
|
60
60
|
|
|
61
|
+
### 1.5 Freeze what you are about to read, and resolve what to compare it against
|
|
62
|
+
|
|
63
|
+
**`/flow:feat:review` §1.5, in full and unchanged.** In short, before §2 launches anything:
|
|
64
|
+
|
|
65
|
+
- **Candidate**: `git rev-parse HEAD` over a clean tree, `git stash create` over a dirty one (a real commit object, the checkout untouched, nothing to pop), anchored with `git update-ref refs/flow/candidate/<TICKET> <sha>` so nothing collects it and `/flow:bug:ship §0` can still resolve it. Untracked files are in no revision — name them and read them from disk. Written to `meta.json.candidate_sha` here, not later: a candidate recorded after the reading is not a freeze.
|
|
66
|
+
- **Review base**: the previous `reviewed_sha` when it is non-empty and an ancestor of the candidate, otherwise `git.default_base`, with the reason in one line. `--full` forces the whole branch.
|
|
67
|
+
- **Then**: `bundle --rev <candidate_sha> --base <review base>`, and every brief names that range rather than the live tree.
|
|
68
|
+
|
|
69
|
+
A fix is usually small enough that the delta and the branch are the same thing — which is exactly why the freeze matters more here than the scoping: a one-file fix whose round applies its own correction is the case where `reviewed_sha` used to equal `HEAD` while describing a tree nobody read.
|
|
70
|
+
|
|
61
71
|
## 2. Run the code reviews
|
|
62
72
|
|
|
63
|
-
Scope for every reviewer: the
|
|
73
|
+
Scope for every reviewer: **the candidate revision of §1.5, against the review base of §1.5** — the fix against `git.default_base` on a first review, the delta since the last passing one afterwards. The candidate carries the uncommitted work; untracked files stay outside it and §1.5 named them.
|
|
64
74
|
|
|
65
75
|
### 2.0 Resolve review depth (scale to *this diff* and the risk)
|
|
66
76
|
Read `quality.review_depth` from `FLOW.md` (`light` | `proportional` | `full`; empty → `proportional`) and `meta.json.size`. Built-in `code-review` effort ladder: **low < medium < high < xhigh < max** (lower = fewer, higher-confidence findings; higher = broader coverage).
|
|
67
77
|
|
|
68
|
-
**The tier is resolved against the diff in front of you
|
|
78
|
+
**The tier is resolved by the CLI, against the diff in front of you** — `/flow:feat:review §2.0`, in full and unchanged: `npx flow-workflows@<version> tier --harness gemini --rev <candidate_sha> --base <review base>` prints changed lines, diff size, `meta.json.size`, effective size (the lower of the two — a one-file fix inside a bug classified M is an XS review), the effort with and without the bump, the resolved ceilings, the within-10% flag and which `quality.sensitive_paths` globs matched. **Copy it verbatim** into §7 and record any deviation with its reason; no CLI or a non-zero exit falls back to the prose there (≤150 → XS · 151-600 → S · 601-1500 → M · >1500 → L) and `Review path` names the fallback. What stays yours is what a command cannot see: whether a generic category applies, and whether a matched path is a control-flow change or observability only. Every size-gated step here (§4.5, §5) reads the effective size; the bump is never scaled away.
|
|
69
79
|
|
|
70
80
|
**Say what the round will run on** (flow-core §1): the skeptics and the completeness check have no agent of their own, so with the fan-out key empty they inherit this thread's model — one line before the first round of 4 or more naming the count and the inheritance, and the same fact on the artifact's `Agent models` line. Name the key (`models.workers`, then `models.agents`), never a model.
|
|
71
81
|
|
|
@@ -93,6 +103,8 @@ Launch the reviewers selected in §2.0 and **consolidate their findings into a s
|
|
|
93
103
|
1. **Built-in `code-review`** (the Claude Code one, no prefix), at the effort of §2.0. Single pass over the local diff: correctness + simplification/efficiency.
|
|
94
104
|
2. **Project panel** (only when §2.0 selected it): skill `quality.review_skill` from FLOW.md, invoked as `<review_skill> branch`. `review_skill` empty and `quality.reviewers` set → launch those agents in parallel as a panel. Both empty → the built-in `code-review` is the whole review. Launch the panel **as defined** — whole roster, no subset, no substitutions; an agent that cannot run goes to §7 `Agents launched` with the reason. **Every brief you write for it — and for the §3 reinforcements — ends with the report contract of flow-core §6** (`agents.report_max_words`, empty → 250; findings only, one line each): an uncapped report is truncated in transit and reads exactly like a reviewer with nothing to say. The built-in `code-review` takes no brief; bound it with the §2.0 tier and hold it to the same fan-out deadline.
|
|
95
105
|
|
|
106
|
+
**Nothing edits the tree while a round is in flight** — `/flow:feat:review` §2.1, unchanged: the reviewers all read the same working tree, and this phase's own fixes wait until the round is consolidated, so §3 onward read a tree that stopped moving (flow-core §6).
|
|
107
|
+
|
|
96
108
|
Deduplicate overlaps (count once). Fix-specific focus beyond generic analysis:
|
|
97
109
|
- The change genuinely resolves the problem from `03-investigation.md`.
|
|
98
110
|
- No expanded scope (hidden refactor) — list any.
|
|
@@ -132,7 +144,7 @@ Review the diff for new defensive mechanisms smuggled in "just in case" (validat
|
|
|
132
144
|
|
|
133
145
|
## 4.5. Completeness check (M/L, no loop)
|
|
134
146
|
|
|
135
|
-
**M/L by effective size (§2.0) only**, **one** check, no loop, and only while the budget covers it: after consolidating §2-§3 — never in parallel with them, since the check's input is what they covered — contrast `git diff --stat <
|
|
147
|
+
**M/L by effective size (§2.0) only**, **one** check, no loop, and only while the budget covers it: after consolidating §2-§3 — never in parallel with them, since the check's input is what they covered — contrast `git diff --stat <review base>...<candidate_sha>` (§1.5) against what was reviewed. Any changed file no reviewer looked at → targeted pass with the applicable reviewer, merge. A small diff (normal for a fix) resolves this in seconds or makes it not apply.
|
|
136
148
|
|
|
137
149
|
## 5. Adversarial finding verification (parallel fan-out, optional)
|
|
138
150
|
|
|
@@ -204,17 +216,18 @@ Cost line: count every subagent this command launched — reviewers = §2.1 buil
|
|
|
204
216
|
<only if §5 was run; refuted findings with their reason, or "not applicable">
|
|
205
217
|
|
|
206
218
|
## Blockers
|
|
207
|
-
1. [file:line] …
|
|
219
|
+
1. [file:line] · <origin> · …
|
|
208
220
|
|
|
209
221
|
## Suggestions
|
|
210
|
-
1. …
|
|
222
|
+
1. [file:line] · <origin> · …
|
|
211
223
|
```
|
|
212
224
|
|
|
213
225
|
## 8. Close
|
|
214
226
|
|
|
215
227
|
- With blockers: `phase` stays where it was (`validate` for size ≥ S, `fix` on XS, where validate never ran). Iterate.
|
|
216
228
|
- Without blockers: `phase = "review"`, add to `phases_done`. Suggest `/flow:bug:postmortem` (M/L) or `/flow:bug:ship` (XS/S).
|
|
217
|
-
- **Record *what* you reviewed
|
|
229
|
+
- **Record *what* you reviewed, and separately what you changed after reading it** — `/flow:feat:review` §9, unchanged: `reviewed_sha` = the **candidate** of §1.5 (the revision the reviewers read, never `git rev-parse HEAD`, which by now holds this round's own fixes), and `fixed_sha` = `git rev-parse HEAD` after those fixes, empty when the round applied none. `phases_done` says a review happened; these two say on which tree and what moved afterwards, and `/flow:bug:ship §0` reads both against what is being pushed. Only when the phase advances: a review that ended in blockers reviewed nothing that stands.
|
|
230
|
+
- **Record which pass found what** — `/flow:feat:review §9`, unchanged: one `meta.json.review_findings[]` entry per finding **per source** (`{ round, origin, severity, file, discarded_by_skeptic }`, no finding text), written by `flow review --record` when the CLI ran the panel and by this Close when the agentic panel did. `flow cost` reads them back per origin, and the retirement rule is the same: a pass with no exclusive surviving finding across twenty reviews comes out of the command.
|
|
218
231
|
- **Stage what the review taught** (`knowledge.stage` set; silence by default). Review is where a project teaches the most and, until now, the one phase that never staged — a work with three review rounds and seventeen blockers produced zero knowledge cards because nothing asked for them while they were in context. Candidates are findings about the **domain or the codebase's real behaviour**, not about this diff: a library that does other than its name says, a test disguise that kept the suite green over a live defect, a module rule the reviewers had to cite from its own prose, a measurement. A blocker fixed here is not knowledge; *why it was written wrong* may be. Same evidence rule as `/flow:feat:design` §8 — one line of evidence per finding or it is not staged. One call per finding, one line to the user («Staged N finding(s) for `postmortem`/`ship`»). Never `knowledge.save` here.
|
|
219
232
|
- Overwrite `00-summary.md` whole (≤15 lines, flow-core §5).
|
|
220
233
|
- Stop body (after the flow-core §3 header): the findings that survived and what you did with each, plus the same Cost line as the Summary: "- Cost: <n>/<budget_max> subagents launched (<k> reviewers · <m> reinforcements · <s> skeptics), tier <light|proportional|full>".
|
|
@@ -25,10 +25,10 @@ Read `~/.claude/flow/CORE.gemini.md` first (shared rules: `FLOW.md` step 0, mode
|
|
|
25
25
|
|
|
26
26
|
- Read `meta.json` and `00-summary.md`; open in full only `04-fix.md` (the Brief), `06-review.md` (the verdict), `05-validation.md`, the §"Root cause identified" of `03-investigation.md`, and `99-postmortem.md` if it exists. (flow-core §5)
|
|
27
27
|
- Require `review` in `phases_done`; also `validate` if `size` ≥ S, and `postmortem` if `size` is M or L (the same sizes `/flow:bug:review §8` routes to postmortem — one rule). Missing → refuse and redirect to the missing step.
|
|
28
|
-
- **The review has to be about the tree you are about to push
|
|
29
|
-
- **Equal** → continue.
|
|
28
|
+
- **The review has to be about the tree you are about to push — `/flow:feat:ship` §1, in full and unchanged**, including its four newer cases: `reviewed_sha` is the revision the reviewers *read* (`/flow:bug:review` §1.5 froze it), so `fixed_sha` set alongside an equal sha is a mismatch and not a match; a dirty tree at this end is named and asked about rather than passed over; and a `reviewed_sha` that no longer resolves is reported, then treated as absent. Compare `meta.json.reviewed_sha` and `validated_sha` against `git rev-parse HEAD`:
|
|
29
|
+
- **Equal** (and no `fixed_sha`, over a clean tree) → continue.
|
|
30
30
|
- **Absent** (a work from before the shas were recorded) → say so in one line, continue; absence is not a mismatch.
|
|
31
|
-
- **Different** → read the delta (`git log --oneline <sha>..HEAD`, `git diff --stat <sha>..HEAD`) and judge it by **what it touches**. Only test files (`tests/`, `test/`, `spec/`, `__tests__/`, `*_test.*`, `*Test.*`, `*.test.*`, `*.spec.*`) or this work's folder under `.claude/work/` → append both shas and the file list to `06-review.md`, continue without asking. **Anything else** → stop and ask in **every** `autonomy.mode`, no exceptions (`AskUserQuestion`): *re-review the delta* (`/flow:bug:review`
|
|
31
|
+
- **Different** → read the delta (`git log --oneline <sha>..HEAD`, `git diff --stat <sha>..HEAD`) and judge it by **what it touches**. Only test files (`tests/`, `test/`, `spec/`, `__tests__/`, `*_test.*`, `*Test.*`, `*.test.*`, `*.spec.*`) or this work's folder under `.claude/work/` → append both shas and the file list to `06-review.md`, continue without asking. **Anything else** → stop and ask in **every** `autonomy.mode`, no exceptions (`AskUserQuestion`): *re-review the delta* (`/flow:bug:review`, the recommended default — its §1.5 takes `reviewed_sha` as the base, so the delta is both what it reads and what sets its tier) · *ship as it stands*, recording in `06-review.md` the two shas and that the user accepted them unreviewed.
|
|
32
32
|
|
|
33
33
|
## 1. Draft title and description (without sending anything yet)
|
|
34
34
|
|
|
@@ -169,6 +169,7 @@ nothing was measured. A slowness bug is the case where this comment *is* the pro
|
|
|
169
169
|
|
|
170
170
|
## 4. Close
|
|
171
171
|
|
|
172
|
+
- **A worktree does not own the tree its tools wrote into — `/flow:feat:ship` §5.5, in full and unchanged.** First, before anything below: `meta.json.worktree` not null → read the main checkout's `git status --porcelain`, name any paths it holds in one line as what they are (in the main checkout, not in the branch just pushed, and not necessarily put there by this run), and offer once to carry them over. A fix consolidates its knowledge one phase earlier, in `/flow:bug:postmortem` §4, so by the time this runs those writes have already happened and the branch has already been pushed — which is exactly the window this check exists to close.
|
|
172
173
|
- Update `meta.json`: add `ship` to `phases_done`, update `updated_at`. **`phase` becomes `done` only once the MR/PR is confirmed merged** — creating it is not finishing it. Right after §3.1 it is open, so ask once with `AskUserQuestion` whether it has already been merged: **no** (the normal answer) → leave `phase = "ship"`; **yes** → `phase = "done"`. `/flow:work:green` and `/flow:work:respond` work on the open MR/PR; `/flow:work:clean` only sweeps what merged.
|
|
173
174
|
- Refresh `panel.json`: while the MR/PR is open its line is `wait` with the `link`; once merged it is `done`, and only then say there is nothing left here (`mark: "info"`, `style: "ok"`). Drop the `Decision` line either way.
|
|
174
175
|
- Overwrite `00-summary.md` whole (≤15 lines, flow-core §5).
|
|
@@ -179,6 +180,7 @@ nothing was measured. A slowness bug is the case where this comment *is* the pro
|
|
|
179
180
|
- **Follow-up triage — `/flow:feat:ship` §6.4, in full and unchanged.** Read `meta.json.followups[]`; nothing `proposed` → skip silently. Otherwise §6.4 step 0 first — **3 or more candidates go to a skeptic** whose job is to refute that each deserves a ticket, and only the strongest `tracker.followup_ask_max` (empty → **2**) reach the user (flow-core §7) — then one batched `AskUserQuestion` (**Do it** / **Not worth it** / **Later**; `decision` entries asked as their question, `tooling` and everything `log`ged never asked), the accepted ones get their tracker issue created (outward-facing → **asks in every mode**), the logged ones nothing but `status: "logged"` in `meta.json`, then one offer to start the first. A bug flow is where the gate earns its keep: the prevention actions `/flow:bug:postmortem` wrote, the neighbouring bugs `/flow:bug:validate` found and the similar-risk patterns `/flow:bug:fix` flagged all land here — half a dozen of them, from one fix, and «similar risk elsewhere» that no skeptic ever read is exactly the entry that turns a closed bug into six open questions. Repeat for anything still `proposed` on the re-run that confirms the merge.
|
|
180
181
|
- **Conventions learned — `/flow:feat:ship` §6.4bis, in full and unchanged.** Read `meta.json.conventions_candidates[]` (flow-core §8); nothing pending → skip silently. Otherwise: drop what `FLOW.md` already says, then one batched `AskUserQuestion` (**Add to FLOW.md** / **Not a rule** / **Later**, or **Replace** when it contradicts a line that is there). Asked in every mode — it edits a file in the tree. A fix is where the corrections land hardest: *«never mock the repository in that layer»*, *«the regression test goes next to the unit test, not in the functional suite»* — said once inside `bug:fix`, and proposed again in the next incident unless they reach the file.
|
|
181
182
|
- **Close the follow-up that started this work.** `meta.json.origin` set and this ship moved `phase` to `done` → open the originating work's `meta.json` (live folder or `_archive/`) and set that `followups[]` entry to `status: "done"`. Best-effort: the originating folder is gone or unreadable → warn in one line and continue, never block. Without this the entry stays `in_progress` forever and `status`/`daily` keep reporting work that is finished.
|
|
183
|
+
- **Only once `phase` is `done`**: delete the candidate anchor `/flow:bug:review §1.5` left behind — `git update-ref -d refs/flow/candidate/<TICKET>`. No question: local, never pushed, and the gate that needed it has run.
|
|
182
184
|
- Ask whether to archive `.claude/work/<TICKET>/` to `.claude/work/_archive/`.
|
|
183
185
|
- If `meta.json.worktree` is not null, offer `git worktree remove <worktree>` once the MR/PR is merged (`--force` only if the user confirms discarding remaining changes). Not before merge, not without confirmation.
|
|
184
186
|
"""
|
|
@@ -176,6 +176,17 @@ The step's changes are **always reported before anything is recorded**. Who deci
|
|
|
176
176
|
- **"Something needs to change"** → adjust; the step's commit stays pending until OK.
|
|
177
177
|
- **"Continue without committing, we'll group later"** → next step without committing; changes accumulate in the working tree (fewer clean points if §2.3 cuts).
|
|
178
178
|
|
|
179
|
+
4. **Write the step into the log, committed or not.** Append one line to a `## Steps` section of `05-implementation.md` (create it at the first step):
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
- <short sha> · <step name> · <n files, +a −b>
|
|
183
|
+
- — · <step name> · <n files, +a −b> ← not committed
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
No question, in every autonomy mode — this is flow machinery on the never-ask list of flow-core §2. A step that was **not** committed gets its line too, with `—` where the sha would be: that is the case in `manual`, and the *"continue without committing, we'll group later"* branch above. The log then has no holes, and the absence of a commit is itself what the reader needs to see.
|
|
187
|
+
|
|
188
|
+
The step summary was already written for every step; the sha is the one identifier that makes the log line and the git history the same record. Without it `05-implementation.md` explains *why* each change was made and names not one commit that did it, so §2.3 reads the cut point off `git log --oneline` and matches it by the prose in `WIP <TICKET>: <step>`, and a delta-scoped review (`/flow:feat:review §1.5`) can say which lines are new but not which steps they came from.
|
|
189
|
+
|
|
179
190
|
Rules when a commit does happen:
|
|
180
191
|
- One commit per step. Do not batch steps unless the user explicitly requests it.
|
|
181
192
|
- `--no-verify` **only for WIP commits** (slow hooks run in `/flow:feat:review` and in the final commit of `/flow:feat:ship`).
|
|
@@ -219,13 +230,13 @@ slip under a threshold buys itself the review a smaller change had earned.
|
|
|
219
230
|
**Hot cut mechanics (option 1)**:
|
|
220
231
|
|
|
221
232
|
0. **If there are uncommitted changes** in the working tree: warn the user and ask them to decide before cutting — commit what is done as a WIP for the corresponding step, or stash it (`git stash`) so it does not mix with the next MR/PR.
|
|
222
|
-
1. Identify a cut point: the last
|
|
233
|
+
1. Identify a cut point from the `## Steps` lines of `05-implementation.md` (§2.2): the last committed step where the piece is coherent and mergeable (a closed sub-goal: "endpoint and DTO done", "migration applied", "flow X tests green"). Those lines pair each step with its sha, so the cut is chosen on what the step *was* rather than re-derived from `git log --oneline` and matched by the prose in a commit message. **Name the sha in the proposal** — the user confirms an identifier, not a description. A step with `—` instead of a sha is not a cut point; it never got one. Do not cut in the middle of a change.
|
|
223
234
|
2. Edit `meta.json.mrs`:
|
|
224
235
|
- The current MR/PR keeps `n`, `title`, `wave` and `depends_on`, adjusts `lines_est` and `files_est` to actuals, and stays `in_progress`.
|
|
225
236
|
- Insert a new one with the next `n` (renumbering subsequent ones if any), `title` describing what remains, `status: "pending"`, `phases_done: []` (a fresh MR/PR earns its own review/validate), `depends_on: [n_current]`, `wave` = one after the current one, and new indicative `lines_est` and `files_est`. If you renumber subsequent entries, **update their `depends_on` references accordingly** so no `depends_on` points to a higher `n` than its own.
|
|
226
237
|
3. Edit `04-mr-plan.md`: split the original entry in two, keeping the standalone-mergeable justification for both halves.
|
|
227
238
|
4. Note in `05-implementation.md` under "Hot cut": date, reason, what stays and what moves to the next one.
|
|
228
|
-
5. **Do not rewrite history with `git rebase`**: WIP commits belonging to the next MR/PR stay in the current branch. When building the next one, start from a new branch over the base and transfer them with `git cherry-pick` or equivalent — executed in `/flow:feat:ship` or when starting the next `/flow:feat:build`.
|
|
239
|
+
5. **Do not rewrite history with `git rebase`**: WIP commits belonging to the next MR/PR stay in the current branch. When building the next one, start from a new branch over the base and transfer them with `git cherry-pick` or equivalent — executed in `/flow:feat:ship` or when starting the next `/flow:feat:build`. The shas to transfer are the `## Steps` lines below the cut point, which is what that section is for on this side of the cut too.
|
|
229
240
|
|
|
230
241
|
**If there was already a cut and overrun happens again**: ask the user before cutting again — a second cut on the same MR/PR signals the plan is wrong. The right option is probably **3 (reopen plan)**.
|
|
231
242
|
|
|
@@ -257,6 +268,9 @@ Keep `.claude/work/<TICKET>/05-implementation.md` updated as you work (not at th
|
|
|
257
268
|
## Changes per file
|
|
258
269
|
- <file> — what changed and why (1 line each)
|
|
259
270
|
|
|
271
|
+
## Steps
|
|
272
|
+
<one line per step of §2.2, in order: `- <short sha> · <step name> · <n files, +a −b>`, and `—` in place of the sha where the step was not committed. Written as each step closes, in every autonomy mode. This is what joins the log to the git history: §2.3 reads its cut point here, the transfer after a cut picks its shas here, and a delta-scoped review can say which steps a range came from. A section with no holes is the point — an uncommitted step still gets its line.>
|
|
273
|
+
|
|
260
274
|
## Decisions made during implementation
|
|
261
275
|
- Decision: …
|
|
262
276
|
- Why: …
|