Create and edit pi-flows flows and agents from the main session. Use when the user wants to create a new flow, add or change an agent, or edit an existing flow/agent. Covers agent frontmatter, flow YAML, step types, model references, the flow_agents and flow_write tools, write locations, and how to fix validation errors.
npx skills add https://github.com/BlackBeltTechnology/pi-agent-dashboard --skill edit-flow
You are creating and editing pi-flows flows and agents directly in this session. Two tools do the writing (both validate before writing and return diagnostics on failure):
flow_agents — op: "list" returns the agent catalog; op: "write" validates and writes an agent .md to .pi/flows/agents/<name>.md (filename derived from the agent's frontmatter name).flow_write — namespace (default custom), name, content. Validates and writes a flow to .pi/flows/flows/<namespace>/<name>.yaml, which auto-registers as the /<namespace>:<name> command.These tools derive their write locations from the discovery convention — there is no raw path. Writing to a name that already exists overwrites it (that is how you edit).
> The edit-flow tools are off by default. They are active only when flows.editFlow: true is set in .pi/settings.json (project, when trusted) or ~/.pi/agent/settings.json (global). If flow_agents/flow_write are not available, tell the user to enable that setting and restart the session.
flow_agents with op: "list" to see existing agents and their inputs, outputs, and source_type. Reuse built-in/local agents where they fit.flow_agents op: "write". Do not repurpose infrastructure agents (flow-decision, project-context-reader) for unrelated tasks.flow_write. Wire every declared input. Fix any validation diagnostics and retry./<namespace>:<name>).Editing an existing flow/agent = read the current file, change it, then write it back with the same tool and the same name/namespace.
.md)YAML frontmatter + Markdown body (the system prompt).
---
name: code-reviewer
description: Reviews source code for quality and correctness
model: @coding
thinking: medium
tools: read, grep, find
inputs:
- research_context
outputs:
- name: findings
description: Categorized issues found
- name: verdict
description: "pass" or "fail"
access:
read:
- "src/**"
write:
- "src/**"
bash:
deny:
- "rm -rf *"
card:
label: "Reviewer"
metric: "default"
architect:
use_when: "User wants code reviewed for quality"
produces: "A findings report and a pass/fail verdict"
depends_on: "An implementer must have produced code"
domain: "review"
---
# System Prompt
You are a code reviewer. Task: ${{task}}
Context: ${{input.research_context}}
| Field | Required | Notes |
|-------|----------|-------|
| name | Yes | Unique. Filename = <name>.md. Referenced as agent: <name> in steps. |
| description | Yes | One line. Shown in catalog. |
| model | Yes | See Model references. |
| tools | Yes | Comma-separated. Guard blocks anything not listed. Standard: read, write, edit, grep, find, ls, bash, ask_user, skill_read. |
| thinking | No | off/minimal/low/medium/high/xhigh. Overrides any :level suffix in model. |
| skills | No | Comma-separated skill names injected into the prompt. |
| inputs | No | Names → ${{input.NAME}} in the prompt. Flow step must wire each one. |
| outputs | No | Names (or {name, description} objects). Become finish parameters and ${{result.STEP.NAME}} downstream. |
| interactive | No | true allows mid-task UI prompts. Default false. |
| output | No | Output file hint (display only). |
| access | No | read/write glob allowlists; bash.deny command patterns. * = segment, ** = any depth. |
| card | No | label, metric (default/files/tests/custom), role. |
| architect | No | use_when/produces/depends_on/domain metadata surfaced in flow_agents op: list. |
The model: field accepts three forms. Prefer @role. Use the other two when a specific model is required regardless of role config, or when the user explicitly asks for a non-role model.
| Form | Example | When |
|------|---------|------|
| @role (preferred) | model: @coding | Default. Resolves via the active role→model map (/roles). Built-in roles: @planning, @coding, @fast, @architect. |
| provider/model[:thinking] | model: anthropic/claude-haiku-4-5:high | A specific provider+model is required; optional :thinking suffix sets the thinking level. |
| bare model-id | model: claude-haiku-4-5 | A specific model id with no provider qualifier; thinking comes from the thinking: field or none. |
A thinking: field always overrides any :thinking suffix in model.
.yaml)name: my-flow # REQUIRED
description: What it does # REQUIRED
max_concurrent: 3 # optional (default 4)
task_required: true # optional — prompt for task if invoked with no args
task_prompt: "Task:" # optional
steps:
- id: research
agent: code-reviewer
task: Review ${{task}}
name is the frontmatter name; the command name comes from the on-disk location (namespace/name you pass to flow_write). Every step needs a unique id. Step type is usually inferred from which fields are present; set type: explicitly when ambiguous.
- id: impl
agent: implementer
task: Implement ${{task}}
blockedBy: [research]
inputs:
ctx: ${{result.research.summary}}
on_complete: verify # optional cross-segment jump
on_error: handler # optional
agent: in autonomous mode) picks a branch. - id: choose
type: fork
question: Which strategy?
options: [Fast, Full]
branches: { Fast: fast-impl, Full: full-impl }
agent: flow-decision # autonomous-mode decider
allowCustom: false
multiSelect: false
Branch keys must match options exactly.
- id: has-gaps
type: conditional
check: research.artifacts # stepId.field
present: gap-filler
absent: finalize
finish({ branch }) to choose. - id: complexity
type: agent-decision
agent: analyzer
task: Simple or complex?
branches: { simple: quick, complex: thorough }
- id: should-fix
type: agent-loop-decision
agent: flow-decision
task: Iteration ${{loop.should-fix.iteration}}/${{loop.should-fix.max}}. ${{result.verify.summary}}
loop_target: fixer # jump back
exit_target: done # continue forward
max_iterations: 3
- id: sub
type: flow-ref
path: "project/changes/*/exec.yaml" # glob ok
on_complete: verify
Expanded in task, inputs values, and question. Not validated — a typo silently becomes empty string.
${{task}} — the user task.${{input.NAME}} — input wired into this step.${{result.STEP_ID.status|summary|artifacts|files|fullOutput|OUTPUTNAME}} — STEP_ID is the step id, not the agent name.${{loop.STEP_ID.iteration|max}} — loop counters.Wire data between steps via inputs: (agent declares names in frontmatter, step supplies values). Prefix an input value with file:// to inject file content verbatim; that file's producer step must be in blockedBy.
| Content | Tool | Lands at |
|---------|------|----------|
| Agent | flow_agents op: write | .pi/flows/agents/<name>.md |
| Flow | flow_write | .pi/flows/flows/<namespace>/<name>.yaml → /<namespace>:<name> |
Project-local definitions (.pi/flows/) override package and built-in ones.
Both tools validate before writing. On failure they return { written: false, diagnostics: [...] } and write nothing. Read each diagnostic's message and suggestion, fix the content, and call the tool again. Common cases:
name, description, model, tools for agents; name, description for flows) → add it.flow_agents op: write, then retry flow_write.inputs: block.tools: → use a valid tool name (see the standard list above) or an extension-registered tool name.Take blackbelttechnology/edit-flow from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.