# pi-workflows

pi-workflows is a workflow extension for the [pi coding agent](https://pi.dev).
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](https://github.com/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

```bash
pi install npm:@osolmaz/pi-workflows
```

You can also install directly from GitHub:

```bash
pi install git:github.com/osolmaz/pi-workflows
```

Or try the npm package without installing it:

```bash
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`:

```bash
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):

```typescript
// .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:

```bash
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](docs/tui-viewer.md).

```
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  ┃            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](docs/workflows.md) for the full authoring reference
and [docs/run-bundles.md](docs/run-bundles.md) for the on-disk run format.

## Examples

The [examples/workflows/](examples/workflows/) directory mirrors the acpx
example set. Copy any of them into `.pi/workflows/` to use them:

- `echo` is the smallest possible workflow, one agent step.
- `branch` classifies a task with a `decision` and routes to either a
  continue lane or a clarification checkpoint.
- `shell` runs a runtime-owned shell command and parses its output, with no
  agent step at all.
- `two-turn` chains three agent steps that build on each other's outputs in
  the same conversation.
- `elegant-solution` is the mid-conversation trigger described above.
- `autoimplement` runs an implement, verify, review loop where the review
  decision routes `issues_found` back to a fix step until it comes back
  `clean`, bounded by `maxSteps`.
- `autoresearch` runs an iterative feature-search loop in the style of
  [karpathy/autoresearch](https://github.com/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.

## License

[MIT](LICENSE)
