@davidorex/pi-workflows
Workflow orchestration extension for Pi
Package details
Install @davidorex/pi-workflows from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@davidorex/pi-workflows- Package
@davidorex/pi-workflows- Version
0.30.0- Published
- Jun 4, 2026
- Downloads
- 533/mo · 102/wk
- Author
- davidorex
- License
- MIT
- Types
- extension, skill
- Size
- 819 KB
- Dependencies
- 7 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./dist/index.js"
],
"skills": [
"./skills"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-workflows
Schema-driven workflow orchestration for Pi.
Data flows through workflows as typed JSON, not strings. Each agent step declares an output.schema — the agent's output is validated against a JSON Schema before it's accepted into the pipeline. The expression engine passes typed fields between steps (${{ steps.investigate.output.findings }}), not raw text. Templates compose typed data into agent prompts, so agents receive structured context. The entire pipeline is schema-governed: schema defines shape → agent produces to shape → validator enforces shape → next step consumes typed fields.
The schemas in schemas/ (investigation-findings, decomposition-specs, execution-results, etc.) are the typed contracts between workflow steps. They're not metadata — they're the enforcement boundary.
Install
pi install npm:@davidorex/pi-context # dependency
pi install npm:@davidorex/pi-workflows
Or install both at once: pi install npm:@davidorex/pi-project-workflows
Getting Started
/workflow init
Creates .workflows/ for run state. Workflow YAML specs are discovered automatically from the package's bundled workflows — no setup needed to start running them.
What It Does
pi-workflows replaces ad-hoc agent chaining with composable, typed workflow orchestration. Workflows are YAML specs. Steps run as subprocesses (pi --mode json) with their own context windows. The main conversation is the control plane; workflows are subordinate.
Workflows consume project blocks as typed input via readBlock() — structured data, not raw files. When workflow agents write back to project blocks, pi-context's schema validation enforces the shape at write time. Block-write steps stamp a workflow-kind DispatchContext (created_by: "workflow/<step_id>") so workflow-written items carry attestation; the post-step artifact write threads the same context (workflow/<name>:<runId>:artifact:<artifact>). The two extensions form a typed loop: project state → workflow input → agent output → validated project state.
Tools registered:
workflow-execute— execute a named workflow with typed input (auto-resumes compatible incomplete runs unlessfresh: "true")workflow-resume— explicitly resume an incomplete workflow run by name + runId; rejects on no-match or runId mismatchworkflow-list,workflow-agents,workflow-validate,workflow-status,workflow-init— discovery / inspection / scaffolding surfacesrender-item-by-id,enforce-budget— per-item rendering + budget enforcement helpers
Commands registered:
/workflow init— scaffold.workflows/directory for run state/workflow list— discover and select a workflow to run/workflow run <name> [--input '<json>']— execute a workflow/workflow resume <name>— resume an incomplete run from checkpoint/workflow validate [name]— validate workflow specs (agents, schemas, step references, filters)
Keybindings:
Ctrl+H— pause running workflow after current stepCtrl+J— resume a paused/incomplete workflow
Workflow Spec Format
Workflows are .workflow.yaml files discovered from .workflows/ (project), ~/.pi/agent/workflows/ (user), or the package's workflows/ directory (builtin).
name: my-workflow
description: What this workflow does
input:
type: object
properties:
target: { type: string, description: "What to analyze" }
required: [target]
steps:
investigate:
agent: investigator
input: |
Investigate: ${{ input.target }}
output:
schema: investigation-findings
synthesize:
agent: synthesizer
input: |
Findings: ${{ steps.investigate.output | json }}
completion:
message: |
Analysis complete. Key findings: ${{ steps.synthesize.output.summary }}
Step Types
| Type | Purpose |
|---|---|
agent |
Dispatch to a Pi agent subprocess |
command |
Run a shell command |
transform |
Map/reshape data between steps |
gate |
Conditional branching (check expression) |
parallel |
Run nested steps concurrently |
foreach |
Iterate over an array |
loop |
Repeat steps with a condition |
pause |
Halt execution for human review |
Expressions
${{ }} expressions access step outputs, inputs, and apply filters:
${{ input.target }} # workflow input
${{ steps.investigate.output }} # step output
${{ steps.investigate.output | json }} # pipe through filter
${{ steps.gather.output | length }} # array length
Available filters: length, keys, filter, json, upper, lower, trim, default, first, last, join, split, replace, includes, map, sum, min, max, sort, unique, flatten, zip, group_by, count_by, chunk, pick, omit, entries, from_entries, merge, values, not, and, or.
Source Files
| File | Purpose |
|---|---|
src/index.ts |
Extension entry point — tool, command, keybinding registration |
src/workflow-executor.ts |
Main orchestration loop |
src/workflow-spec.ts |
YAML parsing, STEP_TYPES registry |
src/workflow-sdk.ts |
SDK: vocabulary, discovery, introspection |
src/workflow-discovery.ts |
Three-tier workflow discovery (project > user > builtin) |
src/expression.ts |
${{ }} evaluator, FILTER_NAMES registry |
src/template.ts |
Nunjucks template environment |
src/dispatch.ts |
Agent subprocess spawn (pi --mode json) |
src/dag.ts |
Dependency graph, execution plan from ${{ steps.X }} refs |
src/agent-spec.ts |
.agent.yaml parser |
src/state.ts |
Atomic run state persistence |
src/checkpoint.ts |
Checkpoint detection, resume validation |
src/output.ts |
Step output persistence |
src/completion.ts |
Post-workflow message resolution |
src/tui.ts |
Terminal progress widget |
src/types.ts |
Shared type definitions |
src/format.ts |
Output formatting utilities |
src/step-shared.ts |
Shared step execution utilities |
src/workflows-dir.ts |
WORKFLOWS_DIR constant (.workflows) |
src/step-*.ts |
Step type executors (one per type) |
Bundled Resources
| Directory | Contents |
|---|---|
agents/ |
agent specs (.agent.yaml): investigator, decomposer, verifier, synthesizer, … — ls agents/ or availableAgents(cwd) for the current set |
schemas/ |
output schemas (.schema.json): investigation-findings, execution-results, … — ls schemas/ for the current set |
workflows/ |
workflow specs (.workflow.yaml): do-gap, create-phase, parallel-analysis, … — ls workflows/ or availableWorkflows(cwd) for the current set |
The Nunjucks prompt templates no longer ship from this package. They were relocated into @davidorex/pi-jit-agents; consumers resolve the bundled template root via its bundledTemplateDir() export, and project (.pi/templates/) / user overrides still take precedence in the three-tier search.
SDK (src/workflow-sdk.ts)
Single queryable surface for the extension's capabilities:
// Vocabulary (derived from code registries)
stepTypes(): StepTypeDescriptor[]
filterNames(): string[]
expressionRoots(): readonly string[]
// Discovery (derived from filesystem, three-tier search)
availableAgents(cwd): AgentSpec[]
availableWorkflows(cwd): WorkflowSpec[]
availableTemplates(cwd): string[]
availableSchemas(cwd): string[]
// Introspection (derived from parsed spec)
extractExpressions(spec): ExpressionRef[]
declaredSteps(spec): string[]
declaredAgentRefs(spec): string[]
declaredSchemaRefs(spec): string[]
Architecture
- Each workflow step runs as a subprocess (
pi --mode json) with its own context window - DAG planner infers parallelism from
${{ steps.X }}references — no manual dependency declaration - Agent specs are
.agent.yamlonly. Compiled to prompts via Nunjucks at dispatch time. - State persisted atomically after each step (tmp + rename). State write failure is fatal.
- Three-tier resource search: project (
.workflows/,.pi/agents/,.pi/templates/) > user~/.pi/agent/> package builtin completionfield controls what message is sent back to the main conversation after a workflow finishes
For LLMs
When working with this extension:
- Read
src/workflow-sdk.tsfor the full vocabulary, discovery, and introspection API - Read
src/workflow-spec.tsfor theSTEP_TYPESregistry and YAML parsing rules - Read
src/expression.tsforFILTER_NAMESand expression evaluation rules - Read
src/types.tsforWorkflowSpec,StepSpec,AgentSpec, andExecutionStatetype definitions - Read
src/dag.tsto understand how execution order is inferred from expressions - Read agent
.agent.yamlfiles inagents/to understand available agent capabilities - Read workflow
.workflow.yamlfiles inworkflows/for examples of workflow structure - Use the
workflow-executetool to execute workflows — it handles discovery, input validation, checkpoint detection (auto-resume), and result formatting. Useworkflow-resumefor explicit-only resume by runId (rejects on no-match). - The
/workflow listcommand provides an interactive picker;/workflow run <name>runs directly
Tests
npm test
Runs tsx --test src/*.test.ts. 500+ tests covering step types, expressions, DAG planning, state persistence, checkpoint/resume, and template compilation.
Development
Part of the pi-project-workflows monorepo. All four packages (pi-context, pi-jit-agents, pi-workflows, pi-behavior-monitors) are versioned in lockstep (current version in each package.json).
npm run build compiles TypeScript to dist/ via tsc. The package ships dist/, not src/ — the pi.extensions entry point is ./dist/index.js.