flow-workflows 0.85.0 → 0.86.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 (43) hide show
  1. package/adapters/codex/CORE.md +9 -2
  2. package/adapters/codex/skills/flow-bug-start/SKILL.md +1 -1
  3. package/adapters/codex/skills/flow-feat-build/SKILL.md +2 -2
  4. package/adapters/codex/skills/flow-feat-design/SKILL.md +1 -1
  5. package/adapters/codex/skills/flow-feat-plan/SKILL.md +1 -1
  6. package/adapters/codex/skills/flow-feat-ship/SKILL.md +1 -1
  7. package/adapters/codex/skills/flow-feat-start/SKILL.md +1 -1
  8. package/adapters/codex/skills/flow-work-green/SKILL.md +1 -1
  9. package/adapters/codex/skills/flow-work-respond/SKILL.md +1 -1
  10. package/adapters/codex/skills/flow-work-run/SKILL.md +26 -3
  11. package/adapters/gemini/CORE.md +9 -2
  12. package/adapters/gemini/commands/flow/bug/start.toml +1 -1
  13. package/adapters/gemini/commands/flow/feat/build.toml +2 -2
  14. package/adapters/gemini/commands/flow/feat/design.toml +1 -1
  15. package/adapters/gemini/commands/flow/feat/plan.toml +1 -1
  16. package/adapters/gemini/commands/flow/feat/ship.toml +1 -1
  17. package/adapters/gemini/commands/flow/feat/start.toml +1 -1
  18. package/adapters/gemini/commands/flow/work/green.toml +1 -1
  19. package/adapters/gemini/commands/flow/work/respond.toml +1 -1
  20. package/adapters/gemini/commands/flow/work/run.toml +26 -3
  21. package/adapters/hermes/CORE.md +9 -2
  22. package/adapters/hermes/skills/flow-bug-start/SKILL.md +1 -1
  23. package/adapters/hermes/skills/flow-feat-build/SKILL.md +2 -2
  24. package/adapters/hermes/skills/flow-feat-design/SKILL.md +1 -1
  25. package/adapters/hermes/skills/flow-feat-plan/SKILL.md +1 -1
  26. package/adapters/hermes/skills/flow-feat-ship/SKILL.md +1 -1
  27. package/adapters/hermes/skills/flow-feat-start/SKILL.md +1 -1
  28. package/adapters/hermes/skills/flow-work-green/SKILL.md +1 -1
  29. package/adapters/hermes/skills/flow-work-respond/SKILL.md +1 -1
  30. package/adapters/hermes/skills/flow-work-run/SKILL.md +26 -3
  31. package/adapters/opencode/CORE.md +9 -2
  32. package/adapters/opencode/commands/flow-bug-start.md +1 -1
  33. package/adapters/opencode/commands/flow-feat-build.md +2 -2
  34. package/adapters/opencode/commands/flow-feat-design.md +1 -1
  35. package/adapters/opencode/commands/flow-feat-plan.md +1 -1
  36. package/adapters/opencode/commands/flow-feat-ship.md +1 -1
  37. package/adapters/opencode/commands/flow-feat-start.md +1 -1
  38. package/adapters/opencode/commands/flow-work-green.md +1 -1
  39. package/adapters/opencode/commands/flow-work-respond.md +1 -1
  40. package/adapters/opencode/commands/flow-work-run.md +26 -3
  41. package/package.json +1 -1
  42. package/plugins/flow/.claude-plugin/plugin.json +1 -1
  43. package/plugins/flow/CHANGELOG.md +22 -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.85.0`.** Compare it once, at the start of the session, against
20
+ **This file belongs to flow `0.86.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
@@ -258,11 +258,17 @@ assumed:
258
258
  recommended one first), title, body, reason and summary are written into the work folder
259
259
  (`ask-question.md`, `ask-options.md`, `publish-title.md`, `publish-body.md`, `blocked-reason.md`,
260
260
  `done-summary.md`) — or a `mktemp -d` directory before the folder exists — and passed by path. A
261
- backtick or a quote in a ticket title must never meet a shell.
261
+ backtick or a quote in a ticket title must never meet a shell. `publish-title.md` holds **one
262
+ line**, the title alone — no `#`, no second line: the orchestrator refuses a title file with two.
262
263
  - **The orchestrator pushes and opens the MR/PR; the run never does.** No `git push`, no `gh`, no
263
264
  `glab`, no tracker write in this mode — not before `ship`, not in it. The orchestrator also keeps,
264
265
  between runs, the work folder as the run left it and the work branch at the commit where it
265
266
  stopped; the run trusts that and does not re-check it.
267
+ - **The work is the one `$flow-work-run` found** — by the ticket's `number`, never by the current
268
+ branch. A phase whose pre-flight says "load `meta.json` by current branch" takes that work instead:
269
+ the checkout can be the ticket's `base` (a study restored from elsewhere) or an umbrella branch (a
270
+ part just merged), and neither names the work. `run` puts a work whose branch is not checked out
271
+ back on it before handing over (its §2).
266
272
  - **Before any closing order, commit** what this run left uncommitted outside `.claude/work/`, new
267
273
  files included (`WIP <TICKET>: before <gate|order>` — `auto`'s WIP authority): the orchestrator
268
274
  keeps only what is committed. **Only on the work branch**: before it exists (`start` refusing a
@@ -297,6 +303,7 @@ run has.
297
303
  | Clarifying questions on the ticket (`start`) | question `clarify` — after the branch and the work folder exist, with the questions also written to `01-context.md` |
298
304
  | An unanswered high-severity challenge (`design`, `investigate`) | question `design_challenge` / `investigation_challenge` |
299
305
  | `<cmd> ticket` failing or empty, a checkout that is not clean on the ticket's `base` (`start`) | blocked — the orchestrator owns the checkout and the ticket |
306
+ | A work whose branch is not checked out (`run`) | as `$flow-work-run` §2 says — switch onto a branch an unattended run made, or record `unattended:rehomed` and create `<number>-<slug>` from `base`; blocked on a dirty checkout or a branch with the work's name that no run here recorded |
300
307
  | Below-XS check (`start`) | record — open the work |
301
308
  | "Create the branch?" (`start`), the 2–3 line note an XS `build`/`fix` asks for, a contract the design left in prose (`build`) | record — create it · write the note from the ticket · convert it to literal and say so in the artifact |
302
309
  | `git.worktree: ask` | record — in place |
@@ -183,7 +183,7 @@ Create the work directory per §0: `.claude/work/<TICKET>-<slug>/` in ticket mod
183
183
 
184
184
  **Live panel**: publish it now (flow-core §4 — the panel tools, or `<work-dir>/panel.json`). A bug has no MR/PR train, so it is short: the title (the symptom, `style: title`), a `Now` line for what is starting, a `Next` line for the phase this size routes to, and any sibling repo from §1.6 as a `block` line. Every later phase updates it.
185
185
 
186
- In `unattended`, add `"base"`: the ticket's `base`, the branch the fix starts from and targets. Omit it in every other mode.
186
+ In `unattended`, add `"base"`: the ticket's `base`, or `git.default_base` when it is empty — never empty; the branch the fix starts from and targets. Omit it in every other mode.
187
187
 
188
188
  Populate `related_repos` from §1.6 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo the fix touches; `[]` for a single-repo fix. `pending` only when the fix **changes a surface that sibling consumes** (a payload key, an error code, a route, an event shape); otherwise `none`.
189
189
 
@@ -28,14 +28,14 @@ Implementation phase. Code is written here.
28
28
 
29
29
  ## 1. Pre-flight
30
30
 
31
- - Load `meta.json` by current branch. Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
31
+ - Load `meta.json` by current branch — in `unattended`, the work `$flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
32
32
  - `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`.
33
33
  - `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).
34
34
  - **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`".)
35
35
  - **Parallel siblings**: startable `pending` MRs/PRs in the **same `wave`** with no dependency between them can be built in parallel or as a train. `manual`: let the user choose which to take now (default: lowest `n`); `guided`/`auto`: take the lowest `n`, record the choice. Mark the chosen one `in_progress`.
36
36
  - All `merged` → warn: feature is done, nothing to build (in `unattended`: `done`, the summary saying so).
37
37
  - Some `pending` but **none** startable → start nothing: tell the user which MR/PR must merge to unlock the next wave, and stop. In `unattended`: `blocked`, the reason naming it.
38
- - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>` and created as `$flow-feat-start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `$flow-feat-ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `$flow-feat-start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `$flow-feat-start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
38
+ - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>`, written to `meta.json.branch` (a relaunch of this part then finds it) and created as `$flow-feat-start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `$flow-feat-ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `$flow-feat-start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `$flow-feat-start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
39
39
 
40
40
  ## 2. Business brief (before typing)
41
41
 
@@ -38,7 +38,7 @@ after writing each challenge's Response.
38
38
 
39
39
  ## 1. Pre-flight
40
40
 
41
- - Load `meta.json` by current branch. Missing → ask the user to start with `$flow-feat-start`.
41
+ - Load `meta.json` by current branch — in `unattended`, the work `$flow-work-run` found (flow-core §2.1). Missing → ask the user to start with `$flow-feat-start`.
42
42
  - Read `meta.json` and `00-summary.md`; open in full only `01-context.md` (ticket, decisions, contracts received). (flow-core §5)
43
43
  - `size` is `XS` → suggest jumping to `$flow-feat-build` and stop unless the user insists.
44
44
 
@@ -28,7 +28,7 @@ Delivery planning phase. **No code is written.** Splits the feature into MRs/PRs
28
28
 
29
29
  ## 1. Pre-flight
30
30
 
31
- - Load `meta.json` by current branch. Missing → send the user to `$flow-feat-start`.
31
+ - Load `meta.json` by current branch — in `unattended`, the work `$flow-work-run` found (flow-core §2.1). Missing → send the user to `$flow-feat-start`.
32
32
  - Require `design` in `phases_done`. Missing → send to `$flow-feat-design` and stop.
33
33
  - Read `meta.json` and `00-summary.md`; open in full only `03-design.md`. (flow-core §5)
34
34
  - **`size` `XS` or `S`** → warn that this phase does not apply (always 1 MR/PR), add `"plan:skipped"` to `phases_done`, suggest `$flow-feat-build`. Stop.
@@ -31,7 +31,7 @@ it hands the finished MR/PR to the orchestrator, which pushes the branch and ope
31
31
  place it would ask:
32
32
 
33
33
  - **The MR/PR itself (§3–§4)** — no confirmation and no forge. §2's title and description are
34
- written to `publish-title.md` and `publish-body.md` in the work folder; the body gains one line
34
+ written to `publish-title.md` (one line, the title alone) and `publish-body.md` in the work folder; the body gains one line
35
35
  saying an unattended run prepared it and nobody confirmed its brief. §4.0's branch check still
36
36
  runs (never the base; the name starts with `<ticket>-`) — and an upstream on the base is unset
37
37
  (`git branch --unset-upstream`), with no push after it. §4.1–§4.3 do not: no push, no
@@ -255,7 +255,7 @@ Create the work directory per §1: `.claude/work/<TICKET>-<slug>/` (ticket mode)
255
255
  ```
256
256
 
257
257
  - Ticket-less (§2.5) → `draft_from_conversation: true`, `tracker_issue` = created issue id/url (or `null` if local-only). Ticket mode → defaults above.
258
- - `base` — `unattended` only: the ticket's `base` (the branch every MR/PR of this work starts from and targets; `$flow-work-run` refreshes it on `merged`). Omit it in every other mode.
258
+ - `base` — `unattended` only: the ticket's `base`, or `git.default_base` when it is empty — never empty (the branch every MR/PR of this work starts from and targets; `$flow-work-run` refreshes it on `merged`). Omit it in every other mode.
259
259
  - `related_repos` from §3.5 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo; `[]` for a single-repo task.
260
260
  - **This work *is* an accepted follow-up** (the ticket came from another work's `followups[]`, flow-core §7) → set `origin: { "work": "<originating work dir>", "followup": "F<n>" }`, carry that entry's recorded `why` into `01-context.md` verbatim instead of re-deriving it, and set the originating entry to `in_progress` with `work` naming this folder. Not a follow-up → omit `origin` entirely.
261
261
 
@@ -70,7 +70,7 @@ resolve this way:
70
70
 
71
71
  ## 1. Pre-flight — locate the work and the MR/PR
72
72
 
73
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
73
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`) — in `unattended`, the work `$flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
74
74
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale, keep going.
75
75
  - Resolve the target MR/PR, in this order:
76
76
  1. `$ARGUMENTS` if given (IID or URL).
@@ -85,7 +85,7 @@ back through it, and the hard gates above resolve this way:
85
85
 
86
86
  ## 1. Pre-flight — locate the work and the MR/PR
87
87
 
88
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
88
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches) — in `unattended`, the work `$flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
89
89
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale to draw on, keep going — triage and reply loop still work.
90
90
  - Resolve the target MR/PR, in this order:
91
91
  1. `$ARGUMENTS` if given (IID or URL).
@@ -38,7 +38,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
38
38
  - Run `<cmd> why`. It fails, or prints anything but `start`, `answer`, `review`, `pipeline` or
39
39
  `merged` → print what it returned and its stderr in the §3 header and end. No closing order: an
40
40
  orchestrator that cannot say why it launched the run cannot take one either.
41
- - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent → `feat`).
41
+ - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent or `null` → `feat`: the tracker could not tell, so flow decides). `kind` is re-read on every run; only `start` uses it — once the work exists, its folder says feat or bug.
42
42
  It fails or prints no `number` → `blocked` (flow-core §2.1).
43
43
  - Find the work: the `meta.json` under `.claude/work/` whose `ticket` equals `number` (archive
44
44
  excluded). None is not an error — it is the "none" of the table below.
@@ -50,15 +50,38 @@ of truth, and an argument that disagrees with it is ignored and named in the log
50
50
  | `start` | none for this ticket | `$flow-feat-start <number>` — `$flow-bug-start <number>` when `kind` is `bug` |
51
51
  | `start` | exists, `pending` set | a stop whose `ask` never landed, or a crash after it: send the same question again — `ask` with `<work>/<pending.question_file>`, `<work>/<pending.options_file>`, `--recommended 1` when that options file is not empty, `--free-text` when `pending.free_text`, `--gate pending.gate` — and end. `pending` stays as it is; nothing is recomputed |
52
52
  | `start` | exists, an `mrs[]` entry `published`, or `meta.json.published` true (a work with no `mrs`) | `done` — the summary says it is waiting for that merge; the next launch for it is `merged` |
53
- | `start` | exists, nothing pending | the phase after `meta.json.phase` on this work's route (`$flow-feat-start` §4 for a feature, `$flow-bug-start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
53
+ | `start` | exists, nothing pending | the work's branch first (below), then the phase after `meta.json.phase` on this work's route (`$flow-feat-start` §4 for a feature, `$flow-bug-start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
54
54
  | `answer` | `pending` set | apply `<cmd> answer` as flow-core §2.1 "The answer comes back" says, then `pending.resume` at `pending.resume_at`. The order fails or prints nothing → `blocked` |
55
55
  | `answer` | nothing pending | `blocked` — there is no question for that answer to decide |
56
- | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read; the next startable MR/PR → `$flow-feat-build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
56
+ | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read (empty → `git.default_base`); the next startable MR/PR → `$flow-feat-build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
57
57
  | `merged` | none, or nothing published | `blocked` — nothing of this ticket was published from here |
58
58
  | `review` | exists | `$flow-work-respond` — the threads come from `<cmd> events --json` |
59
59
  | `pipeline` | exists | `$flow-work-green` — the failed jobs come from `<cmd> events --json` |
60
60
  | `review` · `pipeline` | none | `blocked` — there is no work of this ticket to answer for |
61
61
 
62
+ **The work's branch, on `start`.** The current branch is `meta.json.branch` → nothing to do. It is
63
+ not — a study made on another machine arrives on the ticket's `base`, a run that died before its
64
+ closing order is relaunched there — then, in this order:
65
+
66
+ 1. Anything `git status --porcelain` lists outside `.claude/work/` — untracked files included, since
67
+ the WIP commit before a closing order takes new files too → `blocked`: the orchestrator owns the
68
+ checkout.
69
+ 2. `meta.json.base` is set and `meta.json.worktree` is a worktree of this checkout (`git worktree
70
+ list`) whose branch is `meta.json.branch` → run the phase from there: `git switch` would refuse a
71
+ branch checked out elsewhere. A path that is not such a worktree falls through to step 3.
72
+ 3. `meta.json.base` is set — the work was started or re-homed by an unattended run, so its branch is
73
+ one this kind of run made — and `meta.json.branch` exists locally → `git switch` onto it, change
74
+ nothing. It holds the commits a previous run left.
75
+ 4. `<number>-<slug>` (`slug` from `meta.json`), or `meta.json.branch` without `meta.json.base`,
76
+ exists locally → `blocked`, naming it: a branch with the work's name that no run here recorded is
77
+ history nobody can vouch for.
78
+ 5. Otherwise create it as `$flow-feat-start` does in this mode: `git switch --create <name>
79
+ --no-track <base>` (`base` empty → `git.default_base`), `<name>` being `<number>-<slug>`, or
80
+ `<number>-<slug>-<n>` when the `in_progress` entry of `meta.json.mrs` has `n` > 1 — the name
81
+ `$flow-feat-build` gives that part, since the first part's name is already published. Then
82
+ `meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
83
+ other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
84
+
62
85
  The phase you hand the run to is unattended too: it reads §2.1, chains as `auto` and makes the
63
86
  run's one closing order. This command makes none of its own except the re-sent `ask`, the `blocked`
64
87
  and the `done` of the table above.
@@ -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.85.0`.** Compare it once, at the start of the session, against
19
+ **This file belongs to flow `0.86.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
@@ -257,11 +257,17 @@ assumed:
257
257
  recommended one first), title, body, reason and summary are written into the work folder
258
258
  (`ask-question.md`, `ask-options.md`, `publish-title.md`, `publish-body.md`, `blocked-reason.md`,
259
259
  `done-summary.md`) — or a `mktemp -d` directory before the folder exists — and passed by path. A
260
- backtick or a quote in a ticket title must never meet a shell.
260
+ backtick or a quote in a ticket title must never meet a shell. `publish-title.md` holds **one
261
+ line**, the title alone — no `#`, no second line: the orchestrator refuses a title file with two.
261
262
  - **The orchestrator pushes and opens the MR/PR; the run never does.** No `git push`, no `gh`, no
262
263
  `glab`, no tracker write in this mode — not before `ship`, not in it. The orchestrator also keeps,
263
264
  between runs, the work folder as the run left it and the work branch at the commit where it
264
265
  stopped; the run trusts that and does not re-check it.
266
+ - **The work is the one `/flow:work:run` found** — by the ticket's `number`, never by the current
267
+ branch. A phase whose pre-flight says "load `meta.json` by current branch" takes that work instead:
268
+ the checkout can be the ticket's `base` (a study restored from elsewhere) or an umbrella branch (a
269
+ part just merged), and neither names the work. `run` puts a work whose branch is not checked out
270
+ back on it before handing over (its §2).
265
271
  - **Before any closing order, commit** what this run left uncommitted outside `.claude/work/`, new
266
272
  files included (`WIP <TICKET>: before <gate|order>` — `auto`'s WIP authority): the orchestrator
267
273
  keeps only what is committed. **Only on the work branch**: before it exists (`start` refusing a
@@ -296,6 +302,7 @@ run has.
296
302
  | Clarifying questions on the ticket (`start`) | question `clarify` — after the branch and the work folder exist, with the questions also written to `01-context.md` |
297
303
  | An unanswered high-severity challenge (`design`, `investigate`) | question `design_challenge` / `investigation_challenge` |
298
304
  | `<cmd> ticket` failing or empty, a checkout that is not clean on the ticket's `base` (`start`) | blocked — the orchestrator owns the checkout and the ticket |
305
+ | A work whose branch is not checked out (`run`) | as `/flow:work:run` §2 says — switch onto a branch an unattended run made, or record `unattended:rehomed` and create `<number>-<slug>` from `base`; blocked on a dirty checkout or a branch with the work's name that no run here recorded |
299
306
  | Below-XS check (`start`) | record — open the work |
300
307
  | "Create the branch?" (`start`), the 2–3 line note an XS `build`/`fix` asks for, a contract the design left in prose (`build`) | record — create it · write the note from the ticket · convert it to literal and say so in the artifact |
301
308
  | `git.worktree: ask` | record — in place |
@@ -179,7 +179,7 @@ Create the work directory per §0: `.claude/work/<TICKET>-<slug>/` in ticket mod
179
179
 
180
180
  **Live panel**: publish it now (flow-core §4 — the panel tools, or `<work-dir>/panel.json`). A bug has no MR/PR train, so it is short: the title (the symptom, `style: title`), a `Now` line for what is starting, a `Next` line for the phase this size routes to, and any sibling repo from §1.6 as a `block` line. Every later phase updates it.
181
181
 
182
- In `unattended`, add `"base"`: the ticket's `base`, the branch the fix starts from and targets. Omit it in every other mode.
182
+ In `unattended`, add `"base"`: the ticket's `base`, or `git.default_base` when it is empty — never empty; the branch the fix starts from and targets. Omit it in every other mode.
183
183
 
184
184
  Populate `related_repos` from §1.6 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo the fix touches; `[]` for a single-repo fix. `pending` only when the fix **changes a surface that sibling consumes** (a payload key, an error code, a route, an event shape); otherwise `none`.
185
185
 
@@ -24,14 +24,14 @@ Implementation phase. Code is written here.
24
24
 
25
25
  ## 1. Pre-flight
26
26
 
27
- - Load `meta.json` by current branch. Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
27
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow:work:run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
28
28
  - `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`.
29
29
  - `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).
30
30
  - **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`".)
31
31
  - **Parallel siblings**: startable `pending` MRs/PRs in the **same `wave`** with no dependency between them can be built in parallel or as a train. `manual`: let the user choose which to take now (default: lowest `n`); `guided`/`auto`: take the lowest `n`, record the choice. Mark the chosen one `in_progress`.
32
32
  - All `merged` → warn: feature is done, nothing to build (in `unattended`: `done`, the summary saying so).
33
33
  - Some `pending` but **none** startable → start nothing: tell the user which MR/PR must merge to unlock the next wave, and stop. In `unattended`: `blocked`, the reason naming it.
34
- - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>` and created as `/flow:feat:start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `/flow:feat:ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `/flow:feat:start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `/flow:feat:start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
34
+ - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>`, written to `meta.json.branch` (a relaunch of this part then finds it) and created as `/flow:feat:start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `/flow:feat:ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `/flow:feat:start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `/flow:feat:start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
35
35
 
36
36
  ## 2. Business brief (before typing)
37
37
 
@@ -34,7 +34,7 @@ after writing each challenge's Response.
34
34
 
35
35
  ## 1. Pre-flight
36
36
 
37
- - Load `meta.json` by current branch. Missing → ask the user to start with `/flow:feat:start`.
37
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow:work:run` found (flow-core §2.1). Missing → ask the user to start with `/flow:feat:start`.
38
38
  - Read `meta.json` and `00-summary.md`; open in full only `01-context.md` (ticket, decisions, contracts received). (flow-core §5)
39
39
  - `size` is `XS` → suggest jumping to `/flow:feat:build` and stop unless the user insists.
40
40
 
@@ -24,7 +24,7 @@ Delivery planning phase. **No code is written.** Splits the feature into MRs/PRs
24
24
 
25
25
  ## 1. Pre-flight
26
26
 
27
- - Load `meta.json` by current branch. Missing → send the user to `/flow:feat:start`.
27
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow:work:run` found (flow-core §2.1). Missing → send the user to `/flow:feat:start`.
28
28
  - Require `design` in `phases_done`. Missing → send to `/flow:feat:design` and stop.
29
29
  - Read `meta.json` and `00-summary.md`; open in full only `03-design.md`. (flow-core §5)
30
30
  - **`size` `XS` or `S`** → warn that this phase does not apply (always 1 MR/PR), add `"plan:skipped"` to `phases_done`, suggest `/flow:feat:build`. Stop.
@@ -27,7 +27,7 @@ it hands the finished MR/PR to the orchestrator, which pushes the branch and ope
27
27
  place it would ask:
28
28
 
29
29
  - **The MR/PR itself (§3–§4)** — no confirmation and no forge. §2's title and description are
30
- written to `publish-title.md` and `publish-body.md` in the work folder; the body gains one line
30
+ written to `publish-title.md` (one line, the title alone) and `publish-body.md` in the work folder; the body gains one line
31
31
  saying an unattended run prepared it and nobody confirmed its brief. §4.0's branch check still
32
32
  runs (never the base; the name starts with `<ticket>-`) — and an upstream on the base is unset
33
33
  (`git branch --unset-upstream`), with no push after it. §4.1–§4.3 do not: no push, no
@@ -251,7 +251,7 @@ Create the work directory per §1: `.claude/work/<TICKET>-<slug>/` (ticket mode)
251
251
  ```
252
252
 
253
253
  - Ticket-less (§2.5) → `draft_from_conversation: true`, `tracker_issue` = created issue id/url (or `null` if local-only). Ticket mode → defaults above.
254
- - `base` — `unattended` only: the ticket's `base` (the branch every MR/PR of this work starts from and targets; `/flow:work:run` refreshes it on `merged`). Omit it in every other mode.
254
+ - `base` — `unattended` only: the ticket's `base`, or `git.default_base` when it is empty — never empty (the branch every MR/PR of this work starts from and targets; `/flow:work:run` refreshes it on `merged`). Omit it in every other mode.
255
255
  - `related_repos` from §3.5 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo; `[]` for a single-repo task.
256
256
  - **This work *is* an accepted follow-up** (the ticket came from another work's `followups[]`, flow-core §7) → set `origin: { "work": "<originating work dir>", "followup": "F<n>" }`, carry that entry's recorded `why` into `01-context.md` verbatim instead of re-deriving it, and set the originating entry to `in_progress` with `work` naming this folder. Not a follow-up → omit `origin` entirely.
257
257
 
@@ -66,7 +66,7 @@ resolve this way:
66
66
 
67
67
  ## 1. Pre-flight — locate the work and the MR/PR
68
68
 
69
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
69
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`) — in `unattended`, the work `/flow:work:run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
70
70
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale, keep going.
71
71
  - Resolve the target MR/PR, in this order:
72
72
  1. `{{args}}` if given (IID or URL).
@@ -81,7 +81,7 @@ back through it, and the hard gates above resolve this way:
81
81
 
82
82
  ## 1. Pre-flight — locate the work and the MR/PR
83
83
 
84
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
84
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches) — in `unattended`, the work `/flow:work:run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
85
85
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale to draw on, keep going — triage and reply loop still work.
86
86
  - Resolve the target MR/PR, in this order:
87
87
  1. `{{args}}` if given (IID or URL).
@@ -34,7 +34,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
34
34
  - Run `<cmd> why`. It fails, or prints anything but `start`, `answer`, `review`, `pipeline` or
35
35
  `merged` → print what it returned and its stderr in the §3 header and end. No closing order: an
36
36
  orchestrator that cannot say why it launched the run cannot take one either.
37
- - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent → `feat`).
37
+ - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent or `null` → `feat`: the tracker could not tell, so flow decides). `kind` is re-read on every run; only `start` uses it — once the work exists, its folder says feat or bug.
38
38
  It fails or prints no `number` → `blocked` (flow-core §2.1).
39
39
  - Find the work: the `meta.json` under `.claude/work/` whose `ticket` equals `number` (archive
40
40
  excluded). None is not an error — it is the "none" of the table below.
@@ -46,15 +46,38 @@ of truth, and an argument that disagrees with it is ignored and named in the log
46
46
  | `start` | none for this ticket | `/flow:feat:start <number>` — `/flow:bug:start <number>` when `kind` is `bug` |
47
47
  | `start` | exists, `pending` set | a stop whose `ask` never landed, or a crash after it: send the same question again — `ask` with `<work>/<pending.question_file>`, `<work>/<pending.options_file>`, `--recommended 1` when that options file is not empty, `--free-text` when `pending.free_text`, `--gate pending.gate` — and end. `pending` stays as it is; nothing is recomputed |
48
48
  | `start` | exists, an `mrs[]` entry `published`, or `meta.json.published` true (a work with no `mrs`) | `done` — the summary says it is waiting for that merge; the next launch for it is `merged` |
49
- | `start` | exists, nothing pending | the phase after `meta.json.phase` on this work's route (`/flow:feat:start` §4 for a feature, `/flow:bug:start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
49
+ | `start` | exists, nothing pending | the work's branch first (below), then the phase after `meta.json.phase` on this work's route (`/flow:feat:start` §4 for a feature, `/flow:bug:start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
50
50
  | `answer` | `pending` set | apply `<cmd> answer` as flow-core §2.1 "The answer comes back" says, then `pending.resume` at `pending.resume_at`. The order fails or prints nothing → `blocked` |
51
51
  | `answer` | nothing pending | `blocked` — there is no question for that answer to decide |
52
- | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read; the next startable MR/PR → `/flow:feat:build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
52
+ | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read (empty → `git.default_base`); the next startable MR/PR → `/flow:feat:build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
53
53
  | `merged` | none, or nothing published | `blocked` — nothing of this ticket was published from here |
54
54
  | `review` | exists | `/flow:work:respond` — the threads come from `<cmd> events --json` |
55
55
  | `pipeline` | exists | `/flow:work:green` — the failed jobs come from `<cmd> events --json` |
56
56
  | `review` · `pipeline` | none | `blocked` — there is no work of this ticket to answer for |
57
57
 
58
+ **The work's branch, on `start`.** The current branch is `meta.json.branch` → nothing to do. It is
59
+ not — a study made on another machine arrives on the ticket's `base`, a run that died before its
60
+ closing order is relaunched there — then, in this order:
61
+
62
+ 1. Anything `git status --porcelain` lists outside `.claude/work/` — untracked files included, since
63
+ the WIP commit before a closing order takes new files too → `blocked`: the orchestrator owns the
64
+ checkout.
65
+ 2. `meta.json.base` is set and `meta.json.worktree` is a worktree of this checkout (`git worktree
66
+ list`) whose branch is `meta.json.branch` → run the phase from there: `git switch` would refuse a
67
+ branch checked out elsewhere. A path that is not such a worktree falls through to step 3.
68
+ 3. `meta.json.base` is set — the work was started or re-homed by an unattended run, so its branch is
69
+ one this kind of run made — and `meta.json.branch` exists locally → `git switch` onto it, change
70
+ nothing. It holds the commits a previous run left.
71
+ 4. `<number>-<slug>` (`slug` from `meta.json`), or `meta.json.branch` without `meta.json.base`,
72
+ exists locally → `blocked`, naming it: a branch with the work's name that no run here recorded is
73
+ history nobody can vouch for.
74
+ 5. Otherwise create it as `/flow:feat:start` does in this mode: `git switch --create <name>
75
+ --no-track <base>` (`base` empty → `git.default_base`), `<name>` being `<number>-<slug>`, or
76
+ `<number>-<slug>-<n>` when the `in_progress` entry of `meta.json.mrs` has `n` > 1 — the name
77
+ `/flow:feat:build` gives that part, since the first part's name is already published. Then
78
+ `meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
79
+ other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
80
+
58
81
  The phase you hand the run to is unattended too: it reads §2.1, chains as `auto` and makes the
59
82
  run's one closing order. This command makes none of its own except the re-sent `ask`, the `blocked`
60
83
  and the `done` of the table above.
@@ -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.85.0`.** Compare it once, at the start of the session, against
20
+ **This file belongs to flow `0.86.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
@@ -258,11 +258,17 @@ assumed:
258
258
  recommended one first), title, body, reason and summary are written into the work folder
259
259
  (`ask-question.md`, `ask-options.md`, `publish-title.md`, `publish-body.md`, `blocked-reason.md`,
260
260
  `done-summary.md`) — or a `mktemp -d` directory before the folder exists — and passed by path. A
261
- backtick or a quote in a ticket title must never meet a shell.
261
+ backtick or a quote in a ticket title must never meet a shell. `publish-title.md` holds **one
262
+ line**, the title alone — no `#`, no second line: the orchestrator refuses a title file with two.
262
263
  - **The orchestrator pushes and opens the MR/PR; the run never does.** No `git push`, no `gh`, no
263
264
  `glab`, no tracker write in this mode — not before `ship`, not in it. The orchestrator also keeps,
264
265
  between runs, the work folder as the run left it and the work branch at the commit where it
265
266
  stopped; the run trusts that and does not re-check it.
267
+ - **The work is the one `/flow-work-run` found** — by the ticket's `number`, never by the current
268
+ branch. A phase whose pre-flight says "load `meta.json` by current branch" takes that work instead:
269
+ the checkout can be the ticket's `base` (a study restored from elsewhere) or an umbrella branch (a
270
+ part just merged), and neither names the work. `run` puts a work whose branch is not checked out
271
+ back on it before handing over (its §2).
266
272
  - **Before any closing order, commit** what this run left uncommitted outside `.claude/work/`, new
267
273
  files included (`WIP <TICKET>: before <gate|order>` — `auto`'s WIP authority): the orchestrator
268
274
  keeps only what is committed. **Only on the work branch**: before it exists (`start` refusing a
@@ -297,6 +303,7 @@ run has.
297
303
  | Clarifying questions on the ticket (`start`) | question `clarify` — after the branch and the work folder exist, with the questions also written to `01-context.md` |
298
304
  | An unanswered high-severity challenge (`design`, `investigate`) | question `design_challenge` / `investigation_challenge` |
299
305
  | `<cmd> ticket` failing or empty, a checkout that is not clean on the ticket's `base` (`start`) | blocked — the orchestrator owns the checkout and the ticket |
306
+ | A work whose branch is not checked out (`run`) | as `/flow-work-run` §2 says — switch onto a branch an unattended run made, or record `unattended:rehomed` and create `<number>-<slug>` from `base`; blocked on a dirty checkout or a branch with the work's name that no run here recorded |
300
307
  | Below-XS check (`start`) | record — open the work |
301
308
  | "Create the branch?" (`start`), the 2–3 line note an XS `build`/`fix` asks for, a contract the design left in prose (`build`) | record — create it · write the note from the ticket · convert it to literal and say so in the artifact |
302
309
  | `git.worktree: ask` | record — in place |
@@ -183,7 +183,7 @@ Create the work directory per §0: `.claude/work/<TICKET>-<slug>/` in ticket mod
183
183
 
184
184
  **Live panel**: publish it now (flow-core §4 — the panel tools, or `<work-dir>/panel.json`). A bug has no MR/PR train, so it is short: the title (the symptom, `style: title`), a `Now` line for what is starting, a `Next` line for the phase this size routes to, and any sibling repo from §1.6 as a `block` line. Every later phase updates it.
185
185
 
186
- In `unattended`, add `"base"`: the ticket's `base`, the branch the fix starts from and targets. Omit it in every other mode.
186
+ In `unattended`, add `"base"`: the ticket's `base`, or `git.default_base` when it is empty — never empty; the branch the fix starts from and targets. Omit it in every other mode.
187
187
 
188
188
  Populate `related_repos` from §1.6 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo the fix touches; `[]` for a single-repo fix. `pending` only when the fix **changes a surface that sibling consumes** (a payload key, an error code, a route, an event shape); otherwise `none`.
189
189
 
@@ -28,14 +28,14 @@ Implementation phase. Code is written here.
28
28
 
29
29
  ## 1. Pre-flight
30
30
 
31
- - Load `meta.json` by current branch. Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
31
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
32
32
  - `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`.
33
33
  - `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).
34
34
  - **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`".)
35
35
  - **Parallel siblings**: startable `pending` MRs/PRs in the **same `wave`** with no dependency between them can be built in parallel or as a train. `manual`: let the user choose which to take now (default: lowest `n`); `guided`/`auto`: take the lowest `n`, record the choice. Mark the chosen one `in_progress`.
36
36
  - All `merged` → warn: feature is done, nothing to build (in `unattended`: `done`, the summary saying so).
37
37
  - Some `pending` but **none** startable → start nothing: tell the user which MR/PR must merge to unlock the next wave, and stop. In `unattended`: `blocked`, the reason naming it.
38
- - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>` and created as `/flow-feat-start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `/flow-feat-ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `/flow-feat-start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `/flow-feat-start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
38
+ - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>`, written to `meta.json.branch` (a relaunch of this part then finds it) and created as `/flow-feat-start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `/flow-feat-ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `/flow-feat-start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `/flow-feat-start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
39
39
 
40
40
  ## 2. Business brief (before typing)
41
41
 
@@ -38,7 +38,7 @@ after writing each challenge's Response.
38
38
 
39
39
  ## 1. Pre-flight
40
40
 
41
- - Load `meta.json` by current branch. Missing → ask the user to start with `/flow-feat-start`.
41
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Missing → ask the user to start with `/flow-feat-start`.
42
42
  - Read `meta.json` and `00-summary.md`; open in full only `01-context.md` (ticket, decisions, contracts received). (flow-core §5)
43
43
  - `size` is `XS` → suggest jumping to `/flow-feat-build` and stop unless the user insists.
44
44
 
@@ -28,7 +28,7 @@ Delivery planning phase. **No code is written.** Splits the feature into MRs/PRs
28
28
 
29
29
  ## 1. Pre-flight
30
30
 
31
- - Load `meta.json` by current branch. Missing → send the user to `/flow-feat-start`.
31
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Missing → send the user to `/flow-feat-start`.
32
32
  - Require `design` in `phases_done`. Missing → send to `/flow-feat-design` and stop.
33
33
  - Read `meta.json` and `00-summary.md`; open in full only `03-design.md`. (flow-core §5)
34
34
  - **`size` `XS` or `S`** → warn that this phase does not apply (always 1 MR/PR), add `"plan:skipped"` to `phases_done`, suggest `/flow-feat-build`. Stop.
@@ -31,7 +31,7 @@ it hands the finished MR/PR to the orchestrator, which pushes the branch and ope
31
31
  place it would ask:
32
32
 
33
33
  - **The MR/PR itself (§3–§4)** — no confirmation and no forge. §2's title and description are
34
- written to `publish-title.md` and `publish-body.md` in the work folder; the body gains one line
34
+ written to `publish-title.md` (one line, the title alone) and `publish-body.md` in the work folder; the body gains one line
35
35
  saying an unattended run prepared it and nobody confirmed its brief. §4.0's branch check still
36
36
  runs (never the base; the name starts with `<ticket>-`) — and an upstream on the base is unset
37
37
  (`git branch --unset-upstream`), with no push after it. §4.1–§4.3 do not: no push, no
@@ -255,7 +255,7 @@ Create the work directory per §1: `.claude/work/<TICKET>-<slug>/` (ticket mode)
255
255
  ```
256
256
 
257
257
  - Ticket-less (§2.5) → `draft_from_conversation: true`, `tracker_issue` = created issue id/url (or `null` if local-only). Ticket mode → defaults above.
258
- - `base` — `unattended` only: the ticket's `base` (the branch every MR/PR of this work starts from and targets; `/flow-work-run` refreshes it on `merged`). Omit it in every other mode.
258
+ - `base` — `unattended` only: the ticket's `base`, or `git.default_base` when it is empty — never empty (the branch every MR/PR of this work starts from and targets; `/flow-work-run` refreshes it on `merged`). Omit it in every other mode.
259
259
  - `related_repos` from §3.5 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo; `[]` for a single-repo task.
260
260
  - **This work *is* an accepted follow-up** (the ticket came from another work's `followups[]`, flow-core §7) → set `origin: { "work": "<originating work dir>", "followup": "F<n>" }`, carry that entry's recorded `why` into `01-context.md` verbatim instead of re-deriving it, and set the originating entry to `in_progress` with `work` naming this folder. Not a follow-up → omit `origin` entirely.
261
261
 
@@ -70,7 +70,7 @@ resolve this way:
70
70
 
71
71
  ## 1. Pre-flight — locate the work and the MR/PR
72
72
 
73
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
73
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`) — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
74
74
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale, keep going.
75
75
  - Resolve the target MR/PR, in this order:
76
76
  1. `$ARGUMENTS` if given (IID or URL).
@@ -85,7 +85,7 @@ back through it, and the hard gates above resolve this way:
85
85
 
86
86
  ## 1. Pre-flight — locate the work and the MR/PR
87
87
 
88
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
88
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches) — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
89
89
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale to draw on, keep going — triage and reply loop still work.
90
90
  - Resolve the target MR/PR, in this order:
91
91
  1. `$ARGUMENTS` if given (IID or URL).
@@ -38,7 +38,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
38
38
  - Run `<cmd> why`. It fails, or prints anything but `start`, `answer`, `review`, `pipeline` or
39
39
  `merged` → print what it returned and its stderr in the §3 header and end. No closing order: an
40
40
  orchestrator that cannot say why it launched the run cannot take one either.
41
- - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent → `feat`).
41
+ - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent or `null` → `feat`: the tracker could not tell, so flow decides). `kind` is re-read on every run; only `start` uses it — once the work exists, its folder says feat or bug.
42
42
  It fails or prints no `number` → `blocked` (flow-core §2.1).
43
43
  - Find the work: the `meta.json` under `.claude/work/` whose `ticket` equals `number` (archive
44
44
  excluded). None is not an error — it is the "none" of the table below.
@@ -50,15 +50,38 @@ of truth, and an argument that disagrees with it is ignored and named in the log
50
50
  | `start` | none for this ticket | `/flow-feat-start <number>` — `/flow-bug-start <number>` when `kind` is `bug` |
51
51
  | `start` | exists, `pending` set | a stop whose `ask` never landed, or a crash after it: send the same question again — `ask` with `<work>/<pending.question_file>`, `<work>/<pending.options_file>`, `--recommended 1` when that options file is not empty, `--free-text` when `pending.free_text`, `--gate pending.gate` — and end. `pending` stays as it is; nothing is recomputed |
52
52
  | `start` | exists, an `mrs[]` entry `published`, or `meta.json.published` true (a work with no `mrs`) | `done` — the summary says it is waiting for that merge; the next launch for it is `merged` |
53
- | `start` | exists, nothing pending | the phase after `meta.json.phase` on this work's route (`/flow-feat-start` §4 for a feature, `/flow-bug-start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
53
+ | `start` | exists, nothing pending | the work's branch first (below), then the phase after `meta.json.phase` on this work's route (`/flow-feat-start` §4 for a feature, `/flow-bug-start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
54
54
  | `answer` | `pending` set | apply `<cmd> answer` as flow-core §2.1 "The answer comes back" says, then `pending.resume` at `pending.resume_at`. The order fails or prints nothing → `blocked` |
55
55
  | `answer` | nothing pending | `blocked` — there is no question for that answer to decide |
56
- | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read; the next startable MR/PR → `/flow-feat-build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
56
+ | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read (empty → `git.default_base`); the next startable MR/PR → `/flow-feat-build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
57
57
  | `merged` | none, or nothing published | `blocked` — nothing of this ticket was published from here |
58
58
  | `review` | exists | `/flow-work-respond` — the threads come from `<cmd> events --json` |
59
59
  | `pipeline` | exists | `/flow-work-green` — the failed jobs come from `<cmd> events --json` |
60
60
  | `review` · `pipeline` | none | `blocked` — there is no work of this ticket to answer for |
61
61
 
62
+ **The work's branch, on `start`.** The current branch is `meta.json.branch` → nothing to do. It is
63
+ not — a study made on another machine arrives on the ticket's `base`, a run that died before its
64
+ closing order is relaunched there — then, in this order:
65
+
66
+ 1. Anything `git status --porcelain` lists outside `.claude/work/` — untracked files included, since
67
+ the WIP commit before a closing order takes new files too → `blocked`: the orchestrator owns the
68
+ checkout.
69
+ 2. `meta.json.base` is set and `meta.json.worktree` is a worktree of this checkout (`git worktree
70
+ list`) whose branch is `meta.json.branch` → run the phase from there: `git switch` would refuse a
71
+ branch checked out elsewhere. A path that is not such a worktree falls through to step 3.
72
+ 3. `meta.json.base` is set — the work was started or re-homed by an unattended run, so its branch is
73
+ one this kind of run made — and `meta.json.branch` exists locally → `git switch` onto it, change
74
+ nothing. It holds the commits a previous run left.
75
+ 4. `<number>-<slug>` (`slug` from `meta.json`), or `meta.json.branch` without `meta.json.base`,
76
+ exists locally → `blocked`, naming it: a branch with the work's name that no run here recorded is
77
+ history nobody can vouch for.
78
+ 5. Otherwise create it as `/flow-feat-start` does in this mode: `git switch --create <name>
79
+ --no-track <base>` (`base` empty → `git.default_base`), `<name>` being `<number>-<slug>`, or
80
+ `<number>-<slug>-<n>` when the `in_progress` entry of `meta.json.mrs` has `n` > 1 — the name
81
+ `/flow-feat-build` gives that part, since the first part's name is already published. Then
82
+ `meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
83
+ other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
84
+
62
85
  The phase you hand the run to is unattended too: it reads §2.1, chains as `auto` and makes the
63
86
  run's one closing order. This command makes none of its own except the re-sent `ask`, the `blocked`
64
87
  and the `done` of the table above.
@@ -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.85.0`.** Compare it once, at the start of the session, against
19
+ **This file belongs to flow `0.86.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
@@ -257,11 +257,17 @@ assumed:
257
257
  recommended one first), title, body, reason and summary are written into the work folder
258
258
  (`ask-question.md`, `ask-options.md`, `publish-title.md`, `publish-body.md`, `blocked-reason.md`,
259
259
  `done-summary.md`) — or a `mktemp -d` directory before the folder exists — and passed by path. A
260
- backtick or a quote in a ticket title must never meet a shell.
260
+ backtick or a quote in a ticket title must never meet a shell. `publish-title.md` holds **one
261
+ line**, the title alone — no `#`, no second line: the orchestrator refuses a title file with two.
261
262
  - **The orchestrator pushes and opens the MR/PR; the run never does.** No `git push`, no `gh`, no
262
263
  `glab`, no tracker write in this mode — not before `ship`, not in it. The orchestrator also keeps,
263
264
  between runs, the work folder as the run left it and the work branch at the commit where it
264
265
  stopped; the run trusts that and does not re-check it.
266
+ - **The work is the one `/flow-work-run` found** — by the ticket's `number`, never by the current
267
+ branch. A phase whose pre-flight says "load `meta.json` by current branch" takes that work instead:
268
+ the checkout can be the ticket's `base` (a study restored from elsewhere) or an umbrella branch (a
269
+ part just merged), and neither names the work. `run` puts a work whose branch is not checked out
270
+ back on it before handing over (its §2).
265
271
  - **Before any closing order, commit** what this run left uncommitted outside `.claude/work/`, new
266
272
  files included (`WIP <TICKET>: before <gate|order>` — `auto`'s WIP authority): the orchestrator
267
273
  keeps only what is committed. **Only on the work branch**: before it exists (`start` refusing a
@@ -296,6 +302,7 @@ run has.
296
302
  | Clarifying questions on the ticket (`start`) | question `clarify` — after the branch and the work folder exist, with the questions also written to `01-context.md` |
297
303
  | An unanswered high-severity challenge (`design`, `investigate`) | question `design_challenge` / `investigation_challenge` |
298
304
  | `<cmd> ticket` failing or empty, a checkout that is not clean on the ticket's `base` (`start`) | blocked — the orchestrator owns the checkout and the ticket |
305
+ | A work whose branch is not checked out (`run`) | as `/flow-work-run` §2 says — switch onto a branch an unattended run made, or record `unattended:rehomed` and create `<number>-<slug>` from `base`; blocked on a dirty checkout or a branch with the work's name that no run here recorded |
299
306
  | Below-XS check (`start`) | record — open the work |
300
307
  | "Create the branch?" (`start`), the 2–3 line note an XS `build`/`fix` asks for, a contract the design left in prose (`build`) | record — create it · write the note from the ticket · convert it to literal and say so in the artifact |
301
308
  | `git.worktree: ask` | record — in place |
@@ -181,7 +181,7 @@ Create the work directory per §0: `.claude/work/<TICKET>-<slug>/` in ticket mod
181
181
 
182
182
  **Live panel**: publish it now (flow-core §4 — the panel tools, or `<work-dir>/panel.json`). A bug has no MR/PR train, so it is short: the title (the symptom, `style: title`), a `Now` line for what is starting, a `Next` line for the phase this size routes to, and any sibling repo from §1.6 as a `block` line. Every later phase updates it.
183
183
 
184
- In `unattended`, add `"base"`: the ticket's `base`, the branch the fix starts from and targets. Omit it in every other mode.
184
+ In `unattended`, add `"base"`: the ticket's `base`, or `git.default_base` when it is empty — never empty; the branch the fix starts from and targets. Omit it in every other mode.
185
185
 
186
186
  Populate `related_repos` from §1.6 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo the fix touches; `[]` for a single-repo fix. `pending` only when the fix **changes a surface that sibling consumes** (a payload key, an error code, a route, an event shape); otherwise `none`.
187
187
 
@@ -26,14 +26,14 @@ Implementation phase. Code is written here.
26
26
 
27
27
  ## 1. Pre-flight
28
28
 
29
- - Load `meta.json` by current branch. Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
29
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `03-design.md` (§"External contracts", verbatim) and the current MR/PR entry of `04-mr-plan.md`. (flow-core §5)
30
30
  - `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`.
31
31
  - `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).
32
32
  - **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`".)
33
33
  - **Parallel siblings**: startable `pending` MRs/PRs in the **same `wave`** with no dependency between them can be built in parallel or as a train. `manual`: let the user choose which to take now (default: lowest `n`); `guided`/`auto`: take the lowest `n`, record the choice. Mark the chosen one `in_progress`.
34
34
  - All `merged` → warn: feature is done, nothing to build (in `unattended`: `done`, the summary saying so).
35
35
  - Some `pending` but **none** startable → start nothing: tell the user which MR/PR must merge to unlock the next wave, and stop. In `unattended`: `blocked`, the reason naming it.
36
- - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>` and created as `/flow-feat-start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `/flow-feat-ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `/flow-feat-start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `/flow-feat-start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
36
+ - **Train/stacked** (never in `unattended`: there the startable MR/PR gets a **new branch of its own** from `meta.json.base` (empty → `git.default_base`) — the base the orchestrator gave the ticket, an umbrella branch once a split task's first part is merged. That branch may exist only on the remote, or locally without the part that just merged: `git fetch origin <base>` when a remote is configured (best-effort — a fetch the container cannot make is not an error), then start from `origin/<base>` when it resolves, the local `<base>` otherwise. Named `<ticket>-<slug>-<n>`, written to `meta.json.branch` (a relaunch of this part then finds it) and created as `/flow-feat-start §5.2` (in place) or `§5.4` (worktree) says — `git.worktree: always` → worktree, `off`/empty/`ask` → in place; that base is already decided, so §5.1 asks nothing; `--no-track`, no linked remote branch — and never commits onto a previous MR/PR's branch; flow-core §2.1): this MR/PR needs its own branch stacked on the previous one — do **not** keep committing on the previous MR/PR's branch. `/flow-feat-ship §6.2` creates and links it when it chains here; if you arrived directly and are still on the previous branch, create it now per `/flow-feat-start §5` (explicit base = the previous MR/PR's branch, `--no-track`, worktree per `git.worktree`) and, for `tracker.tool: gh`, the linked-branch step `/flow-feat-start §5.5`. Record `stacked_on` in `meta.json`. The train does **not** wait for the previous MR/PR to merge.
37
37
 
38
38
  ## 2. Business brief (before typing)
39
39
 
@@ -36,7 +36,7 @@ after writing each challenge's Response.
36
36
 
37
37
  ## 1. Pre-flight
38
38
 
39
- - Load `meta.json` by current branch. Missing → ask the user to start with `/flow-feat-start`.
39
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Missing → ask the user to start with `/flow-feat-start`.
40
40
  - Read `meta.json` and `00-summary.md`; open in full only `01-context.md` (ticket, decisions, contracts received). (flow-core §5)
41
41
  - `size` is `XS` → suggest jumping to `/flow-feat-build` and stop unless the user insists.
42
42
 
@@ -26,7 +26,7 @@ Delivery planning phase. **No code is written.** Splits the feature into MRs/PRs
26
26
 
27
27
  ## 1. Pre-flight
28
28
 
29
- - Load `meta.json` by current branch. Missing → send the user to `/flow-feat-start`.
29
+ - Load `meta.json` by current branch — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Missing → send the user to `/flow-feat-start`.
30
30
  - Require `design` in `phases_done`. Missing → send to `/flow-feat-design` and stop.
31
31
  - Read `meta.json` and `00-summary.md`; open in full only `03-design.md`. (flow-core §5)
32
32
  - **`size` `XS` or `S`** → warn that this phase does not apply (always 1 MR/PR), add `"plan:skipped"` to `phases_done`, suggest `/flow-feat-build`. Stop.
@@ -29,7 +29,7 @@ it hands the finished MR/PR to the orchestrator, which pushes the branch and ope
29
29
  place it would ask:
30
30
 
31
31
  - **The MR/PR itself (§3–§4)** — no confirmation and no forge. §2's title and description are
32
- written to `publish-title.md` and `publish-body.md` in the work folder; the body gains one line
32
+ written to `publish-title.md` (one line, the title alone) and `publish-body.md` in the work folder; the body gains one line
33
33
  saying an unattended run prepared it and nobody confirmed its brief. §4.0's branch check still
34
34
  runs (never the base; the name starts with `<ticket>-`) — and an upstream on the base is unset
35
35
  (`git branch --unset-upstream`), with no push after it. §4.1–§4.3 do not: no push, no
@@ -253,7 +253,7 @@ Create the work directory per §1: `.claude/work/<TICKET>-<slug>/` (ticket mode)
253
253
  ```
254
254
 
255
255
  - Ticket-less (§2.5) → `draft_from_conversation: true`, `tracker_issue` = created issue id/url (or `null` if local-only). Ticket mode → defaults above.
256
- - `base` — `unattended` only: the ticket's `base` (the branch every MR/PR of this work starts from and targets; `/flow-work-run` refreshes it on `merged`). Omit it in every other mode.
256
+ - `base` — `unattended` only: the ticket's `base`, or `git.default_base` when it is empty — never empty (the branch every MR/PR of this work starts from and targets; `/flow-work-run` refreshes it on `merged`). Omit it in every other mode.
257
257
  - `related_repos` from §3.5 — one `{ "repo": "<name>", "scope": "<one line>", "status": "pending", "contract_handoff": "pending" | "none" }` per *other* repo; `[]` for a single-repo task.
258
258
  - **This work *is* an accepted follow-up** (the ticket came from another work's `followups[]`, flow-core §7) → set `origin: { "work": "<originating work dir>", "followup": "F<n>" }`, carry that entry's recorded `why` into `01-context.md` verbatim instead of re-deriving it, and set the originating entry to `in_progress` with `work` naming this folder. Not a follow-up → omit `origin` entirely.
259
259
 
@@ -68,7 +68,7 @@ resolve this way:
68
68
 
69
69
  ## 1. Pre-flight — locate the work and the MR/PR
70
70
 
71
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
71
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (via `meta.json`, matching `branch`) — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `09-ci.md` (previous rounds) and, when §3/§5.C need the recorded "why", `03-design.md`, `05-implementation.md`/`04-fix.md`. (flow-core §5)
72
72
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale, keep going.
73
73
  - Resolve the target MR/PR, in this order:
74
74
  1. `$ARGUMENTS` if given (IID or URL).
@@ -83,7 +83,7 @@ back through it, and the hard gates above resolve this way:
83
83
 
84
84
  ## 1. Pre-flight — locate the work and the MR/PR
85
85
 
86
- - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
86
+ - Identify the current branch and its work folder `.claude/work/<TICKET>/` (the `meta.json` whose `branch` matches) — in `unattended`, the work `/flow-work-run` found (flow-core §2.1). Read `meta.json` and `00-summary.md`; open in full only `08-feedback.md` (spent rounds, below) and, in §3, the rationale artifacts a thread needs (`03-design.md`, `05-implementation.md`/`04-fix.md`). (flow-core §5)
87
87
  - **No** work folder (MR opened outside the flow) → **lightweight mode**: skip `meta.json`/artifact reads, warn once that there is no recorded design rationale to draw on, keep going — triage and reply loop still work.
88
88
  - Resolve the target MR/PR, in this order:
89
89
  1. `$ARGUMENTS` if given (IID or URL).
@@ -36,7 +36,7 @@ of truth, and an argument that disagrees with it is ignored and named in the log
36
36
  - Run `<cmd> why`. It fails, or prints anything but `start`, `answer`, `review`, `pipeline` or
37
37
  `merged` → print what it returned and its stderr in the §3 header and end. No closing order: an
38
38
  orchestrator that cannot say why it launched the run cannot take one either.
39
- - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent → `feat`).
39
+ - Run `<cmd> ticket --json` and keep `number`, `title`, `base` and `kind` (`kind` absent or `null` → `feat`: the tracker could not tell, so flow decides). `kind` is re-read on every run; only `start` uses it — once the work exists, its folder says feat or bug.
40
40
  It fails or prints no `number` → `blocked` (flow-core §2.1).
41
41
  - Find the work: the `meta.json` under `.claude/work/` whose `ticket` equals `number` (archive
42
42
  excluded). None is not an error — it is the "none" of the table below.
@@ -48,15 +48,38 @@ of truth, and an argument that disagrees with it is ignored and named in the log
48
48
  | `start` | none for this ticket | `/flow-feat-start <number>` — `/flow-bug-start <number>` when `kind` is `bug` |
49
49
  | `start` | exists, `pending` set | a stop whose `ask` never landed, or a crash after it: send the same question again — `ask` with `<work>/<pending.question_file>`, `<work>/<pending.options_file>`, `--recommended 1` when that options file is not empty, `--free-text` when `pending.free_text`, `--gate pending.gate` — and end. `pending` stays as it is; nothing is recomputed |
50
50
  | `start` | exists, an `mrs[]` entry `published`, or `meta.json.published` true (a work with no `mrs`) | `done` — the summary says it is waiting for that merge; the next launch for it is `merged` |
51
- | `start` | exists, nothing pending | the phase after `meta.json.phase` on this work's route (`/flow-feat-start` §4 for a feature, `/flow-bug-start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
51
+ | `start` | exists, nothing pending | the work's branch first (below), then the phase after `meta.json.phase` on this work's route (`/flow-feat-start` §4 for a feature, `/flow-bug-start`'s routing for a bug, by `size`), or `phase` itself when its own Close never ran. A work folder the orchestrator restored from a study made elsewhere enters here, and is never started a second time |
52
52
  | `answer` | `pending` set | apply `<cmd> answer` as flow-core §2.1 "The answer comes back" says, then `pending.resume` at `pending.resume_at`. The order fails or prints nothing → `blocked` |
53
53
  | `answer` | nothing pending | `blocked` — there is no question for that answer to decide |
54
- | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read; the next startable MR/PR → `/flow-feat-build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
54
+ | `merged` | exists, something published | the entry of `meta.json.mrs` whose `status` is `published` (the only one: one MR/PR per run) becomes `merged`; set `meta.json.base` to the `base` just read (empty → `git.default_base`); the next startable MR/PR → `/flow-feat-build`; none left, or a work with no `mrs` and `published` true (one MR/PR, every bug) → `phase = done` and `done`, the summary naming the ticket as complete |
55
55
  | `merged` | none, or nothing published | `blocked` — nothing of this ticket was published from here |
56
56
  | `review` | exists | `/flow-work-respond` — the threads come from `<cmd> events --json` |
57
57
  | `pipeline` | exists | `/flow-work-green` — the failed jobs come from `<cmd> events --json` |
58
58
  | `review` · `pipeline` | none | `blocked` — there is no work of this ticket to answer for |
59
59
 
60
+ **The work's branch, on `start`.** The current branch is `meta.json.branch` → nothing to do. It is
61
+ not — a study made on another machine arrives on the ticket's `base`, a run that died before its
62
+ closing order is relaunched there — then, in this order:
63
+
64
+ 1. Anything `git status --porcelain` lists outside `.claude/work/` — untracked files included, since
65
+ the WIP commit before a closing order takes new files too → `blocked`: the orchestrator owns the
66
+ checkout.
67
+ 2. `meta.json.base` is set and `meta.json.worktree` is a worktree of this checkout (`git worktree
68
+ list`) whose branch is `meta.json.branch` → run the phase from there: `git switch` would refuse a
69
+ branch checked out elsewhere. A path that is not such a worktree falls through to step 3.
70
+ 3. `meta.json.base` is set — the work was started or re-homed by an unattended run, so its branch is
71
+ one this kind of run made — and `meta.json.branch` exists locally → `git switch` onto it, change
72
+ nothing. It holds the commits a previous run left.
73
+ 4. `<number>-<slug>` (`slug` from `meta.json`), or `meta.json.branch` without `meta.json.base`,
74
+ exists locally → `blocked`, naming it: a branch with the work's name that no run here recorded is
75
+ history nobody can vouch for.
76
+ 5. Otherwise create it as `/flow-feat-start` does in this mode: `git switch --create <name>
77
+ --no-track <base>` (`base` empty → `git.default_base`), `<name>` being `<number>-<slug>`, or
78
+ `<number>-<slug>-<n>` when the `in_progress` entry of `meta.json.mrs` has `n` > 1 — the name
79
+ `/flow-feat-build` gives that part, since the first part's name is already published. Then
80
+ `meta.json.branch` = it, `meta.json.base` = that base, `worktree` and `stacked_on` = `null` — paths and parents from the
81
+ other machine mean nothing here — and record `{ "key": "unattended:rehomed", "default": "<old branch> → <name> from <base>", "phase": "run" }`.
82
+
60
83
  The phase you hand the run to is unattended too: it reads §2.1, chains as `auto` and makes the
61
84
  run's one closing order. This command makes none of its own except the re-sent `ask`, the `blocked`
62
85
  and the `done` of the table above.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-workflows",
3
- "version": "0.85.0",
3
+ "version": "0.86.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.85.0",
6
+ "version": "0.86.0",
7
7
  "author": {
8
8
  "name": "Alberto Vioque",
9
9
  "email": "mashware@gmail.com"
@@ -5,6 +5,28 @@ plugin and is what `/flow:news` reads to show you what changed since your previo
5
5
 
6
6
  The canonical, richest notes live in the [GitHub Releases](https://github.com/mashware/flow-workflows/releases).
7
7
 
8
+ ## v0.86.0 — An unattended run builds a study made on another machine · 2026-10-01
9
+
10
+ **In short**
11
+ - **A study restored on a server is built there, not redone.** When the orchestrator copies a work
12
+ folder made on a laptop and launches `/flow:work:run` on the ticket's base branch, the run gives
13
+ the work a branch of its own (`<number>-<slug>`, from that base) and goes straight to the next
14
+ phase — `build` after a plan. It never designs or plans the ticket again.
15
+ - **A run relaunched after a crash goes back to its branch** instead of failing to find its work.
16
+ - **The next part of a split task finds its work** while the checkout stands on the umbrella branch.
17
+ - **It stops instead of guessing** when the checkout has uncommitted changes, or holds a branch with
18
+ the work's name that the work never recorded.
19
+ - Nothing changes in `manual`, `guided` or `auto`. Part of #186.
20
+
21
+ ## v0.85.1 — An unattended run reads the orchestrator's answers as agent-runner sends them · 2026-10-01
22
+
23
+ **In short**
24
+ - **A ticket whose tracker cannot tell feat from bug starts as a feature.** agent-runner sends
25
+ `kind: null` in that case; `/flow:work:run` now reads it the same as a missing `kind`.
26
+ - **The PR title goes to the orchestrator as one line.** agent-runner refuses a title file with two
27
+ lines; flow now says so where the run writes it.
28
+ - Nothing changes in `manual`, `guided` or `auto`. Follows #177.
29
+
8
30
  ## v0.85.0 — An unattended run answers its reviewers and fixes its own pipeline · 2026-10-01
9
31
 
10
32
  **In short**