flow-workflows 0.92.0 → 0.93.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.
Files changed (39) hide show
  1. package/adapters/codex/CORE.md +12 -5
  2. package/adapters/codex/skills/flow-bug-fix/SKILL.md +9 -1
  3. package/adapters/codex/skills/flow-bug-investigate/SKILL.md +11 -0
  4. package/adapters/codex/skills/flow-feat-build/SKILL.md +9 -2
  5. package/adapters/codex/skills/flow-feat-design/SKILL.md +30 -0
  6. package/adapters/codex/skills/flow-feat-plan/SKILL.md +1 -0
  7. package/adapters/codex/skills/flow-work-README/SKILL.md +4 -0
  8. package/adapters/codex/skills/flow-work-handoff/SKILL.md +19 -5
  9. package/adapters/codex/skills/flow-work-run/SKILL.md +18 -2
  10. package/adapters/gemini/CORE.md +12 -5
  11. package/adapters/gemini/commands/flow/bug/fix.toml +9 -1
  12. package/adapters/gemini/commands/flow/bug/investigate.toml +11 -0
  13. package/adapters/gemini/commands/flow/feat/build.toml +9 -2
  14. package/adapters/gemini/commands/flow/feat/design.toml +30 -0
  15. package/adapters/gemini/commands/flow/feat/plan.toml +1 -0
  16. package/adapters/gemini/commands/flow/work/README.toml +4 -0
  17. package/adapters/gemini/commands/flow/work/handoff.toml +19 -5
  18. package/adapters/gemini/commands/flow/work/run.toml +18 -2
  19. package/adapters/hermes/CORE.md +12 -5
  20. package/adapters/hermes/skills/flow-bug-fix/SKILL.md +9 -1
  21. package/adapters/hermes/skills/flow-bug-investigate/SKILL.md +11 -0
  22. package/adapters/hermes/skills/flow-feat-build/SKILL.md +9 -2
  23. package/adapters/hermes/skills/flow-feat-design/SKILL.md +30 -0
  24. package/adapters/hermes/skills/flow-feat-plan/SKILL.md +1 -0
  25. package/adapters/hermes/skills/flow-work-README/SKILL.md +4 -0
  26. package/adapters/hermes/skills/flow-work-handoff/SKILL.md +19 -5
  27. package/adapters/hermes/skills/flow-work-run/SKILL.md +18 -2
  28. package/adapters/opencode/CORE.md +12 -5
  29. package/adapters/opencode/commands/flow-bug-fix.md +9 -1
  30. package/adapters/opencode/commands/flow-bug-investigate.md +11 -0
  31. package/adapters/opencode/commands/flow-feat-build.md +9 -2
  32. package/adapters/opencode/commands/flow-feat-design.md +30 -0
  33. package/adapters/opencode/commands/flow-feat-plan.md +1 -0
  34. package/adapters/opencode/commands/flow-work-README.md +4 -0
  35. package/adapters/opencode/commands/flow-work-handoff.md +19 -5
  36. package/adapters/opencode/commands/flow-work-run.md +18 -2
  37. package/package.json +1 -1
  38. package/plugins/flow/.claude-plugin/plugin.json +1 -1
  39. package/plugins/flow/CHANGELOG.md +28 -0
@@ -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.92.0`.** Compare it once, at the start of the session, against
20
+ **This file belongs to flow `0.93.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
@@ -253,7 +253,7 @@ assumed:
253
253
  <cmd> ask --question-file F --options-file F [--recommended N] [--free-text] [--gate NAME]
254
254
  <cmd> publish --title-file F --body-file F [--part N --of M]
255
255
  <cmd> blocked --reason-file F
256
- <cmd> done [--summary-file F]
256
+ <cmd> done [--summary-file F] [--depends-on N]…
257
257
  <cmd> reply --thread ID --body-file F
258
258
  ```
259
259
 
@@ -314,12 +314,18 @@ runs the study phases as any run does, and three rules make it stop where it sho
314
314
  study to code crosses that door, an answered question that resumes straight into `build`
315
315
  included, so the phases before it carry no clause. The run kind is read there, never stored: the
316
316
  approval reuses the same work folder with `why = start`.
317
- - **At the door**, a study run first writes the statement of the change when the study holds none
317
+ - **At the door**, a study run first checks each `meta.json.ticket_deps` entry: `N` = its `ticket`
318
+ without a leading `#`, the form `ticket --json` prints `number`, and it must match
319
+ `[A-Za-z0-9][A-Za-z0-9._-]*` — an `N` that does not (a space, a shell character, a leading `-`)
320
+ is never put on a command line: `blocked`, naming the entry, before anything below is written.
321
+ Then it writes the statement of the change when the study holds none
318
322
  (the command says which), then `done-summary.md` — the `flow-study` block of `/flow-work-handoff`
319
323
  §5, the same sections from the same sources, and, when `01-context.md` lists `## Study revisions`,
320
324
  the line `Revised at the reviewer's request: <n> reply(ies)` first under `## What and why`. It
321
325
  overwrites `00-summary.md`, sets the panel's `attention` to `done` and closes with
322
- `done --summary-file`. Nothing else moves — no `mrs[]` entry, no branch, no brief — so
326
+ `done --summary-file`, plus one `--depends-on N` per `meta.json.ticket_deps` entry, in its order —
327
+ so the orchestrator can hold the ticket until those land; what it does with them is its call.
328
+ Nothing else moves — no `mrs[]` entry, no branch, no brief — so
323
329
  `meta.json.phase` stays at the last study phase and approval is an ordinary `start`.
324
330
  - **A person's changes rewind the study.** `/flow-work-run` §2 adds the reply to the ticket in
325
331
  `01-context.md` and sends the work back to `context`; the study phases then run again whole, the
@@ -332,7 +338,7 @@ person asking for changes, a ticket that already has code — is `/flow-work-run
332
338
  | Where | In `unattended` |
333
339
  |---|---|
334
340
  | 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 |
341
+ | 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
342
  | 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
343
  | 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
344
  | `review` with blockers or high-severity findings | question `high_findings` |
@@ -352,6 +358,7 @@ person asking for changes, a ticket that already has code — is `/flow-work-run
352
358
  | The next MR/PR of a train (`ship` close) | record — not started: one MR/PR per unattended run |
353
359
  | `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
360
  | The parent of a stacked MR/PR merged — rebase and force-push | blocked — never force-push unattended |
361
+ | 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
362
  | 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
363
  | 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
364
  | 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 |
@@ -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`. Nothing else in this command runs.
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:
@@ -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`. Nothing else in this command
37
- runs.
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`".)
@@ -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
 
@@ -112,6 +112,9 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
112
112
  "note": "reason if closed/superseded; empty otherwise"
113
113
  }
114
114
  ],
115
+ "ticket_deps": [
116
+ { "ticket": "#253", "why": "one line, what that ticket brings that the base branch lacks" }
117
+ ],
115
118
  "related_repos": [
116
119
  { "repo": "sibling-project", "scope": "what's needed there", "status": "pending" | "in_progress" | "done", "contract_handoff": "none" | "pending" | "published → <location>" }
117
120
  ],
@@ -160,6 +163,7 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
160
163
  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.
161
164
  - **`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.
162
165
  - **`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.
166
+ - **`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.
163
167
  - **`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.
164
168
  - **`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.
165
169
  - **`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.
@@ -148,13 +148,27 @@ the ticket read it there, never in the work folder; the receiver does not parse
148
148
  <!-- end flow-study -->
149
149
  ```
150
150
 
151
- Criteria keep their literal values. The plan lists each MR/PR with what it covers and what it
152
- waits on; a bug's plan is its single fix.
151
+ Criteria keep their literal values. `## Design in brief` ends with each `meta.json.ticket_deps`
152
+ entry and its why — `Depends on #253: <why>` — so whoever approves the study sees what it waits
153
+ for; an unattended study's `done-summary.md` is this block, so it carries them too. The plan
154
+ lists each MR/PR with what it covers and what it waits on; a bug's plan is its single fix.
153
155
  - **The new body**: the body read above with the block between the two markers replaced — or, with
154
- no markers yet, the block appended after a blank line. Written to a `mktemp` file outside the
156
+ no markers yet, the block appended after a blank line. Then, for each `meta.json.ticket_deps`
157
+ entry (`/flow-feat-design` §5.1) whose line is not already a line of that body — same text,
158
+ ignoring case and surrounding whitespace — one line after the end marker, in `ticket_deps` order:
159
+
160
+ ```
161
+ Depends on #253
162
+ ```
163
+
164
+ `#253` being the entry's `ticket` as it stands. Outside the markers so a later rewrite of the
165
+ block leaves it alone, and never removed: a line a person wrote by hand looks exactly like one
166
+ flow wrote, and the convention is theirs too. Written to a `mktemp` file outside the
155
167
  tree — `{BODY_FILE}` — so nothing of it can be committed later.
156
- - **Show the block and ask** with `AskUserQuestion`, **in every mode**: it writes to a shared
157
- tracker. **Write it** · **Skip**. Failure → its message in one line; the push stands.
168
+ - **Show the block, and the `Depends on` lines it adds, and ask** with `AskUserQuestion`, **in
169
+ every mode**: it writes to a shared tracker. A `Depends on` line already in the body, outside the
170
+ markers, that no entry names — a dependency a revised study dropped, or one a person added — is named in the same
171
+ 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.
158
172
 
159
173
  ## 6. Close
160
174
 
@@ -67,7 +67,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
67
67
  | `conflict` | exists | `/flow-work-green` — the MR/PR conflicts with its base; which base, and where it stands, come from `<cmd> events --json` |
68
68
  | `review` · `pipeline` · `conflict` | none | `blocked` — there is no work of this ticket to answer for |
69
69
 
70
- **The work's branch, on `start` and `study`.** The current branch is `meta.json.branch` → nothing to do. It is
70
+ **The work's branch, on `start` and `study`.** The current branch is `meta.json.branch` → no switch. It is
71
71
  not — a study made on another machine arrives on the ticket's `base`, a run that died before its
72
72
  closing order is relaunched there — then, in this order:
73
73
 
@@ -90,6 +90,21 @@ closing order is relaunched there — then, in this order:
90
90
  `meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
91
91
  other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
92
92
 
93
+ **On `start`, a study's branch catches up with its base** — once on the work's branch, the "no
94
+ switch" case included, and only while no build or fix has begun (neither `05-implementation.md` nor
95
+ `04-fix.md` exists). Every command below runs in the work's own checkout — step 2's worktree when
96
+ that is where it lives. A study writes no code, so its branch still sits where the base was when the
97
+ study began; an approval that waited for the tickets the study depends on (`meta.json.ticket_deps`)
98
+ would otherwise build on a base that lacks them. `<base>` = `meta.json.base`, empty →
99
+ `git.default_base`: `git fetch origin <base>`, then `<ref>` = `origin/<base>`; the fetch failing
100
+ with a remote configured → `blocked`, since a stale ref would leave the build on the old base
101
+ unnoticed. No remote → the local `<base>`. `git merge-base --is-ancestor HEAD <ref>` and `HEAD` is not
102
+ `<ref>` → the branch holds no commit of its own and the base moved: `git merge --ff-only <ref>`, and
103
+ record `{ "key": "unattended:base-caught-up", "default": "<old short sha> → <new short sha> on
104
+ <base>", "phase": "run" }`. The fast-forward fails → `blocked`, its message as the reason. Not an
105
+ ancestor → it holds commits a previous run made: leave it as it is — bringing the base into work in
106
+ progress is the orchestrator's (flow-core §2.1).
107
+
93
108
  **A person's changes to a study, on `study`** (flow-core §2.1: they rewind it). The work's branch
94
109
  first, as above. `<work>/study-revision.md` holds the reply, as the row above wrote it. Each step
95
110
  can be run again: a run that dies part-way is finished by the next relaunch, whatever it serves.
@@ -113,7 +128,8 @@ can be run again: a run that dies part-way is finished by the next relaunch, wha
113
128
  `study-revision.md` and earlier `before-*/` folders into `<work>/before-<id7>/` — never
114
129
  overwriting a name already there — so no artifact, summary or agent answer of the discarded study
115
130
  leaks into the next. Then `meta.json`: `phase` = `context`, `phases_done` = `["context"]`, `mrs`
116
- removed (the row that blocks a work past the study guarantees nothing was built), `notes`
131
+ removed (the row that blocks a work past the study guarantees nothing was built), `ticket_deps`
132
+ removed (the redone study finds its dependencies again), `notes`
117
133
  emptied, and every `followups[]` entry a study phase wrote (`source` `design`, `plan` or
118
134
  `investigate`) removed.
119
135
  5. **Re-size**: estimate the size again with `/flow-feat-start` §4's table (`/flow-bug-start`'s for
@@ -16,7 +16,7 @@ Every `/flow-*` command assumes these rules. They are stated once, here, so a co
16
16
  carries what is specific to its phase. Read this once per session; a command that says "load
17
17
  `flow-core`" means this file.
18
18
 
19
- **This file belongs to flow `0.92.0`.** Compare it once, at the start of the session, against
19
+ **This file belongs to flow `0.93.0`.** Compare it once, at the start of the session, against
20
20
  `version` in `~/.claude/flow/.claude-plugin/plugin.json`. The two differing means the session
21
21
  is running a **mixture** — the commands from one copy of the plugin, these shared rules from another
22
22
  — which is exactly what happens when a branch or a release candidate is loaded over an installed
@@ -252,7 +252,7 @@ assumed:
252
252
  <cmd> ask --question-file F --options-file F [--recommended N] [--free-text] [--gate NAME]
253
253
  <cmd> publish --title-file F --body-file F [--part N --of M]
254
254
  <cmd> blocked --reason-file F
255
- <cmd> done [--summary-file F]
255
+ <cmd> done [--summary-file F] [--depends-on N]…
256
256
  <cmd> reply --thread ID --body-file F
257
257
  ```
258
258
 
@@ -313,12 +313,18 @@ runs the study phases as any run does, and three rules make it stop where it sho
313
313
  study to code crosses that door, an answered question that resumes straight into `build`
314
314
  included, so the phases before it carry no clause. The run kind is read there, never stored: the
315
315
  approval reuses the same work folder with `why = start`.
316
- - **At the door**, a study run first writes the statement of the change when the study holds none
316
+ - **At the door**, a study run first checks each `meta.json.ticket_deps` entry: `N` = its `ticket`
317
+ without a leading `#`, the form `ticket --json` prints `number`, and it must match
318
+ `[A-Za-z0-9][A-Za-z0-9._-]*` — an `N` that does not (a space, a shell character, a leading `-`)
319
+ is never put on a command line: `blocked`, naming the entry, before anything below is written.
320
+ Then it writes the statement of the change when the study holds none
317
321
  (the command says which), then `done-summary.md` — the `flow-study` block of `/flow-work-handoff`
318
322
  §5, the same sections from the same sources, and, when `01-context.md` lists `## Study revisions`,
319
323
  the line `Revised at the reviewer's request: <n> reply(ies)` first under `## What and why`. It
320
324
  overwrites `00-summary.md`, sets the panel's `attention` to `done` and closes with
321
- `done --summary-file`. Nothing else moves — no `mrs[]` entry, no branch, no brief — so
325
+ `done --summary-file`, plus one `--depends-on N` per `meta.json.ticket_deps` entry, in its order —
326
+ so the orchestrator can hold the ticket until those land; what it does with them is its call.
327
+ Nothing else moves — no `mrs[]` entry, no branch, no brief — so
322
328
  `meta.json.phase` stays at the last study phase and approval is an ordinary `start`.
323
329
  - **A person's changes rewind the study.** `/flow-work-run` §2 adds the reply to the ticket in
324
330
  `01-context.md` and sends the work back to `context`; the study phases then run again whole, the
@@ -331,7 +337,7 @@ person asking for changes, a ticket that already has code — is `/flow-work-run
331
337
  | Where | In `unattended` |
332
338
  |---|---|
333
339
  | 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 |
334
- | 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 |
340
+ | 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 |
335
341
  | 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 |
336
342
  | 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` |
337
343
  | `review` with blockers or high-severity findings | question `high_findings` |
@@ -351,6 +357,7 @@ person asking for changes, a ticket that already has code — is `/flow-work-run
351
357
  | The next MR/PR of a train (`ship` close) | record — not started: one MR/PR per unattended run |
352
358
  | `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 |
353
359
  | The parent of a stacked MR/PR merged — rebase and force-push | blocked — never force-push unattended |
360
+ | 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 |
354
361
  | 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 |
355
362
  | 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 |
356
363
  | 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 |
@@ -34,7 +34,15 @@ Read `~/.claude/flow/CORE.opencode.md` first (shared rules: `FLOW.md` step 0, mo
34
34
  would make — from the root cause and the constraints for the fix when the investigation has them,
35
35
  the reproduction and the ticket otherwise, `## Study revisions` included — the person approves a
36
36
  stated change, never `none`; then the summary, and
37
- `<cmd> done --summary-file <work>/done-summary.md`. Nothing else in this command runs.
37
+ `<cmd> done --summary-file <work>/done-summary.md`, plus `--depends-on N` per
38
+ `meta.json.ticket_deps` entry, `N` its `ticket` with the leading `#` dropped — a bare `#` starts a
39
+ shell comment — and checked against `[A-Za-z0-9][A-Za-z0-9._-]*` before anything is written, else
40
+ `blocked` (flow-core §2.1). Nothing else in this command runs.
41
+ - **`meta.json.ticket_deps` not empty, and not `unattended`** → the study rests on other tickets
42
+ (`/flow-feat-design` §5.1): name each — `<ticket> — <why>` — in the brief's stop (§2), one line,
43
+ so whoever builds confirms the piece is on **this work's branch**, not only on its base — the
44
+ branch was cut when the study began, and a piece that merged since needs the base brought in
45
+ before writing against it. Nothing is checked; waiting is the builder's call.
38
46
  - `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.
39
47
  - **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).
40
48
  - `size` ≥ S: require `investigate` in `phases_done` (on S it will have run its reproduction half only).
@@ -172,10 +172,21 @@ If `agents.fanout_tool` is set in `FLOW.md`, run the sweep through that tool; br
172
172
  - Do not touch X because…
173
173
  - Consider Y because…
174
174
 
175
+ ## Depends on other tickets
176
+ <§4.1: `- <ticket> — <what it brings that the base branch lacks>`, then "Not dependencies (either order works)", or "none".>
177
+
175
178
  ## Investigation challenges
176
179
  <filled in by §5 with the challenger table>
177
180
  ```
178
181
 
182
+ ### 4.1 Tickets this fix depends on
183
+
184
+ A fix can rest on another ticket the same way a design can — a corrected contract, a migration, a
185
+ decision that lands only when that ticket merges. Detect and record it before the challenger, exactly
186
+ as `/flow-feat-design` §5.1 says: the same rule, the same "Not dependencies (either order works)"
187
+ line, the same `meta.json.ticket_deps` entries, written under `## Depends on other tickets` in
188
+ `03-investigation.md`.
189
+
179
190
  ## 5. Root cause challenge (challenger)
180
191
 
181
192
  Before closing, launch a `Agent general-purpose` challenger with this task:
@@ -31,8 +31,15 @@ Implementation phase. Code is written here.
31
31
  and act as flow-core §2.1 "A study run" says. On `study` → this run writes no code: `size` XS and
32
32
  no `03-design.md` → first write the 2–3 line note below as that file, from `01-context.md` (its
33
33
  `## Study revisions` included) — the person approves a stated change, never `none`; then the
34
- summary, and `<cmd> done --summary-file <work>/done-summary.md`. Nothing else in this command
35
- runs.
34
+ summary, and `<cmd> done --summary-file <work>/done-summary.md`, plus `--depends-on N` per
35
+ `meta.json.ticket_deps` entry, `N` its `ticket` with the leading `#` dropped — a bare `#` starts a
36
+ shell comment — and checked against `[A-Za-z0-9][A-Za-z0-9._-]*` before anything is written, else
37
+ `blocked` (flow-core §2.1). Nothing else in this command runs.
38
+ - **`meta.json.ticket_deps` not empty, and not `unattended`** → the study rests on other tickets
39
+ (`/flow-feat-design` §5.1): name each — `<ticket> — <why>` — in the brief's stop (§2), one line,
40
+ so whoever builds confirms the piece is on **this work's branch**, not only on its base — the
41
+ branch was cut when the study began, and a piece that merged since needs the base brought in
42
+ before writing against it. Nothing is checked; waiting is the builder's call.
36
43
  - `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`.
37
44
  - `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).
38
45
  - **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`".)
@@ -288,6 +288,9 @@ Consolidate outputs into `.claude/work/<TICKET>/03-design.md`:
288
288
  - **Invariant**: <e.g. "after assignTo(user), ticket.assignee == user AND ticket.status != 'unassigned'">
289
289
  - **Edge / boundary**: <e.g. "empty input list → returns 0, does not throw">
290
290
 
291
+ ## Depends on other tickets
292
+ <§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".>
293
+
291
294
  ## Defensive mechanisms and their justification
292
295
  <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.>
293
296
 
@@ -316,6 +319,33 @@ Consolidate outputs into `.claude/work/<TICKET>/03-design.md`:
316
319
 
317
320
  **"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.
318
321
 
322
+ ### 5.1 Tickets this design depends on
323
+
324
+ Fill `## Depends on other tickets` now, before the challenger of §6 reads the design. The study is
325
+ often built by someone who never saw it made — another person, an unattended server — and who
326
+ starts from the base. A design that rests on what another ticket has not delivered yet leaves that
327
+ builder to find the piece missing and either ask or redo it.
328
+
329
+ - **A dependency** is a piece, contract or decision the chosen design needs, that is **not on the
330
+ base this work builds from** (`meta.json.base`, empty → `git.default_base`) — checked there, after
331
+ a best-effort `git fetch origin <base>`, never assumed from a local ref — and that **another
332
+ ticket** of this tracker brings. Missing from the base with no ticket bringing it → it is scope
333
+ or an open question, not a dependency. A ticket in another repo is not a `ticket_deps` entry —
334
+ the orchestrator only resolves this tracker's numbers — so write it in the section as a
335
+ cross-repo dependency, for a person, and leave it out of the list.
336
+ - **Not a dependency**: a premise that holds whichever ticket merges first. Say so under "Not
337
+ dependencies (either order works)", so nobody waits for it.
338
+ - **Record each one** in that section and in `meta.json.ticket_deps` —
339
+ `{ "ticket": "<the reference as a ticket body writes it: #253, MT-123>", "why": "<one line>" }`,
340
+ never one twice. `ticket_deps` is the record the exits read (`/flow-work-handoff` §5, the door to
341
+ code of an unattended study run, flow-core §2.1); the section is the study's prose. Each run of
342
+ this phase writes the list whole from the design it closes; `plan`, which runs after it, appends
343
+ its own again. A §6 response or a §9 edit that changes what the design needs changes
344
+ the section and the list together. None → `[]` and "none".
345
+
346
+ `ticket_deps` is not `mrs[].depends_on`: that one orders this work's own MRs/PRs, this one names
347
+ other tickets. Flow never checks whether a dependency has closed — whoever builds waits for it.
348
+
319
349
  ## 6. Design challenge (challenger)
320
350
 
321
351
  Before closing, **challenge the design** with an `Agent general-purpose` and this self-contained brief:
@@ -124,6 +124,7 @@ Add the `mrs` array with the agreed plan:
124
124
  ```
125
125
 
126
126
  - `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.
127
+ - **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.
127
128
  - **`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.
128
129
  - 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.
129
130
 
@@ -110,6 +110,9 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
110
110
  "note": "reason if closed/superseded; empty otherwise"
111
111
  }
112
112
  ],
113
+ "ticket_deps": [
114
+ { "ticket": "#253", "why": "one line, what that ticket brings that the base branch lacks" }
115
+ ],
113
116
  "related_repos": [
114
117
  { "repo": "sibling-project", "scope": "what's needed there", "status": "pending" | "in_progress" | "done", "contract_handoff": "none" | "pending" | "published → <location>" }
115
118
  ],
@@ -158,6 +161,7 @@ This system **orchestrates** the project's existing sub-agents and skills (it do
158
161
  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.
159
162
  - **`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.
160
163
  - **`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.
164
+ - **`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.
161
165
  - **`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.
162
166
  - **`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.
163
167
  - **`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.
@@ -146,13 +146,27 @@ the ticket read it there, never in the work folder; the receiver does not parse
146
146
  <!-- end flow-study -->
147
147
  ```
148
148
 
149
- Criteria keep their literal values. The plan lists each MR/PR with what it covers and what it
150
- waits on; a bug's plan is its single fix.
149
+ Criteria keep their literal values. `## Design in brief` ends with each `meta.json.ticket_deps`
150
+ entry and its why — `Depends on #253: <why>` — so whoever approves the study sees what it waits
151
+ for; an unattended study's `done-summary.md` is this block, so it carries them too. The plan
152
+ lists each MR/PR with what it covers and what it waits on; a bug's plan is its single fix.
151
153
  - **The new body**: the body read above with the block between the two markers replaced — or, with
152
- no markers yet, the block appended after a blank line. Written to a `mktemp` file outside the
154
+ no markers yet, the block appended after a blank line. Then, for each `meta.json.ticket_deps`
155
+ entry (`/flow-feat-design` §5.1) whose line is not already a line of that body — same text,
156
+ ignoring case and surrounding whitespace — one line after the end marker, in `ticket_deps` order:
157
+
158
+ ```
159
+ Depends on #253
160
+ ```
161
+
162
+ `#253` being the entry's `ticket` as it stands. Outside the markers so a later rewrite of the
163
+ block leaves it alone, and never removed: a line a person wrote by hand looks exactly like one
164
+ flow wrote, and the convention is theirs too. Written to a `mktemp` file outside the
153
165
  tree — `{BODY_FILE}` — so nothing of it can be committed later.
154
- - **Show the block and ask** with `AskUserQuestion`, **in every mode**: it writes to a shared
155
- tracker. **Write it** · **Skip**. Failure → its message in one line; the push stands.
166
+ - **Show the block, and the `Depends on` lines it adds, and ask** with `AskUserQuestion`, **in
167
+ every mode**: it writes to a shared tracker. A `Depends on` line already in the body, outside the
168
+ markers, that no entry names — a dependency a revised study dropped, or one a person added — is named in the same
169
+ 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.
156
170
 
157
171
  ## 6. Close
158
172
 
@@ -65,7 +65,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
65
65
  | `conflict` | exists | `/flow-work-green` — the MR/PR conflicts with its base; which base, and where it stands, come from `<cmd> events --json` |
66
66
  | `review` · `pipeline` · `conflict` | none | `blocked` — there is no work of this ticket to answer for |
67
67
 
68
- **The work's branch, on `start` and `study`.** The current branch is `meta.json.branch` → nothing to do. It is
68
+ **The work's branch, on `start` and `study`.** The current branch is `meta.json.branch` → no switch. It is
69
69
  not — a study made on another machine arrives on the ticket's `base`, a run that died before its
70
70
  closing order is relaunched there — then, in this order:
71
71
 
@@ -88,6 +88,21 @@ closing order is relaunched there — then, in this order:
88
88
  `meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
89
89
  other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
90
90
 
91
+ **On `start`, a study's branch catches up with its base** — once on the work's branch, the "no
92
+ switch" case included, and only while no build or fix has begun (neither `05-implementation.md` nor
93
+ `04-fix.md` exists). Every command below runs in the work's own checkout — step 2's worktree when
94
+ that is where it lives. A study writes no code, so its branch still sits where the base was when the
95
+ study began; an approval that waited for the tickets the study depends on (`meta.json.ticket_deps`)
96
+ would otherwise build on a base that lacks them. `<base>` = `meta.json.base`, empty →
97
+ `git.default_base`: `git fetch origin <base>`, then `<ref>` = `origin/<base>`; the fetch failing
98
+ with a remote configured → `blocked`, since a stale ref would leave the build on the old base
99
+ unnoticed. No remote → the local `<base>`. `git merge-base --is-ancestor HEAD <ref>` and `HEAD` is not
100
+ `<ref>` → the branch holds no commit of its own and the base moved: `git merge --ff-only <ref>`, and
101
+ record `{ "key": "unattended:base-caught-up", "default": "<old short sha> → <new short sha> on
102
+ <base>", "phase": "run" }`. The fast-forward fails → `blocked`, its message as the reason. Not an
103
+ ancestor → it holds commits a previous run made: leave it as it is — bringing the base into work in
104
+ progress is the orchestrator's (flow-core §2.1).
105
+
91
106
  **A person's changes to a study, on `study`** (flow-core §2.1: they rewind it). The work's branch
92
107
  first, as above. `<work>/study-revision.md` holds the reply, as the row above wrote it. Each step
93
108
  can be run again: a run that dies part-way is finished by the next relaunch, whatever it serves.
@@ -111,7 +126,8 @@ can be run again: a run that dies part-way is finished by the next relaunch, wha
111
126
  `study-revision.md` and earlier `before-*/` folders into `<work>/before-<id7>/` — never
112
127
  overwriting a name already there — so no artifact, summary or agent answer of the discarded study
113
128
  leaks into the next. Then `meta.json`: `phase` = `context`, `phases_done` = `["context"]`, `mrs`
114
- removed (the row that blocks a work past the study guarantees nothing was built), `notes`
129
+ removed (the row that blocks a work past the study guarantees nothing was built), `ticket_deps`
130
+ removed (the redone study finds its dependencies again), `notes`
115
131
  emptied, and every `followups[]` entry a study phase wrote (`source` `design`, `plan` or
116
132
  `investigate`) removed.
117
133
  5. **Re-size**: estimate the size again with `/flow-feat-start` §4's table (`/flow-bug-start`'s for
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-workflows",
3
- "version": "0.92.0",
3
+ "version": "0.93.0",
4
4
  "description": "Guided feat/bug workflows (start→ship), post-deploy monitoring and multi-agent code review, stack-agnostic. Each repo uses a shared FLOW.md plus optional harness overlay.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3,7 +3,7 @@
3
3
  "name": "flow",
4
4
  "displayName": "Flow — guided dev workflows",
5
5
  "description": "Guided feat/bug workflows (start→ship), post-deploy monitoring and multi-agent code review, stack-agnostic. Each repo uses a shared FLOW.md plus optional harness overlay.",
6
- "version": "0.92.0",
6
+ "version": "0.93.0",
7
7
  "author": {
8
8
  "name": "Alberto Vioque",
9
9
  "email": "mashware@gmail.com"