Claude Code–style dynamic workflows for Pi: code-mode subagents with real model routing, journaled resume, git-worktree isolation, cost accounting, an interactive /workflows TUI, an /ultracode standing opt-in, and deep research.
$ npx -y skills add QuintinShaw/pi-dynamic-workflows --agent claude-code
Repo: QuintinShaw/pi-dynamic-workflows
What's inside
Turn one request into a JavaScript orchestration script that fans work out across isolated subagents, routes each task to the right model, cross-checks the results, and returns one synthesized answer. Intermediate work stays in script variables instead of filling your chat context.
Built for codebase-wide audits, multi-perspective review, large refactors, and source-checked research—the jobs that are too broad for one agent and one context window.

pi install npm:@quintinshaw/pi-dynamic-workflows
Run /reload in Pi, then ask naturally:
Run a workflow to audit every route under src/routes/ for missing auth checks.
Pi writes and starts the workflow in the background. A live panel tracks progress while you keep working, and the final result is delivered back into the conversation automatically.
Keyword triggering is on by default: use the bounded word workflow or workflows in a message to arm workflow mode — the assistant then handles a request by fanning it out across agents, but still answers plainly if you're only asking about workflows (the trigger authorizes the tool, it doesn't force it). Or run /workflows run <prompt> explicitly. Identifier-like text and paths such as myworkflow, workflow_name, and src/workflow-editor.ts do not trigger. You can change the keyword with /workflows-trigger set pi-workflow or disable it with /workflows-trigger off.

agent(), parallel(), pipeline(), and phase().The orchestration itself is plain JavaScript:
export const meta = {
name: 'auth_audit',
description: 'Find routes missing auth checks and verify the findings',
phases: [{ title: 'Scan' }, { title: 'Review' }, { title: 'Verify' }],
}
phase('Scan')
const files = await agent('List every route file under src/routes/.', { tier: 'small' })
phase('Review')
const findings = await parallel(
files.split('\n').filter(Boolean).map((file) =>
() => agent(`Audit ${file} for missing auth checks.`, {
tier: 'medium',
isolation: 'worktree',
}),
),
)
phase('Verify')
return await agent(
'Synthesize and double-check these findings:\n' + findings.join('\n\n'),
{ tier: 'big' },
)
small, medium, or big tiers, or choose an exact provider/model and thinking level.resumeFromRunId): unchanged agent() calls replay from cache and only edited/new ones re-run — so a single bad prompt no longer means paying to re-run the whole workflow.isolation: "worktree". Kept by default for merge; pass keepWorktree: false to delete (tests).~ prefix (e.g. ~640 tok) — never silently as metered figures. (Script-facing budget.spent()/remaining() are raw numbers and cannot carry the marker.)/workflows navigator.verify(), judgePanel(), loopUntilDry(), and completenessCheck() instead of rebuilding review loops.The installed extension generates this compact index from its executable capability contract. Read the workflow authoring guide or use the packaged workflow-authoring skill for constraints, lifecycle guidance, and adaptable examples; configured route and agent-type values remain environment-specific.
| Name | Classification | Signature | Options and defaults |
|---|---|---|---|
| agent | runtime-global | agent(prompt, options?) => Promise<string | structured value | null> | label: string (optional; default: derived from phase and call count)phase: string (optional; default: current phase)schema: plain JSON Schema (optional)model: string (optional)thinking: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" (optional)tier: string (optional)isolation: "worktree" | false (optional)keepWorktree: boolean (optional; default: true)cwd: string (optional)thread: string (optional)agentType: string (optional)timeoutMs: number | null (optional; default: run timeout, finite ms in [1, 2^31-1]; null disables)retries: number (optional; default: run retry count) |
| parallel | runtime-global | parallel(thunks) => Promise<Array<unknown | null>> | — |
| pipeline | runtime-global | pipeline(items, ...stages) => Promise<Array<unknown | null>> | — |
| workflow | runtime-global | workflow(savedName, childArgs?) => Promise<unknown> | — |
| verify | runtime-global | verify(item: unknown, options?: { reviewers?: number; threshold?: number; lens?: string | string[] }) => Promise<{ real: boolean; realCount: number; total: number; votes: Array<{ real: boolean; reason?: string }> }> | reviewers: number (optional; default: 2)threshold: number (optional; default: 0.5)lens: string | string[] (optional) |
| judgePanel | runtime-global | judgePanel(attempts: unknown[], options?: { judges?: number; rubric?: string }) => Promise<{ index: number; attempt: unknown; score: number; judgments: Array<{ score: number; reason?: string }> } | undefined> | judges: number (optional; default: 3)rubric: string (optional; default: "overall quality and correctness") |
| loopUntilDry | runtime-global | loopUntilDry(options: { round: (roundIndex: number) => unknown[] | Promise<unknown[]>; key?: (item: unknown) => string; consecutiveEmpty?: number; maxRounds?: number }) => Promise<unknown[]> | round: (roundIndex: number) => unknown[] | Promise<unknown[]> (required)key: (item: unknown) => string (optional; default: JSON.stringify)consecutiveEmpty: number (optional; default: 2)maxRounds: number (optional; default: 50) |
| completenessCheck | runtime-global | completenessCheck(taskArgs: unknown, results: unknown) => Promise<{ complete: boolean; missing?: string[] } | null> | — |
| retry | runtime-global | retry(thunk: (attempt: number) => unknown | Promise<unknown>, options?: { attempts?: number; until?: (result: unknown) => boolean }) => Promise<unknown> | attempts: number (optional; default: 3)until: (result: unknown) => boolean (optional; default: accept first result when omitted) |
| gate | runtime-global | gate(thunk: (feedback: string | undefined, attempt: number) => unknown | Promise<unknown>, validator: (value: unknown) => { ok: boolean; feedback?: string } | Promise<{ ok: boolean; feedback?: string }>, options?: { attempts?: number }) => Promise<{ ok: boolean; value: unknown; attempts: number }> | attempts: number (optional; default: 3) |
| checkpoint | runtime-global | checkpoint(prompt, options?) | checkpoint({ kind, checkpointId, payload }) => Promise<unknown> | default: unknown (optional; default: true when no UI and omitted)headless: "default" | "abort" (optional; default: "default")kind: "confirm" | "input" | "select" (optional; default: "confirm")choices: string[] (optional)timeoutMs: number (optional) |
| log | runtime-global | log(message) => void | — |
| phase | runtime-global | phase(title, options?) => void | budget: number (optional) |
| args | runtime-global | args: unknown | — |
| cwd | runtime-global | cwd: string | — |
| process | runtime-global | process: { cwd(): string } | — |
| budget | runtime-global | budget: { total, spent(), remaining() } | — |
| script | workflow-tool-input | script?: string | — |
| name | workflow-tool-input | name?: string | — |
| args | workflow-tool-input | args?: unknown | — |
| background | workflow-tool-input | background?: boolean = true | — |
| maxAgents | workflow-tool-input | maxAgents?: number = 1000 | — |
| concurrency | workflow-tool-input | concurrency?: number | — |
| agentRetries | workflow-tool-input | agentRetries?: number = configured value or 0 | — |
| agentTimeoutMs | workflow-tool-input | agentTimeoutMs?: number = configured default or unbounded | — |
| tokenBudget | workflow-tool-input | tokenBudget?: number = configured default or unlimited | — |
| resumeFromRunId | workflow-tool-input | resumeFromRunId?: string | — |
/deep-research <question> source-checked web research with citations
/adversarial-review <task> findings challenged by skeptical reviewers
/multi-perspective "<topic>" [angle …]
independent angles followed by synthesis
/code-review [target] 7 parallel review angles plus verification
/codebase-audit <scope> "<check>" …
parallel checks followed by cross-validation
/code-review defaults to the current working diff. It also accepts a git range, a file, or a GitHub PR number:
/code-review
/code-review HEAD~3..HEAD
/code-review src/foo.ts
/code-review 42
For an always-on exhaustive mode, use /ultracode; /effort high is the lighter standing option.
These same 5 patterns are also reachable by name without a slash command — Pi can recognize a decomposable request and run the matching curated pattern directly:
Do a deep-research on whether Bun's test runner is production-ready.
FAQ
pi-dynamic-workflows is a Claude Code plugin with 2 hand-picked skills for development work, indexed on Flowy. Install it with the command on its page. It includes workflow-authoring, workflow-patterns. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it