flow-workflows 0.92.0 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/adapters/codex/CORE.md +61 -20
- package/adapters/codex/skills/flow-bug-fix/SKILL.md +9 -1
- package/adapters/codex/skills/flow-bug-investigate/SKILL.md +11 -0
- package/adapters/codex/skills/flow-bug-validate/SKILL.md +1 -1
- package/adapters/codex/skills/flow-doctor/SKILL.md +33 -15
- package/adapters/codex/skills/flow-feat-build/SKILL.md +9 -2
- package/adapters/codex/skills/flow-feat-design/SKILL.md +32 -2
- package/adapters/codex/skills/flow-feat-plan/SKILL.md +1 -0
- package/adapters/codex/skills/flow-feat-ship/SKILL.md +3 -1
- package/adapters/codex/skills/flow-feat-start/SKILL.md +1 -1
- package/adapters/codex/skills/flow-feat-validate/SKILL.md +1 -1
- package/adapters/codex/skills/flow-init/SKILL.md +12 -8
- package/adapters/codex/skills/flow-next/SKILL.md +5 -4
- package/adapters/codex/skills/flow-work-README/SKILL.md +9 -2
- package/adapters/codex/skills/flow-work-handoff/SKILL.md +19 -5
- package/adapters/codex/skills/flow-work-run/SKILL.md +18 -2
- package/adapters/gemini/CORE.md +61 -20
- package/adapters/gemini/commands/flow/bug/fix.toml +9 -1
- package/adapters/gemini/commands/flow/bug/investigate.toml +11 -0
- package/adapters/gemini/commands/flow/bug/validate.toml +1 -1
- package/adapters/gemini/commands/flow/doctor.toml +33 -15
- package/adapters/gemini/commands/flow/feat/build.toml +9 -2
- package/adapters/gemini/commands/flow/feat/design.toml +32 -2
- package/adapters/gemini/commands/flow/feat/plan.toml +1 -0
- package/adapters/gemini/commands/flow/feat/ship.toml +3 -1
- package/adapters/gemini/commands/flow/feat/start.toml +1 -1
- package/adapters/gemini/commands/flow/feat/validate.toml +1 -1
- package/adapters/gemini/commands/flow/init.toml +12 -8
- package/adapters/gemini/commands/flow/next.toml +5 -4
- package/adapters/gemini/commands/flow/work/README.toml +9 -2
- package/adapters/gemini/commands/flow/work/handoff.toml +19 -5
- package/adapters/gemini/commands/flow/work/run.toml +18 -2
- package/adapters/hermes/CORE.md +61 -20
- package/adapters/hermes/skills/flow-bug-fix/SKILL.md +9 -1
- package/adapters/hermes/skills/flow-bug-investigate/SKILL.md +11 -0
- package/adapters/hermes/skills/flow-bug-validate/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-doctor/SKILL.md +33 -15
- package/adapters/hermes/skills/flow-feat-build/SKILL.md +9 -2
- package/adapters/hermes/skills/flow-feat-design/SKILL.md +32 -2
- package/adapters/hermes/skills/flow-feat-plan/SKILL.md +1 -0
- package/adapters/hermes/skills/flow-feat-ship/SKILL.md +3 -1
- package/adapters/hermes/skills/flow-feat-start/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-feat-validate/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-init/SKILL.md +12 -8
- package/adapters/hermes/skills/flow-next/SKILL.md +5 -4
- package/adapters/hermes/skills/flow-work-README/SKILL.md +9 -2
- package/adapters/hermes/skills/flow-work-handoff/SKILL.md +19 -5
- package/adapters/hermes/skills/flow-work-run/SKILL.md +18 -2
- package/adapters/opencode/CORE.md +61 -20
- package/adapters/opencode/commands/flow-bug-fix.md +9 -1
- package/adapters/opencode/commands/flow-bug-investigate.md +11 -0
- package/adapters/opencode/commands/flow-bug-validate.md +1 -1
- package/adapters/opencode/commands/flow-doctor.md +33 -15
- package/adapters/opencode/commands/flow-feat-build.md +9 -2
- package/adapters/opencode/commands/flow-feat-design.md +32 -2
- package/adapters/opencode/commands/flow-feat-plan.md +1 -0
- package/adapters/opencode/commands/flow-feat-ship.md +3 -1
- package/adapters/opencode/commands/flow-feat-start.md +1 -1
- package/adapters/opencode/commands/flow-feat-validate.md +1 -1
- package/adapters/opencode/commands/flow-init.md +12 -8
- package/adapters/opencode/commands/flow-next.md +5 -4
- package/adapters/opencode/commands/flow-work-README.md +9 -2
- package/adapters/opencode/commands/flow-work-handoff.md +19 -5
- package/adapters/opencode/commands/flow-work-run.md +18 -2
- package/bin/cli.mjs +160 -65
- package/package.json +1 -1
- package/plugins/flow/.claude-plugin/plugin.json +1 -1
- package/plugins/flow/CHANGELOG.md +61 -0
- package/plugins/flow/examples/FLOW.template.md +13 -4
|
@@ -21,8 +21,9 @@ runs a phase on its own and never advances `meta.json`.
|
|
|
21
21
|
|
|
22
22
|
## 1. Look
|
|
23
23
|
|
|
24
|
-
1. Identify the active harness. Does `FLOW.md
|
|
25
|
-
|
|
24
|
+
1. Identify the active harness. Does `FLOW.md`, the context file `FLOW_CONTEXT` selects, or the
|
|
25
|
+
active `FLOW.<harness>.md` exist (flow-core §0)? An inactive harness's overlay, or a context file
|
|
26
|
+
no variable selects, does not configure this session.
|
|
26
27
|
2. `git branch --show-current`, and whether `.claude/work/*/meta.json` has a `branch` equal to it (also check `worktree` entries, and `.claude/work/_archive/` is ignored).
|
|
27
28
|
3. `.claude/work/` — how many open works, and their `phase` (from `meta.json`; read `00-summary.md` when present, never the full artifacts).
|
|
28
29
|
3b. `followups[]` across those works **and** `.claude/work/_archive/*/meta.json`: any entry `accepted` with no `work` started (flow-core §7).
|
|
@@ -32,7 +33,7 @@ runs a phase on its own and never advances `meta.json`.
|
|
|
32
33
|
|
|
33
34
|
| Situation | Say | Propose |
|
|
34
35
|
|---|---|---|
|
|
35
|
-
|
|
|
36
|
+
| No FLOW layer present | "This repo is not configured for flow on this harness yet." One line on what the FLOW config is (personal config, auto-detected). | `/flow:init` |
|
|
36
37
|
| A work matches the current branch | Its stop header (flow-core §3: ticket · size · phase · MR #n of N) and the next phase for its size. | `/flow:work:resume` |
|
|
37
38
|
| No match, but open works exist | Count, and the two most recently updated with their phase. | `/flow:work:status`, or `/flow:feat:start` / `/flow:bug:start` if the user said what they want to do |
|
|
38
39
|
| No works at all, but an accepted follow-up is waiting | "Nothing in flight — but `<TICKET>` F1 was accepted and never started: `<title>`." | `/flow:feat:start <ticket>` (or `/flow:bug:start`) for that follow-up · `/flow:feat:start` for something else |
|
|
@@ -41,7 +42,7 @@ runs a phase on its own and never advances `meta.json`.
|
|
|
41
42
|
- The SessionStart hook (`hooks/session-start.sh`) has already printed the first two rows of this table's second case — the header and what the last session was doing — off disk, without reading a ticket or an artifact. Say them again anyway: `next` is where the user asked, and a line they scrolled past is not an answer.
|
|
42
43
|
- An `accepted` follow-up exists **and** other works are open → do not reroute; add one line naming it after the options. It is a standing commitment, not an interruption.
|
|
43
44
|
- Dirty tree and no matching work → mention it in one line ("uncommitted changes on `<branch>`, no work is tracking them") before the options; `start` will warn again.
|
|
44
|
-
- A
|
|
45
|
+
- A FLOW layer is present but `/flow:doctor` has never been run in this session and the
|
|
45
46
|
git host CLI is not on `PATH` → add `/flow:doctor` as a secondary option.
|
|
46
47
|
- In `autonomy.mode: guided`/`auto`, the route is still asked: `next` is where a session begins, and the mode governs what happens *inside* a phase, not which work the user wants to pick up.
|
|
47
48
|
|
|
@@ -22,8 +22,11 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
22
22
|
commands, code conventions, and observability profile.
|
|
23
23
|
- The active `FLOW.<harness>.md` is an optional sparse overlay (`claude`, `codex`, `opencode`,
|
|
24
24
|
`gemini`, `hermes`, or `zcode`) for model names, agents, skills, orchestration, knowledge tools, or any other value that
|
|
25
|
-
differs on that harness. Every command reads the base
|
|
25
|
+
differs on that harness. Every command reads the base, the context layer below, and then the
|
|
26
|
+
active overlay in step 0;
|
|
26
27
|
existing repos with only `FLOW.md` behave exactly as before.
|
|
28
|
+
- `FLOW_CONTEXT=<name>` in the environment adds `FLOW.<name>.md` between the two: a layer the repo
|
|
29
|
+
commits for where flow runs (CI, a server, an orchestrator), with the overlay's merge rules.
|
|
27
30
|
- An overlay key replaces the base even when explicitly empty; an absent key inherits it. Lists
|
|
28
31
|
replace whole lists. Overlay `conventions` are added after base conventions. In the rest of this
|
|
29
32
|
document, `FLOW.md` means the effective merged configuration unless a write target is explicit.
|
|
@@ -108,6 +111,9 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
108
111
|
"note": "reason if closed/superseded; empty otherwise"
|
|
109
112
|
}
|
|
110
113
|
],
|
|
114
|
+
"ticket_deps": [
|
|
115
|
+
{ "ticket": "#253", "why": "one line, what that ticket brings that the base branch lacks" }
|
|
116
|
+
],
|
|
111
117
|
"related_repos": [
|
|
112
118
|
{ "repo": "sibling-project", "scope": "what's needed there", "status": "pending" | "in_progress" | "done", "contract_handoff": "none" | "pending" | "published → <location>" }
|
|
113
119
|
],
|
|
@@ -156,6 +162,7 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
|
|
|
156
162
|
Two fields for the review because they are two facts. `reviewed_sha` used to be `git rev-parse HEAD` at the end of the phase, which by then held the round's own fixes — so `ship` compared a sha against itself and reported a match over code no reviewer had read. Read by `ship` at pre-flight against `HEAD`: a delta of test files and this work's own folder passes with a note in `06-review.md`; anything else stops and asks in every autonomy mode. Empty is not a mismatch; `fixed_sha` set with `reviewed_sha == HEAD` is one. `review` also reads `reviewed_sha` back as **its own base** on a re-review, so the second round reads the delta instead of the whole branch.
|
|
157
163
|
- **`respond_rounds`**: rounds of `/flow:work:respond` on an MR/PR. `/flow:work:respond §1` reads it against `quality.respond_max_rounds` (empty = 3) and refuses the round that would exceed it, handing the open threads back to the user.
|
|
158
164
|
- **`related_repos`**: the **other repos a task touches**. Captured at `/flow:feat:start` / `/flow:bug:start` §cross-repo, refined at `design`/`plan`, reminded at `ship`, shown by `daily`/`resume`/`status`. flow only notes and reminds — never touches the other repo. `[]` for single-repo.
|
|
165
|
+
- **`ticket_deps`**: the **other tickets this study cannot be built without** — something the design needs that is not on the base branch and that another ticket brings (`/flow:feat:design` §5.1, `/flow:bug:investigate` §4.1). Read at the two exits of a study: `/flow:work:handoff` §5 writes a `Depends on <ticket>` line per entry into the ticket body, and an unattended study run passes `--depends-on N` per entry on its `done` (flow-core §2.1). Not `mrs[].depends_on`, which orders this work's own MRs/PRs. Written whole each time `design` (or `investigate`) runs, and removed when an unattended study is rewound. `[]` or absent when the study depends on nothing.
|
|
159
166
|
- **`contract_handoff`**: whether the sibling knows **what shape to build against** (`scope` is prose; distinct from `status`). `none` — consumes no contract declared here. `pending` — consumes one, not handed over yet. `published → <location>` — published where that side reads it (normally the tracker ticket; `/flow:feat:ship` §6.3), picked up by the sibling's `/flow:feat:start` §3.6.
|
|
160
167
|
- **`followups`**: work a phase deliberately did **not** do here — a neighbouring defect found while building, a piece put out of scope while planning, a risk recorded but not mitigated, an edge case left unchecked, a prevention action from a postmortem. Written by the phase that parks it (asks nothing) when it clears the bar of flow-core §7, triaged **once** at `ship`'s Close behind a skeptic and a ceiling on how many may become questions, published in the MR/PR description while still open, and surfaced by `status`/`daily`/`next` — including from `_archive/` — until `declined` or `done`. Shape and rules: flow-core §7. `[]` when the work deferred nothing.
|
|
161
168
|
- **`defaults_used`**: an empty `FLOW.md` key a phase resolved with its default instead of asking — written in `guided`/`auto`, where asking would breach the never-a-question contract (flow-core §0). Not an error and not deferred work: a record, aggregated by `/flow:doctor` across every work including `_archive/`, so a key that keeps defaulting can be pinned once instead of decided every time. `[]` when nothing defaulted.
|
|
@@ -240,7 +247,7 @@ Two signals arrive on an open MR/PR, each with its own cross-cutting loop (feat
|
|
|
240
247
|
|
|
241
248
|
## Cross-cutting commands
|
|
242
249
|
|
|
243
|
-
- `/flow:next` — the entry point: no
|
|
250
|
+
- `/flow:next` — the entry point: no FLOW layer → init; work on the current branch →
|
|
244
251
|
resume; otherwise status.
|
|
245
252
|
- `/flow:work:daily [question]` — the **work assistant** (daily standup), read-only. **Local** (`.claude/work/` + git) + **forge** (open MRs/PRs, reviews awaiting you, red CI, unmergeable, unresolved threads via `git.cli`) + **tracker** (assigned tickets, priority changes via `tracker.tool`); where they cross, concrete commands (`/flow:feat:start`, `/flow:work:green`, `/flow:work:respond`). No argument → *yesterday · today · blockers*; a question → just that. External sources best-effort, never blocking; the only write is a "last seen" marker, like `/flow:news`.
|
|
246
253
|
- `/flow:work:status` — all works in `.claude/work/`, current phase, divergence with git.
|
|
@@ -144,13 +144,27 @@ the ticket read it there, never in the work folder; the receiver does not parse
|
|
|
144
144
|
<!-- end flow-study -->
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
Criteria keep their literal values.
|
|
148
|
-
|
|
147
|
+
Criteria keep their literal values. `## Design in brief` ends with each `meta.json.ticket_deps`
|
|
148
|
+
entry and its why — `Depends on #253: <why>` — so whoever approves the study sees what it waits
|
|
149
|
+
for; an unattended study's `done-summary.md` is this block, so it carries them too. The plan
|
|
150
|
+
lists each MR/PR with what it covers and what it waits on; a bug's plan is its single fix.
|
|
149
151
|
- **The new body**: the body read above with the block between the two markers replaced — or, with
|
|
150
|
-
no markers yet, the block appended after a blank line.
|
|
152
|
+
no markers yet, the block appended after a blank line. Then, for each `meta.json.ticket_deps`
|
|
153
|
+
entry (`/flow:feat:design` §5.1) whose line is not already a line of that body — same text,
|
|
154
|
+
ignoring case and surrounding whitespace — one line after the end marker, in `ticket_deps` order:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
Depends on #253
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`#253` being the entry's `ticket` as it stands. Outside the markers so a later rewrite of the
|
|
161
|
+
block leaves it alone, and never removed: a line a person wrote by hand looks exactly like one
|
|
162
|
+
flow wrote, and the convention is theirs too. Written to a `mktemp` file outside the
|
|
151
163
|
tree — `{BODY_FILE}` — so nothing of it can be committed later.
|
|
152
|
-
- **Show the block and ask** with `AskUserQuestion`, **in
|
|
153
|
-
|
|
164
|
+
- **Show the block, and the `Depends on` lines it adds, and ask** with `AskUserQuestion`, **in
|
|
165
|
+
every mode**: it writes to a shared tracker. A `Depends on` line already in the body, outside the
|
|
166
|
+
markers, that no entry names — a dependency a revised study dropped, or one a person added — is named in the same
|
|
167
|
+
question and left in place: whether it still holds is theirs to say. **Write it** · **Skip**. Failure → its message in one line; the push stands.
|
|
154
168
|
|
|
155
169
|
## 6. Close
|
|
156
170
|
|
|
@@ -63,7 +63,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
|
|
|
63
63
|
| `conflict` | exists | `/flow:work:green` — the MR/PR conflicts with its base; which base, and where it stands, come from `<cmd> events --json` |
|
|
64
64
|
| `review` · `pipeline` · `conflict` | none | `blocked` — there is no work of this ticket to answer for |
|
|
65
65
|
|
|
66
|
-
**The work's branch, on `start` and `study`.** The current branch is `meta.json.branch` →
|
|
66
|
+
**The work's branch, on `start` and `study`.** The current branch is `meta.json.branch` → no switch. It is
|
|
67
67
|
not — a study made on another machine arrives on the ticket's `base`, a run that died before its
|
|
68
68
|
closing order is relaunched there — then, in this order:
|
|
69
69
|
|
|
@@ -86,6 +86,21 @@ closing order is relaunched there — then, in this order:
|
|
|
86
86
|
`meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
|
|
87
87
|
other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
|
|
88
88
|
|
|
89
|
+
**On `start`, a study's branch catches up with its base** — once on the work's branch, the "no
|
|
90
|
+
switch" case included, and only while no build or fix has begun (neither `05-implementation.md` nor
|
|
91
|
+
`04-fix.md` exists). Every command below runs in the work's own checkout — step 2's worktree when
|
|
92
|
+
that is where it lives. A study writes no code, so its branch still sits where the base was when the
|
|
93
|
+
study began; an approval that waited for the tickets the study depends on (`meta.json.ticket_deps`)
|
|
94
|
+
would otherwise build on a base that lacks them. `<base>` = `meta.json.base`, empty →
|
|
95
|
+
`git.default_base`: `git fetch origin <base>`, then `<ref>` = `origin/<base>`; the fetch failing
|
|
96
|
+
with a remote configured → `blocked`, since a stale ref would leave the build on the old base
|
|
97
|
+
unnoticed. No remote → the local `<base>`. `git merge-base --is-ancestor HEAD <ref>` and `HEAD` is not
|
|
98
|
+
`<ref>` → the branch holds no commit of its own and the base moved: `git merge --ff-only <ref>`, and
|
|
99
|
+
record `{ "key": "unattended:base-caught-up", "default": "<old short sha> → <new short sha> on
|
|
100
|
+
<base>", "phase": "run" }`. The fast-forward fails → `blocked`, its message as the reason. Not an
|
|
101
|
+
ancestor → it holds commits a previous run made: leave it as it is — bringing the base into work in
|
|
102
|
+
progress is the orchestrator's (flow-core §2.1).
|
|
103
|
+
|
|
89
104
|
**A person's changes to a study, on `study`** (flow-core §2.1: they rewind it). The work's branch
|
|
90
105
|
first, as above. `<work>/study-revision.md` holds the reply, as the row above wrote it. Each step
|
|
91
106
|
can be run again: a run that dies part-way is finished by the next relaunch, whatever it serves.
|
|
@@ -109,7 +124,8 @@ can be run again: a run that dies part-way is finished by the next relaunch, wha
|
|
|
109
124
|
`study-revision.md` and earlier `before-*/` folders into `<work>/before-<id7>/` — never
|
|
110
125
|
overwriting a name already there — so no artifact, summary or agent answer of the discarded study
|
|
111
126
|
leaks into the next. Then `meta.json`: `phase` = `context`, `phases_done` = `["context"]`, `mrs`
|
|
112
|
-
removed (the row that blocks a work past the study guarantees nothing was built), `
|
|
127
|
+
removed (the row that blocks a work past the study guarantees nothing was built), `ticket_deps`
|
|
128
|
+
removed (the redone study finds its dependencies again), `notes`
|
|
113
129
|
emptied, and every `followups[]` entry a study phase wrote (`source` `design`, `plan` or
|
|
114
130
|
`investigate`) removed.
|
|
115
131
|
5. **Re-size**: estimate the size again with `/flow:feat:start` §4's table (`/flow:bug:start`'s for
|
package/adapters/hermes/CORE.md
CHANGED
|
@@ -17,7 +17,7 @@ Every `/flow-*` command assumes these rules. They are stated once, here, so a co
|
|
|
17
17
|
carries what is specific to its phase. Read this once per session; a command that says "load
|
|
18
18
|
`flow-core`" means this file.
|
|
19
19
|
|
|
20
|
-
**This file belongs to flow `0.
|
|
20
|
+
**This file belongs to flow `0.94.0`.** Compare it once, at the start of the session, against
|
|
21
21
|
`version` in `~/.claude/flow/.claude-plugin/plugin.json`. The two differing means the session
|
|
22
22
|
is running a **mixture** — the commands from one copy of the plugin, these shared rules from another
|
|
23
23
|
— which is exactly what happens when a branch or a release candidate is loaded over an installed
|
|
@@ -25,10 +25,14 @@ copy that stays enabled: the harness resolves a command from the one and a skill
|
|
|
25
25
|
silently. Name both numbers at the first stop and say which half is which; a rule this file adds and
|
|
26
26
|
a command relies on is simply absent in that session, and nothing else will report it.
|
|
27
27
|
|
|
28
|
-
## 0. Effective FLOW config — base
|
|
28
|
+
## 0. Effective FLOW config — base, context layer and harness overlay
|
|
29
29
|
|
|
30
30
|
- **Look before you read.** The first thing a phase does about configuration is list what is there:
|
|
31
|
-
`
|
|
31
|
+
`find <root> -maxdepth 1 -name 'FLOW*.md'; printf 'FLOW_CONTEXT=%q\n' "${FLOW_CONTEXT-}"` (the roots
|
|
32
|
+
being the ones the bullets below resolve — in a worktree, name both in the same `find`). A quoted
|
|
33
|
+
`-name`, not a shell glob: in zsh a glob that matches nothing aborts the whole command, so the
|
|
34
|
+
root that has no FLOW file would hide the one that does; and `%q`, not `echo`, so a trailing
|
|
35
|
+
space or a `\r` from a CRLF `.env` shows instead of reading as a clean name. One call, and it is not
|
|
32
36
|
optional — **an overlay you did not list is an overlay you did not read**, and nothing downstream
|
|
33
37
|
will notice. Every command and artifact calls the effective configuration "`FLOW.md`", a file that
|
|
34
38
|
exists, so reading it and stopping feels finished — and a missed overlay reports its keys as unset,
|
|
@@ -38,24 +42,47 @@ a command relies on is simply absent in that session, and nothing else will repo
|
|
|
38
42
|
this command: `FLOW.claude.md`, `FLOW.codex.md`, `FLOW.opencode.md`, `FLOW.gemini.md`,
|
|
39
43
|
`FLOW.hermes.md`, or `FLOW.zcode.md`. The
|
|
40
44
|
harness is the product executing the command, never guessed from a model name. An overlay is
|
|
41
|
-
valid without a base file
|
|
45
|
+
valid without a base file. **A page can outlive the product it
|
|
42
46
|
was written for**: zcode reads the plugin's Claude pages as well as its own `/flow:`-prefixed
|
|
43
47
|
mirror of them, so a `claude` in a path or in a `--harness` flag records where the page was
|
|
44
48
|
written, never who is running it. On zcode the overlay is `FLOW.zcode.md` and the flag is
|
|
45
49
|
`--harness zcode`, whichever of the two pages you were handed. Throughout every command,
|
|
46
50
|
**"FLOW.md" means this effective merged configuration** unless the command explicitly names a
|
|
47
51
|
file it will edit.
|
|
52
|
+
- **The context layer sits between the two, and whoever launches flow picks it.** `FLOW_CONTEXT`
|
|
53
|
+
set in the environment → `FLOW.<FLOW_CONTEXT>.md` is read after the base and before the harness
|
|
54
|
+
overlay, with the overlay's merge rules. It is how a repo commits what only makes sense where
|
|
55
|
+
flow runs unattended, in CI or on a server — a way to drive the app in a container, a convention
|
|
56
|
+
for those MRs/PRs — without it reaching every laptop through the base. Flow never needs to know
|
|
57
|
+
who set it. Unset or empty → no context layer, and nothing else changes. Set, and the file is
|
|
58
|
+
not there → not an error; say so beside the files you name (`FLOW_CONTEXT=ci: FLOW.ci.md not
|
|
59
|
+
found`), because a typo in the variable is otherwise a repo with no context file. **The name is
|
|
60
|
+
one plain segment, taken exactly as written**: an ASCII letter or digit, then ASCII letters,
|
|
61
|
+
digits, `-` or `_` — nothing trimmed, so a padded `" ci"` fails — and not a harness name in any case
|
|
62
|
+
(`FLOW_CONTEXT=Claude` would read an overlay as the wrong layer). A name that fails → read no
|
|
63
|
+
context layer, say so in the same place, and carry on — never a stop. `flow-workflows` applies
|
|
64
|
+
the same rule, so the two of you resolve the same layers.
|
|
65
|
+
Any other `FLOW.<name>.md` at the root is a context file this run did not select: unread, by
|
|
66
|
+
design.
|
|
48
67
|
- **"The repo root" is the main checkout's, not the worktree's.** With `git.worktree` set, every
|
|
49
68
|
phase after `start` runs inside a linked worktree — and a `FLOW.md` the repo git-ignores (the
|
|
50
69
|
normal case for a personal config, and always the case for a harness overlay) exists **only in
|
|
51
70
|
the main checkout**. Looking for it where the phase happens finds nothing, and a configuration
|
|
52
71
|
that resolves to every fallback looks exactly like a repo that never had one: the models, the
|
|
53
72
|
ceilings and the sensitive paths are silently the defaults, and the phase reports nothing
|
|
54
|
-
because from where it stands there is nothing to report. So
|
|
55
|
-
you are in — a repo that commits its config has one in every worktree,
|
|
56
|
-
differ — and otherwise read
|
|
73
|
+
because from where it stands there is nothing to report. So, **for each file on its own**: prefer
|
|
74
|
+
the copy in the directory you are in — a repo that commits its config has one in every worktree,
|
|
75
|
+
and it may legitimately differ — and otherwise read it from the main checkout, which
|
|
57
76
|
`git rev-parse --path-format=absolute --git-common-dir` locates from anywhere (its parent
|
|
58
|
-
directory)
|
|
77
|
+
directory) — **unless that checkout tracks it**: the main checkout's HEAD is the first `HEAD`
|
|
78
|
+
line of `git worktree list --porcelain`, and `git ls-tree --name-only <that sha> -- <file>`
|
|
79
|
+
printing the name means it is tracked. A tracked file missing here is this branch's own state,
|
|
80
|
+
deleted, renamed or not added yet, and the main checkout's copy is another branch's version.
|
|
81
|
+
Either command failing → do not borrow the file, and say so where you name the files you read.
|
|
82
|
+
The file name matches exactly, case included, even where the filesystem would not care. One root for all of them misses a file whenever
|
|
83
|
+
they live apart: a committed context file is in the worktree while the git-ignored base exists
|
|
84
|
+
only in the main checkout. Name the file you actually
|
|
85
|
+
read, and where, when a stop reports configuration.
|
|
59
86
|
**This is a rule about reading a git-ignored config, and it inverts for anything a phase
|
|
60
87
|
writes into the repo.** A tracked file belongs to the branch, and the branch is the worktree:
|
|
61
88
|
written to the main checkout it lands on whatever that checkout is standing on — usually the
|
|
@@ -68,16 +95,17 @@ a command relies on is simply absent in that session, and nothing else will repo
|
|
|
68
95
|
("add this to try it once") would be read as the configuration it illustrates, while the prose
|
|
69
96
|
around it says otherwise and nothing reports the disagreement. **Skip fenced regions when you read a FLOW
|
|
70
97
|
file**; `flow-workflows` does the same, so the two of you resolve the same config.
|
|
71
|
-
- Merge by section and key
|
|
72
|
-
absent there inherits
|
|
98
|
+
- Merge by section and key, in order: base, context layer, active overlay. A key present in a
|
|
99
|
+
later layer replaces the earlier value; a key absent there inherits it. **A present-but-empty key
|
|
100
|
+
masks what came before** and resolves
|
|
73
101
|
to the normal empty-key fallback — this is how Codex can inherit its session model while a legacy
|
|
74
102
|
`FLOW.md` still names a Claude model. A list-valued key is replaced as a whole, never appended.
|
|
75
|
-
`conventions` is the one unkeyed section:
|
|
76
|
-
|
|
103
|
+
`conventions` is the one unkeyed section: each layer's lines are added after the previous ones,
|
|
104
|
+
so every set applies. **Every value carries the file it came from**, and a phase that prints a value
|
|
77
105
|
prints that file with it — "`agents: opus` (`FLOW.claude.md`)", never the value alone. `doctor` reports it and later
|
|
78
106
|
edits preserve it.
|
|
79
|
-
- The sections in
|
|
80
|
-
conventions, notes, knowledge, and observability.
|
|
107
|
+
- The sections in any of the files are tracker, git, autonomy, quality, agents, models, data,
|
|
108
|
+
conventions, notes, knowledge, and observability. No layer found, or an effective empty key
|
|
81
109
|
→ the default or auto-discovery each step names. Never stop because a file or key is empty.
|
|
82
110
|
- **An empty key that is a real decision for this repo is offered where it first matters**, and
|
|
83
111
|
nowhere else. Three steps, in order:
|
|
@@ -102,7 +130,10 @@ a command relies on is simply absent in that session, and nothing else will repo
|
|
|
102
130
|
The FLOW config is personal, so writing a line is not a team decision; it is still an edit to the
|
|
103
131
|
tree, so the option is an explicit choice the user makes, never a default action (same bar as
|
|
104
132
|
flow-core §8's convention offer, and the two share their wording). Update a value in the file it
|
|
105
|
-
came from
|
|
133
|
+
came from — **except that the context layer is not personal**: it is committed, a value it holds
|
|
134
|
+
is the repo's, and changing it is a change to a tracked file of this branch, written here (the
|
|
135
|
+
inversion above) and shipped in the MR/PR like code, never offered as a quick config line. A new
|
|
136
|
+
key never goes to the context layer by this route. A new repo fact or shared preference goes to `FLOW.md`; a new harness-owned model,
|
|
106
137
|
agent, skill, orchestration tool, or knowledge-tool name goes to the active overlay. Never edit an
|
|
107
138
|
inactive harness's overlay.
|
|
108
139
|
- **Knowledge sources, by role** (`knowledge` section): `search` (one or more tools or commands
|
|
@@ -253,7 +284,7 @@ assumed:
|
|
|
253
284
|
<cmd> ask --question-file F --options-file F [--recommended N] [--free-text] [--gate NAME]
|
|
254
285
|
<cmd> publish --title-file F --body-file F [--part N --of M]
|
|
255
286
|
<cmd> blocked --reason-file F
|
|
256
|
-
<cmd> done [--summary-file F]
|
|
287
|
+
<cmd> done [--summary-file F] [--depends-on N]…
|
|
257
288
|
<cmd> reply --thread ID --body-file F
|
|
258
289
|
```
|
|
259
290
|
|
|
@@ -314,12 +345,18 @@ runs the study phases as any run does, and three rules make it stop where it sho
|
|
|
314
345
|
study to code crosses that door, an answered question that resumes straight into `build`
|
|
315
346
|
included, so the phases before it carry no clause. The run kind is read there, never stored: the
|
|
316
347
|
approval reuses the same work folder with `why = start`.
|
|
317
|
-
- **At the door**, a study run first
|
|
348
|
+
- **At the door**, a study run first checks each `meta.json.ticket_deps` entry: `N` = its `ticket`
|
|
349
|
+
without a leading `#`, the form `ticket --json` prints `number`, and it must match
|
|
350
|
+
`[A-Za-z0-9][A-Za-z0-9._-]*` — an `N` that does not (a space, a shell character, a leading `-`)
|
|
351
|
+
is never put on a command line: `blocked`, naming the entry, before anything below is written.
|
|
352
|
+
Then it writes the statement of the change when the study holds none
|
|
318
353
|
(the command says which), then `done-summary.md` — the `flow-study` block of `/flow-work-handoff`
|
|
319
354
|
§5, the same sections from the same sources, and, when `01-context.md` lists `## Study revisions`,
|
|
320
355
|
the line `Revised at the reviewer's request: <n> reply(ies)` first under `## What and why`. It
|
|
321
356
|
overwrites `00-summary.md`, sets the panel's `attention` to `done` and closes with
|
|
322
|
-
`done --summary-file
|
|
357
|
+
`done --summary-file`, plus one `--depends-on N` per `meta.json.ticket_deps` entry, in its order —
|
|
358
|
+
so the orchestrator can hold the ticket until those land; what it does with them is its call.
|
|
359
|
+
Nothing else moves — no `mrs[]` entry, no branch, no brief — so
|
|
323
360
|
`meta.json.phase` stays at the last study phase and approval is an ordinary `start`.
|
|
324
361
|
- **A person's changes rewind the study.** `/flow-work-run` §2 adds the reply to the ticket in
|
|
325
362
|
`01-context.md` and sends the work back to `context`; the study phases then run again whole, the
|
|
@@ -332,7 +369,7 @@ person asking for changes, a ticket that already has code — is `/flow-work-run
|
|
|
332
369
|
| Where | In `unattended` |
|
|
333
370
|
|---|---|
|
|
334
371
|
| Business brief before code (`build`, `fix`) | record — the brief is written to the phase artifact, marked `recorded (unattended)`, and travels in the MR/PR body |
|
|
335
|
-
| The door to code in a study run (`build`, `fix` pre-flight) | done — `done-summary.md`, the study as `/flow-work-handoff` §5 writes it for the ticket |
|
|
372
|
+
| The door to code in a study run (`build`, `fix` pre-flight) | done — `done-summary.md`, the study as `/flow-work-handoff` §5 writes it for the ticket, and one `--depends-on` per `meta.json.ticket_deps` entry |
|
|
336
373
|
| Push and MR/PR creation (`ship`) | `publish` — the run commits on its own branch, writes title and body, and hands them over; the orchestrator pushes and opens the draft |
|
|
337
374
|
| Writing a DB schema change, index or migration — in any phase, a review's own fixes included — or applying one (`validate`) | question `migration`, before the first line of it is written or run — except in `respond` and `green`, where it is blocked: a schema change agreed after the MR/PR exists goes back through `build` |
|
|
338
375
|
| `review` with blockers or high-severity findings | question `high_findings` |
|
|
@@ -352,6 +389,7 @@ person asking for changes, a ticket that already has code — is `/flow-work-run
|
|
|
352
389
|
| The next MR/PR of a train (`ship` close) | record — not started: one MR/PR per unattended run |
|
|
353
390
|
| `build` with no startable MR/PR (its `depends_on` not `merged` in `meta.json`) | blocked — the reason names what must merge; an unattended `build` never stacks a branch on another, and never creates a remote branch |
|
|
354
391
|
| The parent of a stacked MR/PR merged — rebase and force-push | blocked — never force-push unattended |
|
|
392
|
+
| An approved study's branch (`run`, `why = start`, no build or fix begun) | record — fast-forwarded to its base when it holds no commit of its own (`/flow-work-run` §2); the base unreadable or the fast-forward failing → blocked. Not integrating: nothing of the run's is merged |
|
|
355
393
|
| Integrating the base into the MR/PR's branch (`green`) | on `why = conflict`, record — `git merge origin/<base>` as the orchestrator left it, never rebase, each conflict resolved on its merits (`/flow-work-green` §5.C); on any other `why`, blocked — the orchestrator brings the base in |
|
|
356
394
|
| Any offer about the work's own bookkeeping — a tracker issue, the first `KNOWLEDGE.md` or a knowledge save, a FLOW convention, an agent lesson or a saved specialist, the follow-up survey, carrying files over from the main checkout, a contract handoff, archiving the work | record — `Later`; nothing written outside the work folder |
|
|
357
395
|
| A step the command cannot complete (a red suite it cannot fix, a tool missing, auth failing, the same check failing a second time) | blocked |
|
|
@@ -1073,7 +1111,10 @@ learned during `build` is enforced in the review of that same MR/PR, not of the
|
|
|
1073
1111
|
**`ship` offers them once, at Close** — one `AskUserQuestion`, batched up to 4, options **Add to
|
|
1074
1112
|
FLOW.md** · **Not a rule** · **Later**, the `text` being the whole prompt. *Add* appends a convention
|
|
1075
1113
|
to the base `FLOW.md`. A `quality` correction updates the file its effective value came from, or the
|
|
1076
|
-
base when the key was absent: otherwise an overlay would immediately hide the correction.
|
|
1114
|
+
base when the key was absent: otherwise an overlay would immediately hide the correction. A value
|
|
1115
|
+
that came from the context layer is the exception (§0): that file is committed, so the correction
|
|
1116
|
+
is a change to this branch, made before the MR/PR is created or offered as a follow-up — never a
|
|
1117
|
+
config line written after it. The FLOW
|
|
1077
1118
|
config is personal, but this is still an edit to a file in the tree, so **it is asked in every
|
|
1078
1119
|
mode**, like `KNOWLEDGE.md`'s first creation. No candidates → the step does not exist and says
|
|
1079
1120
|
nothing.
|
|
@@ -36,7 +36,15 @@ Read `~/.claude/flow/CORE.hermes.md` first (shared rules: `FLOW.md` step 0, mode
|
|
|
36
36
|
would make — from the root cause and the constraints for the fix when the investigation has them,
|
|
37
37
|
the reproduction and the ticket otherwise, `## Study revisions` included — the person approves a
|
|
38
38
|
stated change, never `none`; then the summary, and
|
|
39
|
-
`<cmd> done --summary-file <work>/done-summary.md
|
|
39
|
+
`<cmd> done --summary-file <work>/done-summary.md`, plus `--depends-on N` per
|
|
40
|
+
`meta.json.ticket_deps` entry, `N` its `ticket` with the leading `#` dropped — a bare `#` starts a
|
|
41
|
+
shell comment — and checked against `[A-Za-z0-9][A-Za-z0-9._-]*` before anything is written, else
|
|
42
|
+
`blocked` (flow-core §2.1). Nothing else in this command runs.
|
|
43
|
+
- **`meta.json.ticket_deps` not empty, and not `unattended`** → the study rests on other tickets
|
|
44
|
+
(`/flow-feat-design` §5.1): name each — `<ticket> — <why>` — in the brief's stop (§2), one line,
|
|
45
|
+
so whoever builds confirms the piece is on **this work's branch**, not only on its base — the
|
|
46
|
+
branch was cut when the study began, and a piece that merged since needs the base brought in
|
|
47
|
+
before writing against it. Nothing is checked; waiting is the builder's call.
|
|
40
48
|
- `size` `XS`: may start without `investigate`, but require a 2-3 line description of the fix — an `## Intended fix` in `03-investigation.md` is that description.
|
|
41
49
|
- **An `## Intended fix` in `03-investigation.md` binds §2's brief at every size**: it is what a person approved at the end of a study (flow-core §2.1).
|
|
42
50
|
- `size` ≥ S: require `investigate` in `phases_done` (on S it will have run its reproduction half only).
|
|
@@ -174,10 +174,21 @@ If `agents.fanout_tool` is set in `FLOW.md`, run the sweep through that tool; br
|
|
|
174
174
|
- Do not touch X because…
|
|
175
175
|
- Consider Y because…
|
|
176
176
|
|
|
177
|
+
## Depends on other tickets
|
|
178
|
+
<§4.1: `- <ticket> — <what it brings that the base branch lacks>`, then "Not dependencies (either order works)", or "none".>
|
|
179
|
+
|
|
177
180
|
## Investigation challenges
|
|
178
181
|
<filled in by §5 with the challenger table>
|
|
179
182
|
```
|
|
180
183
|
|
|
184
|
+
### 4.1 Tickets this fix depends on
|
|
185
|
+
|
|
186
|
+
A fix can rest on another ticket the same way a design can — a corrected contract, a migration, a
|
|
187
|
+
decision that lands only when that ticket merges. Detect and record it before the challenger, exactly
|
|
188
|
+
as `/flow-feat-design` §5.1 says: the same rule, the same "Not dependencies (either order works)"
|
|
189
|
+
line, the same `meta.json.ticket_deps` entries, written under `## Depends on other tickets` in
|
|
190
|
+
`03-investigation.md`.
|
|
191
|
+
|
|
181
192
|
## 5. Root cause challenge (challenger)
|
|
182
193
|
|
|
183
194
|
Before closing, launch a `Agent general-purpose` challenger with this task:
|
|
@@ -37,7 +37,7 @@ Read `~/.claude/flow/CORE.hermes.md` first (shared rules: `FLOW.md` step 0, mode
|
|
|
37
37
|
|
|
38
38
|
**Mandatory regression test**: launch the `agents.testing` agent from FLOW.md (empty → `Agent general-purpose` with a test-writing role):
|
|
39
39
|
|
|
40
|
-
> Write a test that **fails** before the fix and **passes** after. Read `.claude/work/<TICKET>/03-investigation.md` (minimal reproduction), `04-fix.md` (what was changed). Follow the effective conventions from `FLOW.md`
|
|
40
|
+
> Write a test that **fails** before the fix and **passes** after. Read `.claude/work/<TICKET>/03-investigation.md` (minimal reproduction), `04-fix.md` (what was changed). Follow the effective conventions from `FLOW.md`, the context layer `FLOW_CONTEXT` selects and the active harness overlay. Report the path of the added test.
|
|
41
41
|
|
|
42
42
|
Then:
|
|
43
43
|
1. Run only that test with `quality.test_one` from FLOW.md; it must pass.
|
|
@@ -30,15 +30,19 @@ changing machines, after `/flow-init`, or when a command failed the way an envir
|
|
|
30
30
|
## 1. Load
|
|
31
31
|
|
|
32
32
|
- Identify the active harness and read the effective configuration exactly as flow-core §0: base
|
|
33
|
-
`FLOW.md`, then
|
|
33
|
+
`FLOW.md`, then the context layer `FLOW.<FLOW_CONTEXT>.md` when the variable is set, then its
|
|
34
|
+
`FLOW.<harness>.md` overlay. Never read another harness's overlay. **Name the active context** —
|
|
35
|
+
its value and the file it selects, `none` when the variable is unset, and the reason when the name
|
|
36
|
+
was refused or the file is missing (flow-core §0): a context set on a server and lost on the way
|
|
37
|
+
reads here as `none`, and nowhere else. No layer present
|
|
34
38
|
is **not** an error: say so in one line, check what needs no config (git, hooks, harness, base
|
|
35
39
|
branch, plugin files), and note that `/flow-init` would let this command check the rest.
|
|
36
40
|
**Say which checkout the configuration came from** whenever it is not the directory you are in
|
|
37
41
|
(flow-core §0: a worktree does not carry a git-ignored `FLOW.md`). A diagnosis run from a
|
|
38
42
|
worktree that quietly read nothing is the one that certifies a repo as unconfigured.
|
|
39
|
-
- Parse
|
|
43
|
+
- Parse each layer by section: `tracker`, `git`, `autonomy`, `quality`, `agents`, `models`, `data`,
|
|
40
44
|
`conventions`, `notes`, `knowledge`, `observability`; merge keys and empty masks per flow-core §0.
|
|
41
|
-
Keep the source of every effective value.
|
|
45
|
+
Keep the source of every effective value. No layer present → §1.5 runs with **every** key empty (all
|
|
42
46
|
fallbacks), which is a legitimate and complete answer.
|
|
43
47
|
|
|
44
48
|
## 1.5 What the configuration says
|
|
@@ -52,14 +56,14 @@ documented keys absent from the effective configuration (the "empty → fallback
|
|
|
52
56
|
For **every** documented key in `examples/FLOW.template.md`, one row:
|
|
53
57
|
|
|
54
58
|
- **set** → the value and source file (list keys like `git.worktree_resync` or
|
|
55
|
-
`quality.reviewers`: the items). A value overridden by
|
|
56
|
-
value here; do not make the user mentally merge two tables.
|
|
59
|
+
`quality.reviewers`: the items). A value overridden by a later layer names only the winning
|
|
60
|
+
value and its file here; do not make the user mentally merge two tables.
|
|
57
61
|
- **empty / absent** → `(empty → <what happens>)`, taken from the key's comment in the template
|
|
58
62
|
(e.g. `quality.test` → "auto-discover from Makefile/npm/composer/Gradle/dotnet/Xcode/Flutter"; `tracker.tool` → "manual paste";
|
|
59
63
|
`agents.security` → "general-purpose with the role"; `git.worktree` → "off / in-place";
|
|
60
64
|
`git.worktree_resync` → "`/flow-work-try` only switches, no re-sync"; `quality.review_depth` →
|
|
61
|
-
"proportional" — the other depths are `light` and `full`). An empty
|
|
62
|
-
`(masked by FLOW.<harness>.md → <what happens>)`. Never leave a reader guessing what an empty key
|
|
65
|
+
"proportional" — the other depths are `light` and `full`). An empty mask says
|
|
66
|
+
`(masked by FLOW.<context or harness>.md → <what happens>)`. Never leave a reader guessing what an empty key
|
|
63
67
|
does.
|
|
64
68
|
|
|
65
69
|
For `knowledge`, print the four roles resolved with who decided each: the `knowledge` key, or empty with its fallback (`search` → no lookups; `stage` → artifact only; `read_staging` → artifacts; `save` → `KNOWLEDGE.md`). A `domain_memory` section still in the file → one line: *"`domain_memory` is no longer read; name the tools you want under `knowledge`"* — it is retired configuration, not an error.
|
|
@@ -73,7 +77,7 @@ print one informational line: those values currently apply to every harness with
|
|
|
73
77
|
override. This is valid configuration, not a warning and never a claim that a free-text model name
|
|
74
78
|
is invalid.
|
|
75
79
|
|
|
76
|
-
#### 1.5.2 Resolved models (only if
|
|
80
|
+
#### 1.5.2 Resolved models (only if any layer has a `models` key)
|
|
77
81
|
|
|
78
82
|
Three keys, all about subagents. Print what each one actually reaches:
|
|
79
83
|
|
|
@@ -123,10 +127,23 @@ data.volumes (none — duel ran schema-only) 2 works last: query
|
|
|
123
127
|
|
|
124
128
|
### 1.5.4 Problems in the configuration files (flag, do not fix)
|
|
125
129
|
|
|
126
|
-
Report problems, change nothing. Validate the base
|
|
127
|
-
that owns each problem, and ignore inactive overlays.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
Report problems, change nothing. Validate the base, the active context file and the active
|
|
131
|
+
overlay separately, name the file that owns each problem, and ignore inactive overlays. Any other
|
|
132
|
+
root `FLOW.<name>.md` is a context file this run did not select: list it once, as inactive, with the
|
|
133
|
+
`FLOW_CONTEXT=<name>` that would select it and the six harness overlay names beside it — a
|
|
134
|
+
misspelled overlay (`FLOW.cluade.md`) reads exactly like a context, and only the reader can tell —
|
|
135
|
+
never as unknown, and its keys are not validated. Only a name the context rule refuses (flow-core
|
|
136
|
+
§0) gets a warning, because nothing will ever read it.
|
|
137
|
+
- **A context file git would swallow**: run `git check-ignore -v --no-index FLOW.flow-probe.md` at
|
|
138
|
+
the repo root — a name no repo tracks, so a context file that was force-added does not hide the
|
|
139
|
+
rule, and `--no-index` asks the ignore rules rather than the index. It prints a rule that does not
|
|
140
|
+
start with `!` → one warning naming that rule and its file (`.gitignore`, `.git/info/exclude`, a
|
|
141
|
+
global excludes file): a `FLOW.*.md` written by an older `/flow-init` hides every new context file
|
|
142
|
+
from `git add`, and the run that needs it reports it `not found` somewhere else, long after.
|
|
143
|
+
Replace the glob with the names `/flow-init` §5 lists. A `!` rule, or nothing printed → no
|
|
144
|
+
warning.
|
|
145
|
+
|
|
146
|
+
**Scope: these files.** Whether the world they describe exists —
|
|
130
147
|
CLIs installed *and authenticated*, agents discoverable, hooks executable, the MCP reachable, the
|
|
131
148
|
base branch resolvable — is §2 below; flag the key here, check the world there, never both.
|
|
132
149
|
|
|
@@ -266,10 +283,11 @@ refuse) · **degraded** (it runs, quietly worse than the config promises), plus
|
|
|
266
283
|
## 3. Output
|
|
267
284
|
|
|
268
285
|
§1.5 always prints — it is the answer to half the question. Start it with one line naming the files
|
|
269
|
-
that produced the effective configuration
|
|
270
|
-
|
|
286
|
+
that produced the effective configuration, in merge order and with the checkout each came from
|
|
287
|
+
when it is not this one (`FLOW.md + FLOW.ci.md [FLOW_CONTEXT=ci] + FLOW.codex.md`, `FLOW.md only`,
|
|
288
|
+
active overlay only, or defaults only), and the active context on the next line. **The checks are quiet on success**:
|
|
271
289
|
one line per check that is *not* ok, grouped by the six areas above, plus a summary line. Close with
|
|
272
|
-
`N effective keys set (O from overlay), M using fallbacks, K warnings` from §1.5 next to the
|
|
290
|
+
`N effective keys set (C from the context layer, O from overlay), M using fallbacks, K warnings` from §1.5 next to the
|
|
273
291
|
findings count.
|
|
274
292
|
|
|
275
293
|
|
|
@@ -33,8 +33,15 @@ Implementation phase. Code is written here.
|
|
|
33
33
|
and act as flow-core §2.1 "A study run" says. On `study` → this run writes no code: `size` XS and
|
|
34
34
|
no `03-design.md` → first write the 2–3 line note below as that file, from `01-context.md` (its
|
|
35
35
|
`## Study revisions` included) — the person approves a stated change, never `none`; then the
|
|
36
|
-
summary, and `<cmd> done --summary-file <work>/done-summary.md
|
|
37
|
-
|
|
36
|
+
summary, and `<cmd> done --summary-file <work>/done-summary.md`, plus `--depends-on N` per
|
|
37
|
+
`meta.json.ticket_deps` entry, `N` its `ticket` with the leading `#` dropped — a bare `#` starts a
|
|
38
|
+
shell comment — and checked against `[A-Za-z0-9][A-Za-z0-9._-]*` before anything is written, else
|
|
39
|
+
`blocked` (flow-core §2.1). Nothing else in this command runs.
|
|
40
|
+
- **`meta.json.ticket_deps` not empty, and not `unattended`** → the study rests on other tickets
|
|
41
|
+
(`/flow-feat-design` §5.1): name each — `<ticket> — <why>` — in the brief's stop (§2), one line,
|
|
42
|
+
so whoever builds confirms the piece is on **this work's branch**, not only on its base — the
|
|
43
|
+
branch was cut when the study began, and a piece that merged since needs the base brought in
|
|
44
|
+
before writing against it. Nothing is checked; waiting is the builder's call.
|
|
38
45
|
- `size` M/L: require both `03-design.md` **and** `04-mr-plan.md`. Plan missing → send to `/flow-feat-plan`; design missing → send to `/flow-feat-design`.
|
|
39
46
|
- `size` XS/S: may start without a design — ask the user for a 2-3 line note on what will be done and save it as a minimal `03-design.md`. No MR/PR plan (always 1 MR/PR).
|
|
40
47
|
- **If `meta.json.mrs` has more than one entry**: pick the **startable** MR/PR — the `pending` one with the **lowest `n` whose `depends_on` are all `merged`**. Dependencies still `pending`/`in_progress` → not startable, even with a low `n`. (No `wave`/`depends_on` — an older plan — → "first pending by `n`".)
|
|
@@ -103,8 +103,8 @@ authorization, payments, personal data, a public contract, a migration):
|
|
|
103
103
|
Each advisor gets this brief, with its lens substituted:
|
|
104
104
|
|
|
105
105
|
> Propose ONE approach to solve ticket `<TICKET>`, from this lens: `<lens brief>`. Read
|
|
106
|
-
> `.claude/work/<TICKET>/01-context.md` for context and the effective FLOW configuration (base
|
|
107
|
-
> active harness overlay) for project conventions. What already exists in the repository:
|
|
106
|
+
> `.claude/work/<TICKET>/01-context.md` for context and the effective FLOW configuration (base, the
|
|
107
|
+
> context layer `FLOW_CONTEXT` selects, and the active harness overlay) for project conventions. What already exists in the repository:
|
|
108
108
|
> `<the §1.5.1 inventory>` — propose a new piece only where nothing there fits. Do not
|
|
109
109
|
> write code. Be specific about real modules and layers of this project. Report: name, what it is
|
|
110
110
|
> (one sentence), modules/layers affected, main risk, and why it could be a bad idea. Under 250 words.
|
|
@@ -290,6 +290,9 @@ Consolidate outputs into `.claude/work/<TICKET>/03-design.md`:
|
|
|
290
290
|
- **Invariant**: <e.g. "after assignTo(user), ticket.assignee == user AND ticket.status != 'unassigned'">
|
|
291
291
|
- **Edge / boundary**: <e.g. "empty input list → returns 0, does not throw">
|
|
292
292
|
|
|
293
|
+
## Depends on other tickets
|
|
294
|
+
<§5.1: one line per ticket this design cannot be built without — `- <ticket> — <what it brings that the base branch lacks>` — then, under "Not dependencies (either order works)", each premise on another ticket that holds whichever merges first, with one line why. Neither → "none".>
|
|
295
|
+
|
|
293
296
|
## Defensive mechanisms and their justification
|
|
294
297
|
<One row per validation, guard, retry, lock, fallback, cache, idempotency, queue, or flag the design introduces. If you cannot name a REAL and PRESENT scenario that justifies it, the piece is unnecessary — remove it from the design.>
|
|
295
298
|
|
|
@@ -318,6 +321,33 @@ Consolidate outputs into `.claude/work/<TICKET>/03-design.md`:
|
|
|
318
321
|
|
|
319
322
|
**"Acceptance criteria"**: start from the provisional list in `01-context.md` (pinned from the ticket in `/flow-feat-start`), fold in the clarifications and the internal/external contracts decided here, and promote it to the canonical enumerated list `/flow-feat-validate` gates against — observable, verifiable, proportional to size.
|
|
320
323
|
|
|
324
|
+
### 5.1 Tickets this design depends on
|
|
325
|
+
|
|
326
|
+
Fill `## Depends on other tickets` now, before the challenger of §6 reads the design. The study is
|
|
327
|
+
often built by someone who never saw it made — another person, an unattended server — and who
|
|
328
|
+
starts from the base. A design that rests on what another ticket has not delivered yet leaves that
|
|
329
|
+
builder to find the piece missing and either ask or redo it.
|
|
330
|
+
|
|
331
|
+
- **A dependency** is a piece, contract or decision the chosen design needs, that is **not on the
|
|
332
|
+
base this work builds from** (`meta.json.base`, empty → `git.default_base`) — checked there, after
|
|
333
|
+
a best-effort `git fetch origin <base>`, never assumed from a local ref — and that **another
|
|
334
|
+
ticket** of this tracker brings. Missing from the base with no ticket bringing it → it is scope
|
|
335
|
+
or an open question, not a dependency. A ticket in another repo is not a `ticket_deps` entry —
|
|
336
|
+
the orchestrator only resolves this tracker's numbers — so write it in the section as a
|
|
337
|
+
cross-repo dependency, for a person, and leave it out of the list.
|
|
338
|
+
- **Not a dependency**: a premise that holds whichever ticket merges first. Say so under "Not
|
|
339
|
+
dependencies (either order works)", so nobody waits for it.
|
|
340
|
+
- **Record each one** in that section and in `meta.json.ticket_deps` —
|
|
341
|
+
`{ "ticket": "<the reference as a ticket body writes it: #253, MT-123>", "why": "<one line>" }`,
|
|
342
|
+
never one twice. `ticket_deps` is the record the exits read (`/flow-work-handoff` §5, the door to
|
|
343
|
+
code of an unattended study run, flow-core §2.1); the section is the study's prose. Each run of
|
|
344
|
+
this phase writes the list whole from the design it closes; `plan`, which runs after it, appends
|
|
345
|
+
its own again. A §6 response or a §9 edit that changes what the design needs changes
|
|
346
|
+
the section and the list together. None → `[]` and "none".
|
|
347
|
+
|
|
348
|
+
`ticket_deps` is not `mrs[].depends_on`: that one orders this work's own MRs/PRs, this one names
|
|
349
|
+
other tickets. Flow never checks whether a dependency has closed — whoever builds waits for it.
|
|
350
|
+
|
|
321
351
|
## 6. Design challenge (challenger)
|
|
322
352
|
|
|
323
353
|
Before closing, **challenge the design** with an `Agent general-purpose` and this self-contained brief:
|
|
@@ -126,6 +126,7 @@ Add the `mrs` array with the agreed plan:
|
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
- `n` = execution order (topological): `depends_on` only ever references a **lower** `n`; `wave` groups MRs/PRs that can run in parallel. `/flow-feat-build §1` reads `depends_on` to pick the next **startable** MR/PR and to say which can go in parallel — keep both accurate whenever the plan is edited or renumbered.
|
|
129
|
+
- **Another ticket is not a `depends_on`.** An MR/PR that turns out, while splitting, to need something another ticket brings is a dependency of the study: append it to `meta.json.ticket_deps` as `/flow-feat-design` §5.1 says, name it in that MR/PR's entry of `04-mr-plan.md` beside what it waits on, and leave `03-design.md` as it closed. The design's own entries stand as they are.
|
|
129
130
|
- **`phases_done`** starts `[]` in every seeded entry: it tracks `build`/`review`/`validate` **for that MR/PR specifically**, so the gates in `/flow-feat-review §1`, `/flow-feat-validate §1` and `/flow-feat-ship §1` judge *this* MR/PR — a sibling's review never satisfies a new MR/PR's gate.
|
|
130
131
|
- Estimates are **indicative**, not contractual. `/flow-feat-build` uses them as a thermometer: real work over `lines_est` +50% or `files_est + 2` triggers the "cut or continue" question (see §2.3 in build). **A thermometer is not a target** (flow-core §9): an estimate is never met by deleting comments, tests or blank lines, by compressing readable code, or by cutting where the piece is not coherent — the overrun is recorded instead, and a diff shaped to fit a number is the one case where these estimates lie to the phases downstream.
|
|
131
132
|
|
|
@@ -533,7 +533,9 @@ Read `meta.json.conventions_candidates[]` (flow-core §8). **No entries with `st
|
|
|
533
533
|
decision — the FLOW config is personal — so it is one question, never a negotiation.
|
|
534
534
|
4. **Add / Replace** → append a `conventions` line to the base `FLOW.md`. For a `quality.<key>`,
|
|
535
535
|
update the file its effective value came from, or the base when it was absent; otherwise an
|
|
536
|
-
overlay would immediately hide the correction.
|
|
536
|
+
overlay would immediately hide the correction. A value from the context layer (flow-core §0) is
|
|
537
|
+
not edited here: that file is committed and the MR/PR is already out, so record the candidate as
|
|
538
|
+
a `followups[]` entry (`kind: "tooling"`) naming the file and the line instead. Show the old value and source in the result.
|
|
537
539
|
Then `status: "added"`. **Not a rule** → `declined`, never offered again in any work.
|
|
538
540
|
**Later** → stays `proposed` and is offered again by the next `ship` of a work that has it.
|
|
539
541
|
5. **One line on screen**: how many rules were added and where, never a list of the texts —
|
|
@@ -50,7 +50,7 @@ its reason file in a `mktemp -d` directory (flow-core §2.1).
|
|
|
50
50
|
|
|
51
51
|
## 1. Pre-flight
|
|
52
52
|
|
|
53
|
-
- Read the effective FLOW configuration per flow-core §0;
|
|
53
|
+
- Read the effective FLOW configuration per flow-core §0; no FLOW layer present → each
|
|
54
54
|
step's default. This command **creates** `00-summary.md` (§6) instead of reading it (flow-core §5).
|
|
55
55
|
- No recognizable project structure → warn and stop.
|
|
56
56
|
- **Determine the mode**: `$ARGUMENTS` non-empty → *ticket mode* (identifier = `$ARGUMENTS`); empty → *ticket-less* (identifier = the §2.5 slug).
|