# Pi Dynamic Workflows

> Source: <https://github.com/Michaelliv/pi-dynamic-workflows>
> Published: 2026-06-03 03:43:53+00:00

Claude-Code-style dynamic workflows for

[Pi].

A Pi extension that adds a `workflow`

tool. Instead of one assistant doing everything sequentially, the model writes a small JavaScript script that fans out the work across many isolated subagents, then synthesizes the results.

Great for codebase audits, multi-perspective review, large refactors, and fan-out research.

Inspired by Anthropic's [dynamic workflows in Claude Code](https://claude.com/blog/introducing-dynamic-workflows-in-claude-code).

```
pi install npm:pi-dynamic-workflows
# or from a local checkout
pi install /path/to/pi-dynamic-workflows
```

Then in Pi:

```
/reload
```

That's it. The extension registers a `workflow`

tool and activates it on session start.

Just ask Pi for a workflow in plain language:

```
Run a workflow to inspect this repository and summarize the main modules.
```

The model will write a workflow script and call the `workflow`

tool. Live progress shows up inline:

```
◆ Workflow: inspect_project (3/3 done)
  ✓ Scan 1/1
    #1 ✓ repo inventory
  ✓ Analyze 2/2
    #2 ✓ source modules
    #3 ✓ final summary
```

Press `Esc`

to cancel a running workflow. Active subagents are aborted and surfaced as skipped.

A workflow is plain JavaScript. The first statement must export literal metadata. `name`

and `description`

are required; `phases`

is optional documentation for an expected outline. The live progress view is driven by `phase(...)`

calls at runtime:

``` js
export const meta = {
  name: 'inspect_project',
  description: 'Inspect a repository and summarize the main modules',
  phases: [
    { title: 'Scan' },
    { title: 'Analyze' },
  ],
}

phase('Scan')
const inventory = await agent('Inspect the repository structure.', {
  label: 'repo inventory',
})

phase('Analyze')
const summary = await agent(
  'Summarize the main modules from this inventory:\n' + inventory,
  { label: 'module summary' },
)

return { inventory, summary }
```

Phases are discovered as the script runs, so conditional and loop-created phases work naturally. If a branch is skipped, its phase does not show up as an empty progress row.

Reusable workflow files can opt into editor hints for workflow globals:

```
/// <reference types="pi-dynamic-workflows/workflow" />
```

This declares `agent`

, `parallel`

, `pipeline`

, `phase`

, `log`

, `args`

, `cwd`

, and `budget`

for TypeScript-aware editors.

| Global | Description |
|---|---|
`agent(prompt, opts)` |
Spawn an isolated subagent. Returns its final text or, with `opts.schema` , a validated object. |
`parallel(thunks)` |
Run an array of `() => agent(...)` thunks concurrently. Results are returned in input order. |
`pipeline(items, ...stages)` |
Run each item through sequential stages while items fan out. Each stage receives `(prev, original, index)` . |
`phase(title)` |
Mark the current phase. Used for grouping in the live progress view. |
`log(message)` |
Append a workflow-level log line. |
`args` |
Optional JSON value passed in via the tool's `args` parameter. |
`cwd` , `process.cwd()` |
Current working directory for subagents. |
`budget` |
`{ total, spent(), remaining() }` token budget tracker. |

Workflow scripts are evaluated inside a Node `vm`

sandbox. The following are intentionally unavailable:

`Date.now()`

,`new Date()`

`Math.random()`

`require`

,`import`

,`fs`

, network APIs- spreads, computed keys, template interpolation, function calls inside
`meta`

This keeps `meta`

parseable, runs reproducible, and the surface area small.

Pass a JSON Schema via `opts.schema`

and the subagent will return a validated object:

``` js
const finding = await agent('Find security-sensitive files.', {
  label: 'security scan',
  schema: {
    type: 'object',
    properties: {
      paths: { type: 'array', items: { type: 'string' } },
      reason: { type: 'string' },
    },
    required: ['paths', 'reason'],
  },
})
```

Under the hood this is a Pi `structured_output`

tool with `terminate: true`

, so the subagent ends on that call without an extra assistant turn.

```
user prompt
  → Pi model writes a workflow script
  → workflow tool parses + runs script in a vm sandbox
  → script calls agent(), parallel(), pipeline()
  → each agent() spawns an in-memory Pi subagent session
  → snapshots stream back as compact progress
  → final structured result returned to the parent assistant
```

Subagents run in fresh in-memory Pi sessions with the standard coding tools, so they can read files, run shell commands, and call structured output exactly like a normal Pi turn.

| File | Purpose |
|---|---|
`src/workflow.ts` |
AST-validated parser and sandboxed workflow runtime. |
`src/workflow-tool.ts` |
The Pi `workflow` tool, prompt guidelines, rendering, abort handling. |
`src/agent.ts` |
`WorkflowAgent` , an in-memory Pi subagent runner. |
`src/structured-output.ts` |
Terminating structured-output tool backed by TypeBox/JSON Schema. |
`src/display.ts` |
Workflow snapshots and compact text renderers. |
`extensions/workflow.ts` |
The Pi extension entrypoint. |

```
npm install
npm test     # biome check + tsc + unit tests
npm run dev
```

Parser unit tests live in `tests/workflow-parser.test.ts`

and cover both accepted and rejected script shapes.

This is a prototype. It implements the core workflow primitive (script, subagents, parallel/pipeline, phases, abort, structured output) but does not yet implement persisted or resumable runs, or a `/workflows`

manager.

MIT
