Warning: this is a 100% vibe coded experiment, not recommended for serious usage. The README might be misleading and mention incomplete or unimplemented features
An AI agent orchestration tool for executing multi-step workflows through the Pi CLI coding agent.
pi-peline (Pi + Pipeline) is a tool for defining and executing multi-step AI agent workflows. Inspired by CI/CD tools like GitHub Actions, but designed specifically for orchestrating the Pi CLI coding agent rather than deploying software.
You define a pipeline structure where each step executes a prompt through the Pi CLI agent. Steps can depend on each other, branch based on outputs, or loop back for revision. It's a way to experiment with telling Pi to execute different prompts over a codebase or any task.
Note: pi-peline currently works with the Pi CLI coding agent. In the future, it will support other AI agents like Claude Code.
- YAML-based pipeline definitions - Declarative configuration
- Step dependencies - Define which steps depend on others
- Termination promises - The agent signals completion by printing a specific string
- Continuation promises - The agent can request more work or route to different steps
- Review loops - Implementation steps can route back for revision based on feedback
- Execution history - All runs are persisted to SQLite
- Local execution - Runs locally
- Feature development workflow - Plan β Implement β Review β Deploy
- Code refactoring - Analyze β Plan β Refactor β Verify
- Documentation generation - Analyze code β Generate docs β Review
- Testing workflows - Generate tests β Execute β Report
- Multi-step code analysis - Break complex tasks into coordinated agent steps
cargo install --path .Create a simple pipeline in pipeline.yaml:
name: "Feature Development Pipeline"
version: "1.0"
variables:
feature_name: "user authentication"
# File variable - validates README.md exists
readme:
path: "README.md"
validate_exists: true
steps:
- id: "planning"
name: "Create Implementation Plan"
prompt: |
Create a detailed implementation plan for {{ feature_name }}.
Reference this README:
{{ readme }}
termination:
success_pattern: "β
PLAN COMPLETE"
on_success: "implementation"
- id: "implementation"
name: "Implement Feature"
depends_on: ["planning"]
prompt: |
Implement the feature based on this plan:
{{ steps.planning.output }}
termination:
success_pattern: "β
IMPLEMENTATION_DONE"
on_success: "review"
continuation:
pattern: "π CONTINUE"
action: "retry"
- id: "review"
name: "Review Implementation"
depends_on: ["implementation"]
prompt: |
Review this implementation:
{{ steps.implementation.output }}
If issues found, specify what's missing.
termination:
success_pattern: "β
APPROVED"
on_success: "deploy"
on_failure: "implementation"
continuation:
pattern: "π NEEDS_REVISION"
action: "route"
target: "implementation"
carry_notes: true
- id: "deploy"
name: "Prepare Deployment"
depends_on: ["review"]
prompt: "Prepare deployment checklist for approved implementation"
termination:
success_pattern: "β
DEPLOYED"Run the pipeline:
pi-peline run --file pipeline.yamlpi-peline run --file pipeline.yaml
# With variable overrides
pi-peline run --file pipeline.yaml --variable feature_name="new feature"
# With streaming output
pi-peline run --file pipeline.yaml --stream
# Skip history
pi-peline run --file pipeline.yaml --no-historypi-peline validate --file pipeline.yamlpi-peline list
# With execution counts
pi-peline list --with-counts
# JSON output
pi-peline list --jsonpi-peline history
# For a specific pipeline
pi-peline history --pipeline "Feature Development Pipeline"
# With details
pi-peline history --verbose
# JSON output
pi-peline history --json| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Pipeline name |
version |
string | No | Pipeline version |
variables |
map | No | Global variables available to all steps |
max_retries |
number | No | Default max retries per step |
default_timeout_secs |
number | No | Default timeout per step |
steps |
array | Yes | Array of step definitions |
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique step identifier |
name |
string | Yes | Human-readable step name |
description |
string | No | Step description |
prompt |
string | Yes | The prompt template for the agent |
depends_on |
array | No | List of step IDs this step depends on |
termination |
object | No | Termination condition |
continuation |
object | No | Continuation condition |
max_retries |
number | No | Override default max retries |
timeout_secs |
number | No | Override default timeout |
allow_parallel |
boolean | No | Allow parallel execution (default: false) |
| Field | Type | Required | Description |
|---|---|---|---|
success_pattern |
string | Yes | String that signals successful completion |
on_success |
string | No | Step ID to execute on success (null = end) |
on_failure |
string | No | Step ID to execute on failure |
use_regex |
boolean | No | Use regex pattern matching (default: false) |
| Field | Type | Required | Description |
|---|---|---|---|
pattern |
string | Yes | String that signals continuation needed |
action |
enum | Yes | "retry" or "route" |
target |
string | No* | Target step when action is "route" |
carry_notes |
boolean | No | Pass notes when routing |
use_regex |
boolean | No | Use regex pattern matching (default: false) |
- Required when action is "route"
Variables can be defined in two formats:
Simple string variable:
variables:
feature_name: "user authentication"File variable with validation:
variables:
readme:
path: "README.md"
validate_exists: true # Optional, defaults to falseWhen a file variable is used in a prompt, it is expanded as @path so the Pi CLI agent can read the file directly:
steps:
- id: "analyze"
prompt: |
Analyze this README:
{{ readme }}
# Expands to: "Analyze this README: @README.md"File variable fields:
| Field | Type | Required | Description |
|---|---|---|---|
path |
string | Yes | Path to the file |
validate_exists |
boolean | No | If true, validation fails if file doesn't exist (default: false) |
Use validate_exists: true for input files that must exist, and validate_exists: false for output files or optional files.
- Pipeline Loading: The YAML file is parsed and validated
- Graph Construction: Steps are organized into a DAG based on dependencies
- Execution: The engine executes steps in dependency order:
- Waits for dependencies to complete
- Injects termination/continuation instructions into the prompt
- Executes the Pi CLI agent
- Watches for termination pattern
- Routes to next step based on success/failure/continuation
The agent sees an enhanced prompt that includes instructions:
[YOUR PROMPT]
--- IMPORTANT: When you complete this task successfully, print exactly: β
DONE
If you need more work on this task, print exactly: π CONTINUE
A common pattern is a review loop where implementation and review steps iterate:
- Implementation step creates something
- Review step evaluates it
- If approved β Continue to next step
- If rejected β Back to Implementation with notes
steps:
- id: "implement"
prompt: "Create X"
termination:
success_pattern: "β
DONE"
on_success: "review"
- id: "review"
prompt: "Review the implementation"
termination:
success_pattern: "β
APPROVED"
on_success: "deploy"
on_failure: "implement"
continuation:
pattern: "π NEEDS_REVISION"
action: "route"
target: "implement"
carry_notes: trueVariables are injected using {{ variable_name }} syntax:
variables:
feature_name: "authentication"
project_dir: "./src"
steps:
- id: "analyze"
prompt: |
Analyze {{ feature_name }} in {{ project_dir }}Previous step outputs are also available:
steps:
- id: "plan"
prompt: "Create a plan"
- id: "implement"
depends_on: ["plan"]
prompt: |
Implement based on:
{{ steps.plan.output }}cargo buildcargo testcargo run -- run --file examples/pipeline.yamlβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLI β
β (pi-peline run, validate, list, history) β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Execution Engine β
β - Scheduler (sequential/parallel) β
β - Step Executor β
β - Event Handlers β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Pi Agent Client (Subprocess) β
β - Spawns `pi --mode text --print` β
β - Captures stdout as response β
β - Handles timeouts and errors β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Pi CLI (subprocess) β
β - Executes prompts β
β - Uses tools (read, write, edit, bash) β
β - Returns formatted response β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Pi CLI agent integration
- Context file support (read files from disk)
- Human-in-the-loop checkpoints
- Shell script quality gates
- Web UI
pi-peline uses the pi CLI agent to execute prompts. By default, it assumes pi is on your PATH. To use a custom path:
Set the PI_BINARY_PATH environment variable, or the endpoint field will be used for this in a future release.
# Use pi from a specific location
export PATH="/custom/path:$PATH"
# Or run with full path
ln -s /path/to/pi /usr/local/bin/pipiCLI must be installed (see pi-coding-agent)pimust be accessible on PATH or viaPI_BINARY_PATH
MIT