Delegate bounded work from Pi to isolated subagents with single-task, chain, parallel, and DAG workflows, including conditional edges, nested workflows, and bounded loops.
pi-subflow is a Pi extension and TypeScript orchestration core for coordinating focused subagents without putting planning, policy checks, execution, validation, and rendering into one oversized prompt.
Use it when work benefits from independent research/review streams, staged handoffs, or a final verifier. Do not use it for small direct tasks the current assistant can do faster by itself.
- Single, chain, parallel, DAG, conditional-edge, bounded-loop, and nested-workflow subagent execution
- DAG preflight validation with precise diagnostics
- PocketFlow node-backed internal DAG execution for validation, max-turns guards, stage execution, verifier repair, and result aggregation
dagYamlshorthand for concise LLM-authored task graphs- Inline nested workflows with parent/child namespacing and synthetic summaries
- Verifier fan-in with dependency-output injection
- Markdown-section and minimal JSON required-field validation
- Retry, timeout, max-turn, and budget helpers
- Project/user agent discovery with policy gates
- Runtime tool allowlist checks
- Workflow slash commands from
.pi/subflow/workflows/*.{yaml,yml}and~/.pi/agent/subflow/workflows/*.{yaml,yml} - Dry-run workflow optimization with
subflow_optimize, scorer-backed eval sets, objective scoring, manual candidate comparison, train/holdout splits, budget controls, and safe JSON reports in.pi/subflow/optimizer-reports/ - JSONL run history at
.pi/subflow/runs.jsonl
git clone git@github.com:5queezer/pi-subflow.git pi-subflow
cd pi-subflow
npm install
npm run build
pi -e ./dist/extension.jsThen ask Pi to use the subflow tool, for example:
Use subflow to run API, test, and docs reviewers in parallel, then run a verifier that synthesizes the findings.
For local development, you can symlink the built extension and reload Pi after rebuilding. The build also links dist/node_modules back to the project dependencies so Pi can resolve runtime packages such as yaml when the extension directory points at dist.
ln -sfn "$PWD/dist" ~/.pi/agent/extensions/subflow
npm run build
# then run /reload inside Piflowchart TD
U[User request] --> D{Work shape?}
D -->|One bounded task| S[Single]
D -->|Linear handoff| C[Chain]
D -->|Independent tasks| P[Parallel]
D -->|Named dependencies| G[DAG]
P --> V[Verifier fan-in]
G --> V
| Mode | Use when | Input shape |
|---|---|---|
| Single | exactly one focused subagent task is useful | agent + task |
| Chain | each step needs the previous step's output | chain: [{ agent, task }] with optional {previous} |
| Parallel | 2+ tasks are independent | tasks: [...] with no dependsOn |
| DAG | tasks have named dependencies, conditional edges, verifier fan-in, or bounded loops | tasks: [...] with dependsOn, when, loop, or dagYaml |
| Nested workflows | a task contains inline child tasks or statically includes a relative workflow file | workflow: { tasks: [...] }, workflow: { dagYaml }, or workflow: { uses } |
Example DAG shorthand:
api-review:
agent: reviewer
task: Review src/index.ts and public exports
test-review:
agent: reviewer
task: Review tests for coverage gaps
final-verdict:
agent: reviewer
role: verifier
needs: [api-review, test-review]
task: Synthesize the findings into a prioritized verdictVerifier tasks receive dependency outputs automatically. A verifier with no explicit dependsOn depends on all non-verifier tasks. dagYaml is parsed as YAML, so arrays can be written inline (needs: [api-review, test-review]) or as block sequences. Conditional edges use when expressions against dependency outputs. Nested workflows namespace child task names under the parent, flow the parent dependsOn into workflow roots, and expose a synthetic parent summary for downstream dependents. Bounded loops repeat a namespaced body up to loop.maxIterations, can stop early with loop.until, and expose a synthetic loop summary for downstream dependents. DAG execution is node-backed internally even though the public API stays runDag; chain and parallel remain custom orchestration.
Example workflows live in examples/workflows/, split into concrete recipes (task-specific jobs) and abstract patterns (reusable shapes). Both advertise the DAG YAML schema with:
# yaml-language-server: $schema=https://raw.githubusercontent.com/5queezer/pi-subflow/refs/heads/master/schemas/subflow-dag.schema.jsonRecipes (concrete jobs):
code-review.yamlimplementation-planning.yamlred-green-implementation.yamlresearch-synthesis.yamldocs-consistency.yamlbug-investigation.yaml
Patterns (reusable DAG shapes — see Workflow patterns for model fit and rationale):
adversarial-triangle.yamltwo-tier-audit.yamltournament.yamlcross-validation.yamlmap-group-reduce.yaml
Copy a .yaml or .yml template into .pi/subflow/workflows/ to register it as a slash command at Pi session startup:
.pi/subflow/workflows/code-review.yaml -> /code-review
.pi/subflow/workflows/code-review.yml -> /code-review
User-level workflow files are also supported under ~/.pi/agent/subflow/workflows/. If a project and user workflow have the same command name, the project workflow wins. During prompt-resource discovery, the extension writes generated prompt stubs under .pi/subflow/prompts/ or ~/.pi/agent/subflow/prompts/ when no manual prompt file with the same name exists, so Pi can discover the workflow prompt surface. Run /reload or start a new session after adding, removing, or renaming workflow files.
npm install
npm run build && npm testBefore submitting changes, run:
npm run build && npm testsubflow_propose_candidates generates validated static DAG candidate YAMLs without executing or mutating workflows. safe and exploratory currently share the verifier fan-in transform; model-thinking proposes deterministic verifier-only model/thinking variants for later optimizer evaluation. subflow_optimize is dry-run-only and writes JSON reports without mutating workflow files:
subflow_optimize({
workflowPath | dagYaml,
evalSet: { path | inline },
candidateDagYamls?,
maxCandidateRuns?,
maxCost?,
maxRunCost?,
maxCandidateCost?,
maxTotalCost?,
maxConcurrency?,
timeoutSeconds?,
})
- Use
subflow_propose_candidatesto generate candidate YAMLs, then pass selected valid outputs tosubflow_optimizeascandidateDagYamls. - Use
strategy: "model-thinking"to generate verifier-only model/thinking variants from the built-in Mini/Strong search space; Bayesian search, all-task mutation, and custom search spaces are future work. - Canonical eval sets should be stored at
.pi/subflow/evals/*.yamland loaded viaevalSet.path. - For quick experiments, use
evalSet.inline(not recommended for reusable cases). maxCandidateRunslimits candidate runs per case.maxRunCostcaps cost per run,maxCandidateCostcaps total cost per candidate, andmaxTotalCostcaps total optimizer spend.maxCostis a compatibility alias for current per-candidate budget behavior; when no dedicated caps are provided, it is also passed as the run-level cost cap.maxConcurrencyandtimeoutSecondscontrol executor behavior.- Invalid candidates are reported individually and do not abort the entire optimizer run.
- Reports are written under
.pi/subflow/optimizer-reports/. - Optimizer assets:
examples/evals/docs-consistency.yaml,examples/workflows/recipes/docs-consistency.yaml
- GitHub Wiki — detailed usage, TypeScript API, configuration, policy, architecture, current DAG expressiveness (conditional edges, nested workflows, bounded loops), remaining graph roadmap items, workflow optimization, self-optimizing static DAGs, and troubleshooting. Source pages live in
doc/wiki/and are published withnpm run wiki:syncornpm run wiki:sync:push. doc/wiki/Workflow-optimization.md— dry-run optimizer, canonical eval sets, scorer-backed recommendations, train/holdout splits, and safety modelschemas/subflow-dag.schema.json— YAML schema for workflow templatesschemas/subflow-eval.schema.json— YAML schema for optimizer eval setsdoc/adr/— architecture decision recordsCONTRIBUTING.md— contribution workflow
Keep the README, wiki, ADRs, and the subflow tool's LLM-facing guidance synchronized when behavior, schema, validation, public API, install/test commands, or design rationale change.
ISC