Summary
Add an experimental workflow feature to pi-web: supervised local scripts that can coordinate normal pi-web sessions through a small SDK/API.
The goal is not to build a full workflow engine, DAG runner, or extension framework yet. The goal is to validate a minimal primitive:
Workflows are ordinary local TypeScript/JavaScript scripts that can spawn, message, wait on, and summarize pi-web sessions, while pi-web supervises the run lifecycle.
Motivation
pi-web is already session-oriented and minimal. For larger tasks, it would be useful to let a script coordinate multiple independent sessions, for example:
- start a security review session
- start a test-gap review session
- wait for both to finish
- start a synthesis session with their findings
This should preserve pi-web's ethos: small, local-first, inspectable, and user-controlled.
Product direction
For the first version, ignore extensions/server-extension architecture.
Build workflows as a small built-in experimental feature, but keep the internal boundary clean enough that it could be extracted into an extension later if pi-web grows a proper server-extension host.
Do not build:
- a generic workflow engine
- DAGs/phases/retry semantics
- a visual workflow builder
- a new extension host
- parent/child session hierarchy as a core abstraction
Do build:
- supervised script runs
- session spawn/send/wait primitives
- durable run state
- append-only audit events
- stdout/stderr logs
- human and agent cancellation
- a small UI to inspect running/completed workflows
Core invariant: always cancellable
Every workflow must be cancellable by both:
- the human, from the pi-web UI
- an agent/session, through an explicit workflow API
Cancellation should not rely only on workflow script cooperation. pi-web should supervise the process and enforce cancellation.
Suggested cancellation sequence:
- mark run as
cancellation_requested
- append an audit event with actor/reason
- broadcast a runtime/state update
- signal the workflow process gracefully
- after a grace period, hard-kill if still running
- mark run as
cancelled
- preserve logs, events, and any sessions created by the run
Cancelling a workflow should abort active prompts in sessions created by that workflow, but should not delete those sessions. They should remain available for audit/review.
Core invariant: always auditable and viewable
All workflow runs should have durable state and append-only audit logs.
Suggested storage layout:
.pi/web/workflows/runs/<run-id>/run.json
.pi/web/workflows/runs/<run-id>/events.jsonl
.pi/web/workflows/runs/<run-id>/stdout.log
.pi/web/workflows/runs/<run-id>/stderr.log
Example WorkflowRun shape:
type WorkflowRun = {
id: string;
name: string;
scriptPath: string;
cwd: string;
status:
| "starting"
| "running"
| "cancellation_requested"
| "cancelled"
| "succeeded"
| "failed";
startedAt: string;
updatedAt: string;
endedAt?: string;
pid?: number;
exitCode?: number;
signal?: string;
createdBy: {
actor: "human" | "agent";
sessionId?: string;
};
cancelledBy?: {
actor: "human" | "agent";
sessionId?: string;
reason?: string;
timestamp: string;
};
sessionIds: string[];
currentStep?: string;
progress?: {
completed?: number;
total?: number;
label?: string;
};
logPath: string;
eventLogPath: string;
};
Example audit events:
{"type":"workflow_started","runId":"...","actor":"human","timestamp":"..."}
{"type":"step_started","step":"spawn security reviewer","timestamp":"..."}
{"type":"session_spawned","sessionId":"...","name":"security review","timestamp":"..."}
{"type":"session_prompt_sent","sessionId":"...","promptPreview":"Review auth/session risks...","timestamp":"..."}
{"type":"cancellation_requested","actor":"agent","reason":"Branch is stale","timestamp":"..."}
{"type":"process_killed","signal":"SIGTERM","timestamp":"..."}
{"type":"workflow_cancelled","timestamp":"..."}
Minimal server API
Initial endpoints could be:
GET /api/workflows
GET /api/workflows/:runId
GET /api/workflows/:runId/events
GET /api/workflows/:runId/logs
POST /api/workflows/run
POST /api/workflows/:runId/cancel
Minimal workflow SDK
A workflow script should be able to coordinate normal sessions:
const security = await pi.sessions.spawn({
name: "security review",
message: "Review the current branch for security issues only.",
});
const tests = await pi.sessions.spawn({
name: "test review",
message: "Review the current branch for missing or weak tests.",
});
await Promise.all([
pi.sessions.waitForIdle(security.id, { signal: pi.workflow.signal }),
pi.sessions.waitForIdle(tests.id, { signal: pi.workflow.signal }),
]);
pi.workflow.throwIfCancelled();
await pi.sessions.spawn({
name: "final synthesis",
message: "Combine the security and test findings into a concise review.",
});
Suggested SDK surface:
pi.sessions.list();
pi.sessions.spawn({ name, cwd, message });
pi.sessions.send({ sessionId, message, mode });
pi.sessions.waitForIdle(sessionId, { signal });
pi.sessions.abort(sessionId);
pi.workflow.currentRun();
pi.workflow.setStep(label);
pi.workflow.setProgress(progress);
pi.workflow.throwIfCancelled();
pi.workflow.signal;
pi.workflows.list();
pi.workflows.get(runId);
pi.workflows.cancel(runId, { reason });
Minimal UI
Add a small workflow runs panel/drawer:
- list running and recent workflow runs
- show status: starting/running/cancellation requested/cancelled/succeeded/failed
- show current step/progress if provided
- show sessions created by the run
- open stdout/stderr logs
- open event audit log
- cancel button always visible for active runs
UX principle
Running a generated workflow script should require explicit approval. A workflow script is code and can spend tokens, spawn sessions, and potentially drive tools.
Suggested approval copy:
Pi created workflow script:
.pi/web/workflows/<name>.ts
It will:
- start N sessions
- use cwd <path>
- wait for completion
- create a synthesis session
[Run once] [Open script] [Cancel]
Future considerations
- This could become a bundled pi-web extension later, but only after pi-web has multiple features that need a server-extension host.
- Do not introduce server-extension architecture as part of the MVP.
- Keep the workflow service behind a small internal interface so extraction remains possible later.
Example internal boundary:
type WorkflowService = {
run(input: WorkflowRunInput): Promise<WorkflowRun>;
cancel(runId: string, reason?: string): Promise<void>;
get(runId: string): Promise<WorkflowRun>;
list(): Promise<WorkflowRun[]>;
events(runId: string): Promise<WorkflowEvent[]>;
};
Acceptance criteria
Summary
Add an experimental workflow feature to pi-web: supervised local scripts that can coordinate normal pi-web sessions through a small SDK/API.
The goal is not to build a full workflow engine, DAG runner, or extension framework yet. The goal is to validate a minimal primitive:
Motivation
pi-web is already session-oriented and minimal. For larger tasks, it would be useful to let a script coordinate multiple independent sessions, for example:
This should preserve pi-web's ethos: small, local-first, inspectable, and user-controlled.
Product direction
For the first version, ignore extensions/server-extension architecture.
Build workflows as a small built-in experimental feature, but keep the internal boundary clean enough that it could be extracted into an extension later if pi-web grows a proper server-extension host.
Do not build:
Do build:
Core invariant: always cancellable
Every workflow must be cancellable by both:
Cancellation should not rely only on workflow script cooperation. pi-web should supervise the process and enforce cancellation.
Suggested cancellation sequence:
cancellation_requestedcancelledCancelling a workflow should abort active prompts in sessions created by that workflow, but should not delete those sessions. They should remain available for audit/review.
Core invariant: always auditable and viewable
All workflow runs should have durable state and append-only audit logs.
Suggested storage layout:
Example
WorkflowRunshape:Example audit events:
{"type":"workflow_started","runId":"...","actor":"human","timestamp":"..."} {"type":"step_started","step":"spawn security reviewer","timestamp":"..."} {"type":"session_spawned","sessionId":"...","name":"security review","timestamp":"..."} {"type":"session_prompt_sent","sessionId":"...","promptPreview":"Review auth/session risks...","timestamp":"..."} {"type":"cancellation_requested","actor":"agent","reason":"Branch is stale","timestamp":"..."} {"type":"process_killed","signal":"SIGTERM","timestamp":"..."} {"type":"workflow_cancelled","timestamp":"..."}Minimal server API
Initial endpoints could be:
Minimal workflow SDK
A workflow script should be able to coordinate normal sessions:
Suggested SDK surface:
Minimal UI
Add a small workflow runs panel/drawer:
UX principle
Running a generated workflow script should require explicit approval. A workflow script is code and can spend tokens, spawn sessions, and potentially drive tools.
Suggested approval copy:
Future considerations
Example internal boundary:
Acceptance criteria