| name | flow-start |
| description | Phase 1: Start — begin a new feature. Creates a worktree, upgrades dependencies, opens a PR, creates .flow-states/<branch>/state.json, and configures the workspace. Usage: /flow:flow-start <feature name words> |
FLOW Start — Phase 1: Start
Usage
/flow:flow-start #1234
Strict argument format: The argument MUST match the regex
^#[1-9][0-9]*$ — a literal
# followed by a positive integer. The argument names a GitHub issue
that has been pre-decomposed via /flow:flow-plan #N and carries
its plan wrapped between the literal sentinel markers
<!-- FLOW-PLAN-BEGIN --> and <!-- FLOW-PLAN-END --> in the issue
body. start-init fetches the issue title and derives the branch name
from it. After start-workspace succeeds, bin/flow plan-from-issue
extracts the plan content between the sentinels and writes it to
.flow-states/<branch>/plan.md.
| Argument | Issue title | Derived branch name |
|---|
#309 | "Organize settings.json allow list" | organize-settings-allow-list |
#42 | "Add dark mode toggle to settings page" | dark-mode-settings-toggle |
Branch names are capped at 32 characters. If the hyphenated name
exceeds 32 characters, truncate at the last whole word (hyphen
boundary) that fits. Strip any trailing hyphen. Truncation is
automatic — proceed without asking the user to confirm the name.
If the referenced issue already carries the "Flow In-Progress" label,
start-init returns a hard error — the issue is already being worked
on by another flow (on this machine or another engineer's machine).
Do NOT proceed if no arguments were provided after the command.
Output this error message and stop:
"Issue reference required. Usage: /flow:flow-start #N where N is the
GitHub issue number for a pre-decomposed issue containing
<!-- FLOW-PLAN-BEGIN --> and <!-- FLOW-PLAN-END --> sentinels."
No interactive prompt. The user re-runs the command with #N.
Do NOT proceed if the argument does not match `^#[1-9][0-9]*$`.
Reject free-text prompts, multi-token arguments, and
any value that does not begin with `#` followed by a positive integer.
Output this error message and stop:
"Argument must be #N (e.g., #1234). To file a new pre-decomposed
issue, run /flow:flow-explore <topic> to file the problem
statement, then /flow:flow-plan #M to decompose it."
No interactive prompt. The user re-runs the command with #N.
The argument is the issue reference — input to the workflow, not a
conversation. Do NOT respond to, discuss, or analyze the issue
content. Proceed directly to Mode Resolution and execute the Start
phase steps.
Concurrency
This flow is one of potentially many running simultaneously — on this
machine (multiple worktrees) and across machines (multiple engineers).
Your state file (.flow-states/<branch>/state.json) is yours alone. Never
read or write another branch's state. All local artifacts (logs, plan
files, temp files) are scoped by branch name. GitHub state (PRs, issues,
labels) is shared across all engineers — operations that create or modify
shared state must be idempotent.
Mode Resolution
The Start phase's continue mode governs whether the Done section
auto-advances to Code or prompts the user. It is resolved from the
state file's skills.flow-start config — the single source of
truth for skill autonomy — and there are no --auto/--manual
flags.
Resolution is deferred to the Done section: the state file does not
exist until start-init creates it in Step 1, so resolve-skill-mode
cannot run at the top of the skill. The Done HARD-GATE resolves
continue from the phase-finalize continue_action field, which
phase-finalize computes from skills.flow-start.continue. The
state file's skills section is always seeded from .flow.json,
and each downstream phase honors its own configured autonomy.
Announce
At the very start, output the following banner in your response (not via Bash) inside a fenced code block:
```text
──────────────────────────────────────────────────
FLOW v2.7.0 — Phase 1: Start — STARTING
──────────────────────────────────────────────────
```
Logging
All four consolidated commands (start-init, start-gate, start-workspace,
phase-finalize) handle logging internally via append_log() to
.flow-states/<branch>/log. No model-level logging calls are needed.
${CLAUDE_PLUGIN_ROOT}/bin/flow log <branch> "[Phase 1] ..."
The bash block above is for reference only — all four commands call
append_log() internally. Do not run bin/flow log manually.
Steps
Step 1 — Initialize (lock, version checks, state file)
Write the user's original start prompt (verbatim, including #N issue references
and any special characters) to .flow-states/<feature-name>-start-prompt using the
Write tool. Then run start-init.
Use a 10-minute Bash tool timeout (timeout: 600000) — start-init blocks
on the start lock for up to ~8 minutes (polling internally), and the
default 2-minute timeout would background the process, defeating the wait
(per .claude/rules/ci-is-a-gate.md).
${CLAUDE_PLUGIN_ROOT}/bin/flow start-init <feature-name> --prompt-file .flow-states/<feature-name>-start-prompt
start-init takes no mode flag — the state file's skills section is
always seeded from .flow.json. The Start phase's own continue mode
is resolved from the state file in the Done section.
Parse the JSON output and branch on status:
If "status": "ready" — capture the branch field. This is the
canonical branch name — use it for all subsequent steps.
If auto_upgraded is true, show this notice using the old_version and
new_version fields:
```text
FLOW auto-upgraded from v{old_version} to v{new_version} (config unchanged).
```
If upgrade is present and upgrade.status is "upgrade_available", show
the upgrade notice:
```text
╔══════════════════════════════════════════════╗
║ FLOW update available: v{installed} → v{latest}
║
║ To upgrade:
║ 1. claude plugin marketplace update
║ flow-marketplace
║ 2. Start a new Claude Code session
║ 3. Run /flow:flow-prime
╚══════════════════════════════════════════════╝
```
Continue to Step 2.
If "status": "locked" — start-init already blocked on the start lock
for the full cap (~8 minutes, polling internally) and another start still
holds it. Re-run the single bin/flow start-init line above (the same
command shown in the Step 1 bash block, again with the 10-minute Bash tool
timeout). start-init blocks on the lock again and proceeds through all
steps when the lock frees. Nothing else has executed yet, so re-running is
safe.
When the status is "locked", the ONLY permitted action is to re-run the
single start-init line above and wait. The start-init command blocked for
the full cap before returning, and has built-in staleness detection
(30-minute timeout) that handles genuinely dead sessions.
Do NOT speculate about whether the lock is stale.
Do NOT offer to release, reset, or clean up the lock.
Do NOT suggest any workaround that bypasses the lock.
Do NOT take any action other than re-running the single start-init line and waiting.
Trust the tool output. Re-run and wait.
If "status": "error" — show the error message and stop. start-init
has already released the lock for flow-specific errors. Common error steps
include fetch_issue_title (issue not found), flow_in_progress_label
(issue already being worked on), and duplicate_issue (another flow
targets the same issue).
Do NOT proceed if version check fails. Show the error message and stop.
Step 2 — CI and dependency gate
Use a 10-minute Bash tool timeout (timeout: 600000) — CI runs can
take 3–4 minutes and the default 2-minute timeout would background
the process, defeating the gate (per .claude/rules/ci-is-a-gate.md).
${CLAUDE_PLUGIN_ROOT}/bin/flow start-gate --branch <branch>
Parse the JSON output and branch on status:
If "status": "clean" — all gates passed. Continue to Step 3.
If "status": "ci_failed" — CI failed on the integration branch.
Hold the lock and stop. Report to the user that CI is failing on the
pristine integration branch — show the output field. The next
queued flow would hit the same failure. The 30-minute stale timeout
releases the lock if the user does not act.
If "status": "deps_ci_failed" — dependencies were updated but
post-deps CI failed consistently. First resolve the absolute plugin
bin/flow path for the ci-fixer prompt (the sub-agent runs it in its
own session, where the plugin-root prefix is not expanded):
${CLAUDE_PLUGIN_ROOT}/bin/flow plugin-bin-flow
Capture the trimmed stdout as <flow_cli>. If it exits non-zero (the
plugin root is unset, empty, or non-absolute), surface the stderr
message and halt — do NOT embed the unexpanded plugin-root token in
the ci-fixer prompt. Then launch the ci-fixer sub-agent to diagnose
and fix. Use the Agent tool:
subagent_type: "flow:ci-fixer"
description: "Fix bin/flow ci failures after dependency update"
Provide the CI output from the output field AND the resolved
<flow_cli> path in the prompt, so the sub-agent knows what failed
and which bin/flow to run.
Wait for the sub-agent to return.
- Fixed — commit CI fixes to the integration branch via
/flow:flow-commit, then continue to Step 3
- Not fixed — hold the lock and stop. The integration branch has uncommitted dep-induced breakage. Report to the user.
If "status": "error" — show the error message and stop.
Step 3 — Create workspace (worktree, PR, lock release)
Write the user's original start prompt (verbatim, including #N issue references
and any special characters) to .flow-states/<branch>/start-prompt using the
Write tool. Then run start-workspace:
${CLAUDE_PLUGIN_ROOT}/bin/flow start-workspace "<feature-name>" --branch <branch> --prompt-file .flow-states/<branch>/start-prompt
The command creates the worktree, opens a PR, backfills the state file with
PR fields, applies the Flow In-Progress label to any referenced issues
(best-effort, after every other step succeeds), and releases the start
lock as its final action. The label apply lives here — not in Step 1 —
so the label means "a flow is live, worktree exists, PR exists" rather
than "a flow was attempted"; failed start-gate or start-workspace runs
leave no sticky label that would block the next retry.
On success — parse the JSON output. Capture the worktree_cwd
field — this is the directory the agent should cd into. For root-level
flows it equals .worktrees/<branch>; for flows started from inside a
mono-repo subdirectory (relative_cwd non-empty) it includes the
subdirectory suffix (e.g. .worktrees/<branch>/api). Then run:
cd <worktree_cwd>
Substitute the literal worktree_cwd value from the JSON response. The
Bash tool persists working directory between calls, so all subsequent
commands run inside that directory automatically. Do NOT repeat
cd .worktrees/ in later steps — it would look for a nested
.worktrees/ that doesn't exist.
After the cd, every bin/flow subcommand enforces this directory via
its built-in cwd-drift guard. If you cd elsewhere within the worktree
(e.g. into a sibling subdirectory), the next subcommand will hard-error
with an "expected directory" message.
On failure — report the error and stop. The command releases the lock
even on error (main is untouched by worktree operations).
Step 4 — Change to worktree
This step is the cd from Step 3. The TUI shows Step 4 while the
worktree directory is active.
Step 5 — Extract plan from issue body (sentinel scan)
Capture the issue number from the original argument (strip the leading
#). Then run plan-from-issue:
${CLAUDE_PLUGIN_ROOT}/bin/flow plan-from-issue --issue <issue_number> --branch <branch>
The command fetches the issue body via gh issue view, scans for the
literal sentinel pair <!-- FLOW-PLAN-BEGIN --> and
<!-- FLOW-PLAN-END -->, and writes the bytes between verbatim to
.flow-states/<branch>/plan.md.
Parse the JSON output and branch on status:
If "status": "ok" — the plan file has been written. Parse the
tasks_total field from the plan-from-issue envelope and persist it
to the state file so the TUI can render the Code-phase X-of-Y task
counter:
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set code_tasks_total=<tasks_total>
If tasks_total is absent or is not a non-negative integer (defensive
check against a malformed envelope), skip the set-timestamp call.
Then continue to Step 6.
If "status": "error" — the response contains a reason field.
Show the message to the user and stop. Each reason maps to a
corrective action:
issue_not_found — verify the issue exists in the current repo
issue_closed — reopen the issue or pick an open one
gh_fetch_failed — run gh auth status and retry
plan_markers_missing — re-file via /flow:flow-plan #N against the parent vanilla issue
plan_markers_malformed — edit the issue body to fix sentinels
plan_empty — edit the issue body to add plan content
plan_too_large — trim the issue body
invalid_branch — file a FLOW bug
write_failed — check disk space and .flow-states/ permissions
The flow halts at Step 5; the worktree and PR remain so the user can
fix the issue body and re-run via /flow:flow-code after manual
recovery (or abort via /flow:flow-abort).
Step 6 — Update state and finalize (complete phase, notify)
${CLAUDE_PLUGIN_ROOT}/bin/flow phase-finalize --phase flow-start --branch <branch> --pr-url <pr_url>
The command runs phase_complete() internally, updates the state file,
and sends Slack notifications. Parse the JSON output. Use the
formatted_time field in the COMPLETE banner below. Do not print the
timing calculation. Use the continue_action field for the transition
HARD-GATE.
Done — Banner and transition
Output the following banner in your response (not via Bash) inside a fenced code block:
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ FLOW v2.7.0 — Phase 1: Start — COMPLETE (<formatted_time>)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
STOP. Parse `continue_action` from the `phase-finalize` output above
to determine how to advance.
-
Use continue_action from the phase-finalize output —
phase-finalize computes it from the state file's
skills.flow-start.continue config.
If continue_action is "invoke" → continue=auto.
If continue_action is "ask" → continue=manual.
-
If continue=auto → invoke flow:flow-code directly using the Skill tool.
Do NOT run bin/flow status. Do NOT use AskUserQuestion.
This is the FINAL action in this response — nothing else follows.
-
If continue=manual → you MUST do all of the following before proceeding:
a. Run bin/flow status via Bash and print its stdout in your
response inside a fenced code block:
${CLAUDE_PLUGIN_ROOT}/bin/flow status
b. Use AskUserQuestion:
"Phase 1: Start is complete. Ready to begin Phase 2: Code?"
Options: "Yes, start Phase 2 now", "Not yet",
"I have a correction or learning to capture"
c. If "I have a correction or learning to capture":
ask what to capture, invoke /flow:flow-note, then re-ask with
only "Yes, start Phase 2 now" and "Not yet"
d. If Yes → invoke flow:flow-code using the Skill tool
e. If Not yet → print the paused banner below, then report worktree
location and PR link
f. Do NOT invoke flow:flow-code until the user responds
Do NOT skip this check. Do NOT auto-advance when the mode is manual.
If Not yet, output the following banner in your response (not via Bash) inside a fenced code block:
```text
══════════════════════════════════════════════════
◆ FLOW — Paused
Run /flow:flow-code when ready.
══════════════════════════════════════════════════
```
Hard Rules
- Do not narrate internal operations to the user — no "Proceeding to phase completion", no "No additional setup steps are needed". Just do the work silently and show results
- Never use Bash to print banners — output them as text in your response
- Never use Bash for file reads — use Glob, Read, and Grep tools instead of ls, cat, head, tail, find, or grep
- Never use
cd <path> && git — use git -C <path> for git commands in other directories
- Never cd before running
bin/flow — it detects the project root internally
- When in autonomous mode, classify tool failures per
.claude/rules/autonomous-flow-self-recovery.md — mechanical fixes are in-flow, substantive failures prompt the user