flow-workflows 0.85.1 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/adapters/codex/CORE.md +7 -1
- package/adapters/codex/skills/flow-bug-start/SKILL.md +1 -1
- package/adapters/codex/skills/flow-feat-build/SKILL.md +2 -2
- package/adapters/codex/skills/flow-feat-design/SKILL.md +1 -1
- package/adapters/codex/skills/flow-feat-plan/SKILL.md +1 -1
- package/adapters/codex/skills/flow-feat-start/SKILL.md +1 -1
- package/adapters/codex/skills/flow-work-README/SKILL.md +1 -0
- package/adapters/codex/skills/flow-work-green/SKILL.md +1 -1
- package/adapters/codex/skills/flow-work-handoff/SKILL.md +158 -0
- package/adapters/codex/skills/flow-work-respond/SKILL.md +1 -1
- package/adapters/codex/skills/flow-work-run/SKILL.md +25 -2
- package/adapters/gemini/CORE.md +7 -1
- package/adapters/gemini/commands/flow/bug/start.toml +1 -1
- package/adapters/gemini/commands/flow/feat/build.toml +2 -2
- package/adapters/gemini/commands/flow/feat/design.toml +1 -1
- package/adapters/gemini/commands/flow/feat/plan.toml +1 -1
- package/adapters/gemini/commands/flow/feat/start.toml +1 -1
- package/adapters/gemini/commands/flow/work/README.toml +1 -0
- package/adapters/gemini/commands/flow/work/green.toml +1 -1
- package/adapters/gemini/commands/flow/work/handoff.toml +155 -0
- package/adapters/gemini/commands/flow/work/respond.toml +1 -1
- package/adapters/gemini/commands/flow/work/run.toml +25 -2
- package/adapters/hermes/CORE.md +7 -1
- package/adapters/hermes/skills/flow-bug-start/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-feat-build/SKILL.md +2 -2
- package/adapters/hermes/skills/flow-feat-design/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-feat-plan/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-feat-start/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-work-README/SKILL.md +1 -0
- package/adapters/hermes/skills/flow-work-green/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-work-handoff/SKILL.md +158 -0
- package/adapters/hermes/skills/flow-work-respond/SKILL.md +1 -1
- package/adapters/hermes/skills/flow-work-run/SKILL.md +25 -2
- package/adapters/opencode/CORE.md +7 -1
- package/adapters/opencode/commands/flow-bug-start.md +1 -1
- package/adapters/opencode/commands/flow-feat-build.md +2 -2
- package/adapters/opencode/commands/flow-feat-design.md +1 -1
- package/adapters/opencode/commands/flow-feat-plan.md +1 -1
- package/adapters/opencode/commands/flow-feat-start.md +1 -1
- package/adapters/opencode/commands/flow-work-README.md +1 -0
- package/adapters/opencode/commands/flow-work-green.md +1 -1
- package/adapters/opencode/commands/flow-work-handoff.md +156 -0
- package/adapters/opencode/commands/flow-work-respond.md +1 -1
- package/adapters/opencode/commands/flow-work-run.md +25 -2
- package/package.json +1 -1
- package/plugins/flow/.claude-plugin/plugin.json +1 -1
- package/plugins/flow/CHANGELOG.md +29 -0
- package/plugins/flow/examples/FLOW.template.md +3 -0
package/README.md
CHANGED
|
@@ -173,6 +173,7 @@ Symmetrically, `guided`/`auto` never ask about the flow's own machinery (panels,
|
|
|
173
173
|
| `/flow:work:try` | Point the main checkout at a branch to test it, and print the manual test plan once it is up (then `--back`) |
|
|
174
174
|
| `/flow:work:clean` | Sweep merged worktrees, dead branches, unarchived folders. Never deletes on a guess |
|
|
175
175
|
| `/flow:work:abandon` | Close a work item without shipping |
|
|
176
|
+
| `/flow:work:handoff` | Hand a finished study to whoever builds it elsewhere — pushes only its folder to a branch of its own, offers a summary for the ticket |
|
|
176
177
|
| `/flow:news` | What changed in the plugin since the version you last saw |
|
|
177
178
|
|
|
178
179
|
## What a work looks like on disk
|
package/adapters/codex/CORE.md
CHANGED
|
@@ -17,7 +17,7 @@ Every `$flow-*` command assumes these rules. They are stated once, here, so a co
|
|
|
17
17
|
carries what is specific to its phase. Read this once per session; a command that says "load
|
|
18
18
|
`flow-core`" means this file.
|
|
19
19
|
|
|
20
|
-
**This file belongs to flow `0.
|
|
20
|
+
**This file belongs to flow `0.87.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
|
|
@@ -264,6 +264,11 @@ assumed:
|
|
|
264
264
|
`glab`, no tracker write in this mode — not before `ship`, not in it. The orchestrator also keeps,
|
|
265
265
|
between runs, the work folder as the run left it and the work branch at the commit where it
|
|
266
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).
|
|
267
272
|
- **Before any closing order, commit** what this run left uncommitted outside `.claude/work/`, new
|
|
268
273
|
files included (`WIP <TICKET>: before <gate|order>` — `auto`'s WIP authority): the orchestrator
|
|
269
274
|
keeps only what is committed. **Only on the work branch**: before it exists (`start` refusing a
|
|
@@ -298,6 +303,7 @@ run has.
|
|
|
298
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` |
|
|
299
304
|
| An unanswered high-severity challenge (`design`, `investigate`) | question `design_challenge` / `investigation_challenge` |
|
|
300
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 |
|
|
301
307
|
| Below-XS check (`start`) | record — open the work |
|
|
302
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 |
|
|
303
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
|
|
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.
|
|
@@ -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
|
|
|
@@ -249,6 +249,7 @@ Two signals arrive on an open MR/PR, each with its own cross-cutting loop (feat
|
|
|
249
249
|
- `$flow-work-daily [question]` — the **work assistant** (daily standup), read-only. **Local** (`.claude/work/` + git) + **forge** (open MRs/PRs, reviews awaiting you, red CI, unmergeable, unresolved threads via `git.cli`) + **tracker** (assigned tickets, priority changes via `tracker.tool`); where they cross, concrete commands (`$flow-feat-start`, `$flow-work-green`, `$flow-work-respond`). No argument → *yesterday · today · blockers*; a question → just that. External sources best-effort, never blocking; the only write is a "last seen" marker, like `$flow-news`.
|
|
250
250
|
- `$flow-work-status` — all works in `.claude/work/`, current phase, divergence with git.
|
|
251
251
|
- `$flow-work-run [ticket]` — the **entry an orchestrator launches** for an `unattended` run: asks it `why` (start · answer · merged · review · pipeline), routes to the phase that answers it, and makes no decision of its own. Refuses to run in any other mode.
|
|
252
|
+
- `$flow-work-handoff` — hands a **finished study** to whoever builds it elsewhere (an unattended server, another machine): refuses an unfinished one, pushes only this work's folder as a parentless commit to `git.handoff_branch` without touching the checkout, asks before the push, then offers a marked summary for the ticket body (`tracker.edit_cmd`).
|
|
252
253
|
- `$flow-work-resume` — detects the branch, reads `meta.json`, recaps, suggests the next step. **Re-reads the ticket's comment thread** (§2.5), reports only what is new since `01-context.md`, appends it to the artifact; never amends the design on its own.
|
|
253
254
|
- `$flow-work-try <branch>` / `$flow-work-try --back` — point the main checkout at a branch to test it here, then return; re-syncs per `git.worktree_resync`. Resolves the work behind the branch and, once the environment is up, **prints the manual test plan already written** (the `needs-manual`/`unproven` criteria, or the acceptance criteria when `validate` has not run) and offers to collect Pass/Fail/Blocked into the validation artifact. No work behind the branch → the plain switch, as before.
|
|
254
255
|
- `$flow-work-clean [--dry-run]` — **periodic sweep** of finished work's residue: worktree, local branch, `.claude/work/` folder (intermediate train MR/PRs never set `phase: done`, so the `ship`/`abandon` prompt never fires). Verdict per branch from **the forge** with local fallbacks, including patch-equivalence for **squash merges** (`git branch --merged` misses them); acts only on `merged`/`empty`. `unknown` never a candidate; dirty and unpushed protected; work folders **archived, never deleted**; remote never touched. **`autonomy.mode` does not authorize deletion**: `auto` confirms the list too. `--purge-archive <N>d`: separate opt-in pass over `_archive/`, only folders already committed to git.
|
|
@@ -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).
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow-work-handoff
|
|
3
|
+
description: "Hand a finished study to whoever builds it elsewhere — push only this work's folder to a branch of its own, then offer a summary for the ticket"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by script/adapter-build.py from plugins/flow/commands/work/handoff.md — do not edit; change the plugin file and run the script. -->
|
|
7
|
+
|
|
8
|
+
# `$flow-work-handoff`
|
|
9
|
+
|
|
10
|
+
> **codex adapter — how the Claude Code primitives named below map here.**
|
|
11
|
+
> - `AskUserQuestion` → ask in plain text with numbered options and wait for the reply.
|
|
12
|
+
> - `Agent <role>` / `Agent general-purpose` / subagents → the subagent declared under `[agents.<name>]` in `~/.codex/config.toml`; the name comes from `agents.<role>` in `FLOW.md`, empty → do it in this context.
|
|
13
|
+
> - Parallel fan-out → several subagents in one response, capped at `agents.fanout_max` (empty → 4); `agents.fanout_tool` is Claude Code-only, ignore it.
|
|
14
|
+
> - `ScheduleWakeup` / `Monitor` / `/loop` → not available in-session: run one cycle, persist state in `monitor.md`, let the user schedule `codex exec "<command>"` with cron or Codex automations.
|
|
15
|
+
> - `TaskCreate` → a markdown checklist in the phase artifact.
|
|
16
|
+
> - `Skill commit-commands:commit-push-pr` → `git add` · `git commit` · `git push -u origin HEAD` · the `git.cli` CLI (`gh pr create` / `glab mr create`).
|
|
17
|
+
> - `/model <value>` → the `--model` flag at launch (or `/model` if your Codex version has it).
|
|
18
|
+
> - `knowledge.*` roles → whatever tools `FLOW.md` names there; an MCP tool keeps its name, its server is declared under `[mcp_servers.<name>]` in `config.toml` (see `config.snippet.toml`).
|
|
19
|
+
> - `$ARGUMENTS` → whatever the user typed after the skill name, empty if nothing — Codex substitutes nothing, so read it off their message.
|
|
20
|
+
|
|
21
|
+
Read `~/.claude/flow/CORE.codex.md` first (shared rules: `FLOW.md` step 0, autonomy, how a stop reads, the live panel, `00-summary.md`) — skip if you already read it in this session.
|
|
22
|
+
|
|
23
|
+
**Panel words are closed** — `mark`: `done` · `current` · `pending` · `wait` · `block` · `info`; `style`: `normal` · `dim` · `title` · `accent` · `ok` · `warn` · `error`. Anything else is dropped by the reader in silence: the panel still paints, and nobody is told.
|
|
24
|
+
|
|
25
|
+
For a study made here and built somewhere else — a server running `$flow-work-run` unattended,
|
|
26
|
+
another person, another machine. The builder gets the work folder at the same path and nothing
|
|
27
|
+
else: no conversation, maybe a less capable model. So this command checks the study can stand on
|
|
28
|
+
its own, pushes the folder to a branch that holds only it, and offers to put a summary in the
|
|
29
|
+
ticket for the people who review it.
|
|
30
|
+
|
|
31
|
+
## 1. Pre-flight
|
|
32
|
+
|
|
33
|
+
- Effective FLOW configuration per flow-core §0. `autonomy.mode: unattended` → refuse in one line:
|
|
34
|
+
an unattended run never pushes (flow-core §2.1); handing off is a person's step.
|
|
35
|
+
- Locate the active `meta.json` by current branch; not found → ask the user for the ticket.
|
|
36
|
+
- `git.handoff_branch` empty → refuse, naming the key and an example
|
|
37
|
+
(`git.handoff_branch: study/{TICKET}`): where the study goes is the receiver's convention, never
|
|
38
|
+
flow's guess. `{TICKET}` = `meta.json.ticket`.
|
|
39
|
+
- `origin` not configured → refuse; there is nowhere to push.
|
|
40
|
+
|
|
41
|
+
## 2. Is the study finished?
|
|
42
|
+
|
|
43
|
+
The builder can ask no one. Refuse — pushing nothing, naming every reason that holds — when:
|
|
44
|
+
|
|
45
|
+
- **The study's last phase is not in `phases_done`.** A feature: `context` on XS (what `start`
|
|
46
|
+
records), `design` on S, `plan` on M/L. A bug: `context` on XS, `investigate` otherwise.
|
|
47
|
+
- **`meta.json.pending` is set** — a question is still waiting for its answer.
|
|
48
|
+
- **A clarification is still open** — a question under "Decisions clarified at start" in
|
|
49
|
+
`01-context.md` recorded without its answer.
|
|
50
|
+
|
|
51
|
+
Then, **before anything is pushed**: decisions this session settled while talking that no artifact
|
|
52
|
+
records yet → write them where they belong now (`01-context.md` "Decisions clarified at start",
|
|
53
|
+
`03-design.md` "Decisions (ADR-light)", `04-mr-plan.md`), and say which. What was decided only in
|
|
54
|
+
the chat does not travel.
|
|
55
|
+
|
|
56
|
+
## 3. Build the commit, without touching the checkout
|
|
57
|
+
|
|
58
|
+
A throwaway index holds only this folder, so the current branch, `HEAD`, the real index (staged
|
|
59
|
+
work included) and the working tree are never read into it nor written to, and a git-ignored
|
|
60
|
+
`.claude/work/` is no obstacle.
|
|
61
|
+
|
|
62
|
+
**Each block below is one shell call, run as it stands** — a harness need not keep variables from
|
|
63
|
+
one call to the next, so every block sets its own. Replace each `@…@` with its literal value first:
|
|
64
|
+
`@WORK@` the work folder relative to the repository root (`.claude/work/<work-dir>`, no trailing
|
|
65
|
+
slash), `@BRANCH@` the resolved `git.handoff_branch`, `@TICKET@` `meta.json.ticket`, `@COMMIT@` the
|
|
66
|
+
sha the build block printed. A value holding a `'` cannot go inside those quotes: refuse it and
|
|
67
|
+
say which.
|
|
68
|
+
|
|
69
|
+
First, the branch must not exist on `origin` — a second push would need a force, and this command
|
|
70
|
+
never forces:
|
|
71
|
+
|
|
72
|
+
```bash handoff-check
|
|
73
|
+
BRANCH='@BRANCH@'
|
|
74
|
+
git ls-remote --exit-code origin "refs/heads/$BRANCH" >/dev/null; echo "rc=$?"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`rc=0` → the branch exists: refuse, and say what the person does next — delete it on the forge
|
|
78
|
+
(only when nothing still reads it), or set another name in `git.handoff_branch`. `rc=2` → absent,
|
|
79
|
+
continue. Anything else → stop and say why (no network, no access). Then build the commit:
|
|
80
|
+
|
|
81
|
+
```bash handoff-build
|
|
82
|
+
WORK='@WORK@'; TICKET='@TICKET@'
|
|
83
|
+
cd "$(git rev-parse --show-toplevel)" || exit 1
|
|
84
|
+
[ -d "$WORK" ] || { echo "no such folder: $WORK"; exit 1; }
|
|
85
|
+
tmp=$(mktemp -d) || exit 1
|
|
86
|
+
idx="$tmp/index" # does not exist yet: git starts an empty index there
|
|
87
|
+
GIT_INDEX_FILE="$idx" git add -f -- "$WORK" ":(exclude)$WORK/panel.json" &&
|
|
88
|
+
files=$(GIT_INDEX_FILE="$idx" git ls-files) &&
|
|
89
|
+
tree=$(GIT_INDEX_FILE="$idx" git write-tree) &&
|
|
90
|
+
commit=$(git commit-tree "$tree" -m "study $TICKET")
|
|
91
|
+
rc=$?; rm -rf "$tmp"
|
|
92
|
+
[ "$rc" -eq 0 ] && [ -n "$files" ] || { echo "nothing was built (rc=$rc)"; exit 1; }
|
|
93
|
+
printf '%s\n' "$files"; echo "commit=$commit"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`GIT_INDEX_FILE` is set per command, never exported, so a failure leaves no session pointing git
|
|
97
|
+
at a deleted index. `panel.json` stays out: it is this machine's terminal panel, and on another one
|
|
98
|
+
it would show this session's last state as if it were theirs. The block failing → its message, and
|
|
99
|
+
stop: `commit-tree` with no git identity configured is the usual cause.
|
|
100
|
+
|
|
101
|
+
## 4. Confirm, then push
|
|
102
|
+
|
|
103
|
+
Show the branch, the remote and the file list the build printed — every path, one per line — then
|
|
104
|
+
ask with `AskUserQuestion` **in every `autonomy.mode`**: a push leaves the machine (flow-core §2).
|
|
105
|
+
**Push** · **Cancel**. Nothing between the list and the question (flow-core §3).
|
|
106
|
+
|
|
107
|
+
```bash handoff-push
|
|
108
|
+
BRANCH='@BRANCH@'; COMMIT='@COMMIT@'
|
|
109
|
+
case "$COMMIT" in ''|*[!0-9a-f]*) echo "not a commit sha: $COMMIT"; exit 1 ;; esac
|
|
110
|
+
git cat-file -e "$COMMIT^{commit}" || exit 1
|
|
111
|
+
git push origin "$COMMIT:refs/heads/$BRANCH"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The sha is checked first because `git push origin :refs/heads/<branch>` — an empty source —
|
|
115
|
+
deletes the branch on the remote. A rejected push → its message, verbatim, and stop. Never retried
|
|
116
|
+
with `--force`.
|
|
117
|
+
|
|
118
|
+
## 5. The ticket summary (offer)
|
|
119
|
+
|
|
120
|
+
Only after a successful push, and only in ticket mode with a real tracker id. The people reviewing
|
|
121
|
+
the ticket read it there, never in the work folder; the receiver does not parse it.
|
|
122
|
+
|
|
123
|
+
- **Read the body back** — the summary goes inside the ticket's own text, never over it:
|
|
124
|
+
`gh` → `gh issue view {TICKET} --json body -q .body` · `glab` → `glab issue view {TICKET} -F json`,
|
|
125
|
+
its `description`. Any other tracker → the offer is not made: one line saying flow cannot read that
|
|
126
|
+
body back to keep its text.
|
|
127
|
+
- **The write command** — `tracker.edit_cmd`, `{TICKET}` and `{BODY_FILE}` substituted. Empty →
|
|
128
|
+
`gh issue edit {TICKET} --body-file {BODY_FILE}` for `gh`,
|
|
129
|
+
`glab issue update {TICKET} --description-file {BODY_FILE}` for `glab`.
|
|
130
|
+
- **The block**, short, in the language of the ticket. A feature takes it from `01-context.md`,
|
|
131
|
+
`03-design.md` and `04-mr-plan.md`; a bug from `01-context.md` and `03-investigation.md` — the
|
|
132
|
+
expected behaviour as its criteria, the root cause and the intended fix as its design, "Areas with
|
|
133
|
+
similar risk" as its risks. A section whose source does not exist (an XS study, an S feature with
|
|
134
|
+
no plan) says `none`:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
<!-- flow-study -->
|
|
138
|
+
## What and why
|
|
139
|
+
## Acceptance criteria
|
|
140
|
+
## Design in brief
|
|
141
|
+
## MR/PR plan
|
|
142
|
+
## Risks
|
|
143
|
+
<!-- end flow-study -->
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Criteria keep their literal values. The plan lists each MR/PR with what it covers and what it
|
|
147
|
+
waits on; a bug's plan is its single fix.
|
|
148
|
+
- **The new body**: the body read above with the block between the two markers replaced — or, with
|
|
149
|
+
no markers yet, the block appended after a blank line. Written to a `mktemp` file outside the
|
|
150
|
+
tree — `{BODY_FILE}` — so nothing of it can be committed later.
|
|
151
|
+
- **Show the block and ask** with `AskUserQuestion`, **in every mode**: it writes to a shared
|
|
152
|
+
tracker. **Write it** · **Skip**. Failure → its message in one line; the push stands.
|
|
153
|
+
|
|
154
|
+
## 6. Close
|
|
155
|
+
|
|
156
|
+
Report following flow-core §3: the branch and the commit, the file count, whether the ticket
|
|
157
|
+
summary was written. Refresh the panel: a `Now` line saying the study was handed off, no `Decision`
|
|
158
|
+
line. `meta.json` gains nothing — the branch on `origin` is the record, and the §3 refusal reads it.
|
|
@@ -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).
|
|
@@ -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.
|
package/adapters/gemini/CORE.md
CHANGED
|
@@ -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.
|
|
19
|
+
**This file belongs to flow `0.87.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
|
|
@@ -263,6 +263,11 @@ assumed:
|
|
|
263
263
|
`glab`, no tracker write in this mode — not before `ship`, not in it. The orchestrator also keeps,
|
|
264
264
|
between runs, the work folder as the run left it and the work branch at the commit where it
|
|
265
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).
|
|
266
271
|
- **Before any closing order, commit** what this run left uncommitted outside `.claude/work/`, new
|
|
267
272
|
files included (`WIP <TICKET>: before <gate|order>` — `auto`'s WIP authority): the orchestrator
|
|
268
273
|
keeps only what is committed. **Only on the work branch**: before it exists (`start` refusing a
|
|
@@ -297,6 +302,7 @@ run has.
|
|
|
297
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` |
|
|
298
303
|
| An unanswered high-severity challenge (`design`, `investigate`) | question `design_challenge` / `investigation_challenge` |
|
|
299
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 |
|
|
300
306
|
| Below-XS check (`start`) | record — open the work |
|
|
301
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 |
|
|
302
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
|
|
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.
|
|
@@ -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
|
|
|
@@ -245,6 +245,7 @@ Two signals arrive on an open MR/PR, each with its own cross-cutting loop (feat
|
|
|
245
245
|
- `/flow:work:daily [question]` — the **work assistant** (daily standup), read-only. **Local** (`.claude/work/` + git) + **forge** (open MRs/PRs, reviews awaiting you, red CI, unmergeable, unresolved threads via `git.cli`) + **tracker** (assigned tickets, priority changes via `tracker.tool`); where they cross, concrete commands (`/flow:feat:start`, `/flow:work:green`, `/flow:work:respond`). No argument → *yesterday · today · blockers*; a question → just that. External sources best-effort, never blocking; the only write is a "last seen" marker, like `/flow:news`.
|
|
246
246
|
- `/flow:work:status` — all works in `.claude/work/`, current phase, divergence with git.
|
|
247
247
|
- `/flow:work:run [ticket]` — the **entry an orchestrator launches** for an `unattended` run: asks it `why` (start · answer · merged · review · pipeline), routes to the phase that answers it, and makes no decision of its own. Refuses to run in any other mode.
|
|
248
|
+
- `/flow:work:handoff` — hands a **finished study** to whoever builds it elsewhere (an unattended server, another machine): refuses an unfinished one, pushes only this work's folder as a parentless commit to `git.handoff_branch` without touching the checkout, asks before the push, then offers a marked summary for the ticket body (`tracker.edit_cmd`).
|
|
248
249
|
- `/flow:work:resume` — detects the branch, reads `meta.json`, recaps, suggests the next step. **Re-reads the ticket's comment thread** (§2.5), reports only what is new since `01-context.md`, appends it to the artifact; never amends the design on its own.
|
|
249
250
|
- `/flow:work:try <branch>` / `/flow:work:try --back` — point the main checkout at a branch to test it here, then return; re-syncs per `git.worktree_resync`. Resolves the work behind the branch and, once the environment is up, **prints the manual test plan already written** (the `needs-manual`/`unproven` criteria, or the acceptance criteria when `validate` has not run) and offers to collect Pass/Fail/Blocked into the validation artifact. No work behind the branch → the plain switch, as before.
|
|
250
251
|
- `/flow:work:clean [--dry-run]` — **periodic sweep** of finished work's residue: worktree, local branch, `.claude/work/` folder (intermediate train MR/PRs never set `phase: done`, so the `ship`/`abandon` prompt never fires). Verdict per branch from **the forge** with local fallbacks, including patch-equivalence for **squash merges** (`git branch --merged` misses them); acts only on `merged`/`empty`. `unknown` never a candidate; dirty and unpushed protected; work folders **archived, never deleted**; remote never touched. **`autonomy.mode` does not authorize deletion**: `auto` confirms the list too. `--purge-archive <N>d`: separate opt-in pass over `_archive/`, only folders already committed to git.
|
|
@@ -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).
|