@osolmaz/pi-workflows
Workflow engine, JSON control-flow tool, and live terminal viewer for the pi coding agent
Package details
Install @osolmaz/pi-workflows from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@osolmaz/pi-workflows- Package
@osolmaz/pi-workflows- Version
0.2.0- Published
- Jul 30, 2026
- Downloads
- 487/mo · 487/wk
- Author
- osolmaz
- License
- MIT
- Types
- extension
- Size
- 902.4 KB
- Dependencies
- 1 dependency · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/extension/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-workflows
pi-workflows is a workflow extension for the pi coding agent.
It lets you define multi-step agent workflows as TypeScript graphs, trigger
them at any point in a pi conversation with /workflow, and watch them run
live in a standalone terminal viewer.
The workflow model is a port of openclaw/acpx
flows into pi itself. Agent steps run inside your current pi conversation, so
the model keeps everything it already knows from the discussion. The model
completes each step by calling a JSON workflow tool, which gives the engine
structured, validated output to route on.
Install
pi install npm:@osolmaz/pi-workflows
You can also install directly from GitHub:
pi install git:github.com/osolmaz/pi-workflows
Or try the npm package without installing it:
pi -e npm:@osolmaz/pi-workflows
Install the interactive terminal viewer separately from crates.io. The crate
is named pi-workflows; its command is piw:
cargo install pi-workflows
piw
The npm package also includes the simpler pi-workflows snapshot viewer. To
link that command from a clone, run npm install && npm run build && npm link,
or run it in place with npx tsx src/viewer/cli.ts.
Quick start
Put a workflow file in .pi/workflows/ (project) or ~/.pi/agent/workflows/
(global):
// .pi/workflows/echo.workflow.ts
import { agent, defineWorkflow } from "@osolmaz/pi-workflows";
export default defineWorkflow({
name: "echo",
presentationPrompt: "Give the user the concise reply from the workflow result.",
startAt: "reply",
nodes: {
reply: agent({
prompt: ({ input }) => `Answer concisely: ${(input as { task?: string }).task}`,
expectedOutput: `{ "reply": "your concise answer" }`,
}),
},
edges: [],
});
Then, from any pi conversation:
/workflow echo summarize this repository
/workflow with no arguments lists discovered workflows. /workflow pause
lets the current step finish and then holds the run before the next node —
useful when you want to interject in the conversation mid-workflow —
and /workflow resume continues it. Pressing escape to interrupt a turn
pauses the workflow automatically, so the run never nudges the model while
you have taken the conversation back; /workflow resume re-delivers the
pending step prompt. /workflow cancel stops the active run; if the last run
already ended (for example parked at a checkpoint), it clears the leftover
widget instead. Trailing text becomes { task: "..." }; pass arbitrary input
with --input-json {"key": "value"}. The names cancel, list, pause,
and resume are reserved and rejected as workflow names.
While a run is on screen, the footer status bar shows a compact
wf <name> [status] <node> indicator alongside the widget.
presentationPrompt is optional. When present, pi-workflows uses it after the
structured run ends to request one normal, human-readable assistant response.
Workflows without it remain silent after their final structured output, which
keeps shell-only and machine-consumed workflows model-free.
Because the workflow runs in your current conversation, you can have a long
discussion first and then trigger a workflow that builds on it. The
elegant-solution example does exactly that. It asks the model for the most
elegant long-term production-ready solution to the problem you discussed, then
for the holy grail, then whether the two are the same (y/n). On y it routes
straight into implementation, and on n it asks the model to reconcile the
gap and pauses at a checkpoint for you to decide. In either case, its
presentationPrompt turns the final structured result into a plain assistant
response.
Watching a run
Runs persist to ~/.pi/agent/workflows/runs/ as they execute. The viewer
tails that directory and re-renders on every state change:
pi-workflows view # interactive picker, live updates
pi-workflows view <runId> # jump straight to one run
pi-workflows runs # plain list of recent runs
pi-workflows view --once # print a snapshot and exit (good for scripts)
The run detail view draws the workflow as a boxed graph, like the acpx replay
viewer. Every card has a centered step-name header and a divider above its
structured metadata. Border characters keep the graph background, the body
surface begins inside the border, and the header interior uses a separate
surface. Node type, status, attempts, and timing use compact symbol rows; start
and terminal markers sit outside the card. Node types have distinct
semantic colors, active cards use a heavy border, branches carry their case
labels, the taken path is highlighted, and loops route through a gutter on the
right back into their target from above. ←/→ scrubs
backwards and forwards through the recorded steps and re-derives every node's
status as of that step, with the selected step's full output shown below;
scrubbing to the end snaps back to following the run live.
The Rust piw viewer under tui/ adds a Catppuccin interface, selectable
themes, centered active-node following, draggable browser and inspector sizes,
detailed trace and conversation inspection, temporal replay, and reconnecting
remote viewing. Full cards have one fixed graph-wide size, so streaming,
selection, timer ticks, and replay never move nodes or edges. Live conversation
capture shows text, thinking, tool calls, and tool execution as they happen,
then reconciles settled messages to verbatim Pi entries. See
the piw guide.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ review ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ ● agent ◐ running ┃
┃ ↻ 2 ◷ 12s ┃
┃ ◇ clean ┃
┃ ◇ issues_found ┃
┃ … reviewing implementation ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Inside pi, a widget above the editor shows the same boxed graph while a
workflow is running, windowed around the active node when it is taller than
pi's widget budget. Scroll the window with shift+↑ / shift+↓; it snaps back
to following the active node whenever the workflow advances a step.
Node types
A workflow is a graph of named nodes with exactly one entry point. Each node finishes with a JSON output, and edges decide what runs next.
An agent node sends a prompt into the pi conversation and waits for the
model to submit its output through the workflow tool. A compute node runs
a pure TypeScript function. An action node performs a side effect, either a
TypeScript function (action({ run })) or a runtime-owned shell command
(shell({ exec, parse })). A checkpoint node ends the run in a waiting
state so a human can pick it up. On top of agent, the decision helper asks
the model to pick from a fixed set of choices and validates the answer, and
decisionEdge routes on the result with compile-time case checking.
See docs/workflows.md for the full authoring reference and docs/run-bundles.md for the on-disk run format.
Examples
The examples/workflows/ directory mirrors the acpx
example set. Copy any of them into .pi/workflows/ to use them:
echois the smallest possible workflow, one agent step.branchclassifies a task with adecisionand routes to either a continue lane or a clarification checkpoint.shellruns a runtime-owned shell command and parses its output, with no agent step at all.two-turnchains three agent steps that build on each other's outputs in the same conversation.elegant-solutionis the mid-conversation trigger described above.autoimplementruns an implement, verify, review loop where the review decision routesissues_foundback to a fix step until it comes backclean, bounded bymaxSteps.autoresearchruns an iterative feature-search loop in the style of karpathy/autoresearch: setup creates a frozen evaluation harness, one editable feature file, and a journal; each loop iteration runs one generation of experiments and journals every result; an assess decision keeps looping until a kept result plateaus or a diverse generation all fails, then conclusions are written before the winner is promoted out of the loop directory.