From flow
Reviews full git diff of pending changes, stages all with git add -A, commits with configurable format, and pushes. For FLOW workflow commit checkpoints.
npx claudepluginhub benkruger/flowThis skill uses the workspace's default tool permissions.
Review all pending changes as a diff before committing.
Creates git commits with clear messages from working tree changes, following repo conventions or conventional commits. Handles clean trees and detached HEAD.
Creates git commits with clear, value-communicating messages from staged or unstaged changes, following repo conventions or conventional commit format. Use when user says 'commit' or 'save changes'.
Stages and commits git changes atomically with conventional messages. Analyzes status and diffs, groups into logical units (structural, behavioral, docs, config) without modifying code.
Share bugs, ideas, or general feedback.
Review all pending changes as a diff before committing.
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.
Run git worktree list --porcelain. Note the path on the first
worktree line (this is the project root). Find the worktree entry
whose path matches your current working directory — the
branch refs/heads/<name> line in that entry is the current branch
(strip the refs/heads/ prefix).
Keep the project root and branch in context for the rest of this skill.
Step 1. Use the Glob tool: pattern *.json, path <project_root>/.flow-states — if any results, a FLOW phase is active (used for banner selection only).
Step 2. If any .flow-states/*.json results exist, use the Read tool to read the state file for the current branch at <project_root>/.flow-states/<branch>/state.json.
commit_format: "title-only" or "full".commit_format key → use "full".Keep commit_format in context.
At the very start, output the following banner in your response (not via Bash) inside a fenced code block:
If a state file exists (.flow-states/*.json Glob returned results):
```text
──────────────────────────────────────────────────
FLOW v1.1.0 — flow:flow-commit — STARTING
──────────────────────────────────────────────────
```
Otherwise (no state file):
```text
──────────────────────────────────────────────────
Commit — STARTING
──────────────────────────────────────────────────
```
On completion (whether nothing to commit or committed successfully), print the same way:
If a state file exists:
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ FLOW v1.1.0 — flow:flow-commit — COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
Otherwise:
```text
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ Commit — COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
/flow:flow-commit
git add -A
Run both in parallel (one response, two Bash calls):
git status
git diff --cached
If git diff --cached is empty, tell the user "Nothing to commit", print the COMPLETE banner, and return to the caller.
Render the output directly in your response — do not ask the user to expand tool output.
If the diff is too large to render inline (the Bash tool truncates and
persists the output), use git diff --cached --stat for the summary
and read the persisted output file with the Read tool. Never redirect
output to /tmp/ — shell redirects trigger permission prompts.
Format the status as:
**Status**
modified: path/to/file.rb
new file: path/to/other.rb
deleted: path/to/removed.rb
Format the diff as a fenced diff code block:
```diff
- removed line
+ added line
```
The diff code block renders red/green in most markdown environments.
Write a commit message that a developer reading git log six months from now would find genuinely useful.
Use the commit_format from Round 2 to determine the structure.
If commit_format is "full":
Full-sentence subject line (imperative verb + what + why, ends with a period.)
tl;dr
One or two sentences explaining the WHY — what problem this solves,
what behaviour changes, or what was wrong before.
- path/to/file.rb: What changed and why
- path/to/other.rb: What changed and why
- path/to/another.rb: What changed and why
Before displaying your draft, verify it contains all of these in order:
tl;dr on its own line — no colon, no elaboration, just tl;drIf any element is missing or out of order, rewrite before displaying.
If commit_format is "title-only":
Full-sentence subject line (imperative verb + what + why, ends with a period.)
- path/to/file.rb: What changed and why
- path/to/other.rb: What changed and why
- path/to/another.rb: What changed and why
Before displaying your draft, verify it contains all of these in order:
If any element is missing or out of order, rewrite before displaying.
Subject line rules (both formats):
feat:, chore:, fix: — just the verb)Body rules (both formats):
Additional body rules (full format only):
Display the full message under the heading Commit Message.
Files are already staged from Round 3. No need to git add -A again.
Use the Write tool to write the commit message content to
<project_root>/.flow-states/<branch>/commit-msg-content.txt — a
branch-scoped temp path, not the final commit-msg file. This avoids
Claude Code's Write-tool preflight tripping on a pre-existing final
file from a prior commit retry (see
.claude/rules/file-tool-preflights.md).
/tmp/ — paths outside the project trigger permission prompts that settings.json cannot suppresspython3 -c to write the message — literal $(...) in the body triggers command substitution warningsgit commit -m with heredoc — the multi-line command fails permission pattern matchingRoute the content to the final commit-msg file via bin/flow write-rule:
${CLAUDE_PLUGIN_ROOT}/bin/flow write-rule --path <project_root>/.flow-states/<branch>/commit-msg.txt --content-file <project_root>/.flow-states/<branch>/commit-msg-content.txt
Both files live inside the per-branch subdirectory
.flow-states/<branch>/ (alongside state.json, plan.md, etc.) so
concurrent flows in different worktrees of the same repo never collide
on a single shared file, and flow-abort/flow-complete cleanup
removes the whole subdirectory in one remove_dir_all call.
finalize-commit reads and deletes the final commit-msg file
unchanged by this routing.
Run the finalize script to commit, clean up the message file, pull,
and push in one call. finalize-commit runs ci::run_impl() before
git commit (see CLAUDE.md "CI is enforced inside finalize-commit
itself"), so 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 finalize-commit <project_root>/.flow-states/<current-branch>-commit-msg.txt <current-branch>
The script returns JSON:
{"status": "ok", "sha": "..."} — success. Confirm and show the commit SHA.{"status": "conflict", "files": [...]} — merge conflicts from pull. Resolve each conflicting file:
git add <file>git add -A, then git push{"status": "error", ...} — report the step and message to the user.--no-verifygit rebase is forbidden.git diff to the user and ask how to proceed before taking any action