Templates
Five ready-to-run taskflow templates you can save and adapt.
Templates are complete, runnable taskflow definitions for common agent workflows. Each one is a real JSON graph you can save verbatim and run, then tune for your own repo. They are not toy examples — every phase, dependency, and field here is one you would write in production.
These templates run identically on Pi (/tf run) and on Codex / Claude Code / OpenCode (taskflow_run). See the Pi guide or Codex guide for the host-specific invocation surface.
The gallery
PR Security Audit
Discover changed files, fan out per-file security review, gate on risk, emit one report.
Release Note Generation
Research a feature, run a headline tournament, and assemble a full release note.
Codebase Migration
Discover legacy call sites, plan the migration, and loop until none remain.
API Doc Generation
Discover public API surface, draft per-file reference docs, merge into one document.
Dependency Upgrade Review
Enumerate outdated dependencies, evaluate breaking-change risk, and gate on criticals.
Save any template as a .json file in your project, then verify it for free before running:
/tf verify <name>1. PR Security Audit
Discover the files a pull request touches, fan out a per-file security review with bounded concurrency, run a parallel architecture review at the same time, gate the whole thing on risk, and finish with one merged report. Only the report returns to your context — the per-file transcripts stay inside the runtime.
{
"name": "pr-security-audit",
"description": "Audit a pull request: discover changed files, fan out per-file security review, run a parallel architecture review, gate on risk, and emit one merged report.",
"args": {
"base": { "default": "origin/main", "description": "The git ref to diff against." }
},
"concurrency": 6,
"budget": { "maxUSD": 3.0 },
"phases": [
{
"id": "discover",
"type": "agent",
"agent": "scout",
"task": "List the source files changed between {args.base} and HEAD. Output ONLY a JSON array of {\"path\": \"<relative-path>\"} objects. No prose.",
"output": "json",
"expect": { "type": "array", "items": { "type": "object" } },
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "security-each",
"type": "map",
"over": "{steps.discover.json}",
"as": "file",
"agent": "security-reviewer",
"task": "Review {file.path} for security risks: missing auth checks, unsanitized input, hardcoded secrets, unsafe deserialization. Return one paragraph of findings, or 'No issues found.' if clean. Begin with the file path.",
"dependsOn": ["discover"],
"concurrency": 4,
"context": ["{file.path}"],
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "arch-review",
"type": "parallel",
"branches": [
{
"task": "Review the changed files for layering violations, leaked internals, and missing abstractions. Return a short prioritized list.",
"agent": "reviewer"
}
],
"concurrency": 2
},
{
"id": "risk-gate",
"type": "gate",
"agent": "reviewer",
"dependsOn": ["security-each", "arch-review"],
"join": "all",
"task": "You are the final risk gate. If any finding is high-risk (missing auth, secret leak, broken layering, data-loss path), end with: VERDICT: BLOCK. Otherwise end with: VERDICT: PASS.\n\nSecurity:\n{steps.security-each.output}\n\nArchitecture:\n{steps.arch-review.output}",
"onBlock": "halt"
},
{
"id": "report",
"type": "reduce",
"from": ["security-each", "arch-review", "risk-gate"],
"agent": "writer",
"task": "Write the final PR review report: 1) Risk verdict, 2) Security findings (prioritized), 3) Architecture findings (prioritized), 4) Recommended actions before merge. Be concise.\n\nSecurity:\n{steps.security-each.output}\n\nArchitecture:\n{steps.arch-review.output}\n\nGate verdict:\n{steps.risk-gate.output}",
"dependsOn": ["risk-gate"],
"final": true
}
]
}/tf run pr-security-audit base=origin/main/tf save pr-security-audit
/tf:pr-security-audit base=origin/maintaskflow_run { "name": "pr-security-audit", "args": { "base": "origin/main" } }Walk through how this flow is built incrementally — discover, fan out, gate, report — in the code audit case study.
2. Release Note Generation
Research the feature into a shared set of facts, run a four-variant tournament to pick the strongest headline, then assemble a full release note from the research and the winning headline. The losing headlines and the judge's reasoning are discarded; only the finished note reaches your context.
{
"name": "release-note",
"description": "Research a feature, run a 4-variant headline tournament, and assemble a full release note.",
"args": {
"feature": { "description": "The feature to write a release note for.", "required": true }
},
"concurrency": 6,
"budget": { "maxUSD": 1.5 },
"phases": [
{
"id": "research",
"type": "agent",
"agent": "scout",
"task": "Read the diff and release notes for {args.feature}. Summarize in 5 bullets: what it does, who it helps, and the single most surprising benefit. Return bullets only.",
"output": "json",
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "headline",
"type": "tournament",
"agent": "writer",
"dependsOn": ["research"],
"task": "Write a punchy release-note headline based on the research below. It must be accurate and under 80 characters. Return ONLY the headline.\n\n{steps.research.output}",
"variants": 4,
"judge": "Pick the headline that is the most punchy while staying accurate and under 80 characters. Prefer specific over generic.",
"judgeAgent": "final-arbiter",
"mode": "best"
},
{
"id": "note",
"type": "reduce",
"from": ["research", "headline"],
"agent": "writer",
"task": "Assemble a complete release note. Use the winning headline as the title, then write a 2-3 paragraph body from the research. End with a one-line 'How to try it' call to action.\n\nHeadline:\n{steps.headline.output}\n\nResearch:\n{steps.research.output}",
"dependsOn": ["headline"],
"final": true
}
]
}/tf run release-note feature="subagent context isolation"/tf save release-notetaskflow_run { "name": "release-note", "args": { "feature": "subagent context isolation" } }The headline tournament is explained end to end — variants, judge rubric, and best vs aggregate modes — in the tournament case study.
3. Codebase Migration
Discover every call site of a legacy API, plan the migration per file, gate the plan for safety, then loop: re-plan based on what remains until no old calls are left. The runtime validates any model-authored sub-flow before it executes, so a bad plan never crashes the run.
{
"name": "codebase-migration",
"description": "Iteratively re-plan a legacyAuth() -> authorize() migration until no calls remain, then execute the final plan.",
"args": {
"oldApi": { "default": "legacyAuth()", "description": "The old API call to migrate away from." },
"newApi": { "default": "authorize()", "description": "The new API to migrate to." }
},
"concurrency": 4,
"budget": { "maxUSD": 4.0 },
"phases": [
{
"id": "refine",
"type": "loop",
"agent": "planner",
"task": "Inspect the codebase for remaining calls to {args.oldApi}. If any remain, output {\"plan\": <taskflow-definition that fixes the remaining files>, \"done\": false}. If none remain, output {\"done\": true}. The plan, when present, must be a JSON taskflow with a 'name' and a 'phases' array.",
"until": "{steps.refine.json.done} == true",
"maxIterations": 6,
"output": "json"
},
{
"id": "execute-final",
"type": "flow",
"def": "{steps.refine.json.plan}",
"when": "{steps.refine.json.done} == false",
"dependsOn": ["refine"],
"final": true
}
]
}/tf run codebase-migration oldApi=legacyAuth\(\) newApi=authorize\(\)/tf save codebase-migrationtaskflow_run { "name": "codebase-migration", "args": { "oldApi": "legacyAuth()", "newApi": "authorize()" } }The full plan → gate → execute → loop cycle, including dynamic hardening caps, is walked through in the migration planner case study.
4. API Doc Generation
Discover the public API surface of a directory, draft reference documentation for each file in parallel, then reduce the drafts into one coherent API reference document. The per-file drafts stay inside the runtime; only the compiled reference returns to your context.
{
"name": "api-docs",
"description": "Discover public API surface, draft per-file reference docs, and merge into one document.",
"args": {
"dir": { "default": "src", "description": "The source directory to document." }
},
"concurrency": 4,
"budget": { "maxUSD": 2.0 },
"phases": [
{
"id": "discover",
"type": "agent",
"agent": "scout",
"task": "List the source files under {args.dir} that export a public API (exported functions, classes, types). Output ONLY a JSON array of {\"path\": \"<relative-path>\", \"module\": \"<module-name>\"} objects. No prose.",
"output": "json",
"expect": { "type": "array", "items": { "type": "object" } },
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "draft-each",
"type": "map",
"over": "{steps.discover.json}",
"as": "file",
"agent": "writer",
"task": "Write reference documentation for the public API in {file.path} (module: {file.module}). For each export: a one-line summary, parameter descriptions, return type, and one usage example. Use Markdown. Begin with a '## {file.module}' heading.",
"dependsOn": ["discover"],
"concurrency": 4,
"context": ["{file.path}"],
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "compile",
"type": "reduce",
"from": ["draft-each"],
"agent": "writer",
"task": "Compile the per-module drafts into a single API reference document. Add a top-level title and a table of contents listing each module. Deduplicate cross-referenced types. Preserve the per-module sections in dependency order.\n\n{steps.draft-each.output}",
"dependsOn": ["draft-each"],
"final": true
}
]
}/tf run api-docs dir=src/tf save api-docstaskflow_run { "name": "api-docs", "args": { "dir": "src" } }The discover phase is a pure function of the codebase. Mark it cross-run with a glob!: fingerprint so a re-run after an unrelated change reuses the cached discovery — only files that actually changed get re-documented.
5. Dependency Upgrade Review
Enumerate the project's outdated dependencies, evaluate each for breaking-change risk in parallel, gate on any critical finding, and finish with a prioritized upgrade plan. The gate can halt the run before the plan is written if a dependency is too dangerous to upgrade blindly.
{
"name": "dep-upgrade-review",
"description": "Enumerate outdated dependencies, evaluate breaking-change risk, gate on criticals, and emit a prioritized upgrade plan.",
"args": {
"manager": { "default": "npm", "description": "The package manager to query (npm, pnpm, yarn)." }
},
"concurrency": 4,
"budget": { "maxUSD": 2.0 },
"phases": [
{
"id": "discover",
"type": "agent",
"agent": "scout",
"task": "Run `{args.manager} outdated --json` (or the equivalent) and list every outdated dependency. Output ONLY a JSON array of {\"name\": \"<package>\", \"current\": \"<version>\", \"wanted\": \"<version>\", \"latest\": \"<version>\"} objects. No prose.",
"output": "json",
"expect": { "type": "array", "items": { "type": "object" } },
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "evaluate-each",
"type": "map",
"over": "{steps.discover.json}",
"as": "dep",
"agent": "risk-reviewer",
"task": "Evaluate the risk of upgrading {dep.name} from {dep.current} to {dep.latest}. Check the changelog for breaking changes, deprecations, and peer-dependency shifts. Return: package name, risk level (LOW|MEDIUM|HIGH|CRITICAL), a one-sentence reason, and a recommended action (safe-to-upgrade|test-first|pin-major|hold). Begin with the package name.",
"dependsOn": ["discover"],
"concurrency": 4,
"retry": { "max": 2, "backoffMs": 1000, "factor": 2 }
},
{
"id": "risk-gate",
"type": "gate",
"agent": "reviewer",
"dependsOn": ["evaluate-each"],
"join": "all",
"task": "You are the upgrade risk gate. If any dependency is rated CRITICAL (a known breaking change with no migration path, or a security-sensitive package), end with: VERDICT: BLOCK. Otherwise end with: VERDICT: PASS.\n\n{steps.evaluate-each.output}",
"onBlock": "halt"
},
{
"id": "plan",
"type": "reduce",
"from": ["evaluate-each", "risk-gate"],
"agent": "writer",
"task": "Write a prioritized dependency upgrade plan. Group by risk level (CRITICAL first, then HIGH, MEDIUM, LOW). For each dependency: the recommended action and a one-line reason. End with a suggested upgrade order that respects peer-dependency constraints.\n\n{steps.evaluate-each.output}\n\nGate verdict:\n{steps.risk-gate.output}",
"dependsOn": ["risk-gate"],
"final": true
}
]
}/tf run dep-upgrade-review manager=npm/tf save dep-upgrade-reviewtaskflow_run { "name": "dep-upgrade-review", "args": { "manager": "npm" } }The risk-gate uses onBlock: "halt". If a CRITICAL dependency is found, the run stops before the plan phase runs — you get the gate's verdict instead of a plan that would greenlight a dangerous upgrade. Drop the gate (or set onBlock: "continue") if you always want the plan, regardless of risk.
Adapting a template
Every template above is a starting point, not a prescription. The knobs worth turning are the same across all of them:
concurrency— raise it on a generous rate limit to finish faster; lower it to avoid 429s. Theretrypolicy absorbs the rest.budget— the run-wide cost ceiling. ABLOCKverdict or budget breach halts the run before downstream phases spend more tokens.cache— mark pure, expensive phases (discover, per-file reviews)cross-runwith agit:HEADorglob!:fingerprint so re-runs reuse work whose inputs did not change.retry— two attempts with exponential backoff covers most transient provider errors. Raisemaxfor phases that hit larger models.
Always run /tf verify <name> on a template after you edit it. Verification is zero-token and catches the vast majority of authoring mistakes — cycles, dead-ends, dangling references — before you spend anything.
Where to go next
Getting Started
Install taskflow and run your first flow.
Phase Types
Full field reference for every phase type used in these templates.
Guides
End-to-end walkthroughs that build several of these templates incrementally.
Last updated on
Was this helpful?
Help us improve the docs or ask a question in the community.