pi-agents
A generic framework for agent orchestration in pi.
Package details
Install pi-agents from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-agents- Package
pi-agents- Version
0.19.0- Published
- Aug 24, 2026
- Downloads
- 3,326/mo · 577/wk
- Author
- mavam
- License
- Apache-2.0
- Types
- extension
- Size
- 589.6 KB
- Dependencies
- 3 dependencies · 5 peers
Pi manifest JSON
{
"extensions": [
"./src"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
🤖 pi-agents
Run explicit, composable multi-agent workflows in Pi. Use one agent for a focused task, run several in parallel, or connect agents with sequences, maps, loops, conditions, and reducers.
Every workflow node returns a value. Data moves between nodes only through
references such as {previous}, {review}, or {item}. Because nothing
flows implicitly, Pi validates every reference before the run starts, and a
broken data dependency fails before any agent spawns.
🚀 Installation
pi install npm:pi-agents
The package works without configuration. It includes two workflows:
/reviewperforms a read-only code review./review-fixreviews, implements fixes, and reviews again until the change passes or the workflow cannot continue.
✨ Quick start
Ask Pi explicitly to delegate work:
Delegate a review of src/run to an agent.
Review src/run and src/ui in parallel, then merge the findings.
Run the review-fix workflow on my current changes.
Pi starts workflows only when you ask for delegation, parallel agents, or a saved workflow. Mentioning a workflow or asking how one works does not start it.
The model can create an inline workflow without any agent or workflow files:
{
"flow": {
"kind": "parallel",
"branches": {
"bugs": { "kind": "agent", "task": "Review src/run for bugs" },
"clarity": { "kind": "agent", "task": "Review src/run for clarity" }
},
"reduce": { "task": "Merge and prioritize these reviews:\n{branches}" }
},
"label": "review src/run"
}
An agent without a profile is anonymous and ad hoc. It inherits the current
model and thinking level unless the node overrides them.
📖 Core concepts
| Concept | Meaning |
|---|---|
| Agent | One delegated Pi session working on a task. It can be anonymous or use a saved profile. |
| Workflow | A saved or inline composition of agents and control-flow nodes. |
| Run | One persisted execution of a workflow. |
Workflow nodes
| Node | Purpose | Result |
|---|---|---|
agent |
Run one delegated agent. | The agent's submitted result. |
sequence |
Run steps in order. | The last step's result. |
parallel |
Run named branches concurrently. | An object of branch results, or a reducer result. |
map |
Run a body for each item in an array. | An array of results, or a reducer result. |
loop |
Run a body at least once, then test a condition. | The last result. |
while |
Carry a value through a body while a condition holds. | The final carried value. |
switch |
Select the first matching branch. | The selected branch's result. |
value |
Return interpolated JSON without starting an agent. | The interpolated value. |
workflow |
Invoke a saved workflow. | The saved workflow's result. |
Data flow
Name a sequence step with as, then reference its result later:
kind: sequence
steps:
- kind: agent
task: Find files that need review
as: discovery
json:
type: object
required: [files]
properties:
files:
type: array
items: { type: string }
- kind: map
over: "{discovery.files}"
body:
kind: agent
task: "Review {item}"
Available references depend on the node:
- Sequence steps can use named earlier results and
{previous}. - Map bodies receive
{item}and{index}. - Loop bodies receive
{iteration}and{last}. - While bodies receive
{iteration}and{current}. - Parallel reducers receive
{branches}. - Map reducers receive
{items}. - Saved workflows receive their declared
{params.*}values.
A string containing only one reference preserves the referenced JSON type.
References mixed with other text produce a string. Escape literal braces as
{{ and }}.
Pi validates references before starting the run. Add a json schema to an
agent when later nodes need fields from its result.
🧑💻 Create an agent profile
Profiles are optional. Use one when you want to reuse a persona or a common set of model, skill, and tool settings.
Create .pi/agents/planner.md:
---
name: planner
description: Maps a codebase and proposes implementation plans
thinking: medium
skills: []
tools: [read, grep, find]
---
Map the relevant code and return a concrete implementation plan with file
paths. Do not edit files.
Reference it from a workflow:
kind: agent
profile: planner
task: Plan the requested change
Pi-agents discovers agent profiles in:
- User:
~/.pi/agent/agents - Project:
<project>/.pi/agents
The nearest ancestor containing .pi is the project resource root. Project
profiles take precedence over user profiles with the same name.
Agent-node settings override profile settings, which override the active Pi session. Lists replace rather than merge:
- Omit
skillsto retain ambient skill discovery for an ad-hoc agent. - Set
skills: []to disable skill discovery. - Set
tools: []to give the agent no working tools. - Use
scope: user,scope: project, orscope: bothto control profile and skill discovery.
Named skills resolve from <project>/.pi/skills, .agents/skills up to the
Git root, ~/.pi/agent/skills, and ~/.agents/skills according to scope.
Unknown profile and skill names fail validation before the run starts.
🧩 Create a saved workflow
Save workflows as YAML or JSON in one of these directories:
- User:
~/.pi/agent/workflows - Project:
<project>/.pi/workflows
A flat workflow describes one agent. For example, .pi/workflows/review.yaml:
name: review
description: Review a target with structured findings
trigger: when the user asks for a read-only code review
display: report
params:
- { name: target, required: true }
- { name: focus, default: "Apply normal risk-based lens selection." }
task: |-
Review {params.target}.
Focus: {params.focus}
json:
type: object
required: [outcome, report]
properties:
outcome: { enum: [approved, changes_required, cannot_proceed] }
report: { type: string, minLength: 1 }
additionalProperties: false
thinking: high
tools: [read, bash]
A composed workflow uses flow:
name: inspect-and-fix
description: Inspect two areas, merge findings, then fix them
params:
- { name: target, required: true }
flow:
kind: sequence
steps:
- kind: parallel
as: reviews
branches:
behavior:
kind: agent
task: "Review {params.target} for correctness"
tests:
kind: agent
task: "Review {params.target} for missing tests"
reduce:
task: "Merge and prioritize:\n{branches}"
- kind: agent
task: "Fix these findings:\n{reviews}"
Each saved workflow registers a slash command. /review src/run passes
src/run to the first declared parameter. Slash commands accept one free-form
text argument; use workflow_create when you need several named parameters.
Human-facing results
A run can return structured data while presenting one Markdown string to the
user. The default is the report convention: when a structured result
contains a top-level report string, completion cards and
/workflow <id> result render it as Markdown. Without report, the UI shows
the complete structured result. Parent workflows always receive the complete
value. workflow_result returns the complete value by default and applies the
human-facing selection only with view: "presented"; use /workflow <id> raw
to inspect it in the UI.
Saved workflows may instead pin an explicit dot path with display, which
overrides the convention:
display: report
Request-time presentation settings are best effort. An invalid display or
label, or a display path that is missing from the completed value, produces
a run warning and falls back without failing execution. Saved workflow files
validate display strictly and report malformed definitions in the catalog.
Agent results
A delegated agent must submit one final result that matches its json schema.
Without json, the result must be a string. Assistant messages, thinking,
tool calls, and tool output are progress; the last visible assistant message
is not used as an implicit result.
An agent that cannot complete its task can submit an error with a reason. The node then fails, and the surrounding workflow applies its configured error policy.
🧮 Compose workflows
Sequence
kind: sequence
steps:
- { kind: agent, task: Map the code, as: map }
- { kind: agent, task: "Plan using {map}" }
- { kind: agent, task: "Implement {previous}" }
Parallel
kind: parallel
branches:
a: { kind: agent, task: Review module A }
b: { kind: agent, task: Review module B }
mode: all # all | any | { quorum: 1 }
onError: fail # fail | collect
concurrency: 4
reduce:
task: "Merge {branches}"
mode: any returns the first successful result and cancels the remaining
branches. onError: collect keeps failures as {error: "..."} values unless
every branch fails.
Map
kind: map
over: "{discovery.files}"
concurrency: 4
body:
kind: agent
task: "Review {item}"
reduce:
task: "Combine {items}"
Map results preserve input order.
Loop
kind: loop
max: 3
body:
kind: agent
task: "Iteration {iteration}; previous result: {last}"
json:
type: object
required: [done]
properties: { done: { type: boolean } }
until: { eq: [done, true] }
A loop runs at least once. It stops when until matches or when it reaches
max.
While
kind: while
on: "{initial_state}"
condition: { eq: [outcome, changes_required] }
max: 3
body:
kind: agent
task: "Round {iteration}; fix {current.actionable}"
A while node checks its condition before each iteration. It can run zero
times. The body's result becomes the next {current} value.
Switch
kind: switch
on: "{review}"
cases:
- when: { eq: [outcome, approved] }
then: { kind: value, value: approved }
- when: { exists: actionable }
then: { kind: agent, task: "Fix {review.actionable}" }
else:
kind: value
value: cannot-proceed
Switch cases run in order. The first matching case wins, and else is
required.
Predicates support eq, ne, gt, lt, exists, and empty, plus and,
or, and not.
Saved workflow
kind: workflow
name: review
params:
target: "{previous}"
Pi-agents expands saved workflows into the caller's run. Cycles fail validation.
🎛️ Budgets
Set optional limits on a run:
| Budget | Default | Meaning |
|---|---|---|
maxAgents |
50 |
Total agent and reducer executions. Set 0 for a data-only workflow. |
maxParallelism |
8 |
Agents that can run simultaneously. |
maxIterations |
10 |
Default cap for every loop and while node. |
maxDepth |
5 |
Maximum delegated process depth. |
maxTurns |
250 |
Assistant turns per delegated agent. |
maxAgentDuration |
Unbounded | Seconds per delegated agent. |
maxDuration |
Unbounded | Seconds for the complete run. |
maxTokens |
Unbounded | Input and output tokens, excluding cache traffic. |
maxCost |
Unbounded | Total cost in USD. |
Example:
{
"name": "review",
"params": { "target": "src" },
"budgets": {
"maxAgents": 8,
"maxDuration": 300,
"maxCost": 1.0
}
}
An agent or run that exceeds a limit fails and preserves the latest available output. If you are attached to an agent, enforcement waits until you detach; usage accounting continues while you are attached.
🧭 Run and inspect workflows
Commands
| Command | Action |
|---|---|
/agents |
Browse agent profiles. Add list for plain text. |
/agent <name> |
Show one profile. |
/workflows |
Browse workflows, runs, and delegated agents. |
/workflow <name> |
Show a saved workflow. |
/<name> [argument] |
Run a saved workflow. |
/workflow <id> |
Inspect a run. Unique ID prefixes work. |
/workflow <id> result |
Show the human-facing result. |
/workflow <id> raw |
Show the complete result as JSON. |
/workflow <id> copy |
Copy the human-facing result. |
/workflow <id> agents |
Show per-agent status and output. |
/workflow <id> watch |
Wait for a live run and show its final tree. |
/workflow <id> mermaid |
Show the run as a Mermaid diagram. |
/workflow <id> stop |
Stop a live run. |
/agent-session <run-id> [node] |
Open a settled agent's Pi session. |
Model-facing tools
Pi uses one tool for each run operation:
| Tool | Action |
|---|---|
workflow_create |
Start a saved workflow or an inline flow. |
workflow_list |
List runs. |
workflow_inspect |
Inspect live state, usage, and errors. |
workflow_result |
Retrieve a run or node result. |
workflow_stop |
Stop a live run after you request cancellation. |
These tools see runs from the current Pi session. Large lists and results use cursor-based pagination.
Interactive browser
/workflows opens a browser with three levels: workflows, runs, and agents.
Use these keys:
| Key | Action |
|---|---|
↑/↓ or j/k |
Move the selection. |
Enter |
Open the selected item or attach to an agent. |
Esc |
Go back or close the browser. |
r |
Run or rerun the selected workflow. |
c |
Compose a command, cancel a live run, or copy a completed result, depending on the current view. |
a |
Open a run's agents. |
o |
Post an agent's output to the parent conversation. |
h |
Show or hide a run in the live panel. |
n |
Draft a new workflow or agent profile. |
Shift+↑/Shift+↓ |
Scroll details or an attached transcript. |
The live run panel appears above the editor. Press ← from an empty editor,
or Ctrl+Q, to focus it. Select an agent and press Enter to attach.
Talk to a running agent
Attaching opens the agent's live transcript and a dedicated editor. Your messages join the existing delegated session; they do not start a new agent. If a tool is running, the message waits until the current tool-call batch finishes.
While attached:
- Press
Enterto send a message. - Press
Escto interrupt the current turn. - Press
←from an empty editor to return to the parent session. - Press
Shift+↑orShift+↓to scroll the transcript.
An interrupted built-in shell command is cancelled immediately. Other tools must support cancellation. The delegated session remains alive after an interrupt, so you can send another instruction.
Result submission is deferred while you are attached. When you leave, an idle agent finishes its assignment and submits its workflow result. Conversation messages are not substituted for that result unless you explicitly instruct the agent to use their content.
Attaching to a settled agent opens its saved Pi session. Switching sessions stops active workflows, so Pi asks for confirmation when necessary.
Optional footer counters
When
pi-fancy-footer is installed,
pi-agents can show ❖N for active workflows and ✦A/T for completed and total
agents. Enable the workflows and agents widgets through /fancy-footer.
Both are disabled by default.
⚙️ Configuration
Model guidance
The planning agent picks a model for every node, and by default it only sees a bare list of model IDs. So it plays it safe. Every branch of a ten-way fan-out runs on the session model, usually your most capable and most expensive one. A review that should spend a premium model on the final merge and cheap fast models on the mechanical branches spends premium everywhere.
Two things narrow this gap.
- Automatic price tiers. The planning prompt marks every model with
$,$$, or$$$, derived from list prices, and tells the planner to prefer$for mechanical subtasks and$$$for planning, review, and reduces. Tiers describe spend, not quality. For subscription providers they indicate relative quota use. This needs no configuration. - Your fit notes. Price alone cannot say what a model is for. If
flash-class models handle your triage well, or one model writes your best
reviews, teach the planner once in
~/.pi/agent/workflows.jsoninstead of repeating it in every request:
{
"models": {
"google/gemini-*-flash*": "fast triage, summaries, extraction",
"claude-opus-*": "planning, reduces, final review"
}
}
With these notes, "review this PR with parallel lenses" yields a plan whose fan-out branches run on flash-class models and whose merging reduce runs on Opus. You never name a model in the request.
Patterns match provider-qualified model IDs. A pattern without / matches
any provider, and * is the only wildcard. The match with the longest
literal prefix wins; a trusted project's .pi/workflows.json wins a tie with
the user configuration. Pi-agents ignores project model notes until you trust
the project, because notes flow into the planning prompt.
To check what the planner chose, read the workflow tree. Static trees attach
@model where a node pins a model directly. Live run rows and trees show the
planned or effective model for every agent. A node without @model in a
static tree does not imply the session default, since an agent profile may
pin a model.
Bundled workflows
A user or project workflow named review or review-fix overrides the bundled
workflow with the same name.
Disable all bundled workflows in ~/.pi/agent/workflows.json:
{
"bundledWorkflows": false
}
Control them individually:
{
"bundledWorkflows": {
"review": true,
"review-fix": false
}
}
A trusted project can use .pi/workflows.json. Project settings override user
settings. The bundled review-fix workflow depends on review; disabling
review also disables review-fix unless another workflow provides it.
Event-triggered workflows
A saved workflow can run after a Pi event:
name: after-turn
on: [turn_end]
debounce: 1000
task: "Inspect this event: {params.event}"
Event workflows always run in the background.
Project trust
Pi-agents follows Pi's project-trust decision. Until you trust a project, project-local profiles, workflows, and skills remain unavailable. User-level resources continue to work.
Run history
Run history belongs to the originating Pi session and survives reloads. After
a Pi restart, pi-agents marks unfinished runs as stopped because delegated
processes cannot resume. Completed history remains available through
/workflows.
🔌 Extension integration
Other Pi extensions can start runs and observe lifecycle events through the
typed pi-agents/api client:
import { createPiAgentsClient } from "pi-agents/api";
const agents = createPiAgentsClient(pi, { caller: "my-extension" });
const stopListening = agents.onRunEvent((event) => {
if (event.type === "run_completed") {
console.log(event.status);
}
});
const { runId } = await agents.start({
workflow: "review",
params: { target: "src" },
display: "report",
});
await agents.stop(runId);
stopListening();
The client supports start, stop, list, and onRunEvent. A successful
start response may include warnings for recoverable request problems. Runs
started by extensions obey the current session's budgets, resource scope, and
project trust settings.
🧰 Requirements
Pi-agents follows the latest Pi release. Keep Pi updated:
pi update pi
The pi executable must be available on PATH for delegated agents.
🩺 Troubleshooting
- Open
/workflowsto view invalid workflow diagnostics and failed runs. - Check profile, workflow, and skill names when validation fails before a run starts.
- Update Pi if a delegated process reports an initialization error.
- Use
/workflow <id> agentsto identify the delegated agent that failed. - Open a settled agent with
/agent-session <run-id> [node]when you need its complete conversation and tool history.
📄 License
Apache-2.0