feature-flow-cli 0.14.0__tar.gz → 0.18.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.
Files changed (78) hide show
  1. {feature_flow_cli-0.14.0/feature_flow_cli.egg-info → feature_flow_cli-0.18.0}/PKG-INFO +57 -2
  2. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/README.md +56 -1
  3. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/adapters/codex/feature-flow/SKILL.md +3 -3
  4. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/__init__.py +1 -1
  5. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/command.py +10 -2
  6. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/conductor.py +8 -1
  7. feature_flow_cli-0.18.0/feature_flow/evaluate.py +378 -0
  8. feature_flow_cli-0.18.0/feature_flow/importer.py +222 -0
  9. feature_flow_cli-0.18.0/feature_flow/profiles.py +43 -0
  10. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/report.py +1 -1
  11. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/state.py +1 -1
  12. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/status.py +8 -2
  13. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0/feature_flow_cli.egg-info}/PKG-INFO +57 -2
  14. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow_cli.egg-info/SOURCES.txt +3 -0
  15. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/templates/commands.md +3 -1
  16. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/skills/feature-flow/SKILL.md +6 -6
  17. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/LICENSE +0 -0
  18. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/MANIFEST.in +0 -0
  19. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/adapters/codex/feature-flow/agents/openai.yaml +0 -0
  20. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/feature-planner.md +0 -0
  21. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/flow-architect.md +0 -0
  22. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/flow-designer.md +0 -0
  23. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/flow-po.md +0 -0
  24. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/flow-scout.md +0 -0
  25. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/flow-web.md +0 -0
  26. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/plan-reviewer.md +0 -0
  27. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/ticket-builder.md +0 -0
  28. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/agents/ticket-reviewer.md +0 -0
  29. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/__main__.py +0 -0
  30. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/checks.py +0 -0
  31. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/cli.py +0 -0
  32. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/codehash.py +0 -0
  33. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/floorguard.py +0 -0
  34. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/gate.py +0 -0
  35. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/git.py +0 -0
  36. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/install.py +0 -0
  37. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/lanes.py +0 -0
  38. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/proc.py +0 -0
  39. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/prompts.py +0 -0
  40. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/proof.py +0 -0
  41. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/released.py +0 -0
  42. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/scouts.py +0 -0
  43. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/suggest.py +0 -0
  44. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/tickets.py +0 -0
  45. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/uninstall.py +0 -0
  46. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow/view.py +0 -0
  47. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow_cli.egg-info/dependency_links.txt +0 -0
  48. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow_cli.egg-info/entry_points.txt +0 -0
  49. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/feature_flow_cli.egg-info/top_level.txt +0 -0
  50. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/brief.md +0 -0
  51. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/build.md +0 -0
  52. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/debug.md +0 -0
  53. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/plan-review.md +0 -0
  54. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/plan.md +0 -0
  55. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/replan.md +0 -0
  56. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/review-feature.md +0 -0
  57. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/review-quality.md +0 -0
  58. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/review-single.md +0 -0
  59. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/review.md +0 -0
  60. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/show.md +0 -0
  61. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/templates/learnings.md +0 -0
  62. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/templates/map.md +0 -0
  63. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/templates/spec.md +0 -0
  64. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/templates/ticket.md +0 -0
  65. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/guides/templates/ui-mockup.md +0 -0
  66. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/install.py +0 -0
  67. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/install.sh +0 -0
  68. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/pyproject.toml +0 -0
  69. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/floor-guard.py +0 -0
  70. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/flow-status.py +0 -0
  71. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/flow-trust.py +0 -0
  72. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/flow-view.html +0 -0
  73. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/flow-view.py +0 -0
  74. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/flow.py +0 -0
  75. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/scripts/gate.py +0 -0
  76. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/setup.cfg +0 -0
  77. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.0}/skills/architect-review/SKILL.md +0 -0
  78. {feature_flow_cli-0.14.0 → feature_flow_cli-0.18.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.14.0
3
+ Version: 0.18.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
@@ -45,13 +45,22 @@ python3 install.py /path/to/your/repo --agent all # both, side by side
45
45
  # `bash install.sh ...` still works on Linux and macOS: it only runs install.py
46
46
  ```
47
47
 
48
+ As a Claude Code plugin, with nothing written into your repo (this repo is its own marketplace):
49
+
50
+ ```
51
+ /plugin marketplace add hamilton-sky/feature-flow
52
+ /plugin install feature-flow@feature-flow
53
+ ```
54
+
55
+ The plugin carries the skills, the roles (named `feature-flow:ticket-builder` and so on), the conductor, the scripts and the guides, and the skill runs the conductor from the plugin's folder. A repo with its own install still uses that one. Claude Code cloud sessions (claude.ai/code) do not install plugins, so for them install into the repo and commit `.claude/`, `scripts/` and `.feature-flow/` as below. The plugin path is new and has not had a real run yet.
56
+
48
57
  Without a clone, the same installer runs from [PyPI](https://pypi.org/project/feature-flow-cli/):
49
58
 
50
59
  ```bash
51
60
  uvx feature-flow-cli install /path/to/your/repo --agent all # or: pipx run feature-flow-cli install ...
52
61
  ```
53
62
 
54
- The package puts a `feature-flow` command on your PATH with `install`, `uninstall`, `status <feature>`, `view <feature>`, `reset <feature>` and `report <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
63
+ The package puts a `feature-flow` command on your PATH with `install`, `uninstall`, `status <feature>`, `view <feature>`, `reset <feature>`, `report <feature>` and `eval <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
55
64
 
56
65
  The installer lists what it wrote in `.feature-flow/installed.txt`, with each file's hash in `.feature-flow/installed.sha256`. Commit those files (`git add --pathspec-from-file=.feature-flow/installed.txt`); until you do, the flow does not count them as uncommitted changes. Installing a newer version over an older one updates every file nobody edited since it was installed, and keeps (and names) the ones you changed; `--force` replaces those too.
57
66
 
@@ -305,6 +314,49 @@ A builder, reviewer or planner that hits a question it should not decide alone a
305
314
  - **Still over, a re-plan offer.** Once fast mode has finished a ticket and the run is still over (or at once, if fast mode was already on), the run stops once with the minutes spent, the tickets left, and an offer to re-plan. If one ticket took more than half the time over several attempts, the stop names it as stuck, since that is a stuck ticket, not a slow plan. `next` goes on as planned, and a new `budget` earns a new offer.
306
315
  - **The re-plan needs your yes.** On your yes, between tickets, `replan-prompt` hands the `feature-planner` the open tickets with `guides/replan.md`. It folds them into fewer, larger tickets with the same bar: every Done when item and check moves into the ticket that takes over, folded tickets become `Status: parked (folded into NN)`, and resolved tickets stay as they are. The session shows you the change and commits it only on a second yes. The next `next` stops if the re-plan changed a resolved ticket. Nothing is ever cut without you.
307
316
 
317
+ ## Recording a run (eval)
318
+
319
+ 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
+
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 you (stops, questions, handoffs, resets); active minutes; and tokens.
322
+ - **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
+ - **`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
+ - **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.
325
+
326
+ Both files sit in the plan folder, so they are committed with it and survive a cloud session. Nothing is sent anywhere; attach `eval.json` to a field-run issue if you want to share it. Run logs from before 0.15.0 have no dates, so they give no tokens.
327
+
328
+ ## Profiles
329
+
330
+ Most settings below never need touching. One word picks a sensible set:
331
+
332
+ | Profile | Sets | For |
333
+ |---|---|---|
334
+ | `careful` | `FLOW_GATE_FULL=1`, `FLOW_FAST=0`, `FLOW_SMALL_LINES=0`, `FLOW_TICKETS_PER_SESSION=3` | code where a wrong "done" is expensive: the full gate and an own review for every ticket |
335
+ | `normal` | nothing: the defaults | everyday features |
336
+ | `fast` | `FLOW_FAST=1`, `FLOW_SCOUTS=off`, `FLOW_TICKETS_PER_SESSION=6` | small, low-risk features: one feature review at the end |
337
+
338
+ Pick one with `/feature-flow <feature> careful` (or `fast`), `FLOW_PROFILE=<name>` on `start`, or a `Profile:` line in the plan's `commands.md`, approved with the plan. A profile fills only settings you did not set: `FLOW_PROFILE=fast FLOW_SCOUTS=on` keeps the scouts. The log records `PROFILE-<NAME>` at the start. A level 3 or `Sensitive:` ticket keeps its own reviews in every profile.
339
+
340
+ 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
+
342
+ ## Starting from Spec Kit or OpenSpec
343
+
344
+ 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:
345
+
346
+ ```bash
347
+ feature-flow import specs/001-photo-albums albums # a Spec Kit feature folder (or its tasks.md)
348
+ feature-flow import openspec/changes/add-auth auth # an OpenSpec change folder
349
+ python3 scripts/flow-status.py albums --import specs/001-photo-albums # the same, from a repo install
350
+ ```
351
+
352
+ Or ask the session to plan `albums` from `specs/001-photo-albums`. Either way it writes `plans/<feature>/`, never over an existing plan (`--dry-run` shows what it would write):
353
+
354
+ - **One ticket per phase or section**, its tasks as the Done when items, so thirty small tasks become five tickets with real reviews, not thirty.
355
+ - **Order:** each section waits for the one before. Spec Kit's user story phases (`[US1]`, `[US2]`) wait only for the phases before the first story, so with lanes they are built side by side, and the polish phase waits for every story.
356
+ - **Touches:** the paths the tasks name, when every task in the section names one.
357
+ - **spec.md** carries the source's `spec.md` and `plan.md` (Spec Kit) or `proposal.md` and `design.md` (OpenSpec).
358
+ - **What you add:** the commands (`commands.md` is the template), a `check` block per ticket and the levels. `flow-status.py <feature> --lint` says what is missing. The skill does this with you, then asks for a yes before it commits the plan.
359
+
308
360
  ## Long features and handoff
309
361
 
310
362
  A session's context fills up, so the flow moves to a fresh session every few tickets. After `FLOW_TICKETS_PER_SESSION` tickets (default 4) pass review, `next` prints a `HANDOFF` line instead of the next ticket, for example `HANDOFF /feature-flow csv-export 3f9c0a1b2c3d4e5f.0a1b2c3d4e5f6a7b` (the last word is the runner's digest, which lets the new session check that the flow's files did not change in between). The session stops and tells you to open a new session and type that line. The new session picks up exactly where the last one stopped. Set `FLOW_TICKETS_PER_SESSION=0` to never hand off.
@@ -329,6 +381,8 @@ python3 scripts/flow-status.py <feature> --counts one line of counts
329
381
  python3 scripts/flow-status.py <feature> --check cycles, missing blockers, missing Done when, unordered mentions
330
382
  python3 scripts/flow-status.py <feature> --lint --check plus: a check block (or `Check: none <why>`) on every ticket, a Test command
331
383
  feature-flow report <feature> what a run did, from its log: builds, reviews, failed checks, stops
384
+ feature-flow import <spec-kit or openspec folder> <feature> start plans/<feature>/ from their task list
385
+ feature-flow eval <feature> [--later] record the run in plans/<feature>/eval.json, with your verdict (also: flow-status.py <feature> --eval)
332
386
  python3 scripts/flow-status.py <feature> --mermaid the ticket graph, coloured by status (add "plain" for none)
333
387
  python3 scripts/flow-status.py <feature> --json every ticket with status, blockers and readiness
334
388
  python3 scripts/flow-view.py <feature> [--watch] the animated graph page, opened in your browser
@@ -344,6 +398,7 @@ The commands in `commands.md` run through `bash -c` on Linux and macOS and throu
344
398
 
345
399
  | Variable | Default | Meaning |
346
400
  |---|---|---|
401
+ | `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 |
347
402
  | `FLOW_TICKETS_PER_SESSION` | `4` | tickets per session before `HANDOFF`; `0` never hands off |
348
403
  | `FLOW_RELAY` | `0` | `1` hands off after every build and every review |
349
404
  | `FLOW_LANES` | `1` | read by `start`: `2` to `4` builds tickets with disjoint `Touches:` side by side in worktrees (not with `FLOW_RELAY`) |
@@ -26,13 +26,22 @@ python3 install.py /path/to/your/repo --agent all # both, side by side
26
26
  # `bash install.sh ...` still works on Linux and macOS: it only runs install.py
27
27
  ```
28
28
 
29
+ As a Claude Code plugin, with nothing written into your repo (this repo is its own marketplace):
30
+
31
+ ```
32
+ /plugin marketplace add hamilton-sky/feature-flow
33
+ /plugin install feature-flow@feature-flow
34
+ ```
35
+
36
+ The plugin carries the skills, the roles (named `feature-flow:ticket-builder` and so on), the conductor, the scripts and the guides, and the skill runs the conductor from the plugin's folder. A repo with its own install still uses that one. Claude Code cloud sessions (claude.ai/code) do not install plugins, so for them install into the repo and commit `.claude/`, `scripts/` and `.feature-flow/` as below. The plugin path is new and has not had a real run yet.
37
+
29
38
  Without a clone, the same installer runs from [PyPI](https://pypi.org/project/feature-flow-cli/):
30
39
 
31
40
  ```bash
32
41
  uvx feature-flow-cli install /path/to/your/repo --agent all # or: pipx run feature-flow-cli install ...
33
42
  ```
34
43
 
35
- The package puts a `feature-flow` command on your PATH with `install`, `uninstall`, `status <feature>`, `view <feature>`, `reset <feature>` and `report <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
44
+ The package puts a `feature-flow` command on your PATH with `install`, `uninstall`, `status <feature>`, `view <feature>`, `reset <feature>`, `report <feature>` and `eval <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
36
45
 
37
46
  The installer lists what it wrote in `.feature-flow/installed.txt`, with each file's hash in `.feature-flow/installed.sha256`. Commit those files (`git add --pathspec-from-file=.feature-flow/installed.txt`); until you do, the flow does not count them as uncommitted changes. Installing a newer version over an older one updates every file nobody edited since it was installed, and keeps (and names) the ones you changed; `--force` replaces those too.
38
47
 
@@ -286,6 +295,49 @@ A builder, reviewer or planner that hits a question it should not decide alone a
286
295
  - **Still over, a re-plan offer.** Once fast mode has finished a ticket and the run is still over (or at once, if fast mode was already on), the run stops once with the minutes spent, the tickets left, and an offer to re-plan. If one ticket took more than half the time over several attempts, the stop names it as stuck, since that is a stuck ticket, not a slow plan. `next` goes on as planned, and a new `budget` earns a new offer.
287
296
  - **The re-plan needs your yes.** On your yes, between tickets, `replan-prompt` hands the `feature-planner` the open tickets with `guides/replan.md`. It folds them into fewer, larger tickets with the same bar: every Done when item and check moves into the ticket that takes over, folded tickets become `Status: parked (folded into NN)`, and resolved tickets stay as they are. The session shows you the change and commits it only on a second yes. The next `next` stops if the re-plan changed a resolved ticket. Nothing is ever cut without you.
288
297
 
298
+ ## Recording a run (eval)
299
+
300
+ 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
+
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 you (stops, questions, handoffs, resets); active minutes; and tokens.
303
+ - **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
+ - **`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
+ - **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.
306
+
307
+ Both files sit in the plan folder, so they are committed with it and survive a cloud session. Nothing is sent anywhere; attach `eval.json` to a field-run issue if you want to share it. Run logs from before 0.15.0 have no dates, so they give no tokens.
308
+
309
+ ## Profiles
310
+
311
+ Most settings below never need touching. One word picks a sensible set:
312
+
313
+ | Profile | Sets | For |
314
+ |---|---|---|
315
+ | `careful` | `FLOW_GATE_FULL=1`, `FLOW_FAST=0`, `FLOW_SMALL_LINES=0`, `FLOW_TICKETS_PER_SESSION=3` | code where a wrong "done" is expensive: the full gate and an own review for every ticket |
316
+ | `normal` | nothing: the defaults | everyday features |
317
+ | `fast` | `FLOW_FAST=1`, `FLOW_SCOUTS=off`, `FLOW_TICKETS_PER_SESSION=6` | small, low-risk features: one feature review at the end |
318
+
319
+ Pick one with `/feature-flow <feature> careful` (or `fast`), `FLOW_PROFILE=<name>` on `start`, or a `Profile:` line in the plan's `commands.md`, approved with the plan. A profile fills only settings you did not set: `FLOW_PROFILE=fast FLOW_SCOUTS=on` keeps the scouts. The log records `PROFILE-<NAME>` at the start. A level 3 or `Sensitive:` ticket keeps its own reviews in every profile.
320
+
321
+ 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
+
323
+ ## Starting from Spec Kit or OpenSpec
324
+
325
+ 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:
326
+
327
+ ```bash
328
+ feature-flow import specs/001-photo-albums albums # a Spec Kit feature folder (or its tasks.md)
329
+ feature-flow import openspec/changes/add-auth auth # an OpenSpec change folder
330
+ python3 scripts/flow-status.py albums --import specs/001-photo-albums # the same, from a repo install
331
+ ```
332
+
333
+ Or ask the session to plan `albums` from `specs/001-photo-albums`. Either way it writes `plans/<feature>/`, never over an existing plan (`--dry-run` shows what it would write):
334
+
335
+ - **One ticket per phase or section**, its tasks as the Done when items, so thirty small tasks become five tickets with real reviews, not thirty.
336
+ - **Order:** each section waits for the one before. Spec Kit's user story phases (`[US1]`, `[US2]`) wait only for the phases before the first story, so with lanes they are built side by side, and the polish phase waits for every story.
337
+ - **Touches:** the paths the tasks name, when every task in the section names one.
338
+ - **spec.md** carries the source's `spec.md` and `plan.md` (Spec Kit) or `proposal.md` and `design.md` (OpenSpec).
339
+ - **What you add:** the commands (`commands.md` is the template), a `check` block per ticket and the levels. `flow-status.py <feature> --lint` says what is missing. The skill does this with you, then asks for a yes before it commits the plan.
340
+
289
341
  ## Long features and handoff
290
342
 
291
343
  A session's context fills up, so the flow moves to a fresh session every few tickets. After `FLOW_TICKETS_PER_SESSION` tickets (default 4) pass review, `next` prints a `HANDOFF` line instead of the next ticket, for example `HANDOFF /feature-flow csv-export 3f9c0a1b2c3d4e5f.0a1b2c3d4e5f6a7b` (the last word is the runner's digest, which lets the new session check that the flow's files did not change in between). The session stops and tells you to open a new session and type that line. The new session picks up exactly where the last one stopped. Set `FLOW_TICKETS_PER_SESSION=0` to never hand off.
@@ -310,6 +362,8 @@ python3 scripts/flow-status.py <feature> --counts one line of counts
310
362
  python3 scripts/flow-status.py <feature> --check cycles, missing blockers, missing Done when, unordered mentions
311
363
  python3 scripts/flow-status.py <feature> --lint --check plus: a check block (or `Check: none <why>`) on every ticket, a Test command
312
364
  feature-flow report <feature> what a run did, from its log: builds, reviews, failed checks, stops
365
+ feature-flow import <spec-kit or openspec folder> <feature> start plans/<feature>/ from their task list
366
+ feature-flow eval <feature> [--later] record the run in plans/<feature>/eval.json, with your verdict (also: flow-status.py <feature> --eval)
313
367
  python3 scripts/flow-status.py <feature> --mermaid the ticket graph, coloured by status (add "plain" for none)
314
368
  python3 scripts/flow-status.py <feature> --json every ticket with status, blockers and readiness
315
369
  python3 scripts/flow-view.py <feature> [--watch] the animated graph page, opened in your browser
@@ -325,6 +379,7 @@ The commands in `commands.md` run through `bash -c` on Linux and macOS and throu
325
379
 
326
380
  | Variable | Default | Meaning |
327
381
  |---|---|---|
382
+ | `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 |
328
383
  | `FLOW_TICKETS_PER_SESSION` | `4` | tickets per session before `HANDOFF`; `0` never hands off |
329
384
  | `FLOW_RELAY` | `0` | `1` hands off after every build and every review |
330
385
  | `FLOW_LANES` | `1` | read by `start`: `2` to `4` builds tickets with disjoint `Touches:` side by side in worktrees (not with `FLOW_RELAY`) |
@@ -7,7 +7,7 @@ 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. `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). 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.
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). 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
 
@@ -41,7 +41,7 @@ When `plans/<feature>/` does not exist, or you are planning from the conversatio
41
41
 
42
42
  Then run `python3 scripts/flow-status.py <feature> --check` and list the files `plan-accept` wrote. The second yes also approves committing the plan, so commit the folder `plan-accept` printed (`OK <folder>`, `plans/<feature>` unless `FLOW_DIR` is set) and nothing else: `git add -- <folder> && git commit -m "docs(<feature>): plan" -- <folder>`. If the commit fails, report why and stop. Then go straight on to building it below, unless the user asked to stop after planning.
43
43
 
44
- To add tickets to a plan that exists, edit it by hand following the ticket rules in `.feature-flow/guides/plan.md`.
44
+ To add tickets to a plan that exists, edit it by hand following the ticket rules in `.feature-flow/guides/plan.md`. When the user points at a Spec Kit (`specs/<NNN-name>/`) or OpenSpec (`openspec/changes/<id>/`) task list, start the plan from it instead of the planner: `python3 <S>/flow-status.py <feature> --import <that folder or its tasks.md>` writes `plans/<feature>/` with one ticket per phase or section. Then, with the user, fill in `commands.md` from the project's own config, add a `check` block under each ticket's Done when and set its level, run `flow-status.py <feature> --lint` until it is clean, show the graph, and on the user's yes commit the folder as `docs(<feature>): plan` and build it.
45
45
 
46
46
  ## Before building
47
47
 
@@ -65,7 +65,7 @@ Before the `prompt` of every `BUILD` and `REVIEW`, run `scouts` (with the lane,
65
65
 
66
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
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 catches any edit it makes. 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: 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
- - `DONE <summary>`: report it and suggest `$feature-flow <feature> show`.
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.
71
71
 
@@ -1,3 +1,3 @@
1
1
  """Feature Flow: a ticket-graph workflow for coding agents."""
2
2
 
3
- __version__ = "0.14.0"
3
+ __version__ = "0.18.0"
@@ -9,7 +9,7 @@ import sys
9
9
 
10
10
  from pathlib import Path
11
11
 
12
- from feature_flow import __version__, cli, install, report, status, suggest, uninstall, view
12
+ from feature_flow import __version__, cli, install, evaluate, importer, report, status, suggest, uninstall, view
13
13
 
14
14
  USAGE = """\
15
15
  usage: feature-flow install [target-repo] [--agent claude|codex|all] [--user] [--private] [--force] [--dry-run]
@@ -18,16 +18,20 @@ usage: feature-flow install [target-repo] [--agent claude|codex|all] [--user] [-
18
18
  feature-flow view <feature> [--watch] [--no-open] [--out FILE]
19
19
  feature-flow reset <feature> [NN]
20
20
  feature-flow report <feature>
21
+ feature-flow eval <feature> [--later] [--out DIR] [--claude-home DIR]
22
+ feature-flow import <spec-kit or openspec folder, or its tasks.md> <feature> [--dry-run]
21
23
  feature-flow --version
22
24
  install copies the skill, its roles, scripts and guides into a repo; --user installs them once for every repo, in ~/.claude, ~/.agents and ~/.feature-flow, and writes nothing into a repo. feature-flow install --help says more.
23
25
  uninstall removes exactly what install wrote (files you edited are kept); --user removes the personal install in ~/.claude, ~/.agents and ~/.feature-flow.
24
26
  status and view read plans/<feature>/ in the current directory, like scripts/flow-status.py and scripts/flow-view.py.
25
27
  reset reopens a half-built ticket (or ticket NN), commits that, and clears the run, like scripts/flow.py <feature> reset.
26
28
  report prints what a run did (builds, reviews, failed checks, stops) from its log in .feature-flow/state/. Read-only.
29
+ given a Spec Kit or OpenSpec task list, `import` starts plans/<feature>/ with one ticket per phase or section.
30
+ eval records a field run in plans/<feature>/eval.json: cost, tokens, what each check caught, where it needed you, and your verdict from eval-verdict.md.
27
31
  """
28
32
 
29
33
 
30
- COMMANDS = ("install", "uninstall", "status", "view", "reset", "report", "--version", "--help")
34
+ COMMANDS = ("install", "uninstall", "status", "view", "reset", "report", "eval", "import", "--version", "--help")
31
35
 
32
36
 
33
37
  def main(argv=None):
@@ -50,6 +54,10 @@ def main(argv=None):
50
54
  return view.main(rest, here=os.path.join(install.source_root(), "scripts"))
51
55
  if command == "report":
52
56
  return report.main(rest)
57
+ if command == "eval":
58
+ return evaluate.main(rest)
59
+ if command == "import":
60
+ return importer.main(rest)
53
61
  if command == "reset":
54
62
  if not rest or len(rest) > 2:
55
63
  sys.stderr.write(USAGE)
@@ -14,7 +14,7 @@ import shutil
14
14
  import time
15
15
  from pathlib import Path
16
16
 
17
- from feature_flow import checks, codehash, floorguard, gate, git, lanes, prompts, proof, scouts, state, suggest, tickets
17
+ from feature_flow import checks, codehash, floorguard, gate, git, lanes, profiles, prompts, proof, scouts, state, suggest, tickets
18
18
 
19
19
 
20
20
  NOTE_SEP = "\t" # the state file keeps one line per key, so the review notes are tab separated
@@ -94,6 +94,11 @@ class Conductor:
94
94
  self.root = Path(os.environ.get("FLOW_DIR") or "plans")
95
95
  self.plan = self.root / feature
96
96
  self.commands = self.plan / "commands.md"
97
+ try:
98
+ self.profile = profiles.pick(os.environ, tickets.commands_value(self.commands, "Profile"))
99
+ except profiles.UnknownProfile as err:
100
+ raise Stop(str(err))
101
+ profiles.apply(os.environ, self.profile)
97
102
  self.max_retries = _env_int("FLOW_MAX_RETRIES", 2)
98
103
  self.max_rounds = _env_int("FLOW_MAX_REVIEW_ROUNDS", 3)
99
104
  self.gate_timeout = _env_int("FLOW_GATE_TIMEOUT", 30)
@@ -849,6 +854,8 @@ class Conductor:
849
854
  self.st["seen"] = int(time.time()) # the time between sessions is not spent on the feature
850
855
  self.save()
851
856
  self.log("TAKEOVER" if takeover else "START")
857
+ if self.profile:
858
+ self.log("PROFILE-%s" % self.profile.upper())
852
859
  return "OK %s" % token
853
860
 
854
861
  def next(self, lane=None):