skills/flow-plan/SKILL.md
Decompose a problem statement into a pre-planned decomposed issue. Accepts either an issue reference (#N, re-plans in place) or a bare prompt (synthesizes What/Why/AC and files a new issue). Runs a Tech-Lead-default planning conversation, dispatches to PM/Tech Lead/CTO sub-agents on explicit user request, then files or edits the issue ready for /flow:flow-start. Usage: /flow:flow-plan #N or /flow:flow-plan <topic>
npx skillsauth add benkruger/flow flow-planInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Produce a structured implementation plan and attach it to a
GitHub issue. The skill holds a Tech-Lead-default planning
conversation, runs decompose:decompose against the agreed
approach, transforms the synthesis into an Implementation Plan
section wrapped in FLOW-PLAN sentinels, and either edits an
existing issue in place (issue-input mode) or files a new
decomposed issue (bare-prompt mode).
The output is an issue ready for /flow:flow-start #N (re-planned
issue) or /flow:flow-start #M (new decomposed issue). The
issue body carries the implementation plan that
bin/flow plan-from-issue extracts at flow-start.
/flow:flow-plan #N
/flow:flow-plan <topic>
The skill accepts two argument shapes:
#N — a literal # followed by a positive integer. Plans
against existing issue #N: Step 2 fetches the body. When the
DAG partitions cleanly into ≥ 2 disconnected components,
Step 6 runs multi-track filing — one child issue per
component with cross-component blocked-by links, leaving the
source issue as a plain problem statement (per AC#4 of issue
#1590). Otherwise Step 6 edits the issue in place,
preserving every byte above the opening FLOW-PLAN sentinel.<topic> — any non-empty string that does not match the
#N regex. Seeds discussion in Step 4; Step 6 synthesizes a
brief ## What / ## Why / ## Acceptance Criteria from the
conversation and files one new decomposed issue. Bare-prompt
mode is always single-track per AC#8 — even when the DAG
partitions, exactly one issue is filed.The skill takes no flags. A missing argument is rejected at Step 1.
The skill mutates shared GitHub state only at the very end of
Step 6, on explicit user approval. In bare-prompt mode it files
one new decomposed issue (creation is idempotent by title — warn
the user before filing a duplicate). In issue-input single-track
mode it edits the existing issue's body and re-applies the
decomposed label (the gh issue edit --add-label call is
idempotent). In issue-input multi-track mode it files one new
decomposed issue per component AND encodes blocked-by edges via
bin/flow link-blocked-by (the dependency endpoint is
idempotent — re-applying the same edge is a no-op on GitHub's
side).
The intermediate side effect is the per-session utility-in-progress marker (scoped to the user's Claude home, not the project), which lets the Stop hook refuse turn-end while the discussion-mode skill is running.
Multiple /flow:flow-plan sessions on the same machine in
different terminal windows are independent — each has its own
session id, its own conversation context.
At the very start, output the following banner in your response (not via Bash) inside a fenced code block:
```text
──────────────────────────────────────────────────
FLOW v2.6.1 — flow:flow-plan — STARTING
──────────────────────────────────────────────────
```
Immediately after the banner, write the per-session "utility skill
in progress" marker so the Stop hook refuses turn-end while this
skill is running. Without the marker the model returns control to
the user when a planning sub-agent Skill tool returns mid-pipeline
at Step 5 (Persona Dispatch) or when decompose:decompose returns
mid-pipeline at Step 6 (Wrap-up), breaking the unattended-flow
contract this skill promises.
${CLAUDE_PLUGIN_ROOT}/bin/flow set-utility-in-progress --skill flow:flow-plan
If the marker-write call returns status: error with
no session_id available, the skill proceeds without the marker.
The Stop hook treats a missing marker as a non-block, so the skill
runs without protection but does not break.
/flow:flow-plan accepts either of two argument shapes — #N
(issue-input mode, which plans against an existing problem
statement and edits that same issue in place) or a bare non-empty
prompt (bare-prompt mode, which synthesizes a brief What/Why/AC
from the conversation and files one new decomposed issue). The
gate routes between the two modes; it does not redirect users to
another skill.
If the argument matches the regex ^#[1-9][0-9]*$ after stripping
whitespace, set the working mode to issue-input and proceed
to Step 2. Step 2 fetches the parent issue body and applies the
remaining open-state gate.
If the argument starts with a # character but does NOT match
the ^#[1-9][0-9]*$ regex (e.g., a lone #, #0, #-1,
#1234abc, #1.5), the leading # is a strong signal of
intended issue-input mode but the trailing characters are invalid.
Routing such an argument to bare-prompt mode would silently file
a new decomposed issue with the malformed token as the seeding
topic — almost certainly a typo. Clear the utility-in-progress
marker and reject with usage guidance:
"Argument starts with
#but does not match^#[1-9][0-9]*$. To plan against an existing issue, pass a valid number like#1234. To plan from a bare prompt, drop the leading#."
If the argument is a non-empty string that contains no leading
# (a bare prompt such as /flow:flow-plan add a budget cap),
set the working mode to bare-prompt and skip Step 2 entirely.
The prompt seeds the planning discussion at Step 4 — there is no
GitHub issue to fetch in this mode, so Step 2's fetch and gates
do not apply. Continue at Step 3.
If no argument was provided at all, clear the utility-in-progress marker so the Stop hook does not refuse turn-end after the rejection, then output the usage guidance and stop:
${CLAUDE_PLUGIN_ROOT}/bin/flow clear-utility-in-progress --skill flow:flow-plan
"Argument required. Usage:
/flow:flow-plan #Nto plan against issue N in place, or/flow:flow-plan <topic>to synthesize a brief problem statement and file a new decomposed issue."
Do not proceed without an argument. Do not propose direct edits,
commit changes, or take any action outside this skill without
either an #N argument or a bare-prompt argument.
Only when Step 1 resolved to issue-input mode. In bare-prompt mode there is no GitHub issue to fetch; skip to Step 3.
Read the issue's title, body, number, labels, and state via the
gh CLI. The body becomes the input the Tech Lead reads to
ground the planning conversation; the state gates against closed
issues (planning into a closed problem statement requires the
user to reopen it explicitly, because bin/flow plan-from-issue
refuses closed issues at flow-start and the resulting plan would
be unusable). The state field is load-bearing — without it,
the closed-issue gate below silently bypasses for every issue
because state == "closed" evaluates against an absent field that
is never equal to "closed".
gh issue view <issue_number> --json title,body,number,labels,state,url
Parse the JSON output. Extract title, body, number, url,
and the labels array. The url field is consumed by Step 6's
bin/flow add-issue call so the recorded URL points at the same
issue the user passed.
Verify the fetched issue is in a state this skill can plan against:
The issue MUST exist. If gh issue view returns a non-zero exit
status or an error JSON, clear the marker and report the error
to the user. Do not proceed.
The issue's state MUST be open. Closed issues represent
abandoned or completed work and must not be planned against
without the user explicitly reopening them. bin/flow plan-from-issue rejects closed issues at flow-start with
reason: issue_closed, so a plan written into a closed issue
is unusable downstream. If the issue is closed, clear the
marker and report:
"Issue #N is closed. Re-open it via
gh issue reopen Nbefore planning, or pick a different issue."
The issue's decomposed label is NOT a rejection criterion. An
issue that already carries decomposed is a candidate for
in-place re-planning — Step 6 issue-input mode preserves the
content above the FLOW-PLAN sentinel and swaps the
sentinel-delimited plan block, leaving the original problem
statement intact.
Do not proceed to Step 3, propose direct edits, commit changes, or take any action outside this skill until the fetch succeeds and the gate passes.
</HARD-GATE>Resolve the project root and read .flow.json from it. The file
is gitignored and lives only at the main repo root — never in a
linked worktree — so the read must target the main repo path
regardless of whether the skill was invoked outside a worktree or
from inside one.
Run git worktree list --porcelain. The path on the first
worktree line is the main repo root. Read <project_root>/.flow.json
via the Read tool.
The file is written by /flow:flow-prime and stores per-user
preferences, including the optional role field that records the
user's primary working role.
Extract the role field from the JSON. The field is optional —
older .flow.json files written before the role-selection step
omit it. Treat absence, an unknown value, or a read failure as "no
preferred default" and proceed silently — never block on a missing
role.
The default voice for /flow:flow-plan is the Tech Lead. The
skill's purpose — turning a problem statement into an
implementation plan with a Dependency Graph, Tasks, and
file-target callouts — is the Tech Lead's natural domain. Map the
user's role field to a complementary suggestion only:
| .flow.json role value | Conversation note |
|---|---|
| "pm" | The user is a PM — note once that this skill plans implementation (Tech Lead voice); the PM's natural collaborator on this is the Tech Lead. |
| "tech-lead" | The user IS a Tech Lead — proceed straight into Tech-Lead-voice discussion without a role-suggestion preamble. |
| "founder-solo" | The user wears multiple hats — proceed into Tech-Lead-voice discussion; offer to invite the PM voice via Step 5 if the conversation drifts into user-visible behavior questions. |
| Absent / unknown / read failure | Default to Tech Lead voice silently. |
The note is conversational, not gated. The discussion-mode entry in Step 4 runs the same way for every role, and any sub-agent dispatch in Step 5 still requires an explicit user request.
The planning room exists so the user can think out loud against a collaborator who reads the code, asks clarifying questions about constraints and edge cases, and helps shape the implementation approach. Discussion mode is the default posture — the skill stays here until the user explicitly asks for a persona dispatch (Step 5) or signals that the implementation plan is ready to file (Step 6).
In this step, the skill:
/flow:flow-explore, source-code reads ARE permitted here —
the Tech Lead role requires them.)Discussion mode forbids action. While in this step, the skill must NOT:
/flow:flow-commit.## Implementation Plan /
### Context / ### Tasks headings during discussion mode
would short-circuit the decompose-driven structure that the
wrap-up step builds. Naming files, citing line numbers, and
summarizing the agreed approach in conversational prose is
fine; rendering a sentinel-wrapped or heading-structured draft
is not.AskUserQuestion to manufacture a checkpoint the user did
not ask for. The discussion is conversational; the user drives
the cadence by sending messages. Per
.claude/rules/autonomous-phase-discipline.md, never
self-impose a pause via AskUserQuestion.Stay in discussion mode until the user types one of: a persona request (then proceed to Step 5 for the named persona), a hand-off signal ("ready", "file it", "let's go") (then proceed to Step 6), or any other prose (then continue the conversation in discussion mode).
</HARD-GATE>When the user explicitly asks for a planning persona's view ("PM view?", "What does Tech Lead think?", "CTO take?"), summarize the discussion so far and dispatch to the named sub-agent. The skill remains the orchestrator; the sub-agent returns a structured analysis or a refusal block, and the skill renders the result.
Build the agent prompt with three labeled sections:
| User request | Sub-agent to invoke |
|---|---|
| PM view | flow:pm |
| Tech Lead view | flow:tech-lead |
| CTO view | flow:cto |
Pass the agent prompt above as the Skill tool's input.
<HARD-GATE>When the sub-agent returns, render its response verbatim in the
conversation. If the response is a ## SCOPE REFUSAL block, the
skill MUST surface it as-is and wait for explicit user direction.
The refusal is the agent's signal that the proposed change exceeds
its authority and a different tier should evaluate it.
When a ## SCOPE REFUSAL block returns, the skill must NOT:
Present the refusal block to the user and ask them how to proceed. If the user says "escalate to Tech Lead" or "ask the CTO", the next persona dispatch fires in a fresh Step 5 invocation. If the user wants to discuss the refusal in plain language, return to Step 4.
</HARD-GATE>When the agent returns an in-scope analysis (not a refusal), render it verbatim and return to Step 4 so the user can react, ask follow-ups, or request another persona's view. Do not assume the agent's recommendation is the user's decision.
When the user signals readiness — "ready", "file it", "let's go", "create the issue", or any equivalent phrasing — run the decompose-and-file pipeline. The output shape depends on the Step 1 mode:
## Implementation Plan is appended. The
parent issue stays open; the assignee is not changed.## What / ## Why / ## Acceptance Criteria from the conversation, appends the
sentinel-wrapped plan, and files via bin/flow issue with
--label decomposed --assignee @me. There is no parent to
close.Generate a short session ID using the Bash tool:
${CLAUDE_PLUGIN_ROOT}/bin/flow generate-id
This ID scopes the body file path (.flow-issue-body-<id>) so
concurrent /flow:flow-plan invocations cannot collide on the
same temp file.
Invoke decompose:decompose via the Skill tool with an
implementation-focused prompt. The prompt must make clear that
the problem statement is already agreed; decompose should
structure the implementation into tasks, not re-analyze the
problem.
The prompt's problem-statement input depends on the Step 1 mode:
## What / ## Why / ## Acceptance Criteria the
user filed).Example prompt structure:
"Given the following problem statement and the agreed implementation approach, decompose the work into ordered tasks with dependencies, approach, and file targets. The problem is already understood — focus on structuring the implementation.
[Problem statement —
## What/## Why/## Acceptance Criteria— either from the parent issue body (issue-input mode) or synthesized from the conversation (bare-prompt mode)][Summary of the agreed approach from the conversation]
[Key files and patterns identified during discussion]"
The decompose output produces a structured DAG with nodes, dependencies, and a synthesis — this becomes the foundation for the Implementation Plan.
<HARD-GATE>When the Skill tool returns from the decompose:decompose
invocation, you are still inside flow-plan. The Skill tool's
return is NOT a stopping point — it is a mid-skill handoff. Do
not stop, do not summarize, do not ask the user "want me to
continue?", do not return control to the user. Proceed
immediately to Multi-Track Detection below using the decompose
output you just received.
If you stop here, the user must prompt you again to continue, which breaks the unattended flow that flow-plan promises to its consumers.
</HARD-GATE>Per AC#4 of issue #1590, after decompose:decompose returns,
inspect the DAG before drafting the Implementation Plan. When
the DAG partitions into two or more disconnected components
(groups of nodes with zero cross-group dependency edges) AND
the skill ran in issue-input mode, the work belongs in two or
more separate issues — one child per component — rather than
in a single combined plan. The multi-track branch is restricted
to issue-input mode by design: bare-prompt mode is always
single-track per AC#8 (a bare-prompt invocation must file
exactly one issue, never multiple).
Detection algorithm. Walk the DAG's nodes and edges
fields from the decompose synthesis. Treat the edges as
undirected and partition the node set into connected
components via union-find or BFS. Count the distinct
component IDs. When the count is ≥ 2 AND Step 1 recorded the
issue-input mode, the run is multi-track. Otherwise the run is
single-track and the rest of Step 6 continues unchanged from
### Transform + Draft onward.
Render the proposed split inline. Before any filing, output the proposed split to the user inside a fenced code block so the user sees the structural decision before any side effect:
Multi-Track Filing — proposed split for source issue #N
Component A (root: <node-id>):
- <task or node summary>
- <task or node summary>
Component B (root: <node-id>):
- <task or node summary>
Cross-component edges (will become blocked-by links between
children): Component B blocked-by Component A.
Source issue #N will receive blocked-by links from each root
child and will stay a plain problem statement (no
Implementation Plan block, no `decomposed` label, not closed).
The user may intervene to collapse the split back to single-track by typing a message before the multi-track filing pipeline runs. The flow halts on any real user turn; when the user collapses to single-track, re-route to Transform + Draft below and continue as if the DAG had a single component. When no override arrives, proceed to Multi-Track Filing Pipeline (later in this Step 6) and SKIP the single-track Transform + Draft / Plan Review / Validate / File-or-Edit chain entirely.
Take the decompose synthesis and transform it into an Implementation Plan section. The Implementation Plan must contain these subsections:
## What / ## Why
established, in implementation terms. This is the bridge from
the user-visible problem statement to the implementation plan.| Task | Type | Depends On |
|------|------|------------|
| 1. Write tests | test | — |
| 2. Implement feature | implement | 1 |
Tasks must use #### Task N: heading format.
The title flows downstream into the branch name (via
branch_name), the PR title, the commit subject, and every
user-visible surface.
/flow:flow-explore filing time.Required. Subject + verb + object as a stakeholder would say it out loud. A non-contributor reading the title in a release-notes feed should understand what the change is for without consulting the codebase.
Forbidden. Code symbols, function names, file paths, line numbers, internal acronyms without expansion, one-letter shorthand, repo-specific jargon.
Build the issue body in working memory. The reconstruction is mode-dependent.
Issue-input mode — start from the issue body fetched at Step 2. Split the body into three pieces using the FLOW-PLAN sentinel pair (refer to them by paraphrase here — the literal HTML-comment marker strings live only at their canonical positions inside the issue body, per the discipline below):
## What / ## Why /
## Acceptance Criteria (or whatever shape the issue body
had) lives here.Reassemble the body as <prefix> + fresh sentinel-wrapped
## Implementation Plan block + <suffix> (concatenated with
blank-line separators so each section's ## heading begins on
its own line). Do NOT rewrite or summarize the preserved
pieces; only the sentinel-delimited plan block changes. Re-
planning is idempotent by construction: every re-plan preserves
the same prefix AND the same suffix while swapping only the
plan block.
Bare-prompt mode — synthesize a brief ## What / ## Why
/ ## Acceptance Criteria from the planning conversation (the
bare prompt the user typed plus any clarification surfaced
during Step 4 discussion). Append the freshly-decomposed
sentinel-wrapped ## Implementation Plan after the Acceptance
Criteria section. There is no prior body to preserve.
Each top-level section uses ## headings. The Implementation
Plan's subsections use ### headings. Task entries within the
Tasks subsection use #### headings.
Wrap the Implementation Plan in FLOW-PLAN sentinels. Place
the literal HTML comment <!-- FLOW-PLAN-BEGIN --> on its own
line immediately before the ## Implementation Plan heading,
and the literal HTML comment <!-- FLOW-PLAN-END --> on its own
line immediately after the last Task entry (before the next
## heading). The sentinels delimit the bytes that
bin/flow plan-from-issue will extract verbatim and write to
.flow-states/<branch>/plan.md when the issue is later picked up
via /flow:flow-start #M. Without the sentinel pair,
plan-from-issue rejects the issue with plan_markers_missing
and the flow halts.
Paraphrase every prose reference to the plan-sentinel pair.
The literal HTML-comment marker strings only appear in the body
at two positions — the opening sentinel and the closing sentinel.
They must never appear inside prose, headings, code blocks,
examples, or any other surface of the body. bin/flow plan-from-issue extracts the slice between the FIRST occurrence
of each marker, so a literal marker mid-prose silently redirects
the extraction to the wrong slice. Whenever the body needs to
reference the marker pair, paraphrase: "the FLOW-PLAN sentinel
pair", "the plan-extraction markers", "the canonical sentinels
delimiting the plan block".
Before presenting the draft, scan the body — including the Implementation Plan subsections — for the following forbidden phrasings, which ground the current decision in a historical artifact rather than the code's current merits:
"PR #<N> decided", "the prior PR chose", "the previous commit" — historical decision cited as authority"kept for backward compatibility", "compat shim", "legacy alias for older" — preservation justified by inherited
reasoning rather than a current consumer"older plugin versions", "prior plugin" —
plugin-version-compat reasoning"as PR #<N> chose to", "following the prior PR" —
deferring to past decisionsEvaluate matches in context: a bare PR #<N> reference used for
forensic detection (linking blocked-by, naming a specific merge)
is fine; a PR #<N> reference used to justify the present design
is forbidden. If any match is justifying-shape rather than
identifier-shape, revise the draft. See
.claude/rules/no-backwards-reasoning.md.
Before presenting the draft, scan the body — including the Implementation Plan subsections — for the following forbidden phrasings, which signal defensive scope shrinkage rather than genuine exclusion grounded in a concrete blocker:
"Out of scope" — defensive enumeration of exclusions written
before concrete blockers have surfaced; the scan reads
case-flexibly, so common section-heading title-case forms in
issue bodies are also flagged"Non-goals" — same defensive-enumeration shape under a
different heading"would expand scope" — reflexive scope shrinkage that
bypasses the three-condition gate in
.claude/rules/scope-expansion.md"separate code surface" — code-shape framing used as an
exclusion criterionEvaluate matches in context: a passing mention that names a
concern is fine; an enumerated section or bulleted list of
exclusions is forbidden. If any match is exclusion-shape rather
than identifier-shape, revise the draft. See
.claude/rules/include-bias-in-issues.md.
Present the full draft inline in the response — both title and body. Do not tell the user to look at a file. Render it as a formatted markdown block so the user can review every detail.
The drafted Implementation Plan has been transformed, combined,
and pre-scanned by the orchestrating model — every check so far
has run on the orchestrating model's own output. This subsection
adds a cognitively isolated rule-adherence review before the issue
is filed or edited. The reviewer audits the drafted plan against
the .claude/rules/ corpus; on re-decompose the plan is re-derived
through decompose:decompose (never hand-patched) and re-reviewed,
capped at 3 attempts.
Invoke flow:plan-reviewer via the Agent tool with
subagent_type: "flow:plan-reviewer" (the canonical sub-agent
dispatch shape — matching the flow-review and flow-learn agent
invocations; the Skill tool is reserved for skill-to-skill
dispatch, not sub-agent dispatch). The prompt is a three-block
payload: the drafted Implementation Plan body verbatim, the
parent vanilla issue's Acceptance Criteria verbatim, and an
absolute path to the .claude/rules/ directory. Explicitly
state that no conversation context is provided — the agent must
reason from the artifacts alone.
Substitute <project_root> with the absolute path returned by
pwd at session start; the bare relative .claude/rules/ would
resolve against the sub-agent's cwd, which is not guaranteed to
equal the project root.
The prompt structure:
You are reviewing a drafted Implementation Plan for rule
adherence. No conversation context is provided.
DRAFTED_PLAN:
<the full drafted Implementation Plan body verbatim, in full —
copy every line including Context, Exploration, Risks, Approach,
Dependency Graph, and Tasks; do NOT summarize or paraphrase>
ACCEPTANCE_CRITERIA:
<the parent vanilla issue's Acceptance Criteria section, verbatim>
RULES_DIR: <project_root>/.claude/rules/
Parse the agent's response. First check for the literal
## END-OF-FINDINGS marker as the final structural element. If
the marker is ABSENT, the agent was truncated by maxTurns
exhaustion (per .claude/rules/cognitive-isolation.md "Context
Budget + Truncation Recovery"). Re-invoke the agent with a
narrower scope partitioned by rule-family (e.g., split
.claude/rules/ into architecture/ + correctness/ + the
rest, one re-invocation per partition), then combine findings
across runs. If a re-invocation itself returns without the
marker, that is double-truncation — record the truncation in
the final user-visible violations block rather than splitting
infinitely.
When the marker is present, parse VERDICT: from the response.
The reviewer classifies each violation per-finding (carried on a
Remediation: line) and the aggregate verdict is the routing
signal. Branch three ways:
VERDICT: pass → the plan satisfies the project rules. Fall
through to Validate the Body unchanged.VERDICT: revise-transform → at least one applicable rule
is violated AND every violation is a Transform-step prose
artifact (table placement, a missing required table, doc-surface
enumeration, prose wording). Capture the Violations: block and
run the revise-transform branch of the loop below — apply the
reviewer's named prose fixes directly to the drafted body
without re-running decompose.VERDICT: re-decompose → at least one violation requires a
task-DAG change (an unmotivated component, a missing task, wrong
ordering, a missing gate-consumer task). Capture the
Violations: block from the agent's output and run the
re-decompose branch of the loop below.For re-decompose: do NOT hand-patch the plan. The plan must be
re-derived through decompose:decompose with the violations fed
back as input. Hand-patching a re-decompose-class finding defeats
the cognitive-isolation contract — the orchestrating model would
be editing its own output to satisfy the reviewer, reintroducing
the bias the gate exists to break.
For revise-transform: applying the reviewer's named prose fix
in the Transform step IS the sanctioned remediation — not a
hand-patch the orchestrator self-authorized. The cognitively
isolated reviewer has already classified the fix as a mechanical
prose correction with no design judgment; the orchestrator
executes the reviewer's named instruction, it does not re-judge
the plan's substance. Hand-patching a re-decompose-class finding
remains forbidden in every context.
</HARD-GATE>
When the verdict is re-decompose or revise-transform, run a
bounded retry loop mirroring the Validator Auto-Fix Loop shape
below. A single cap of 3 attempts (including the first failed
review) is shared across both remediation branches — they never
have separate budgets.
For each retry attempt, run the remediation step matching the verdict the most recent review returned:
re-decompose remediation — the fix needs a task-DAG
change:
decompose:decompose prompt that includes
the parent vanilla issue context, the prior plan synthesis,
and the Violations: block returned by the reviewer.decompose:decompose via the Skill tool and wait for
the new synthesis.Transform + Draft on the new synthesis to produce a
revised Implementation Plan.revise-transform remediation — every violation is a
Transform-step prose artifact, so the fix is in-place prose
correction without re-running decompose:
decompose:decompose — the task DAG is
already correct.Then, regardless of which remediation branch ran:
flow:plan-reviewer against the revised plan via
the Agent tool with subagent_type: "flow:plan-reviewer".## END-OF-FINDINGS marker. If absent, re-invoke
with narrower scope per the truncation-recovery path above
before parsing VERDICT:.VERDICT: again. On pass exit the loop and fall
through to Validate the Body. On re-decompose or
revise-transform increment the shared attempt counter and
continue with the matching remediation branch.After 3 failed reviews, do NOT loop further. The plan-reviewer
advises — it never blocks filing. The issue is then
filed with the last drafted plan; the final Violations: block
is surfaced as a non-blocking advisory warning rather than a
halt.
Print the advisory preface, then render the agent's final
Violations: block verbatim:
```text
⚠ Plan Review advisory — the plan-reviewer returned a non-pass
verdict (`re-decompose` or `revise-transform`) on all 3
attempts. The issue is being filed with the last drafted plan;
the violations below are surfaced for the user, not a block on
filing.
```
The user sees which rules the plan repeatedly violated and can
decide whether to address them — by invoking /flow:flow-plan #N
again with additional discussion-mode context, or by escalating
the rule design if a rule itself is at fault — before the issue
reaches /flow:flow-start.
Then fall through to Validate the Body → File or Edit →
Finish with the last drafted plan. The utility-in-progress
marker clears at the normal Finish step.
Write the reconstructed body to .flow-issue-body-<id> using the
Write tool. Per .claude/rules/filing-issues.md "The Pattern":
when invoked inside an active FLOW worktree, prepend the worktree
absolute path so the validate-worktree-paths hook allows the
Write. When invoked outside a worktree, the relative form
resolves cleanly because Write and bin/flow issue both target
the same project root.
Validate the body file through the pre-filing validator with
--mode decomposed before either filing the new issue or editing
the existing one. The validator runs the same sentinel-extraction
logic that bin/flow plan-from-issue applies at flow-start; any
body that fails this gate is unconsumable downstream and must NOT
be sent to GitHub:
${CLAUDE_PLUGIN_ROOT}/bin/flow validate-issue-body --mode decomposed --body-file .flow-issue-body-<id>
Parse the JSON output. If status is ok, proceed to the
mode-specific filing branch below. If status is error, run
the bounded auto-fix loop:
When the validator returns status: error, the skill must NOT
prompt the user. The validator's message names a concrete defect
(missing FLOW-PLAN sentinel pair, missing required subsection,
## Implementation Plan heading on the wrong nesting level, etc.).
Apply a mechanical fix that addresses the named defect — adjust
the sentinel placement, add the missing subsection, normalize the
heading — rewrite the body file with the Write tool, and re-run
the validator. Track the attempt count mentally — the cap is
5 attempts including the first failure.
After 5 failed validator runs, clear the utility-in-progress marker, halt the skill with the structured error envelope, and print the COMPLETE-FAILED banner. Do NOT file the issue. Do NOT edit any issue. Do NOT loop further.
${CLAUDE_PLUGIN_ROOT}/bin/flow clear-utility-in-progress --skill flow:flow-plan
```json
{"status":"error","reason":"validator_max_retries","attempts":5}
```
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✗ FLOW v2.6.1 — flow:flow-plan — COMPLETE-FAILED
Validator rejected the body 5 times. Issue not filed.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
Once the validator returns ok, branch on the Step 1 mode.
Issue-input mode — edit #N in place. Push the rebuilt body
into the same issue, re-applying the decomposed label (the
label may already be present; --add-label is idempotent).
Substitute the issue number (the #N the user passed at Step 1)
for <N>:
gh issue edit <N> --body-file .flow-issue-body-<id> --add-label decomposed
When gh issue edit returns a non-zero exit status (transient
network failure, auth scope mismatch, the issue closed between
Step 2 and now, etc.), the body update may have partially landed
— gh writes the body before applying labels, so a mid-call
failure can leave the issue with the new body but the
decomposed label still missing, making it invisible to
flow-issues / flow-orchestrate. Surface the gh exit status
and stderr inline to the user with a concrete recovery command,
then clear the utility-in-progress marker and stop. Do NOT
retry the edit silently. The recovery command shape:
"
gh issue edit <N>failed. Inspect viagh issue view <N> --json body,labels. If the body landed butdecomposedis missing, rungh issue edit <N> --add-label decomposed. If the body did not land, the.flow-issue-body-<id>file is still on disk — re-rungh issue edit <N> --body-file .flow-issue-body-<id> --add-label decomposed."
gh issue edit does not auto-delete the body file. Delete the
temp file explicitly via the Write tool by writing an empty
string to .flow-issue-body-<id>, then ignore the empty file —
the worktree cleanup at Phase 5 Complete handles disposal. (The
Bash permission allow-list refuses ad-hoc rm calls during a
flow per .claude/rules/permissions.md; rewriting to empty is
the sanctioned alternative.) Skip this empty-write step when
gh issue edit failed — preserving the body file on disk gives
the user a concrete artifact to retry the edit against.
Capture the issue's URL from the gh issue view JSON fetched at
Step 2 (the url field), then record the issue in the state file
(no-op if no FLOW feature is active):
${CLAUDE_PLUGIN_ROOT}/bin/flow add-issue --label decomposed --title "<issue_title>" --url "<issue_url>" --phase flow-plan
Bare-prompt mode — file a new issue. File against the
current repo (no --repo flag — flow-plan always files where
the user is) WITH the decomposed label so flow-issues and
flow-orchestrate recognize it as ready-for-flow-start work,
and WITH --assignee @me so the new decomposed issue is
assigned to the planner who ran flow-plan:
${CLAUDE_PLUGIN_ROOT}/bin/flow issue --title "<issue_title>" --body-file .flow-issue-body-<id> --label decomposed --assignee @me
Capture both the new issue's URL and number from the filer's
output. bin/flow issue returns a JSON envelope including the
full GitHub URL of the issue it created; the trailing
/issues/M segment of that URL gives the decomposed issue
number M. Keep both the full URL (as <issue_url>) and the
number for the recording call below — bare-prompt mode has no
Step 2 fetch to pull these from.
Record the issue in the state file (no-op if no FLOW feature is active):
${CLAUDE_PLUGIN_ROOT}/bin/flow add-issue --label decomposed --title "<issue_title>" --url "<issue_url>" --phase flow-plan
Runs only when Multi-Track Detection routed here — the DAG had ≥ 2 disconnected components AND the run is in issue-input mode (per AC#4 + AC#8). When the run is single-track, this subsection is skipped entirely; the single-track flow above (Transform + Draft through File or Edit) has already filed or edited the issue and the model falls through to Finish below.
For each component in the detected partition, build, validate,
plan-review, and file ONE child issue. After every child is
filed, link the children together via bin/flow link-blocked-by
to encode the cross-component edges, and link the source issue
blocked-by each root child so the AC#5 cascade can close the
source naturally when the children eventually close.
Per-child sub-flow. Repeat the following for each component:
Synthesize a child What/Why/Acceptance-Criteria header from
the component's nodes — the planning conversation already
established the parent's ## What / ## Why; the child
header narrows it to this component's scope only.
Run the same Transform + Draft / Title Authoring /
Reconstruct Issue Body / Pre-Draft scans pipeline that the
single-track subsections describe, but constrained to THIS
component's nodes and dependency subgraph. Produce a
per-child issue body with the FLOW-PLAN sentinel pair and
the ## Implementation Plan block covering only this
component's tasks.
Write the child body to
.flow-issue-body-multi-<id>-<component> via the Write
tool. The unique suffix prevents collisions with the
single-track body file and with sibling children.
Validate the child body BEFORE filing:
${CLAUDE_PLUGIN_ROOT}/bin/flow validate-issue-body --mode decomposed --body-file .flow-issue-body-multi-<id>-<component>
The same Validator Auto-Fix Loop (max 5 attempts) applies
per child — when the validator returns status: error,
apply a mechanical fix and retry up to 5 times for this
child before halting.
Review the child plan via flow:plan-reviewer (one Agent
tool invocation per child) BEFORE filing. The review
contract mirrors the single-track Plan Review subsection
above: the agent receives the DRAFTED_PLAN verbatim and the
absolute <project_root>/.claude/rules/ corpus. Cap the
reviewer loop at 3 attempts per child; on cap exhaustion
file the child with the last drafted plan and surface the
violations as a non-blocking advisory warning, identical to
the single-track cap-exhausted behavior.
File the child issue with the decomposed label and
--assignee @me:
${CLAUDE_PLUGIN_ROOT}/bin/flow issue --title "<child_title>" --body-file .flow-issue-body-multi-<id>-<component> --label decomposed --assignee @me
Capture the new child's URL and issue number from the filer's JSON output — both are needed for the linking step below and for the recording call.
Record the child in the state file (no-op outside an active flow):
${CLAUDE_PLUGIN_ROOT}/bin/flow add-issue --label decomposed --title "<child_title>" --url "<child_url>" --phase flow-plan
Detect the repo. bin/flow link-blocked-by requires
--repo <owner/name>. Resolve it once from the worktree's
git origin before any linking call:
git remote get-url origin
Parse the stdout — both SSH ([email protected]:owner/name.git)
and HTTPS (https://github.com/owner/name.git) forms appear in
practice. Strip the protocol/host prefix and the trailing .git
to produce owner/name. Capture this value as <repo> and
substitute it into every link-blocked-by invocation below.
Link the children to each other. For every cross-component
dependency edge B → A in the original DAG (component B's
root depends on component A's root), link the two child
issues so GitHub's native blocked-by graph reflects the
structural relationship:
${CLAUDE_PLUGIN_ROOT}/bin/flow link-blocked-by --repo <repo> --blocked-number <child_B> --blocking-number <child_A>
Link the source issue to its root children. Cap the dependency graph by linking the source issue blocked-by every root child (a "root child" is a component whose root has no incoming cross-component edges). The source issue then awaits its children's closures:
${CLAUDE_PLUGIN_ROOT}/bin/flow link-blocked-by --repo <repo> --blocked-number <source_issue> --blocking-number <root_child>
When every child has been filed and every blocked-by edge is
encoded, the AC#5 cascade handles the eventual closure of the
source issue: as each child PR merges and closes its child
issue, bin/flow auto-close-parent walks the dependency
graph; once every blocker of the source is closed, the cascade
closes the source. No --state-file mutation is required at
this skill — the cascade is wired in from
complete-post-merge of each child's flow.
Source-issue treatment. Multi-track leaves the source issue as a plain problem statement throughout filing:
decomposed label is applied to the source issue —
only the children receive that label. flow-issues filters
the source as Vanilla (ready for re-planning) until the
cascade closes it.When the per-child loop is complete and every blocked-by edge is encoded, fall through to Finish below. SKIP the single-track File or Edit subsection — the children have already been filed and linked. The Finish banner and post-flow instruction text below render the same way; only the message text changes to name the multi-track outcome (filed children + linked source) instead of a single issue-edit or new-issue result.
Clear the utility-in-progress marker:
${CLAUDE_PLUGIN_ROOT}/bin/flow clear-utility-in-progress --skill flow:flow-plan
Display the issue URL to the user, then output the COMPLETE banner in your response (not via Bash) inside a fenced code block:
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ FLOW v2.6.1 — flow:flow-plan — COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
Then instruct the user. The message names the same issue number the next phase will pick up.
/flow:flow-start #N."/flow:flow-start #M."Do not invoke /flow:flow-start yourself — the user types the
slash command directly.
#N or a bare prompt. Step 1 routes #N to
issue-input mode (Step 2 fetches the issue and Step 6 edits it
in place) and bare non-empty prompts to bare-prompt mode (Step 2
is skipped; Step 6 synthesizes a brief What/Why/AC and files
one new decomposed issue).## What / ## Why /
## Acceptance Criteria) and swaps the sentinel-delimited
plan block. Issue-input multi-track (AC#4) files one child
per disconnected DAG component and leaves the source issue
as a plain problem statement (no Implementation Plan block,
no decomposed label, not closed) — closure of the source
comes via the AC#5 blocked-by cascade. Bare-prompt mode
files one new decomposed issue with --label decomposed --assignee @me and is always single-track per AC#8. There
is no parent-closure step in any mode.--label decomposed. Without the label,
flow-issues and flow-orchestrate won't recognize the issue
as ready-for-flow-start work.--mode decomposed before filing.
Vanilla bodies and decomposed bodies have different shapes; the
wrong mode silently passes a body that bin/flow plan-from-issue
will later reject.AskUserQuestion during discussion mode. The
discussion is conversational; the user drives the cadence.## SCOPE REFUSAL block. Render the refusal verbatim and wait
for explicit user direction on the next move.AskUserQuestion in the Step 6 wrap-up. The user's
readiness signal from the discussion phase is the single
authorization to file; a second confirmation gate would break
the single-signal contract that drives the unattended-flow
promise..flow-issue-body-<id>) — never pass body text as a CLI
argument.bin/flow issue script
handles cleanup..flow.json role
field as "no preferred default" and proceed silently. Never
block on a missing field.bin/flow calls in skill bash blocks use the plugin root
prefix — bare bin/flow only resolves inside the FLOW repo
itself, not in target projects.data-ai
Clear the autonomous-flow halt set when the user spoke mid-flow. Invokes `bin/flow clear-halt` so the next assistant turn resumes execution. User-only: the model cannot invoke this skill.
data-ai
Open a problem-statement conversation. Stays in discussion mode with PM as default voice; on user signal, files a vanilla What/Why/Acceptance Criteria issue against the current repo. Usage: /flow:flow-explore <topic>
tools
Display the FLOW skill catalog grouped by user role. Maintainer and Private buckets render only when invoked inside the FLOW plugin repo.
documentation
Phase 3: Review — six tenants assessed by four cognitively isolated agents (reviewer, pre-mortem, adversarial, documentation) launched in parallel. Parent session gathers context, triages findings, and fixes.