feature-flow-cli 0.18.0__tar.gz → 0.23.0__tar.gz
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.
- {feature_flow_cli-0.18.0/feature_flow_cli.egg-info → feature_flow_cli-0.23.0}/PKG-INFO +44 -15
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/README.md +43 -14
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/adapters/codex/feature-flow/SKILL.md +10 -10
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/adapters/codex/feature-flow/agents/openai.yaml +1 -1
- feature_flow_cli-0.23.0/agents/flow-architect.md +52 -0
- feature_flow_cli-0.23.0/agents/flow-designer.md +52 -0
- feature_flow_cli-0.23.0/agents/flow-po.md +52 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/agents/flow-scout.md +25 -0
- feature_flow_cli-0.23.0/agents/flow-skeptic.md +55 -0
- feature_flow_cli-0.23.0/agents/flow-tester.md +24 -0
- feature_flow_cli-0.23.0/agents/plan-reviewer.md +45 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/agents/ticket-builder.md +2 -2
- feature_flow_cli-0.23.0/agents/ticket-reviewer.md +41 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/__init__.py +1 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/cli.py +20 -2
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/codehash.py +1 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/conductor.py +620 -71
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/evaluate.py +65 -7
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/floorguard.py +4 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/git.py +10 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/prompts.py +38 -4
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/proof.py +19 -10
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/scouts.py +1 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0/feature_flow_cli.egg-info}/PKG-INFO +44 -15
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow_cli.egg-info/SOURCES.txt +5 -0
- feature_flow_cli-0.23.0/guides/brainstorm.md +67 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/brief.md +6 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/build.md +4 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/plan-review.md +3 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/plan.md +7 -4
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/replan.md +1 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/review-single.md +3 -1
- feature_flow_cli-0.23.0/guides/templates/brainstorm.md +50 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/templates/commands.md +2 -1
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/templates/spec.md +4 -3
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/templates/ticket.md +1 -0
- feature_flow_cli-0.23.0/guides/test.md +56 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/flow-trust.py +15 -9
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/skills/feature-flow/SKILL.md +11 -11
- feature_flow_cli-0.18.0/agents/flow-architect.md +0 -27
- feature_flow_cli-0.18.0/agents/flow-designer.md +0 -27
- feature_flow_cli-0.18.0/agents/flow-po.md +0 -27
- feature_flow_cli-0.18.0/agents/plan-reviewer.md +0 -20
- feature_flow_cli-0.18.0/agents/ticket-reviewer.md +0 -16
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/LICENSE +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/MANIFEST.in +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/agents/feature-planner.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/agents/flow-web.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/__main__.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/checks.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/command.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/gate.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/importer.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/install.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/lanes.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/proc.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/profiles.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/released.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/report.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/state.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/status.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/suggest.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/tickets.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/uninstall.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow/view.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow_cli.egg-info/dependency_links.txt +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow_cli.egg-info/entry_points.txt +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/feature_flow_cli.egg-info/top_level.txt +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/debug.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/review-feature.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/review-quality.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/review.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/show.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/templates/learnings.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/templates/map.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/guides/templates/ui-mockup.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/install.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/install.sh +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/pyproject.toml +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/floor-guard.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/flow-status.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/flow-view.html +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/flow-view.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/flow.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/scripts/gate.py +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/setup.cfg +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/skills/architect-review/SKILL.md +0 -0
- {feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/skills/automation-design/SKILL.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: feature-flow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: A ticket-graph workflow for coding agents: installs the feature-flow skill into a repo
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/hamilton-sky/feature-flow
|
|
@@ -105,6 +105,10 @@ The Claude Code skill is `skills/feature-flow/`. The Codex skill is written by h
|
|
|
105
105
|
## How a ticket flows
|
|
106
106
|
|
|
107
107
|
```
|
|
108
|
+
tester subagent (once, before the first ticket, when commands.md
|
|
109
|
+
has Acceptance:): writes acceptance tests from spec.md only
|
|
110
|
+
│
|
|
111
|
+
▼
|
|
108
112
|
smoke command (script): is the base healthy? no ─► stop, spend nothing
|
|
109
113
|
│ yes
|
|
110
114
|
▼
|
|
@@ -125,23 +129,22 @@ The Claude Code skill is `skills/feature-flow/`. The Codex skill is written by h
|
|
|
125
129
|
commit that failed Test before the code fail ─┤
|
|
126
130
|
│ pass │
|
|
127
131
|
▼ │
|
|
128
|
-
|
|
129
|
-
+ diff,
|
|
130
|
-
|
|
131
|
-
▼ │
|
|
132
|
-
quality review: a second fresh reviewer subagent FAIL ─┤
|
|
133
|
-
(a level 1 or 2 ticket gets one combined review instead
|
|
134
|
-
of these two; see "Ticket levels" below)
|
|
132
|
+
review: one fresh reviewer subagent, sees only the ticket │
|
|
133
|
+
+ diff: the spec checklist, then the code's quality; at level 3 │
|
|
134
|
+
it also probes every input as a hostile caller FAIL ─┤
|
|
135
135
|
│ PASS ▼
|
|
136
136
|
▼ findings written into the ticket,
|
|
137
137
|
next ticket reopened, built again (rounds by level);
|
|
138
138
|
the builder's prompt then carries
|
|
139
139
|
a root-cause debugging guide
|
|
140
|
+
|
|
141
|
+
every ticket resolved: the acceptance tests run (script) fail ─► fix ticket, built and
|
|
142
|
+
reviewed like any other
|
|
140
143
|
```
|
|
141
144
|
|
|
142
|
-
`scripts/flow.py` is the conductor. The session asks it `next`, and it answers with one line: `BUILD`, `REVIEW`, `DONE`, `STOP` or `HANDOFF`. It prints the full prompt for each subagent from runtime-neutral guides, so the session never writes one itself.
|
|
145
|
+
`scripts/flow.py` is the conductor. The session asks it `next`, and it answers with one line: `TEST`, `BUILD`, `REVIEW`, `ASK`, `DONE`, `STOP` or `HANDOFF`. It prints the full prompt for each subagent from runtime-neutral guides, so the session never writes one itself.
|
|
143
146
|
|
|
144
|
-
**What the script checks and what it trusts.** The conductor verifies the build from the repo: the ticket file must say `resolved`, the tree must be clean and committed, and it runs the gate and the floor guard itself. It also runs the `check` block under each ticket's Done when and compares the exit code and printed text, and for a `Test first: yes` ticket it proves the red test commit itself: it checks out the test-only commit, runs Test, and requires it to fail before the code. A failure of either goes back to the builder before any reviewer is started. It also checks that the reviewer changed no tracked file and made no commit. The review verdicts are different: each reviewer's reply
|
|
147
|
+
**What the script checks and what it trusts.** The conductor verifies the build from the repo: the ticket file must say `resolved`, the tree must be clean and committed, and it runs the gate and the floor guard itself. It also runs the `check` block under each ticket's Done when and compares the exit code and printed text (a check with a `needs <what>` line, such as `needs network`, that fails is deferred instead: the reviewer is told it is not met, and it goes to `followups.md`), and for a `Test first: yes` ticket it proves the red test commit itself: it checks out the test-only commit, runs Test, and requires it to fail before the code. A failure of either goes back to the builder before any reviewer is started. It also checks that the reviewer changed no tracked file and made no commit (an edit is put back and the review given to a fresh reviewer, see Read only roles below). The review verdicts are different: each reviewer's reply is relayed by the session, which saves it to a file and hands it to `flow.py verdict`. The script reads `REVIEW: PASS` or `REVIEW: FAIL` from that reply; it cannot prove the session passed it on unedited. A ticket with a `Level:` line moves on after one PASS verdict. A ticket with no level (a plan from before 0.9.0) needs two, a spec review and then a quality review, unless the conductor judged it small. The size is measured from the repo (`git diff` against the commit the ticket started from), never taken from the builder.
|
|
145
148
|
|
|
146
149
|
**The gate: full or quick.** The gate runs Build, Test and Lint after every ticket. With an optional `Quick:` line in `commands.md` (a faster subset of `Test`), it runs Build, Quick and Lint after the tickets in the middle of a plan, and the full Build, Test and Lint after the last ticket, before a handoff, and under `FLOW_GATE_FULL=1`. A plan without `Quick:` runs the full gate every time. The test-first proof still runs the full `Test` command.
|
|
147
150
|
|
|
@@ -150,12 +153,12 @@ The Claude Code skill is `skills/feature-flow/`. The Codex skill is written by h
|
|
|
150
153
|
| | Level 1 (light) | Level 2 (standard) | Level 3 (boundary) |
|
|
151
154
|
|---|---|---|---|
|
|
152
155
|
| For | tests, docs, prompt text, spikes, the acceptance ticket | ordinary feature code | auth, tokens, permissions, money and run limits, data loss, the flow's own code, anything a hostile caller reaches |
|
|
153
|
-
| Reviews | one combined review | one combined review, spec checklist first |
|
|
156
|
+
| Reviews | one combined review | one combined review, spec checklist first | one combined review that also probes every input as a hostile caller |
|
|
154
157
|
| Rework rounds | 1, then the run stops for you | 2; from round 3 only a `blocker` sends it back, majors go to `plans/<feature>/followups.md` and the ticket passes | `FLOW_MAX_REVIEW_ROUNDS` (3), then the run stops for you |
|
|
155
158
|
|
|
156
159
|
The gate does not depend on the level: it still runs Quick mid-plan and the full Test on the last ticket and before a handoff. Nobody but you can lower a level. The conductor reads `Level:` from the ticket as it was at the base commit, so a builder's edit does nothing (and the floor guard fails it). It raises the level from what it measures, never lowers it: `Review: full`, `Type: convert` and `Floor: allow flow-edit` make a ticket level 3, so does a diff that touches a path on the optional `Sensitive:` line of `commands.md` (frozen by the floor guard), and a level 1 diff over the small limits becomes level 2. A reviewer can raise it with a line `LEVEL: 3` above the verdict; a raise to 3 during a combined review adds a quality review. The log records `LEVEL-1`, `LEVEL-2` or `LEVEL-3` for each review round, and `feature-flow report` shows it.
|
|
157
160
|
|
|
158
|
-
**
|
|
161
|
+
**One review at level 3 too (0.23.0).** Before 0.23.0 a level 3 ticket got a spec review and then a separate quality review. In the first field run (two features, 19 separate spec reviews), every real catch came from the quality review: the spec review re-ran the Done when checks the conductor had already run and passed, and found nothing they had missed. So a level 3 ticket now gets one review, which does the spec checklist (marking bullets the conductor's check block covered as `MET (conductor)` instead of running them again) and then the quality review with the hostile caller probe. That saves a fresh reviewer per level 3 ticket. A reviewer that raises a ticket to level 3 in a combined review still adds a quality review after it, since it did not probe the change as level 3.
|
|
159
162
|
|
|
160
163
|
**One review for a small ticket (no level).** A ticket with no `Level:` line, from a plan written before 0.9.0, keeps the 0.8.0 rules. A ticket whose built diff is 3 files and 60 changed lines at most (the plan folder left out), and whose `check` block ran and passed, gets one combined review instead of the spec and quality reviews. The conductor measures the diff itself. `Review: full` in the ticket (as it was at the start), `Type: convert`, no `check` block, or `FLOW_GATE=off` keep both reviews. Every other conductor check still runs on every ticket.
|
|
161
164
|
|
|
@@ -173,8 +176,9 @@ The gate does not depend on the level: it still runs Quick mid-plan and the full
|
|
|
173
176
|
| `ticket-reviewer` | Read, Glob, Grep, Bash (no Edit, no Write) | Reviews one ticket by the review guide in its prompt and ends with `REVIEW: PASS` or `REVIEW: FAIL`. |
|
|
174
177
|
| `feature-planner` | Read, Glob, Grep, Bash, Write, Edit, WebSearch, WebFetch | Plans one feature from the approved brief by the plan guide, writes only the draft, cites outside sources, and ends with `PLAN: READY` or `PLAN: QUESTIONS`. |
|
|
175
178
|
| `plan-reviewer` | Read, Glob, Grep, Bash (no Edit, no Write) | Checks the draft against the brief by the plan review guide and ends with `PLAN-REVIEW: PASS` or `PLAN-REVIEW: FAIL`. |
|
|
179
|
+
| `flow-tester` | Read, Glob, Grep, Edit, Write, Bash | Writes the feature's acceptance tests from `spec.md` alone, before the build, by the test guide. Never reads the tickets. |
|
|
176
180
|
|
|
177
|
-
|
|
181
|
+
**Read only roles.** The reviewers, the consultants (`flow-architect`, `flow-designer`, `flow-po`) and `flow-scout` have no Edit or Write tool, and in Claude Code a `PreToolUse` hook in their role file blocks shell commands that change files or the repository: git commands that write (`commit`, `add`, `stash`, `checkout`, `reset` and the like), `sed -i`, `rm`, `mv`, `cp`, `touch`, `tee` and output redirected into a file other than `/dev/null` or `/tmp/`. The hook reads the command's text, so a program that writes files itself (a test runner updating snapshots, a script) still gets through, and Claude Code ignores hooks in a plugin's agents. A Codex subagent cannot be limited at all: Codex gives every child its parent's sandbox. So the conductor is the backstop everywhere: when a reviewer or consultant leaves a tracked file changed, it saves the change as `.feature-flow/state/edit-<feature>-<NN>.patch`, puts the files back, throws that answer away and hands the same review to a fresh reviewer, with a note saying why (`EDIT-UNDONE` in the log). A second edit in a row stops the run, and so does a commit, which it cannot undo safely. A planner's draft reaches `plans/` only through `plan-accept`. On Codex the planner can research the web only if web search is on; otherwise it plans from the code and says so. The Codex planning path has not been run by hand.
|
|
178
182
|
|
|
179
183
|
The guides in `guides/` (installed to `.feature-flow/guides/`) hold the protocol: how to build, review, write the brief, plan, review a plan and show. The skill holds only what differs per agent.
|
|
180
184
|
|
|
@@ -187,6 +191,7 @@ plans/
|
|
|
187
191
|
├── map.md destination, the bar, decisions so far (workers append only)
|
|
188
192
|
├── commands.md build, test, lint, smoke commands (frozen once approved)
|
|
189
193
|
├── learnings.md traps workers found (workers append only)
|
|
194
|
+
├── brainstorm.md the options weighed and the one picked (only after a brainstorm)
|
|
190
195
|
└── tasks/
|
|
191
196
|
├── 01-types.md
|
|
192
197
|
├── 02-service.md
|
|
@@ -282,7 +287,7 @@ Before a planner, builder or reviewer starts, the session can spawn cheap helper
|
|
|
282
287
|
| a level 1 ticket | none |
|
|
283
288
|
| a build below level 3 (first attempt) | one builder scout on the ticket and its `Touches:` |
|
|
284
289
|
| a level 3 build (first attempt) | two builder scouts: the code it changes, and what depends on it |
|
|
285
|
-
| a level 3 ticket's
|
|
290
|
+
| a level 3 ticket's first review | one reviewer scout on the conventions the diff must follow |
|
|
286
291
|
| the feature review (fast path) | one reviewer scout |
|
|
287
292
|
|
|
288
293
|
`scouts [lane]` lists `SCOUT <k> <agent> <reply file>` lines (or `NONE`) and clears the last ones' replies; `scout-prompt <k> [lane]` prints one scout's prompt. The session saves each reply into its file, and the phase's `prompt` adds them under `## Scout findings (unverified)`, cut to 60 lines each. A reply saved for one phase never reaches another. Retries and later rounds get no scouts. `FLOW_SCOUTS=off` turns them off.
|
|
@@ -297,12 +302,23 @@ A builder, reviewer or planner that hits a question it should not decide alone a
|
|
|
297
302
|
- **The planner** starts each open question with `architect:`, `designer:`, `po:` or `user:`. The session runs `consult-prompt <role> <question file>` for the first three, adds the answers to the brief under `Consulted:`, kept apart from your `Decided:` lines, and plans again.
|
|
298
303
|
- **What still comes to you.** Any question the asker marks `user`, any answer a consultant ends with `ANSWER: USER` (it changes what you get, so its options come to you), and a third consultant question on one ticket all stop the run with the question, written into the ticket under `## Ask: user`. You answer under `## Consulted (user)` at the end of the ticket, commit, and run `next`. A reviewer's question for you reopens the ticket, so its builder builds again with your answer.
|
|
299
304
|
|
|
305
|
+
## Acceptance tests (the tester)
|
|
306
|
+
|
|
307
|
+
A builder writes its own tests, so they tend to check what it built rather than what was asked. With an `Acceptance:` line in `commands.md` (the planner writes one for any feature a test can reach from outside), a separate tester writes the feature's acceptance tests before any of it is built, from the product owner's words alone.
|
|
308
|
+
|
|
309
|
+
- **Before the first ticket**, `next` hands out `TEST <plan folder> <sha>`. A fresh `flow-tester` reads `spec.md` (its bar, stories and acceptance criteria, edge cases and interfaces), `map.md`, `commands.md` and the existing code's conventions, never the tickets, and commits tests under `plans/<feature>/acceptance/` that only the `Acceptance:` command runs. The conductor then checks its work: the commits change nothing outside that folder, the gate still passes with the tests in place, and the tests fail now, since nothing is built yet (`TEST-WRITTEN` in the log). Otherwise a fresh tester gets the job again, with a note saying what was wrong. It has no lane, even when lanes run.
|
|
310
|
+
- **Builders cannot change them.** The tests sit inside the plan folder, so the floor guard fails any builder's change there (`acceptance-edit`), and no `Floor:` line allows it. A builder may run them to see where the feature stands.
|
|
311
|
+
- **Once every ticket is resolved**, the conductor runs the `Acceptance:` command itself (`ACCEPT-PASS` or `ACCEPT-FAIL`). A failure becomes a new ticket, `NN-acceptance-fixes-<round>.md`, with the failing output in it, built and reviewed like any other; then the tests run again. After `FLOW_MAX_REVIEW_ROUNDS` failed rounds the run stops for you. With the fast path, the tests run before the feature review.
|
|
312
|
+
- **A disputed test.** The tester can be wrong too, most often where the spec is vague. A fix ticket's builder that is sure a test asks for something `spec.md` does not say asks the product owner with `## Ask: po`. `flow-po` rules from `spec.md` alone with `RULING: TEST WRONG` or `RULING: CODE WRONG` (`RULING-TEST` or `RULING-CODE` in the log). The builder leaves a test ruled wrong failing and finishes the rest; once the ticket is resolved, a tester changes exactly the tests ruled wrong, as the rulings say, and the tests run again. The usual limit on questions holds, so a third one goes to you.
|
|
313
|
+
- **No `Acceptance:` line, no tester**: a plan written before 0.23.0 runs as before.
|
|
314
|
+
|
|
300
315
|
## The fast path
|
|
301
316
|
|
|
302
317
|
`/feature-flow <feature> fast` trades per-ticket reviews for speed. The planner gets `Pace: fast` in the brief and writes a short plan of fewer, larger tickets, and the plan reviewer is skipped. With `FLOW_FAST=1` on `start`, a ticket below level 3 (one with no `Level:` line too) that passes the gate, the floor guard and its Done when checks passes at once (`REVIEW-DEFERRED` in the log). With `FLOW_GATE=off` nothing would check it, so every ticket keeps its review. A level 3 ticket, or one that touches a `Sensitive:` path, still gets its own reviews.
|
|
303
318
|
|
|
304
319
|
- **The feature review.** Once every ticket is resolved, `next` hands out `REVIEW <plan folder> all <sha>`: one fresh reviewer reads the deferred tickets as they were planned and the whole diff from the oldest deferred ticket's base to HEAD, with `guides/review-feature.md`. It has no lane, even when lanes run.
|
|
305
320
|
- **A failed feature review** becomes a new ticket, `NN-feature-review-fixes-<round>.md`, with the findings in it. A builder fixes it, and the feature is reviewed again. After `FLOW_MAX_REVIEW_ROUNDS` failed rounds the run stops for you.
|
|
321
|
+
- **Batches.** In fast mode one builder takes up to 5 ready tickets at once (`BATCH <n>` in the log), when each is level 1 or 2, has a `Touches:` line, and touches nothing another ticket of the batch or a `Sensitive:` path touches. The `BUILD` line names the first ticket and the prompt lists the rest. The builder finishes them one at a time, each with its own commits. The conductor then checks each ticket on its own commits: the gate once at the end (and, if it fails there, at each ticket's last commit, to find the first one that broke it), then the floor guard, the footprint, Done when and test first with HEAD at that ticket's last commit. A ticket that passes is deferred to the feature review like any other. One that fails, or that the builder never finished, goes back to open with its findings and is built alone (`BATCH-FAIL`), never in a batch again. That saves a builder and its context for every ticket but the first. A mistake in one ticket can still carry into the later ones of the batch, which is why only small, separate tickets are batched. Lanes, `FLOW_RELAY` and `FLOW_GATE=off` turn batches off, and so does `FLOW_BATCH=1` (`FLOW_BATCH=<n>` sets the size, at most 5).
|
|
306
322
|
- **Mid-run.** `fast on` and `fast off` (through the runner, like `next`) switch it between phases. Asking the session to go faster runs `fast on`. Asking again while fast is on offers the re-plan below. Tickets already passed without a review still get the feature review, whichever way it is switched.
|
|
307
323
|
- **The cost.** A mistake in an early ticket is found at the end, when later tickets may have built on it. Use it for small or low-risk features. `reset` keeps the list of deferred tickets, so they still get the feature review.
|
|
308
324
|
|
|
@@ -318,7 +334,8 @@ A builder, reviewer or planner that hits a question it should not decide alone a
|
|
|
318
334
|
|
|
319
335
|
Every finished run can leave a record of what it cost and what it caught, so a trial on your own repo gives an answer, not an impression. On `DONE` the skill runs `python3 scripts/flow-status.py <feature> --eval` (or run `feature-flow eval <feature>` yourself) and asks you a few questions.
|
|
320
336
|
|
|
321
|
-
- **`plans/<feature>/eval.json`**: tickets, builds, reviews and rework; every catch by the check that made it (gate, floor guard, Done when, test first, footprint, reviewer, feature review); where the run needed
|
|
337
|
+
- **`plans/<feature>/eval.json`**: tickets, builds, reviews and rework; tickets settled when the plan was approved and never built; every catch by the check that made it (gate, floor guard, Done when, test first, footprint, reviewer, feature review); the follow-ups in `followups.md` and the deferred checks; who drove the run (`driver`: `person` or `agent`); where the run needed its driver (stops, questions, handoffs, resets); active minutes; and tokens.
|
|
338
|
+
- **`plans/<feature>/followups.md`**: what the run left for later, committed as it goes: the `minor` findings of every passing review, the findings a level 2 ticket passed with after its full rounds, and each `needs` check (below) that could not pass on this host.
|
|
322
339
|
- **Tokens** come from Claude Code's own session transcripts (`~/.claude/projects/`, or `CLAUDE_CONFIG_DIR`), never from the agent: every message of the sessions and subagents that worked in this repo during the run, each counted once, by model and, without lanes, split per ticket by time. Codex sessions are not read yet.
|
|
323
340
|
- **`plans/<feature>/eval-verdict.md`**: a form for you. Was the plan right, how many fixes you made by hand, would you use it again, and for each catch whether it was real or a false alarm. Run `--eval` again and your answers land in `eval.json`. The false-alarm count is the only way to tell whether the checks are worth their cost.
|
|
324
341
|
- **Later:** `feature-flow eval <feature> --later`, a week or two on, lists the commits since the run whose subject says fix, revert, bug or regression on the paths each ticket's `Touches:` names: the defects the run let through.
|
|
@@ -339,6 +356,14 @@ Pick one with `/feature-flow <feature> careful` (or `fast`), `FLOW_PROFILE=<name
|
|
|
339
356
|
|
|
340
357
|
The long `python3 -I -c ...` line the skill uses to call the conductor stays as it is: it is how the skill checks `flow-trust.py` against the sha256 it pins before running it, and a shorter wrapper would be one more file nothing checks. The session copies it from the skill; you never type it.
|
|
341
358
|
|
|
359
|
+
## Brainstorm before planning
|
|
360
|
+
|
|
361
|
+
When an idea is still fuzzy, the session can brainstorm it with you before it writes the brief: `/feature-flow <feature> brainstorm`, always in `careful`, and offered on its own when there is no bar yet or there are two real ways to build it. It asks you up to three questions, one at a time, sends a scout to see how the code does the nearest thing today, then lays out two or three options, each with a mermaid diagram, its pros and cons, its size and its risky areas, and recommends one. Your pick and the brief share one yes.
|
|
362
|
+
|
|
363
|
+
Six read only helpers work for the session during a brainstorm: a code scout, a web scout, the architect, designer and product owner, and `flow-skeptic`, who attacks each finished option so the session that wrote the options is not the one that judges them. Each gets its prompt from `brainstorm-prompt <helper> <question file>`, which counts them: `normal` allows 2 scouts, 1 web, 2 consultants and 1 skeptic per brainstorm, `careful` 3, 2, 3 and 1, and `FLOW_SCOUTS=off` no scouts. Helpers never write the brainstorm and never ask you anything; the session does both.
|
|
364
|
+
|
|
365
|
+
The result is `brainstorm.md` ([template](guides/templates/brainstorm.md)), committed with the plan. The planner follows its chosen option and copies its diagram into `spec.md`, the plan reviewer fails a plan that builds a rejected option or leaves a risky area below level 3, and a re-plan keeps the choice. It is skipped in `fast`, for an import, and with `auto`; with `agent`, the driving agent picks, the file says `Picked by: agent`, and the eval records it.
|
|
366
|
+
|
|
342
367
|
## Starting from Spec Kit or OpenSpec
|
|
343
368
|
|
|
344
369
|
If you already plan with [GitHub Spec Kit](https://github.com/github/spec-kit) or [OpenSpec](https://github.com/Fission-AI/OpenSpec), feature-flow can build what they planned:
|
|
@@ -365,6 +390,8 @@ A session's context fills up, so the flow moves to a fresh session every few tic
|
|
|
365
390
|
- **Resuming after a closed session.** If a session ended without `HANDOFF` (you closed it, it crashed, it ran out of budget), the feature is still owned by it, and a new session stops and says so. Once you are sure the old session is gone, answer yes when the new session asks, or start it with `FLOW_TAKEOVER=1`. With `auto` the skill never takes over on its own.
|
|
366
391
|
- **Stuck on a ticket.** `python3 scripts/flow.py <feature> reset` (or `feature-flow reset <feature>`) reopens a ticket left `claimed` or `in-progress`, commits that, and clears the conductor's run state, so the next `/feature-flow <feature>` starts clean from the ticket files. `reset <NN>` reopens that one ticket, even a resolved one, to build it again. While a session owns the feature it needs `FLOW_TAKEOVER=1`. A mistyped command or feature name gets a `did you mean` hint.
|
|
367
392
|
- **Relay mode.** `FLOW_RELAY=1` hands off after every build and every review, so each phase gets a session of its own.
|
|
393
|
+
- **When an agent drives.** An orchestrating agent (another Claude session driving the skill for you) has no context to refresh, so handoffs are pure overhead. `/feature-flow <feature> agent` runs `start` with `FLOW_DRIVER=agent`: no `HANDOFF` unless `FLOW_TICKETS_PER_SESSION` is set by hand, builders skip the "continue in a fresh session" line (they leave it out whenever the flow runs them), and the eval records that an agent drove the run, so its stops, handoffs and resets are not read as your time. `next` runs the gate and the checks before it answers, which can take minutes: a caller with a 2 minute tool timeout should give it 10 minutes or more, or run it in the background.
|
|
394
|
+
- **Argument mistakes say what to do.** `verdict` without its file, `--after-build` in the wrong place (the runner now accepts it anywhere), a `next` after a REVIEW with no `verdict` in between (it used to hand out the same review again; now it changes nothing and says to run `verdict` first), a digest from another feature (the runner says to pass `FLOW_TRUST=new` on a feature's first call), and a commit made between a review and its `next` (the stop says how to take it out and make it again later).
|
|
368
395
|
- **Nobody needs to watch.** With `auto` the skill asks nothing, and a Claude Code cloud session keeps working while you are away. You only come back to type the `HANDOFF` line.
|
|
369
396
|
|
|
370
397
|
The state lives in `.feature-flow/state/` (the state, a log of every step, and the last review reply). That folder ignores itself, so it never shows up in `git status`, and a normal Codex session can write it, which it cannot do under `.git`.
|
|
@@ -401,9 +428,11 @@ The commands in `commands.md` run through `bash -c` on Linux and macOS and throu
|
|
|
401
428
|
| `FLOW_PROFILE` | unset | `careful`, `normal` or `fast`: fills the settings in this table that are not set; a `Profile:` line in `commands.md` does the same |
|
|
402
429
|
| `FLOW_TICKETS_PER_SESSION` | `4` | tickets per session before `HANDOFF`; `0` never hands off |
|
|
403
430
|
| `FLOW_RELAY` | `0` | `1` hands off after every build and every review |
|
|
431
|
+
| `FLOW_DRIVER` | `person` | read by `start`: `agent` when another agent drives the run: no handoffs (unless `FLOW_TICKETS_PER_SESSION` is set), and the eval says so |
|
|
404
432
|
| `FLOW_LANES` | `1` | read by `start`: `2` to `4` builds tickets with disjoint `Touches:` side by side in worktrees (not with `FLOW_RELAY`) |
|
|
405
433
|
| `FLOW_FAST` | unset | read by `start`: `1` defers the reviews of tickets below level 3 to one feature review at the end, `0` turns it off; unset keeps the run's setting |
|
|
406
434
|
| `FLOW_BUDGET` | unset | read by `start`: minutes of active work before fast mode turns on, then a re-plan offer; `off` drops it |
|
|
435
|
+
| `FLOW_BATCH` | `5` | fast mode: most small tickets one builder takes at once; `1` turns batches off |
|
|
407
436
|
| `FLOW_SCOUTS` | `on` | `off` lists no scouts before any phase |
|
|
408
437
|
| `FLOW_TAKEOVER` | unset | `1` lets `start` take a feature over from a session that is gone |
|
|
409
438
|
| `FLOW_MAX_RETRIES` | `2` | builds or reviews per step before the run stops |
|
|
@@ -86,6 +86,10 @@ The Claude Code skill is `skills/feature-flow/`. The Codex skill is written by h
|
|
|
86
86
|
## How a ticket flows
|
|
87
87
|
|
|
88
88
|
```
|
|
89
|
+
tester subagent (once, before the first ticket, when commands.md
|
|
90
|
+
has Acceptance:): writes acceptance tests from spec.md only
|
|
91
|
+
│
|
|
92
|
+
▼
|
|
89
93
|
smoke command (script): is the base healthy? no ─► stop, spend nothing
|
|
90
94
|
│ yes
|
|
91
95
|
▼
|
|
@@ -106,23 +110,22 @@ The Claude Code skill is `skills/feature-flow/`. The Codex skill is written by h
|
|
|
106
110
|
commit that failed Test before the code fail ─┤
|
|
107
111
|
│ pass │
|
|
108
112
|
▼ │
|
|
109
|
-
|
|
110
|
-
+ diff,
|
|
111
|
-
|
|
112
|
-
▼ │
|
|
113
|
-
quality review: a second fresh reviewer subagent FAIL ─┤
|
|
114
|
-
(a level 1 or 2 ticket gets one combined review instead
|
|
115
|
-
of these two; see "Ticket levels" below)
|
|
113
|
+
review: one fresh reviewer subagent, sees only the ticket │
|
|
114
|
+
+ diff: the spec checklist, then the code's quality; at level 3 │
|
|
115
|
+
it also probes every input as a hostile caller FAIL ─┤
|
|
116
116
|
│ PASS ▼
|
|
117
117
|
▼ findings written into the ticket,
|
|
118
118
|
next ticket reopened, built again (rounds by level);
|
|
119
119
|
the builder's prompt then carries
|
|
120
120
|
a root-cause debugging guide
|
|
121
|
+
|
|
122
|
+
every ticket resolved: the acceptance tests run (script) fail ─► fix ticket, built and
|
|
123
|
+
reviewed like any other
|
|
121
124
|
```
|
|
122
125
|
|
|
123
|
-
`scripts/flow.py` is the conductor. The session asks it `next`, and it answers with one line: `BUILD`, `REVIEW`, `DONE`, `STOP` or `HANDOFF`. It prints the full prompt for each subagent from runtime-neutral guides, so the session never writes one itself.
|
|
126
|
+
`scripts/flow.py` is the conductor. The session asks it `next`, and it answers with one line: `TEST`, `BUILD`, `REVIEW`, `ASK`, `DONE`, `STOP` or `HANDOFF`. It prints the full prompt for each subagent from runtime-neutral guides, so the session never writes one itself.
|
|
124
127
|
|
|
125
|
-
**What the script checks and what it trusts.** The conductor verifies the build from the repo: the ticket file must say `resolved`, the tree must be clean and committed, and it runs the gate and the floor guard itself. It also runs the `check` block under each ticket's Done when and compares the exit code and printed text, and for a `Test first: yes` ticket it proves the red test commit itself: it checks out the test-only commit, runs Test, and requires it to fail before the code. A failure of either goes back to the builder before any reviewer is started. It also checks that the reviewer changed no tracked file and made no commit. The review verdicts are different: each reviewer's reply
|
|
128
|
+
**What the script checks and what it trusts.** The conductor verifies the build from the repo: the ticket file must say `resolved`, the tree must be clean and committed, and it runs the gate and the floor guard itself. It also runs the `check` block under each ticket's Done when and compares the exit code and printed text (a check with a `needs <what>` line, such as `needs network`, that fails is deferred instead: the reviewer is told it is not met, and it goes to `followups.md`), and for a `Test first: yes` ticket it proves the red test commit itself: it checks out the test-only commit, runs Test, and requires it to fail before the code. A failure of either goes back to the builder before any reviewer is started. It also checks that the reviewer changed no tracked file and made no commit (an edit is put back and the review given to a fresh reviewer, see Read only roles below). The review verdicts are different: each reviewer's reply is relayed by the session, which saves it to a file and hands it to `flow.py verdict`. The script reads `REVIEW: PASS` or `REVIEW: FAIL` from that reply; it cannot prove the session passed it on unedited. A ticket with a `Level:` line moves on after one PASS verdict. A ticket with no level (a plan from before 0.9.0) needs two, a spec review and then a quality review, unless the conductor judged it small. The size is measured from the repo (`git diff` against the commit the ticket started from), never taken from the builder.
|
|
126
129
|
|
|
127
130
|
**The gate: full or quick.** The gate runs Build, Test and Lint after every ticket. With an optional `Quick:` line in `commands.md` (a faster subset of `Test`), it runs Build, Quick and Lint after the tickets in the middle of a plan, and the full Build, Test and Lint after the last ticket, before a handoff, and under `FLOW_GATE_FULL=1`. A plan without `Quick:` runs the full gate every time. The test-first proof still runs the full `Test` command.
|
|
128
131
|
|
|
@@ -131,12 +134,12 @@ The Claude Code skill is `skills/feature-flow/`. The Codex skill is written by h
|
|
|
131
134
|
| | Level 1 (light) | Level 2 (standard) | Level 3 (boundary) |
|
|
132
135
|
|---|---|---|---|
|
|
133
136
|
| For | tests, docs, prompt text, spikes, the acceptance ticket | ordinary feature code | auth, tokens, permissions, money and run limits, data loss, the flow's own code, anything a hostile caller reaches |
|
|
134
|
-
| Reviews | one combined review | one combined review, spec checklist first |
|
|
137
|
+
| Reviews | one combined review | one combined review, spec checklist first | one combined review that also probes every input as a hostile caller |
|
|
135
138
|
| Rework rounds | 1, then the run stops for you | 2; from round 3 only a `blocker` sends it back, majors go to `plans/<feature>/followups.md` and the ticket passes | `FLOW_MAX_REVIEW_ROUNDS` (3), then the run stops for you |
|
|
136
139
|
|
|
137
140
|
The gate does not depend on the level: it still runs Quick mid-plan and the full Test on the last ticket and before a handoff. Nobody but you can lower a level. The conductor reads `Level:` from the ticket as it was at the base commit, so a builder's edit does nothing (and the floor guard fails it). It raises the level from what it measures, never lowers it: `Review: full`, `Type: convert` and `Floor: allow flow-edit` make a ticket level 3, so does a diff that touches a path on the optional `Sensitive:` line of `commands.md` (frozen by the floor guard), and a level 1 diff over the small limits becomes level 2. A reviewer can raise it with a line `LEVEL: 3` above the verdict; a raise to 3 during a combined review adds a quality review. The log records `LEVEL-1`, `LEVEL-2` or `LEVEL-3` for each review round, and `feature-flow report` shows it.
|
|
138
141
|
|
|
139
|
-
**
|
|
142
|
+
**One review at level 3 too (0.23.0).** Before 0.23.0 a level 3 ticket got a spec review and then a separate quality review. In the first field run (two features, 19 separate spec reviews), every real catch came from the quality review: the spec review re-ran the Done when checks the conductor had already run and passed, and found nothing they had missed. So a level 3 ticket now gets one review, which does the spec checklist (marking bullets the conductor's check block covered as `MET (conductor)` instead of running them again) and then the quality review with the hostile caller probe. That saves a fresh reviewer per level 3 ticket. A reviewer that raises a ticket to level 3 in a combined review still adds a quality review after it, since it did not probe the change as level 3.
|
|
140
143
|
|
|
141
144
|
**One review for a small ticket (no level).** A ticket with no `Level:` line, from a plan written before 0.9.0, keeps the 0.8.0 rules. A ticket whose built diff is 3 files and 60 changed lines at most (the plan folder left out), and whose `check` block ran and passed, gets one combined review instead of the spec and quality reviews. The conductor measures the diff itself. `Review: full` in the ticket (as it was at the start), `Type: convert`, no `check` block, or `FLOW_GATE=off` keep both reviews. Every other conductor check still runs on every ticket.
|
|
142
145
|
|
|
@@ -154,8 +157,9 @@ The gate does not depend on the level: it still runs Quick mid-plan and the full
|
|
|
154
157
|
| `ticket-reviewer` | Read, Glob, Grep, Bash (no Edit, no Write) | Reviews one ticket by the review guide in its prompt and ends with `REVIEW: PASS` or `REVIEW: FAIL`. |
|
|
155
158
|
| `feature-planner` | Read, Glob, Grep, Bash, Write, Edit, WebSearch, WebFetch | Plans one feature from the approved brief by the plan guide, writes only the draft, cites outside sources, and ends with `PLAN: READY` or `PLAN: QUESTIONS`. |
|
|
156
159
|
| `plan-reviewer` | Read, Glob, Grep, Bash (no Edit, no Write) | Checks the draft against the brief by the plan review guide and ends with `PLAN-REVIEW: PASS` or `PLAN-REVIEW: FAIL`. |
|
|
160
|
+
| `flow-tester` | Read, Glob, Grep, Edit, Write, Bash | Writes the feature's acceptance tests from `spec.md` alone, before the build, by the test guide. Never reads the tickets. |
|
|
157
161
|
|
|
158
|
-
|
|
162
|
+
**Read only roles.** The reviewers, the consultants (`flow-architect`, `flow-designer`, `flow-po`) and `flow-scout` have no Edit or Write tool, and in Claude Code a `PreToolUse` hook in their role file blocks shell commands that change files or the repository: git commands that write (`commit`, `add`, `stash`, `checkout`, `reset` and the like), `sed -i`, `rm`, `mv`, `cp`, `touch`, `tee` and output redirected into a file other than `/dev/null` or `/tmp/`. The hook reads the command's text, so a program that writes files itself (a test runner updating snapshots, a script) still gets through, and Claude Code ignores hooks in a plugin's agents. A Codex subagent cannot be limited at all: Codex gives every child its parent's sandbox. So the conductor is the backstop everywhere: when a reviewer or consultant leaves a tracked file changed, it saves the change as `.feature-flow/state/edit-<feature>-<NN>.patch`, puts the files back, throws that answer away and hands the same review to a fresh reviewer, with a note saying why (`EDIT-UNDONE` in the log). A second edit in a row stops the run, and so does a commit, which it cannot undo safely. A planner's draft reaches `plans/` only through `plan-accept`. On Codex the planner can research the web only if web search is on; otherwise it plans from the code and says so. The Codex planning path has not been run by hand.
|
|
159
163
|
|
|
160
164
|
The guides in `guides/` (installed to `.feature-flow/guides/`) hold the protocol: how to build, review, write the brief, plan, review a plan and show. The skill holds only what differs per agent.
|
|
161
165
|
|
|
@@ -168,6 +172,7 @@ plans/
|
|
|
168
172
|
├── map.md destination, the bar, decisions so far (workers append only)
|
|
169
173
|
├── commands.md build, test, lint, smoke commands (frozen once approved)
|
|
170
174
|
├── learnings.md traps workers found (workers append only)
|
|
175
|
+
├── brainstorm.md the options weighed and the one picked (only after a brainstorm)
|
|
171
176
|
└── tasks/
|
|
172
177
|
├── 01-types.md
|
|
173
178
|
├── 02-service.md
|
|
@@ -263,7 +268,7 @@ Before a planner, builder or reviewer starts, the session can spawn cheap helper
|
|
|
263
268
|
| a level 1 ticket | none |
|
|
264
269
|
| a build below level 3 (first attempt) | one builder scout on the ticket and its `Touches:` |
|
|
265
270
|
| a level 3 build (first attempt) | two builder scouts: the code it changes, and what depends on it |
|
|
266
|
-
| a level 3 ticket's
|
|
271
|
+
| a level 3 ticket's first review | one reviewer scout on the conventions the diff must follow |
|
|
267
272
|
| the feature review (fast path) | one reviewer scout |
|
|
268
273
|
|
|
269
274
|
`scouts [lane]` lists `SCOUT <k> <agent> <reply file>` lines (or `NONE`) and clears the last ones' replies; `scout-prompt <k> [lane]` prints one scout's prompt. The session saves each reply into its file, and the phase's `prompt` adds them under `## Scout findings (unverified)`, cut to 60 lines each. A reply saved for one phase never reaches another. Retries and later rounds get no scouts. `FLOW_SCOUTS=off` turns them off.
|
|
@@ -278,12 +283,23 @@ A builder, reviewer or planner that hits a question it should not decide alone a
|
|
|
278
283
|
- **The planner** starts each open question with `architect:`, `designer:`, `po:` or `user:`. The session runs `consult-prompt <role> <question file>` for the first three, adds the answers to the brief under `Consulted:`, kept apart from your `Decided:` lines, and plans again.
|
|
279
284
|
- **What still comes to you.** Any question the asker marks `user`, any answer a consultant ends with `ANSWER: USER` (it changes what you get, so its options come to you), and a third consultant question on one ticket all stop the run with the question, written into the ticket under `## Ask: user`. You answer under `## Consulted (user)` at the end of the ticket, commit, and run `next`. A reviewer's question for you reopens the ticket, so its builder builds again with your answer.
|
|
280
285
|
|
|
286
|
+
## Acceptance tests (the tester)
|
|
287
|
+
|
|
288
|
+
A builder writes its own tests, so they tend to check what it built rather than what was asked. With an `Acceptance:` line in `commands.md` (the planner writes one for any feature a test can reach from outside), a separate tester writes the feature's acceptance tests before any of it is built, from the product owner's words alone.
|
|
289
|
+
|
|
290
|
+
- **Before the first ticket**, `next` hands out `TEST <plan folder> <sha>`. A fresh `flow-tester` reads `spec.md` (its bar, stories and acceptance criteria, edge cases and interfaces), `map.md`, `commands.md` and the existing code's conventions, never the tickets, and commits tests under `plans/<feature>/acceptance/` that only the `Acceptance:` command runs. The conductor then checks its work: the commits change nothing outside that folder, the gate still passes with the tests in place, and the tests fail now, since nothing is built yet (`TEST-WRITTEN` in the log). Otherwise a fresh tester gets the job again, with a note saying what was wrong. It has no lane, even when lanes run.
|
|
291
|
+
- **Builders cannot change them.** The tests sit inside the plan folder, so the floor guard fails any builder's change there (`acceptance-edit`), and no `Floor:` line allows it. A builder may run them to see where the feature stands.
|
|
292
|
+
- **Once every ticket is resolved**, the conductor runs the `Acceptance:` command itself (`ACCEPT-PASS` or `ACCEPT-FAIL`). A failure becomes a new ticket, `NN-acceptance-fixes-<round>.md`, with the failing output in it, built and reviewed like any other; then the tests run again. After `FLOW_MAX_REVIEW_ROUNDS` failed rounds the run stops for you. With the fast path, the tests run before the feature review.
|
|
293
|
+
- **A disputed test.** The tester can be wrong too, most often where the spec is vague. A fix ticket's builder that is sure a test asks for something `spec.md` does not say asks the product owner with `## Ask: po`. `flow-po` rules from `spec.md` alone with `RULING: TEST WRONG` or `RULING: CODE WRONG` (`RULING-TEST` or `RULING-CODE` in the log). The builder leaves a test ruled wrong failing and finishes the rest; once the ticket is resolved, a tester changes exactly the tests ruled wrong, as the rulings say, and the tests run again. The usual limit on questions holds, so a third one goes to you.
|
|
294
|
+
- **No `Acceptance:` line, no tester**: a plan written before 0.23.0 runs as before.
|
|
295
|
+
|
|
281
296
|
## The fast path
|
|
282
297
|
|
|
283
298
|
`/feature-flow <feature> fast` trades per-ticket reviews for speed. The planner gets `Pace: fast` in the brief and writes a short plan of fewer, larger tickets, and the plan reviewer is skipped. With `FLOW_FAST=1` on `start`, a ticket below level 3 (one with no `Level:` line too) that passes the gate, the floor guard and its Done when checks passes at once (`REVIEW-DEFERRED` in the log). With `FLOW_GATE=off` nothing would check it, so every ticket keeps its review. A level 3 ticket, or one that touches a `Sensitive:` path, still gets its own reviews.
|
|
284
299
|
|
|
285
300
|
- **The feature review.** Once every ticket is resolved, `next` hands out `REVIEW <plan folder> all <sha>`: one fresh reviewer reads the deferred tickets as they were planned and the whole diff from the oldest deferred ticket's base to HEAD, with `guides/review-feature.md`. It has no lane, even when lanes run.
|
|
286
301
|
- **A failed feature review** becomes a new ticket, `NN-feature-review-fixes-<round>.md`, with the findings in it. A builder fixes it, and the feature is reviewed again. After `FLOW_MAX_REVIEW_ROUNDS` failed rounds the run stops for you.
|
|
302
|
+
- **Batches.** In fast mode one builder takes up to 5 ready tickets at once (`BATCH <n>` in the log), when each is level 1 or 2, has a `Touches:` line, and touches nothing another ticket of the batch or a `Sensitive:` path touches. The `BUILD` line names the first ticket and the prompt lists the rest. The builder finishes them one at a time, each with its own commits. The conductor then checks each ticket on its own commits: the gate once at the end (and, if it fails there, at each ticket's last commit, to find the first one that broke it), then the floor guard, the footprint, Done when and test first with HEAD at that ticket's last commit. A ticket that passes is deferred to the feature review like any other. One that fails, or that the builder never finished, goes back to open with its findings and is built alone (`BATCH-FAIL`), never in a batch again. That saves a builder and its context for every ticket but the first. A mistake in one ticket can still carry into the later ones of the batch, which is why only small, separate tickets are batched. Lanes, `FLOW_RELAY` and `FLOW_GATE=off` turn batches off, and so does `FLOW_BATCH=1` (`FLOW_BATCH=<n>` sets the size, at most 5).
|
|
287
303
|
- **Mid-run.** `fast on` and `fast off` (through the runner, like `next`) switch it between phases. Asking the session to go faster runs `fast on`. Asking again while fast is on offers the re-plan below. Tickets already passed without a review still get the feature review, whichever way it is switched.
|
|
288
304
|
- **The cost.** A mistake in an early ticket is found at the end, when later tickets may have built on it. Use it for small or low-risk features. `reset` keeps the list of deferred tickets, so they still get the feature review.
|
|
289
305
|
|
|
@@ -299,7 +315,8 @@ A builder, reviewer or planner that hits a question it should not decide alone a
|
|
|
299
315
|
|
|
300
316
|
Every finished run can leave a record of what it cost and what it caught, so a trial on your own repo gives an answer, not an impression. On `DONE` the skill runs `python3 scripts/flow-status.py <feature> --eval` (or run `feature-flow eval <feature>` yourself) and asks you a few questions.
|
|
301
317
|
|
|
302
|
-
- **`plans/<feature>/eval.json`**: tickets, builds, reviews and rework; every catch by the check that made it (gate, floor guard, Done when, test first, footprint, reviewer, feature review); where the run needed
|
|
318
|
+
- **`plans/<feature>/eval.json`**: tickets, builds, reviews and rework; tickets settled when the plan was approved and never built; every catch by the check that made it (gate, floor guard, Done when, test first, footprint, reviewer, feature review); the follow-ups in `followups.md` and the deferred checks; who drove the run (`driver`: `person` or `agent`); where the run needed its driver (stops, questions, handoffs, resets); active minutes; and tokens.
|
|
319
|
+
- **`plans/<feature>/followups.md`**: what the run left for later, committed as it goes: the `minor` findings of every passing review, the findings a level 2 ticket passed with after its full rounds, and each `needs` check (below) that could not pass on this host.
|
|
303
320
|
- **Tokens** come from Claude Code's own session transcripts (`~/.claude/projects/`, or `CLAUDE_CONFIG_DIR`), never from the agent: every message of the sessions and subagents that worked in this repo during the run, each counted once, by model and, without lanes, split per ticket by time. Codex sessions are not read yet.
|
|
304
321
|
- **`plans/<feature>/eval-verdict.md`**: a form for you. Was the plan right, how many fixes you made by hand, would you use it again, and for each catch whether it was real or a false alarm. Run `--eval` again and your answers land in `eval.json`. The false-alarm count is the only way to tell whether the checks are worth their cost.
|
|
305
322
|
- **Later:** `feature-flow eval <feature> --later`, a week or two on, lists the commits since the run whose subject says fix, revert, bug or regression on the paths each ticket's `Touches:` names: the defects the run let through.
|
|
@@ -320,6 +337,14 @@ Pick one with `/feature-flow <feature> careful` (or `fast`), `FLOW_PROFILE=<name
|
|
|
320
337
|
|
|
321
338
|
The long `python3 -I -c ...` line the skill uses to call the conductor stays as it is: it is how the skill checks `flow-trust.py` against the sha256 it pins before running it, and a shorter wrapper would be one more file nothing checks. The session copies it from the skill; you never type it.
|
|
322
339
|
|
|
340
|
+
## Brainstorm before planning
|
|
341
|
+
|
|
342
|
+
When an idea is still fuzzy, the session can brainstorm it with you before it writes the brief: `/feature-flow <feature> brainstorm`, always in `careful`, and offered on its own when there is no bar yet or there are two real ways to build it. It asks you up to three questions, one at a time, sends a scout to see how the code does the nearest thing today, then lays out two or three options, each with a mermaid diagram, its pros and cons, its size and its risky areas, and recommends one. Your pick and the brief share one yes.
|
|
343
|
+
|
|
344
|
+
Six read only helpers work for the session during a brainstorm: a code scout, a web scout, the architect, designer and product owner, and `flow-skeptic`, who attacks each finished option so the session that wrote the options is not the one that judges them. Each gets its prompt from `brainstorm-prompt <helper> <question file>`, which counts them: `normal` allows 2 scouts, 1 web, 2 consultants and 1 skeptic per brainstorm, `careful` 3, 2, 3 and 1, and `FLOW_SCOUTS=off` no scouts. Helpers never write the brainstorm and never ask you anything; the session does both.
|
|
345
|
+
|
|
346
|
+
The result is `brainstorm.md` ([template](guides/templates/brainstorm.md)), committed with the plan. The planner follows its chosen option and copies its diagram into `spec.md`, the plan reviewer fails a plan that builds a rejected option or leaves a risky area below level 3, and a re-plan keeps the choice. It is skipped in `fast`, for an import, and with `auto`; with `agent`, the driving agent picks, the file says `Picked by: agent`, and the eval records it.
|
|
347
|
+
|
|
323
348
|
## Starting from Spec Kit or OpenSpec
|
|
324
349
|
|
|
325
350
|
If you already plan with [GitHub Spec Kit](https://github.com/github/spec-kit) or [OpenSpec](https://github.com/Fission-AI/OpenSpec), feature-flow can build what they planned:
|
|
@@ -346,6 +371,8 @@ A session's context fills up, so the flow moves to a fresh session every few tic
|
|
|
346
371
|
- **Resuming after a closed session.** If a session ended without `HANDOFF` (you closed it, it crashed, it ran out of budget), the feature is still owned by it, and a new session stops and says so. Once you are sure the old session is gone, answer yes when the new session asks, or start it with `FLOW_TAKEOVER=1`. With `auto` the skill never takes over on its own.
|
|
347
372
|
- **Stuck on a ticket.** `python3 scripts/flow.py <feature> reset` (or `feature-flow reset <feature>`) reopens a ticket left `claimed` or `in-progress`, commits that, and clears the conductor's run state, so the next `/feature-flow <feature>` starts clean from the ticket files. `reset <NN>` reopens that one ticket, even a resolved one, to build it again. While a session owns the feature it needs `FLOW_TAKEOVER=1`. A mistyped command or feature name gets a `did you mean` hint.
|
|
348
373
|
- **Relay mode.** `FLOW_RELAY=1` hands off after every build and every review, so each phase gets a session of its own.
|
|
374
|
+
- **When an agent drives.** An orchestrating agent (another Claude session driving the skill for you) has no context to refresh, so handoffs are pure overhead. `/feature-flow <feature> agent` runs `start` with `FLOW_DRIVER=agent`: no `HANDOFF` unless `FLOW_TICKETS_PER_SESSION` is set by hand, builders skip the "continue in a fresh session" line (they leave it out whenever the flow runs them), and the eval records that an agent drove the run, so its stops, handoffs and resets are not read as your time. `next` runs the gate and the checks before it answers, which can take minutes: a caller with a 2 minute tool timeout should give it 10 minutes or more, or run it in the background.
|
|
375
|
+
- **Argument mistakes say what to do.** `verdict` without its file, `--after-build` in the wrong place (the runner now accepts it anywhere), a `next` after a REVIEW with no `verdict` in between (it used to hand out the same review again; now it changes nothing and says to run `verdict` first), a digest from another feature (the runner says to pass `FLOW_TRUST=new` on a feature's first call), and a commit made between a review and its `next` (the stop says how to take it out and make it again later).
|
|
349
376
|
- **Nobody needs to watch.** With `auto` the skill asks nothing, and a Claude Code cloud session keeps working while you are away. You only come back to type the `HANDOFF` line.
|
|
350
377
|
|
|
351
378
|
The state lives in `.feature-flow/state/` (the state, a log of every step, and the last review reply). That folder ignores itself, so it never shows up in `git status`, and a normal Codex session can write it, which it cannot do under `.git`.
|
|
@@ -382,9 +409,11 @@ The commands in `commands.md` run through `bash -c` on Linux and macOS and throu
|
|
|
382
409
|
| `FLOW_PROFILE` | unset | `careful`, `normal` or `fast`: fills the settings in this table that are not set; a `Profile:` line in `commands.md` does the same |
|
|
383
410
|
| `FLOW_TICKETS_PER_SESSION` | `4` | tickets per session before `HANDOFF`; `0` never hands off |
|
|
384
411
|
| `FLOW_RELAY` | `0` | `1` hands off after every build and every review |
|
|
412
|
+
| `FLOW_DRIVER` | `person` | read by `start`: `agent` when another agent drives the run: no handoffs (unless `FLOW_TICKETS_PER_SESSION` is set), and the eval says so |
|
|
385
413
|
| `FLOW_LANES` | `1` | read by `start`: `2` to `4` builds tickets with disjoint `Touches:` side by side in worktrees (not with `FLOW_RELAY`) |
|
|
386
414
|
| `FLOW_FAST` | unset | read by `start`: `1` defers the reviews of tickets below level 3 to one feature review at the end, `0` turns it off; unset keeps the run's setting |
|
|
387
415
|
| `FLOW_BUDGET` | unset | read by `start`: minutes of active work before fast mode turns on, then a re-plan offer; `off` drops it |
|
|
416
|
+
| `FLOW_BATCH` | `5` | fast mode: most small tickets one builder takes at once; `1` turns batches off |
|
|
388
417
|
| `FLOW_SCOUTS` | `on` | `off` lists no scouts before any phase |
|
|
389
418
|
| `FLOW_TAKEOVER` | unset | `1` lets `start` take a feature over from a session that is gone |
|
|
390
419
|
| `FLOW_MAX_RETRIES` | `2` | builds or reviews per step before the run stops |
|
|
@@ -7,23 +7,23 @@ description: "Use to plan a feature (from the conversation so far, with a fresh
|
|
|
7
7
|
|
|
8
8
|
Plan or build the feature in `<arguments>`.
|
|
9
9
|
|
|
10
|
-
The first word is the **feature**. `show` means draw the graph. `auto` means ask nothing and go. `careful` means run `start` with `FLOW_PROFILE=careful` (the full gate and an own review for every ticket, shorter sessions); a `Profile:` line in `commands.md` does the same for the plan. `fast` means the fast path: run `start` with `FLOW_FAST=1`, and tickets below level 3 that pass their checks skip their own review until one review of the whole feature at the end (a level 3 or `Sensitive:` ticket keeps its reviews)
|
|
10
|
+
The first word is the **feature**. `show` means draw the graph. `brainstorm` means weigh ways to build it with the user, with diagrams, before the brief (`.feature-flow/guides/brainstorm.md`; the brief guide also offers it for a fuzzy idea). `auto` means ask nothing and go. `agent` means another agent, not a person, drives this session: it implies `auto`, and you run `start` with `FLOW_DRIVER=agent`, so the run never hands off and its eval says an agent drove it. `careful` means run `start` with `FLOW_PROFILE=careful` (the full gate and an own review for every ticket, shorter sessions); a `Profile:` line in `commands.md` does the same for the plan. `fast` means the fast path: run `start` with `FLOW_FAST=1`, and tickets below level 3 that pass their checks skip their own review until one review of the whole feature at the end (a level 3 or `Sensitive:` ticket keeps its reviews); a `BUILD` there may be a batch of small tickets, which you handle like any `BUILD`. When the user asks mid-run to go faster, run `fast on` (or `fast off`) through `flow-trust.py` between two other conductor commands; if it answers that fast is already on, offer the user the re-plan it names. A time budget (`FLOW_BUDGET=<minutes>` on `start`, `budget <minutes>|+<minutes>|off` mid-run) turns fast on by itself once spent, and later stops to offer a re-plan. A re-plan needs the user's own yes, even with `auto`: then run `replan-prompt` (between tickets), start the planner with it as in planning, with a new `task_name`, show the user its reply and `git diff --stat`, and on a second yes commit the plan folder as `plan(<feature>): re-plan the open tickets` (else `git checkout -- plans/<feature>`), then run `next`. If no feature was given and the conversation so far describes work to build, plan it (below) and propose the feature's name in the brief. If no feature was given otherwise, list `plans/*/` and ask which one.
|
|
11
11
|
|
|
12
12
|
The conductor is `python3 scripts/flow.py <feature> <command>`. If `scripts/flow.py` exists in the repo and the feature-flow package is beside it (`.feature-flow/feature_flow/`, or `feature_flow/` in a feature-flow checkout), use it (the repo's own install wins; an unrelated `scripts/flow.py` does not count); otherwise use `python3 "${FEATURE_FLOW_HOME:-$HOME/.feature-flow}/scripts/flow.py"` (`~/.feature-flow/scripts/flow.py`). Wherever this skill or a message names `scripts/flow.py`, `scripts/flow-status.py` or `scripts/flow-view.py`, it means the same folder, and the guides are then in that folder's sibling `guides/` (`~/.feature-flow/guides/`, else `.feature-flow/guides/` in the repo). Run the conductor with the working directory in the repo: state and plans stay there. It decides the order, runs the gate and the floor guard, and keeps its state in `.feature-flow/state/`, a folder git ignores. You ask it, and you do what it says. The guides it uses are in `.feature-flow/guides/` (in a feature-flow checkout, `guides/`). Read the project's `AGENTS.md` for its conventions.
|
|
13
13
|
|
|
14
14
|
## Calling the conductor
|
|
15
15
|
|
|
16
|
-
Every conductor command (`start`, `next`, `prompt`, `verdict`, `fast`, `scouts`, `scout-prompt`, `reset`, `plan-prompt`, `plan-review-prompt`, `plan-accept`, `plan-scouts`, `plan-scout-prompt`, `consult-prompt`, `budget`, `replan-prompt`) runs through `flow-trust.py`, never `flow.py` itself. `<S>` below is the folder of the `flow.py` picked above: `scripts` for the repo's own install, else `"${FEATURE_FLOW_HOME:-$HOME/.feature-flow}/scripts"`. `flow-trust.py` is started by this loader line, which checks the file against the sha256 pinned here and runs those same bytes. Copy it exactly, replacing only `<S>`:
|
|
16
|
+
Every conductor command (`start`, `next`, `prompt`, `verdict`, `fast`, `scouts`, `scout-prompt`, `reset`, `plan-prompt`, `plan-review-prompt`, `plan-accept`, `plan-scouts`, `plan-scout-prompt`, `consult-prompt`, `brainstorm-prompt`, `budget`, `replan-prompt`) runs through `flow-trust.py`, never `flow.py` itself. `<S>` below is the folder of the `flow.py` picked above: `scripts` for the repo's own install, else `"${FEATURE_FLOW_HOME:-$HOME/.feature-flow}/scripts"`. `flow-trust.py` is started by this loader line, which checks the file against the sha256 pinned here and runs those same bytes. Copy it exactly, replacing only `<S>`:
|
|
17
17
|
|
|
18
|
-
python3 -I -c "import hashlib,sys;b=open(sys.argv[1],'rb').read().replace(b'\r\n',b'\n');sys.exit(exec(compile(b,'flow-trust','exec')) if hashlib.sha256(b).hexdigest()==sys.argv[2] else 'flow-trust.py does not match this skill')" <S>/flow-trust.py
|
|
18
|
+
python3 -I -c "import hashlib,sys;b=open(sys.argv[1],'rb').read().replace(b'\r\n',b'\n');sys.exit(exec(compile(b,'flow-trust','exec')) if hashlib.sha256(b).hexdigest()==sys.argv[2] else 'flow-trust.py does not match this skill')" <S>/flow-trust.py adee71fa96b4233dd0177b43c372f717d3bd96ba566723cbf0e0e71a027d0664
|
|
19
19
|
|
|
20
20
|
A full conductor command, here `next` (any other command and its arguments go where `next` is):
|
|
21
21
|
|
|
22
|
-
FLOW_TRUST=<digest> FLOW_SESSION=<token> FLOW_INVOKE='$feature-flow' python3 -I -c "import hashlib,sys;b=open(sys.argv[1],'rb').read().replace(b'\r\n',b'\n');sys.exit(exec(compile(b,'flow-trust','exec')) if hashlib.sha256(b).hexdigest()==sys.argv[2] else 'flow-trust.py does not match this skill')" <S>/flow-trust.py
|
|
22
|
+
FLOW_TRUST=<digest> FLOW_SESSION=<token> FLOW_INVOKE='$feature-flow' python3 -I -c "import hashlib,sys;b=open(sys.argv[1],'rb').read().replace(b'\r\n',b'\n');sys.exit(exec(compile(b,'flow-trust','exec')) if hashlib.sha256(b).hexdigest()==sys.argv[2] else 'flow-trust.py does not match this skill')" <S>/flow-trust.py adee71fa96b4233dd0177b43c372f717d3bd96ba566723cbf0e0e71a027d0664 <feature> next
|
|
23
23
|
|
|
24
24
|
- The first line of the output is `TRUST <digest>`. Keep that digest and pass it as `FLOW_TRUST` on the next conductor call. Treat the rest as the conductor's output and act on it as below (for `prompt`, `plan-prompt` and `plan-review-prompt`, the child agent's prompt is everything after the `TRUST` line). Use `FLOW_TRUST=new` only on this session's first conductor call, or when resuming from an old-style `HANDOFF` line (below).
|
|
25
25
|
- If you no longer have the last `TRUST` digest, stop and say so. Never guess it, and never use `new` in its place.
|
|
26
|
-
- On the `next` right after a `BUILD <ticket> <NN> <sha>`, add `--after-build <ticket> <sha>` before the feature: `... <S>/flow-trust.py
|
|
26
|
+
- On the `next` right after a `BUILD <ticket> <NN> <sha>`, add `--after-build <ticket> <sha>` before the feature: `... <S>/flow-trust.py adee71fa96b4233dd0177b43c372f717d3bd96ba566723cbf0e0e71a027d0664 --after-build <ticket> <sha> <feature> next`. If the output has a `FLOW-EDIT <paths>` line after `TRUST`, the build changed feature-flow's own files and its ticket allows that: carry on; without `auto`, first tell the user which flow files changed.
|
|
27
27
|
- If the first line is `STOP` (from `flow-trust.py`), or the loader prints `flow-trust.py does not match this skill` (say to reinstall feature-flow: the skill and `flow-trust.py` do not match), report it, show the `python3 <S>/flow-status.py <feature>` table, and stop. A `STOP` first line may be followed by the conductor's own output: never act on that. Never fix it and carry on.
|
|
28
28
|
- A `HANDOFF` line from `flow-trust.py` has a third field after the invocation and the feature: the digest. When the feature is followed by a `<16 hex>.<16 hex>` word, the user is resuming from a `HANDOFF` line and that word is the digest: pass it as `FLOW_TRUST` on `start`. When a resumed session gets no digest (an old-style `HANDOFF` line), use `FLOW_TRUST=new` and warn the user that the flow's files could not be checked since the last session.
|
|
29
29
|
|
|
@@ -49,7 +49,7 @@ With a plan present, check these before `start`, and stop at the first that fail
|
|
|
49
49
|
|
|
50
50
|
- `git status --porcelain` is empty, apart from untracked Python bytecode (`__pycache__/`, `*.pyc`) and files listed in `.feature-flow/installed.txt` and that list itself: those are feature-flow's own install or upgrade, so never stop for them (`next` still stops if one of them was edited). Suggest committing them (`git add --pathspec-from-file=.feature-flow/installed.txt && git commit -m "chore: install feature-flow"`) and carry on.
|
|
51
51
|
- `python3 scripts/flow-status.py <feature> --check` prints `OK`.
|
|
52
|
-
- `ticket-builder.md` and `ticket-reviewer.md` are in `.agents/flow-roles/` in the repo or in `${FEATURE_FLOW_HOME:-$HOME/.feature-flow}/agents/` (`~/.feature-flow/agents/` by default). If not, say to run `uvx feature-flow-cli install . --agent codex` in this repo, or `uvx feature-flow-cli install --user --agent codex` (once for every repo) (or `python3 install.py <repo> --agent codex` from a feature-flow clone).
|
|
52
|
+
- `ticket-builder.md` and `ticket-reviewer.md` (and `flow-tester.md`, when the plan's `commands.md` has an `Acceptance:` line) are in `.agents/flow-roles/` in the repo or in `${FEATURE_FLOW_HOME:-$HOME/.feature-flow}/agents/` (`~/.feature-flow/agents/` by default). If not, say to run `uvx feature-flow-cli install . --agent codex` in this repo, or `uvx feature-flow-cli install --user --agent codex` (once for every repo) (or `python3 install.py <repo> --agent codex` from a feature-flow clone).
|
|
53
53
|
|
|
54
54
|
Then run `start` through `flow-trust.py` with `FLOW_INVOKE='$feature-flow'`. After the `TRUST` line it prints `OK <token>`. Keep the token and put `FLOW_SESSION=<token>` in front of **every** later conductor command, with `FLOW_INVOKE='$feature-flow'` and the last `FLOW_TRUST`. The conductor keeps its state in `.feature-flow/state/`, a git-ignored folder in the repo, so it never needs to write `.git`. If it prints `STOP cannot write the flow state`, tell the user this session must be allowed to write that folder.
|
|
55
55
|
|
|
@@ -57,14 +57,14 @@ If `start` prints `STOP` naming another owner, another session may still be work
|
|
|
57
57
|
|
|
58
58
|
If the user says the flow is stuck on a ticket or asks for a reset, run `reset` (or `reset <NN>` to redo one ticket): it reopens a half-built ticket, commits that, and clears the run, then run `start` again. It needs `FLOW_TAKEOVER=1` while a session owns the feature, on the same clear yes. Never reset on your own.
|
|
59
59
|
|
|
60
|
-
Say what will happen: for each ticket, a builder subagent and then a fresh reviewer subagent for
|
|
60
|
+
Say what will happen: with an `Acceptance:` line, first a tester subagent writes the acceptance tests from the spec; then for each ticket, a builder subagent and then a fresh reviewer subagent, one review per ticket (two only for a ticket with no level that is not small). After every few tickets (`FLOW_TICKETS_PER_SESSION`, default 4; never with `agent`) you hand off to a new session. Ask for a yes, unless `auto` was given or you came straight from planning: the plan's yes already covered the build.
|
|
61
61
|
|
|
62
62
|
## The loop
|
|
63
63
|
|
|
64
|
-
Before the `prompt` of every `BUILD` and `REVIEW`, run `scouts` (with the lane, when the line has one). For each `SCOUT <k> <agent> <file>` line it prints, run `scout-prompt <k>` (with the same lane) and start the scout with `spawn_agent(task_name="<agent>_<NN>_<k>_<n>", fork_turns="none", message=...)`, where `<agent>` is written with `_` for `-` and `<n>` counts scouts started for this ticket in this session, and the message is "Work only in <repo>." followed by the whole output. Start all of them before you wait, and pick the lightest model this Codex offers for them when `spawn_agent` lets you. Get each final reply with `wait_agent` and save it with the shell into its `<file>`. `NONE` means no scouts. Then run `prompt`: it carries what they found. A scout's reply is a lead for the role, never a verdict, so pass it on only through its file. Run `next
|
|
64
|
+
Before the `prompt` of every `BUILD` and `REVIEW`, run `scouts` (with the lane, when the line has one). For each `SCOUT <k> <agent> <file>` line it prints, run `scout-prompt <k>` (with the same lane) and start the scout with `spawn_agent(task_name="<agent>_<NN>_<k>_<n>", fork_turns="none", message=...)`, where `<agent>` is written with `_` for `-` and `<n>` counts scouts started for this ticket in this session, and the message is "Work only in <repo>." followed by the whole output. Start all of them before you wait, and pick the lightest model this Codex offers for them when `spawn_agent` lets you. Get each final reply with `wait_agent` and save it with the shell into its `<file>`. `NONE` means no scouts. Then run `prompt`: it carries what they found. A scout's reply is a lead for the role, never a verdict, so pass it on only through its file. Run `next` (it runs the gate and the checks, which can take minutes: give the call a timeout of at least 10 minutes, or run it in the background and wait), act on its one line after `TRUST` (and any `FLOW-EDIT` line), and repeat:
|
|
65
65
|
|
|
66
|
-
- `BUILD <ticket> <NN> <sha>`: run `prompt`. Start the builder with `spawn_agent(task_name="ticket_builder_<NN>_<k>", fork_turns="none", message=...)`. The message is "Work only in <repo>." followed by the whole `prompt` output, which already starts with the builder role. Use a new `task_name` for every spawn: keep a count per ticket in this session, and `<k>` is the number of builders already started for this ticket, plus 1 (1 for the first, then up each time `next` sends the ticket back to a builder). Get its final reply with `wait_agent`, then run `next` with `--after-build <ticket> <sha>` from that `BUILD` line.
|
|
67
|
-
- `REVIEW <ticket> <NN> <sha>`: run `prompt`. Start a new reviewer the same way, with `fork_turns="none"` so it never sees the builder's context, and a unique `task_name` per spawn: `ticket_reviewer_<NN>_<pass>_<k>`, where `<pass>` is `spec`, `quality` or `single` by the pass the prompt names (`(spec pass)`, `(quality pass)` or `(single pass)`; `review` if it names none) and `<k>` is the number of reviews already started for this ticket in this session, plus 1 (1 for the first). Count every review, also one that ended in `RETRY` or a failed review followed by a rebuild, so a repeated pass never reuses a name. Get its final reply with `wait_agent`. A child cannot be made read-only, so the reviewer works from its instructions; the conductor
|
|
66
|
+
- `BUILD <ticket> <NN> <sha>`: run `prompt`. Start the builder with `spawn_agent(task_name="ticket_builder_<NN>_<k>", fork_turns="none", message=...)`. The message is "Work only in <repo>." followed by the whole `prompt` output, which already starts with the builder role. Use a new `task_name` for every spawn: keep a count per ticket in this session, and `<k>` is the number of builders already started for this ticket, plus 1 (1 for the first, then up each time `next` sends the ticket back to a builder). Get its final reply with `wait_agent`, then run `next` with `--after-build <ticket> <sha>` from that `BUILD` line. `TEST <plan folder> <sha>`: the tester writes the acceptance tests from the spec, before the first build, or changes the ones the product owner ruled wrong. No scouts, and no lane word even when lanes run. Run `prompt` with no lane and start the tester with `spawn_agent(task_name="flow_tester_<k>", fork_turns="none", message=...)`, where `<k>` counts testers started in this session, plus 1, and the message is "Work only in <repo>." followed by the whole `prompt` output. Get its final reply with `wait_agent`, then run `next` (no `verdict`: the conductor judges the tests itself).
|
|
67
|
+
- `REVIEW <ticket> <NN> <sha>`: run `prompt`. Start a new reviewer the same way, with `fork_turns="none"` so it never sees the builder's context, and a unique `task_name` per spawn: `ticket_reviewer_<NN>_<pass>_<k>`, where `<pass>` is `spec`, `quality` or `single` by the pass the prompt names (`(spec pass)`, `(quality pass)` or `(single pass)`; `review` if it names none) and `<k>` is the number of reviews already started for this ticket in this session, plus 1 (1 for the first). Count every review, also one that ended in `RETRY` or a failed review followed by a rebuild, so a repeated pass never reuses a name. Get its final reply with `wait_agent`. A child cannot be made read-only, so the reviewer works from its instructions; the conductor puts back any edit it makes and hands the review out again. Save the whole reply with the shell: `cat > .feature-flow/state/flow-review-<feature>.txt <<'EOF'` ... `EOF`. Then run `verdict .feature-flow/state/flow-review-<feature>.txt` and `next`. If `verdict` prints `RETRY`, just run `next`. `REVIEW <plan folder> all <sha>` is the feature review of `fast`: it has no lane word even when lanes run, so run `prompt`, `verdict` and `next` with no lane, start a new reviewer with `task_name="ticket_reviewer_all_feature_<k>"` as for any review, and save its reply the same way. On a FAIL the conductor adds a fix ticket and reviews the feature again after it. `ASK <role> <ticket> <NN> <sha>` (role `architect`, `designer` or `po`) is a builder's or reviewer's question (on an acceptance fix ticket, the builder may dispute a tester's test, and the `po` rules on it): handle it as a `REVIEW`, scouts first, but start a `flow_<role>_<NN>_<k>` child the same way with the `prompt` output in place of the reviewer, and save its reply into `.feature-flow/state/flow-ask-<feature>.txt` for `verdict`.
|
|
68
68
|
- `DONE <summary>`: report it and suggest `$feature-flow <feature> show`. Then record the run: `python3 <S>/flow-status.py <feature> --eval` writes `plans/<feature>/eval.json` and the form `eval-verdict.md`. Unless `auto`, ask the user the form's questions (is the plan right, hand fixes, would they use it again, and real or false for each catch it lists), write their answers after the colons, and run `--eval` again. Commit both files as `docs(<feature>): eval` and nothing else.
|
|
69
69
|
- `STOP <reason>`: report the reason, run `python3 scripts/flow-status.py <feature>`, show the table, and stop.
|
|
70
70
|
- `HANDOFF <line>`: stop here. Tell the user to open a new session and type exactly `<line>`, the whole line with its digest at the end. The new session resumes where this one stopped.
|
{feature_flow_cli-0.18.0 → feature_flow_cli-0.23.0}/adapters/codex/feature-flow/agents/openai.yaml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "feature-flow"
|
|
3
3
|
short_description: "Plan a feature or build its tickets with a fresh builder and reviewer per ticket"
|
|
4
|
-
default_prompt: "Use $feature-flow [feature] [show] [auto] [fast]"
|
|
4
|
+
default_prompt: "Use $feature-flow [feature] [show] [auto|agent] [fast]"
|
|
5
5
|
policy:
|
|
6
6
|
allow_implicit_invocation: false
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow-architect
|
|
3
|
+
description: Answers one technical design question a builder, reviewer or planner raised mid-flow, from the spec and the code. Read only.
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Glob
|
|
7
|
+
- Grep
|
|
8
|
+
- Bash
|
|
9
|
+
model: inherit
|
|
10
|
+
hooks:
|
|
11
|
+
PreToolUse:
|
|
12
|
+
- matcher: Bash
|
|
13
|
+
hooks:
|
|
14
|
+
- type: command
|
|
15
|
+
command: |-
|
|
16
|
+
python3 -I -c '
|
|
17
|
+
import json, re, sys
|
|
18
|
+
cmd = json.load(sys.stdin).get("tool_input", {}).get("command", "")
|
|
19
|
+
bare = re.sub(r"\x27[^\x27]*\x27|\"(?:\\.|[^\"\\])*\"", "\"\"", cmd)
|
|
20
|
+
at = r"(?:^|[;&|(`\n]|\$\()\s*(?:\w+=\S*\s+|sudo\s+|env\s+|command\s+|xargs\s+(?:-\S+\s+)*)*"
|
|
21
|
+
rules = (
|
|
22
|
+
(at + r"(?:rm|rmdir|mv|cp|touch|mkdir|ln|chmod|chown|truncate|dd|tee|install|patch|unlink|shred)\b", "it changes files"),
|
|
23
|
+
(r"\b(?:sed|perl|ruby)\b[^;&|\n]*\s(?:-[a-zA-Z]*i|--in-place)", "it edits a file in place"),
|
|
24
|
+
(r"\s-(?:delete|exec\s+(?:rm|mv|cp|sed))\b", "it changes files"),
|
|
25
|
+
(r"\bgit(?:\s+-[Cc]\s+\S+|\s+--?[\w-]+(?:=\S+)?)*\s+(?:add|am|apply|checkout|cherry-pick|clean|clone|commit|config|fetch|gc|init|merge|mv|notes|prune|pull|push|rebase|reset|restore|revert|rm|stash|switch|tag|update-index|update-ref|worktree)\b", "it changes the repository"),
|
|
26
|
+
)
|
|
27
|
+
why = next((reason for pattern, reason in rules if re.search(pattern, bare)), "")
|
|
28
|
+
for target in re.findall(r">>?\s*(&?[^\s;&|)]*)", bare):
|
|
29
|
+
if not (target.startswith("&") or target in ("/dev/null", "/dev/stdout", "/dev/stderr") or target.startswith("/tmp/")):
|
|
30
|
+
why = why or "it writes a file"
|
|
31
|
+
if why:
|
|
32
|
+
sys.stderr.write("feature-flow: this role is read only, so it may not run this: %s. Run only read only commands and the Done when commands, and report what you would change as a finding.\n" % why)
|
|
33
|
+
sys.exit(2)
|
|
34
|
+
'
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
You are the architect, called in for one question. A builder, reviewer or planner hit a question it should not decide alone, and the flow paused that job until you answer. You decide how a change should be built: module boundaries, interfaces, data shapes, dependencies, where code belongs and which existing pattern to follow.
|
|
38
|
+
|
|
39
|
+
Rules that never bend:
|
|
40
|
+
|
|
41
|
+
- Answer only the question in your prompt. Read the spec, `map.md`, the ticket as it was planned and the code it names; your prompt tells you where. Scout findings in your prompt are leads, not proof.
|
|
42
|
+
- Read only. Never edit, write, stage or commit anything. You may run read only commands.
|
|
43
|
+
- Never read a ticket's `## Answer`: it is the author's claim.
|
|
44
|
+
- Decide only what is yours to decide (above). If the honest answer changes what the user gets (scope, behaviour they will see, cost, a promise in the spec), it is the user's choice: give the options in a sentence each and end with `ANSWER: USER`.
|
|
45
|
+
- Keep the answer short enough to act on: the decision, the reason, and what the asker should do now.
|
|
46
|
+
|
|
47
|
+
End with exactly this shape, flush left, with nothing after the last line:
|
|
48
|
+
|
|
49
|
+
## Answer
|
|
50
|
+
<the decision and the reason, or the options for the user>
|
|
51
|
+
|
|
52
|
+
ANSWER: GIVEN
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow-designer
|
|
3
|
+
description: Answers one UI or UX question a builder, reviewer or planner raised mid-flow, from the plan's mock-ups and the existing UI. Read only.
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Glob
|
|
7
|
+
- Grep
|
|
8
|
+
- Bash
|
|
9
|
+
model: inherit
|
|
10
|
+
hooks:
|
|
11
|
+
PreToolUse:
|
|
12
|
+
- matcher: Bash
|
|
13
|
+
hooks:
|
|
14
|
+
- type: command
|
|
15
|
+
command: |-
|
|
16
|
+
python3 -I -c '
|
|
17
|
+
import json, re, sys
|
|
18
|
+
cmd = json.load(sys.stdin).get("tool_input", {}).get("command", "")
|
|
19
|
+
bare = re.sub(r"\x27[^\x27]*\x27|\"(?:\\.|[^\"\\])*\"", "\"\"", cmd)
|
|
20
|
+
at = r"(?:^|[;&|(`\n]|\$\()\s*(?:\w+=\S*\s+|sudo\s+|env\s+|command\s+|xargs\s+(?:-\S+\s+)*)*"
|
|
21
|
+
rules = (
|
|
22
|
+
(at + r"(?:rm|rmdir|mv|cp|touch|mkdir|ln|chmod|chown|truncate|dd|tee|install|patch|unlink|shred)\b", "it changes files"),
|
|
23
|
+
(r"\b(?:sed|perl|ruby)\b[^;&|\n]*\s(?:-[a-zA-Z]*i|--in-place)", "it edits a file in place"),
|
|
24
|
+
(r"\s-(?:delete|exec\s+(?:rm|mv|cp|sed))\b", "it changes files"),
|
|
25
|
+
(r"\bgit(?:\s+-[Cc]\s+\S+|\s+--?[\w-]+(?:=\S+)?)*\s+(?:add|am|apply|checkout|cherry-pick|clean|clone|commit|config|fetch|gc|init|merge|mv|notes|prune|pull|push|rebase|reset|restore|revert|rm|stash|switch|tag|update-index|update-ref|worktree)\b", "it changes the repository"),
|
|
26
|
+
)
|
|
27
|
+
why = next((reason for pattern, reason in rules if re.search(pattern, bare)), "")
|
|
28
|
+
for target in re.findall(r">>?\s*(&?[^\s;&|)]*)", bare):
|
|
29
|
+
if not (target.startswith("&") or target in ("/dev/null", "/dev/stdout", "/dev/stderr") or target.startswith("/tmp/")):
|
|
30
|
+
why = why or "it writes a file"
|
|
31
|
+
if why:
|
|
32
|
+
sys.stderr.write("feature-flow: this role is read only, so it may not run this: %s. Run only read only commands and the Done when commands, and report what you would change as a finding.\n" % why)
|
|
33
|
+
sys.exit(2)
|
|
34
|
+
'
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
You are the designer, called in for one question. A builder, reviewer or planner hit a question it should not decide alone, and the flow paused that job until you answer. You decide how something should look and behave for its user: layout, wording, states (empty, loading, error), interaction and accessibility, within the plan's mock-ups and the existing UI.
|
|
38
|
+
|
|
39
|
+
Rules that never bend:
|
|
40
|
+
|
|
41
|
+
- Answer only the question in your prompt. Read the spec, `map.md`, the ticket as it was planned and the code it names; your prompt tells you where. Scout findings in your prompt are leads, not proof.
|
|
42
|
+
- Read only. Never edit, write, stage or commit anything. You may run read only commands.
|
|
43
|
+
- Never read a ticket's `## Answer`: it is the author's claim.
|
|
44
|
+
- Decide only what is yours to decide (above). If the honest answer changes what the user gets (scope, behaviour they will see, cost, a promise in the spec), it is the user's choice: give the options in a sentence each and end with `ANSWER: USER`.
|
|
45
|
+
- Keep the answer short enough to act on: the decision, the reason, and what the asker should do now.
|
|
46
|
+
|
|
47
|
+
End with exactly this shape, flush left, with nothing after the last line:
|
|
48
|
+
|
|
49
|
+
## Answer
|
|
50
|
+
<the decision and the reason, or the options for the user>
|
|
51
|
+
|
|
52
|
+
ANSWER: GIVEN
|