Write flow
This skill should be used when the user asks to 'write a flow', 'create a flow', 'design a flow', 'make a flow for', 'I need a flow', or wants to create a prompt-language flow for a task. Decides whether a flow is needed at all — most tasks don't need one.From its SKILL.md
npx -y skills add 45ck/prompt-language --skill write-flowAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.5 KB, as published. Nobody here has run it
Write a Flow
Given a task description, decide whether a prompt-language flow adds value. Most tasks don't need one. Claude Code already retries on failure, checks if files exist, and follows multi-step instructions. The DSL's narrow but powerful value: mechanically enforcing completion criteria via real command execution, so Claude can't stop early.
Step 1: Do You Need a Flow?
Ask one question: "Is there a command that must exit 0 before this task is done?"
Task --> Has verifiable completion command (test/lint/build)?
Yes --> Could Claude skip or shortcut verification?
Yes --> USE A FLOW WITH GATE
No --> Plain prompt is fine
No --> PLAIN PROMPT
No flow needed (just write a plain prompt):
- "Rename the User class to Account" — no verification command
- "Add a docstring to every public method" — no pass/fail gate
- "Explain how the auth module works" — informational
- "Create a new React component for the sidebar" — Claude does this fine without scaffolding
Flow adds value:
- "Fix the auth tests so they pass" — gate:
tests_pass - "Make the build pipeline green" — gate:
tests_pass+lint_pass - "Migrate the database and verify it works" — gate: tests or a custom command
- "Apply this refactoring to 8 files without breaking tests" — gate:
tests_pass, loop:foreach
If the task doesn't need a flow, write a clear plain-language prompt and stop. Don't add DSL overhead for tasks that don't benefit from it.
Step 2: Pick Your Gate(s)
Gates are the entire reason to use a flow. Always write done when: first.
Available predicates:
JavaScript/TypeScript:
tests_pass—npm testexits 0lint_pass—npm run lintexits 0tests_fail— passes when tests exit non-zero (for "break this" tasks)lint_fail— passes when lint exits non-zero
Python:
pytest_pass—pytestexits 0pytest_fail— passes when pytest exits non-zero
Go:
go_test_pass—go test ./...exits 0go_test_fail— passes when go test exits non-zero
Rust:
cargo_test_pass—cargo testexits 0cargo_test_fail— passes when cargo test exits non-zero
General:
diff_nonempty— passes whengit diffhas outputfile_exists <path>— passes when the file exists
Compound gates catch more issues:
done when:
tests_pass
lint_pass
Step 3: Choose Your Loop Pattern
The Ralph Loop (the core pattern)
This is prompt-language as an advanced custom Ralph Loop — the same concept (keep iterating until done) but with mechanical verification. Gates run actual commands; Claude can't declare victory until they pass.
flow:
retry max 5
run: npm test
if command_failed
prompt: Fix the failing tests. Read the errors carefully.
end
end
done when:
tests_pass
Why this works: Claude already retries when asked — but without a gate, it can decide "close enough" and stop. The gate forces every iteration to prove the fix worked. Eval data shows this pattern consistently outperforms both plain prompts (on verification-heavy tasks) and over-engineered multi-phase flows.
Variations:
retry max Nfor bounded retries (prefer this — it has a clear limit)while command_failedfor condition-based loopsuntil command_succeededfor inverted condition loops
Foreach (batch operations)
For applying the same operation across a list of items:
flow:
foreach file in "src/auth.ts src/db.ts src/api.ts"
prompt: Add error handling to ${file}
run: npm test
end
done when:
tests_pass
Single prompt + gate (simplest)
When Claude just needs to do the work and a gate verifies it:
flow:
prompt: Fix the failing tests
done when:
tests_pass
Step 4: Stop — Check for Over-engineering
Before outputting the flow, check for these anti-patterns.
For the full anti-pattern catalog and deeper examples, see:
references/anti-patterns.mdreferences/advanced.md
Anti-pattern: Sequential prompts
BAD — 3 prompts that could be 1:
flow:
prompt: Read the codebase and understand the architecture
prompt: Write a plan for the migration
prompt: Execute the migration
BETTER — one prompt, one gate:
flow:
prompt: Migrate the database schema. Read the codebase first, plan your approach, then execute.
done when:
tests_pass
Claude follows multi-step instructions naturally. Sequential prompts add latency without improving quality.
Anti-pattern: file_exists gates for things Claude already does
BAD — Claude always creates the file when asked:
done when:
file_exists src/components/Sidebar.tsx
BETTER — plain prompt, no flow:
Create a Sidebar component at src/components/Sidebar.tsx
Only use file_exists when the file is a build artifact or side effect that proves a pipeline worked.
Anti-pattern: Variables at short distances
BAD — variable used 2 lines later:
flow:
let version = run "node -v"
prompt: Check compatibility with Node ${version}
BETTER — Claude can just run the command itself:
flow:
prompt: Check the Node version and ensure the code is compatible
done when:
tests_pass
Only use let when the value must span many steps or feed into a foreach.
Anti-pattern: Control flow for "organization"
BAD — phased structure that adds latency:
flow:
run: npm run lint
if command_failed
retry max 3
prompt: Fix lint errors
run: npm run lint
end
end
run: npm test
if command_failed
retry max 3
prompt: Fix test failures
run: npm test
end
end
BETTER — single loop, let Claude figure out the order:
flow:
retry max 5
run: npm run lint && npm test
if command_failed
prompt: The pipeline failed. Read the errors, fix the issues, and try again.
end
end
done when:
tests_pass
lint_pass
Anti-pattern: Flows longer than 10 lines
If your flow block exceeds 10 lines, you're almost certainly over-engineering. Simplify. Combine prompts. Remove unnecessary variables. Trust Claude to handle sequencing.
Output
Write the flow in a fenced code block, or say "no flow needed" and write a plain prompt instead.
Always explain:
- What the gate enforces and why mechanical verification matters for this task
- Why a plain prompt wouldn't be sufficient (if you chose a flow)
Advanced (available but rarely needed)
These features exist but should be the exception, not the default:
- Try/catch —
try/catchblocks for when a specific command might fail and needs distinct recovery. Most errors are handled fine by the Ralph Loop'sif command_failedbranch. - If/else branching —
if/elsefor conditional paths. Usually indicates the flow is trying to do too much. Consider splitting into separate tasks. - Variable capture —
let x = run "cmd"orlet x = prompt "text"for storing values. Only useful when a value must cross many steps or drive aforeachloop. - While/until loops —
while condition/until conditionfor open-ended loops.retry max Nis preferred for bounded iteration.
Additional advanced guidance and tradeoffs:
references/advanced.md