Agent path
Invoke workflows safely
Use the workflow tools when a task benefits from explicit orchestration, parallel work, durable checkpoints, or worktree-scoped agent changes.
Quick start
For most tasks, call workflow with a named inline script using this parallel fan-out and summary pattern:
{
"name": "review",
"script": "const findings = await parallel('review', { correctness: () => agent('Review correctness'), security: () => agent('Review security') }); return await agent(prompt('Summarize these findings:\\n\\n{findings}', { findings }));"
}
Inline launches require an explicit non-empty name. Registered function launches must omit name; they use workflow as the run name. Use workflow_respond only to answer a pending checkpoint or budget-adjustment proposal, using the exact name or proposal ID reported by the run. Use workflow_stop with the exact run ID to stop an active run from the current Pi session.
Await the keyed parallel results before interpolating them into the summarizing agent. Runs are backgrounded by default; set foreground: true when the final JSON value must be returned in the same tool call.
Advanced: Use registered functions, outputSchema, budgets, checkpoints, worktrees, retry/resume, CLI export, or pipelines only when the task needs them; these capabilities remain available without complicating the default inline path. For example:
{
"workflow": "releaseCheck",
"args": { "commit": "HEAD" }
}
Recovery map: agent(..., { retries }) reruns one agent call in the same run for transient failures; workflow_retry({ runId }) replays a persisted failed run into a child; workflow_resume({ runId, budget? }) continues a budget_exhausted run; parentRunId on a new launch only borrows named worktrees and never replays or resumes. Use each only for its stated case.
Runs are backgrounded by default. Set foreground: true when the final JSON value must be returned in the same tool call; the model-visible foreground result also reports its completed runId. Pass parentRunId with a terminal run ID only to reuse matching explicitly named withWorktree scopes. To recover a failed run, use its failure diagnostic's exact runId with workflow_retry({ runId }); diagnostics list replayable and incomplete paths, artifact locations, and valid named worktrees. The child replays only completed structural operations and executes incomplete work. External side effects before failure are not guaranteed exactly once.
Script and argument contract
The script is immutable, sandboxed JavaScript. It can use args, agent, shell, prompt, parallel, pipeline, phase, log, checkpoint, and withWorktree; entering a worktree passes its callback a frozen public reference containing only string path and branch. It can also use registered globals. It cannot import modules or access the filesystem, network, process, clocks, timers, or dynamic code; shell() is the only host-mediated command capability.
Arguments must be JSON-compatible. If omitted, args is null. Await agent results before passing them to prompt() or serialization. Values returned by agents and combinators are bare values, not { value, ok } wrappers.
const result = await agent("Inspect the target", {
tools: ["read", "grep"],
});
return { result };
Direct calls from the same source location must be sequential unless they are structurally inside parallel or pipeline. Keep operation names and object keys stable so replay can match them. shell() returns { exitCode, stdout, stderr }; a nonzero exit is inspectable command output, while launch failures and timeouts fail the workflow.
const tests = await shell("yarn test", { env: { CI: "1" } });
if (tests.exitCode !== 0) return tests.stderr || tests.stdout;
Minimal workflow patterns
Default: parallel fan-out and summary
const findings = await parallel("review", {
correctness: () => agent("Review correctness"),
security: () => agent("Review security"),
});
return await agent(prompt("Summarize these findings:\n\n{findings}", { findings }));
Advanced: development with a worktree
{
"name": "implement-feature",
"script": "return await withWorktree('implementation', async ({ path, branch }) => ({ path, branch, results: await parallel('implementation', { code: () => agent('Implement the feature'), tests: () => agent('Add integration tests') }) }));",
"parentRunId": "previous-terminal-run-id"
}
Additional pattern: review
const reports = await parallel("review", {
correctness: () => agent("Review correctness and regressions"),
security: () => agent("Review trust and security boundaries"),
});
return reports;
Planning
const plan = await agent("Create a concise implementation plan", {
role: "planner",
});
return plan;
Scouting
return await agent("Scout the repository and report only relevant files", {
role: "scout",
});
Use roles only when the Pi installation provides those role files. Otherwise choose an explicit available model and the smallest required tool list.
Role and model selection
An agent can select a role, a configured model alias, an explicit model such as provider/model:thinking, a thinking level, and a list of tools. Role policy takes precedence and cannot be mixed with model, thinking, or tools options. A requested model or tool must be inside the launching session boundary. When workflow_catalog exposes model aliases, an exact alias name takes precedence over a matching native bare model name; explicit call-level thinking overrides the alias suffix. See global workflow settings for alias and workflow-agent resource policy.
Optional controls are outputSchema, non-negative integer retries, positive integer or null timeoutMs, and the canonical withWorktree(name, callback) scope. Use separate named scopes for independent branches and one enclosing scope for collaborators.
return await agent("Inspect the package API", {
model: "openai-codex/gpt-5.6-sol:high",
tools: ["read", "grep", "find"],
timeoutMs: 120000,
});
Run budgets
Add budget only when a run needs aggregate token, USD cost, active-duration, or agent-launch limits. Each dimension accepts optional soft and hard values; omitted values are unlimited.
{
"budget": {
"tokens": { "soft": 100000, "hard": 120000 },
"agentLaunches": { "hard": 10 }
}
}
Soft crossings ask agents to wrap up; hard limits block new launches or turns but accept an already-finished final response. Usage includes retries and descendants and remains cumulative across Pi context compaction. If more model work is attempted after exhaustion, the run enters budget_exhausted. Runs without effective limits omit budget information from compact TUI views.
Resume an exhausted run with workflow_resume and an optional budget patch. Omitted values remain unchanged and null removes a limit. Tightening resumes directly; raising or removing a limit requires human approval through workflow_respond with the exact proposal ID. Do not retry ordinary agent work to bypass an exhausted budget.
Checkpoints and workflow_respond
Use checkpoint({ name, prompt, context }) when execution must wait for a decision. The name must be a stable non-empty string. The prompt is limited to 1 KB UTF-8 bytes and context to 4 KB serialized JSON.
const approved = await checkpoint({
name: "ship",
prompt: "Ship this build?",
context: { commit: args.commit },
});
if (approved !== "approved") return { cancelled: true };
For a background run, the tool asks for workflow_respond:
{ "runId": "...", "name": "ship", "approved": true }
The first valid response wins. Foreground checkpoints require a Pi UI with an interactive select; workflow_respond alone cannot satisfy that requirement.
Failure, retry, resume, and cancellation
- Failure: catch workflow-source failures as ordinary
Errorvalues and inspectcodeandmessage. Host tool calls reject withWorkflowError; finalized failures expose bounded JSON diagnostics with the run ID, failed branch, completed siblings, retryable paths, named worktrees, and state/journal artifact paths. Background follow-ups include the same diagnostics and warn that external side effects are not exactly-once. - Retry: call
workflow_retry({ runId })only for a persistedfailedrun. Abudget_exhaustedsource points toworkflow_resume({ runId, budget? }); completed, stopped, and interrupted sources keep their own state-specific guidance. - Agent retry: set
retriesonly for safe, repeatable agent work. Each attempt gets a fresh Pi session but preserves filesystem changes. - Resume: provider limits pause native work; Pi shutdown marks active runs
interrupted. Reopen the original Pi session and explicitly resume. Abudget_exhaustedrun can resume throughworkflow_resumewith retained historical usage and an acceptable budget; afailedrun points toworkflow_retry({ runId }); completed and stopped runs remain non-resumable. - Cancellation: stopping a run is immediate, cascades to owned agents, and cannot be undone. A cancelled workflow reports
CANCELLEDor a stopped run state.
Use /workflow to inspect state and budgets, manage model aliases, pause, resume, adjust an exhausted budget, stop, approve, reject, or delete a run. The run navigator presents phases first, then structural operation paths, then agents; on narrow terminals, the first Enter opens details and a second Enter on an agent opens agent actions. In the TUI, open the run script or a completed top-level agent result in the configured external editor; phase and operation nodes have no artifact action. Select an agent to fork an attempt in a Herdr pane when available, inspect its ID, and see applicable branch or worktree actions. The run ID returned by a background invocation is the handle for run-level actions.
Need the implementation details?
See the developer configuration guide for global and project settings, or operations for storage, doctor, inspector, and evaluation commands.