skills/flow-code/SKILL.md
Phase 2: Code — execute plan tasks one at a time with TDD. Review diff before each commit. bin/flow ci must pass before moving to the next task. Project architecture standards enforced.
npx skillsauth add benkruger/flow flow-codeInstall 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.
/flow:flow-code
/flow:flow-code --continue-step
/flow:flow-code — uses the configured mode from the state file's skills.flow-code config/flow:flow-code --continue-step — self-invocation: skip Announce and Update State, dispatch to the next task via Resume Check${CLAUDE_PLUGIN_ROOT}/bin/flow phase-enter --phase flow-code
Parse the JSON output. If "status": "error", STOP and show the error.
If "status": "ok", capture the returned fields:
project_root, branch, worktree_path, worktree_cwd,
relative_cwd, pr_number, pr_url, feature, slack_thread_ts,
and plan_file. The autonomy mode is resolved separately in the
Mode Resolution section below via resolve-skill-mode.
Use the returned fields for all downstream references. Do not re-read
the state file or re-run git commands to gather the same information.
Do not cd to the project root — bin/flow commands find paths
internally.
Mono-repo flows started inside a subdirectory (e.g. api/) capture
that path as relative_cwd and rely on cwd staying at
<worktree>/<relative_cwd> so subsequent bin/flow calls pass the
cwd-drift guard. Context loss between skill invocations can reset cwd
to the main repo root; the bash block below re-anchors regardless of
how the session got here. Substitute the worktree_cwd value from the
phase-enter response — a no-op for root-level flows (where it equals
worktree_path) and a real re-anchor for mono-repo flows.
cd "<worktree_cwd>"
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.
Resolve commit and continue on every entry — fresh invocation and
--continue-step self-invocation alike — from the state file's
skills.flow-code config via resolve-skill-mode. The state file is
the single source of truth for skill autonomy; there are no
--auto/--manual flags.
On a --continue-step self-invocation, recover the worktree directory
before resolving the branch. The resume path skips phase-enter (which
normally cds into the worktree), and the branch resolution just below
is cwd-dependent — so a session whose cwd reset to the main-repo root
would otherwise resolve the integration branch instead of the feature
branch. bin/flow resume-anchor reads the session-keyed phase-anchor
marker and returns the recovered worktree_cwd:
${CLAUDE_PLUGIN_ROOT}/bin/flow resume-anchor
Parse the JSON output and branch on status:
"ok" — cd into the returned worktree_cwd, then resolve the
branch below from the recovered directory."no_marker" — no marker to recover; proceed with the cwd-based
branch detection below as-is."error" — the marker was corrupt; do NOT cd to any returned
path. Treat it exactly like no_marker and proceed with the
cwd-based detection below.Resolve the current branch first: run git worktree list --porcelain,
note the project root (the path on the first worktree line), find
the worktree entry whose path matches the current working directory,
and take the branch refs/heads/<name> line from that entry (strip
the refs/heads/ prefix). Call this <branch>. Then run the resolver:
${CLAUDE_PLUGIN_ROOT}/bin/flow resolve-skill-mode --skill flow-code --branch <branch>
Parse the JSON output. commit and continue are each "auto" or
"manual":
commit=auto — streamline mode active from task 1 (skip per-task
approval, still show diffs).commit=manual — require explicit approval for each task.continue=auto — auto-advance to Review once all tasks are committed.continue=manual — prompt before advancing to Review.If --continue-step was passed, this is a self-invocation from a
previous task's commit. Skip the Announce banner and the phase-enter
call (do not enter the phase again). Run ## Mode Resolution above
(it runs on every entry), then proceed directly to the Resume Check
section.
At the very start, output the following banner in your response (not via Bash) inside a fenced code block:
```text
──────────────────────────────────────────────────
FLOW v2.6.1 — Phase 2: Code — STARTING
──────────────────────────────────────────────────
```
Read the project's CLAUDE.md for project-specific conventions. Each
project owns its own toolchain via bin/{format,lint,build,test} and
documents its conventions in CLAUDE.md. Follow those conventions for:
bin/test --file <path>)After every Bash command completes, log it to .flow-states/<branch>/log
using bin/flow log.
Run the command first, then log the result. Pipeline the log call with the next command where possible (run both in parallel in one response).
${CLAUDE_PLUGIN_ROOT}/bin/flow log <branch> "[Phase 2] Step X — desc (exit EC)"
Get <branch> from the state file.
Read files.plan from the state file to get the plan file path. Use the
Read tool to read the plan file at <project_root>/<files.plan path> — the
.flow-states/ tree lives at the project root, not inside the worktree, so
the <project_root>/ prefix is required (a raw relative read resolves under
the worktree and the validate-worktree-paths hook blocks it). Identify the
Tasks section — this is the ordered list of implementation tasks to execute.
Read code_task from the state file (default 0 if absent).
code_task > 0 and code_task < total tasks: skip to task
code_task + 1. Output in your response (not via Bash) inside a
fenced code block:```text
──────────────────────────────────────────────────
FLOW — Resuming Code
──────────────────────────────────────────────────
Resuming at: <task description>
Tasks complete: <code_task> of <total>
──────────────────────────────────────────────────
```
If code_task >= total tasks: skip to All Tasks Complete.
If code_task is 0 and this is a resume (re-entering the phase after
a session restart), determine progress by comparing the plan to
committed work.
Resolve the integration branch. Run the bin/flow base-branch
command shown below (it uses the plugin root prefix) to retrieve
the base branch the flow coordinates against. Capture its stdout —
call the value <base_branch> — and substitute it into the
git log command below. A repo whose default branch is staging
produces <base_branch> = staging; a standard repo produces
<base_branch> = main.
${CLAUDE_PLUGIN_ROOT}/bin/flow base-branch
Get the commit log. Substitute <base_branch> with the value
you just captured.
git log --oneline origin/<base_branch>..HEAD
Compare commit messages to the tasks in the plan file. Continue from the first task that doesn't have a matching commit.
From the plan file, identify the next task to work on (task number
code_task + 1). Execute only this single task — do not look ahead
to subsequent tasks. After committing, self-invoke to handle the next
task in a fresh skill invocation.
When the plan marks a set of tasks as an atomic group (typically
because they form a circular CI dependency — no intermediate state can
pass bin/flow ci independently), handle them as a single commit
boundary.
Detect the group. When you reach a task that the plan marks as part of an atomic group, switch to the atomic flow below instead of the standard single-task flow. The plan will annotate which tasks belong to the group and explain why they cannot be committed individually (e.g., "Tasks 3-6 form an atomic group — adding a CI check requires fixing violations in the same commit").
Show a group banner. Output in your response (not via Bash):
```text
── Atomic Group: Tasks <first>-<last> of <total> ──
Reason: <why these tasks cannot pass CI independently>
```
Execute all tasks in the group sequentially. Run the full TDD cycle (write failing test, implement, refactor, run targeted tests) and the Architecture Check independently. After completing each task's TDD cycle, record it and persist the task name for TUI display. Both updates can go in a single call:
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set code_task=<n> --set code_task_name="<description>"
For atomic groups with multiple tasks, batch all counter advances in
one call. apply_updates processes --set arguments sequentially
against mutating in-memory state, so each +1 step is validated in
order. Example for tasks 3-5:
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set code_task=3 --set code_task=4 --set code_task=5 --set code_task_name="<description>"
Do NOT run bin/flow ci and do NOT commit after intermediate tasks.
Proceed directly to the next task in the group.
Combined review after the last task. Show the combined diff
covering all tasks in the group. Run git status and git diff HEAD
as two separate commands, then render the output inline following the
same format as the ### Review section. If commit=auto, skip the
AskUserQuestion and proceed to Plan Test Verification. Otherwise,
ask for review of the combined diff.
CI gate routes through /flow:flow-commit. As with single-task
commits, the group's CI gate runs inside finalize-commit
(ci::run_impl() Rust call). A failed internal CI returns the
error to the model, which fixes and retries. Do NOT invoke
bin/flow ci directly between tasks in the group — Layer 11 of
validate-pretool blocks it.
Plan Test Verification. Run the Plan Test Verification check (see the section below) for ALL tasks in the group — not just the last one. Verify that every test function named in any task's plan description exists in the codebase.
Single commit. Use the standard Commit section flow: set the
continuation context and _continue_pending, then invoke
/flow:flow-commit. The commit message should reference the group:
Add <what the group accomplished> — Tasks <first>-<last> of <total>
Self-invoke as usual after the group commit to continue with the next task after the group.
Some plan tasks produce no file changes — a final coverage TOTAL
capture for the PR body, a threshold verification re-run, or a
final regression re-run that the plan explicitly names as a task.
These tasks still route through the standard Commit flow below so
every task honors CLAUDE.md's "All commits via /flow:flow-commit"
convention and never invents a shortcut.
Skip the TDD Cycle (there is no test or implementation to write
for a task that produces no file changes) and perform the task's
measurement action as the task body — for example, bin/flow log
to record a TOTAL into the session log. Do NOT invoke
bin/flow ci directly: Layer 11 of validate-pretool blocks it
during Code phase (the --clean carve-out is the only allowed
form). Then follow the Commit section exactly as a file-changing
task would: advance code_task via set-timestamp, set
_continue_context and _continue_pending=commit, and invoke
/flow:flow-commit. The commit skill stages all changes via
git add -A in Round 3, then runs git diff --cached in Round 4;
when the staged diff is empty it prints "Nothing to commit",
prints its COMPLETE banner, and returns to the caller without
calling finalize-commit. The self-invocation at the end of the
Commit section then fires unchanged — it runs after
/flow:flow-commit returns, independent of whether a commit was
actually produced. Do not skip /flow:flow-commit even when you
already know the diff will be empty.
Some discovery commands during Code phase produce output longer than
the Bash tool's display buffer can return inline. bin/flow ci --lint
after a wide ignore-list removal can emit ~50 violation lines; a
plain git grep over a deletion target can return hundreds of
matches. When the buffer is exceeded the tool truncates the middle,
so any violation enumeration based on the inline output silently
misses entries. Bash redirection to a temp file would be the natural
workaround, but validate-pretool Layer 2 blocks bare > redirects
under the FLOW permission model, so the discipline below uses
existing artifacts and dedicated tools instead.
Apply this when a discovery command's output is enumerable (lint violations, grep hits, file lists) AND the rough output size could exceed a screen of text. Skip it for short queries (one-line counts, single-file reads) where inline output is sufficient.
For bin/flow ci and its single-phase variants (--format,
--lint, --build, --test): the runner already writes the
full unabridged stdout-plus-stderr stream to a log file. The path
appears in the runner's footer (Full log: …-ci-last.log) and is
also predictable: <project_root>/.flow-states/<branch>-ci-last.log.
Use the Read tool on that path to see every violation line — the
Read tool is unaffected by the Bash tool's display-buffer cap.
For grep-style enumeration (line-by-line file searches): use
the Grep tool directly. Grep returns matches in a structured form
that bypasses the Bash display buffer; pass output_mode: "content"
with -n for line-numbered hits, or output_mode: "files_with_matches"
when only the file list matters.
For arbitrary commands without a built-in log file: the FLOW
permission model does not allow ad-hoc shell redirection to /tmp/,
so enumeration must come from a tool that returns structured output.
Glob and Grep cover most cases; for richer output, prefer running
the command in narrower passes (e.g., one directory at a time) so
each pass fits inline.
Persist the task name to the state file for TUI display:
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set code_task_name="<description>"
Output in your response (not via Bash) inside a fenced code block:
```text
── Task <n> of <total> ───────────────────────
<description>
Files: <files>
```
Follow the Architecture Check from the project CLAUDE.md. Check based on task type as described there before writing any code.
For every implementation task, there is a paired test task that runs first.
Step A — Write the failing test
Write the test file. Follow the test task description exactly.
Run the Targeted Test Command from the project CLAUDE.md to confirm it fails.
The test MUST fail before proceeding. If it passes immediately, the test is not testing the right thing — rewrite it until it fails for the right reason.
Step B — Write minimal implementation
Write only what is needed to make the test pass. No over-engineering.
Run the Targeted Test Command again to confirm it passes.
Step C — Refactor
Clean up without changing behaviour. Run the test again to confirm it still passes.
After the TDD cycle passes, show the diff for this task and ask for review before committing.
Run git status and git diff HEAD as two separate commands, then
render the output inline:
Status
modified: <path/to/implementation_file>
new file: <path/to/test_file>
Diff
+ added lines
- removed lines
If commit=auto, streamline is active from task 1 — skip the AskUserQuestion and proceed directly to Plan Test Verification.
If streamline mode is active (opted in during a previous task), skip the AskUserQuestion and proceed directly to Plan Test Verification.
Otherwise, use AskUserQuestion:
"Task <n>: <description> — does this look right?"
- Yes, commit
- Needs changes — describe what to fix
- Streamline remaining tasks — (only shown from the second task onward)
If "Needs changes" — fix the issue, re-run the test, show the diff again. Loop until approved.
If "Streamline remaining tasks" — set a session-only flag (not persisted to state). For all remaining tasks, still show the diff for user visibility, but skip the AskUserQuestion and proceed directly to Plan Test Verification and commit.
/flow:flow-commitThe per-task CI gate runs inside /flow:flow-commit's
finalize-commit call as a Rust function (ci::run_impl()), not
as a separate Bash invocation. Each TDD task's per-file test
verifies the file under change; cross-file regressions are caught
when the commit's internal CI runs. A failed internal CI returns
the error to the model, which fixes and retries. Do NOT invoke
bin/flow ci directly during Code phase — Layer 11 of
validate-pretool blocks it per
.claude/rules/per-file-coverage-iteration.md "Enforcement".
The --clean carve-out is available when phantom-misses
symptoms appear (see the rule). Reach for it only when the
diagnostic signals match.
The plan decomposes work into specific test functions. This step verifies that every test the plan promised was actually written during the TDD cycle — CI proves tests pass, but cannot prove missing tests exist.
After CI passes and before committing, verify that every test function the plan explicitly names for this task exists in the codebase.
Re-read the current task's description from the plan file. Look for explicitly named test functions. These appear as comma-separated lists, under headings like "Rust tests:" or "Tests:", or inline in the task description. Test naming conventions vary by language:
test_ prefix (e.g., test_parser_handles_empty_input)test_ prefix (e.g., test_login_timeout)Test prefix with capital T (e.g., TestParseConfig)test prefix in camelCase (e.g., testLoginTimeout)test_ prefix for minitest; it or describe blocks for RSpecIf the task description names specific test functions, use the Grep
tool to verify each one exists as a function or method definition in
the codebase. Match the language convention: fn <name> for Rust,
def <name> for Python/Ruby, func <name> for Go/Swift.
Record the completed task number:
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set code_task=<n>
Set the continuation context and flag before committing. The
self-invocation carries no mode flag — the resumed run re-resolves
commit/continue from the state file via ## Mode Resolution:
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set "_continue_context=Self-invoke flow:flow-code --continue-step."
${CLAUDE_PLUGIN_ROOT}/bin/flow set-timestamp --set _continue_pending=commit
Invoke /flow:flow-commit.
The commit message subject should reference the task:
Add <what was built> — Task <n> of <total>
To continue to the next task, invoke flow:flow-code --continue-step
using the Skill tool as your final action. Do not output anything
else after this invocation.
Once every task from the plan file is complete, proceed directly to the Done section below.
Every commit during Code phase routed through /flow:flow-commit →
finalize-commit, which runs the full CI gate (ci::run_impl()) and
enforces the 100/100/100 coverage threshold before the commit lands.
The last task's commit verified the same invariants the final sweep
would have measured, so no explicit bin/flow ci is needed before
transitioning to Review. Layer 11 of validate-pretool blocks
bin/flow ci during Code phase to protect against the
single-file-iteration misuse pattern; the per-task per-file gate
(bin/test tests/<name>.rs) plus the commit-time internal CI cover
the same surface at lower cost.
Finalize the phase (complete + Slack notification in one call):
${CLAUDE_PLUGIN_ROOT}/bin/flow phase-finalize --phase flow-code --branch <branch> --thread-ts <slack_thread_ts>
Omit --thread-ts if slack_thread_ts was not returned by phase-enter.
Parse the JSON output. If "status": "error", report the error and stop.
Use the formatted_time field in the COMPLETE banner below. Do not print
the timing calculation.
Output in your response (not via Bash) inside a fenced code block:
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ FLOW v2.6.1 — Phase 2: Code — COMPLETE (<formatted_time>)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
<HARD-GATE>
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-code.continue config.
If continue_action is "invoke" → continue=auto.
If continue_action is "ask" → continue=manual.
If continue=auto → invoke flow:flow-review 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 2: Code is complete. Ready to begin Phase 3: Review?"
Options: "Yes, start Phase 3 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 3 now" and "Not yet"
d. If Yes → invoke flow:flow-review using the Skill tool
e. If Not yet → print the paused banner below
f. Do NOT invoke flow:flow-review until the user responds
Do NOT skip this check. Do NOT auto-advance when the mode is manual.
</HARD-GATE>If Not yet, output in your response (not via Bash) inside a fenced code block:
```text
══════════════════════════════════════════════════
◆ FLOW — Paused
Run /flow:flow-review when ready.
══════════════════════════════════════════════════
```
bin/flow ci directly during Code phase — Layer 11 of validate-pretool blocks it. The per-task targeted test command (see the project CLAUDE.md) plus /flow:flow-commit's internal ci::run_impl() cover the same surface. The --clean carve-out is for the documented phantom-misses recovery path only.cd <path> && git — use git -C <path> for git commands in other directoriesbin/flow — it detects the project root internally.claude/rules/autonomous-flow-self-recovery.md — mechanical fixes are in-flow, substantive failures prompt the userdata-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.