feat: package Pi extensions as Bun workspaces

This commit is contained in:
jb
2026-09-01 17:24:46 -04:00
parent 90f8090f61
commit 118b5bee06
214 changed files with 19566 additions and 5876 deletions
+109
View File
@@ -0,0 +1,109 @@
# workflow
`workflow` plans and implements feature work through persisted human Gates, isolated Git worktrees, focused verification, and independent review.
## Start a feature
Start with:
```text
/workflow start <message>
```
The command sends the message through the assistant, which chooses the descriptive feature name and idempotency key before invoking `workflow` through the normal tool path. In interactive TUI mode, `/workflow start` without a message asks what you want to start working on. Non-interactive modes require the message in the command.
You can also ask the assistant to use `workflow` with:
- `action: "start"`
- `workflow: { mode: "feature" }` (or omit `workflow`)
- A descriptive lowercase kebab-case `featureName`
- The feature request
- A unique idempotency key
The extension creates `feature/<feature-name>` in an exclusive worktree pinned to the source checkout's current `HEAD`. Ordinary staged, unstaged, or untracked source changes are not copied into that worktree. In TUI mode the extension shows bounded path/status evidence and requires explicit confirmation before omitting those changes. Tool, RPC, print, and JSON callers must pass `allowDirtySource: true`. Unmerged paths remain blocked. Existing branch names are rejected rather than silently renamed.
The managed flow is:
1. Discover repository facts and ask unresolved Questions.
2. Design the implementation and explicitly approve the plan and UI-impact classification.
3. For non-trivial UI, review three browser-validated candidates and accept one revision or request refinement.
4. Choose a fresh plan-seeded session, compacted current session, or unchanged current context.
5. Implement with guarded file ownership.
6. Remove prototype-only behavior.
7. Run plan-approved verification commands and focused tests. Approved host commands retain a three-minute timeout, internal Git commands have a 30-second timeout, and process-tree cleanup is bounded.
8. Complete independent specification and standards review.
The assistant must inspect the current run before each state-changing call and obtain the user's explicit Gate Decision. It must not infer approval.
## Agent selection
`workflow` reuses explicitly mapped standard definitions from `pi-interactive-subagents` before falling back to its bundled workflow profiles. By default, `scout` owns Discovery and `worker` owns Implementation; bundled profiles continue to supply Design, Prototype, Verify, and independent Review. Definitions resolve with package, global, then trusted-project precedence and are pinned into the run with their workflow role overlay.
Configure or disable mappings in `~/.pi/agent/workflow.json` or trusted `.pi/workflow.json`:
```json
{
"standardAgents": {
"enabled": true,
"roles": {
"scout": ["discover"],
"worker": ["implement"]
}
}
}
```
A mapping replaces the complete inherited role map at that configuration layer. Agent names must be lowercase kebab case and roles must be workflow roles. Unmapped standard definitions are ignored. Standard definitions provide identity, instructions, model, thinking level, and requested tools, but do not widen permissions: workflow stage allowlists still remove `bash`, recursive subagent tools, and any other unapproved tool.
## Inspect and continue
Use `/workflow` for the drill-down dashboard. TUI mode opens shallow popup overlays for the run list, run actions, Gates, confirmations, questions, and feedback. Plans, reports, prototype evidence, and Assignment transcripts open in a sanitized full-screen reader. Escape returns one level. RPC, print, and JSON modes remain linear and never open custom overlays.
The dashboard lists runs attached to the current session and shows persisted status, core-stage progress, Gate, plan, report, branch, and worktree information. While work is active, one line above Pi's editor tracks only the newest attached run and clears when no attached run remains active. Human-facing surfaces use the feature name as the run label. Analysis and legacy runs fall back to a request label of at most 48 characters, then to the run ID when no request exists. Duplicate labels in one available-run list receive ` · <run-id-prefix>`, using the shortest unique prefix of at least eight characters.
Use `/workflow continue` to select a run with a pending fresh-session handoff or normal-compaction continuation. `/workflow resume` is an alias. A run ID may be supplied directly:
```text
/workflow continue <run-id>
/workflow resume <run-id>
```
Selection requires interactive TUI mode. In non-interactive modes, provide the run ID. Choosing a pending fresh-session continuation in the dashboard immediately enters the existing `newSession()` handoff path; it does not require a second command. Tool and RPC callers receive the explicit `/workflow continue <run-id>` continuation instead. Labels are presentation-only and cannot be used as lookup aliases; copyable continue and stop commands always retain the full run ID. They require no schema migration and do not change persisted paths.
## Stop active work
Use `/workflow stop` to abort an active (`running` or `waiting`) Workflow Run owned by the current parent session. If more than one is active, interactive TUI mode presents a selection list. A run can also be named directly, including in non-interactive modes:
```text
/workflow stop <run-id>
```
Terminal runs and runs owned by historical parent sessions are not offered. The misspelled `/worlflow` alias is not supported.
## Script modes
A feature run may include one restricted read-only script at a closed insertion point:
- `before-design`
- `after-design`
- `before-review`
An analysis run uses `action: "start"` with `workflow: { mode: "analysis-script", source, args? }` and does not create a worktree or feature Gates. Scripts expose only `stage`, `assign`, `parallel`, and immutable `args`. Their Assignment tools are the intersection of the configured analysis allowlist, the selected Markdown profile, and active parent tools.
## Recovery
Interrupted work opens a Recovery Gate with retry, inspect, and abort choices. Completed Assignments and Decisions remain persisted. Potentially mutating interrupted Assignments are preserved and are not replayed automatically; an explicit retry creates newly fenced work where policy permits it. Startup recovery may adopt a continuable run when its recorded owner process is dead or absent. Adoption atomically rotates the lease and Implementation Context parent IDs. A live owner or live Assignment remains fail-closed, and historical sessions remain inspection-only unless such an adoption makes one active. Retry clears prior failed-command output and reruns verification from a pending state. Once remediation completes the Implement stage, an older interrupted mutating Assignment no longer triggers duplicate remediation on later retries.
## Artifacts
Run state and bounded artifacts are stored under:
```text
~/.pi/agent/workflows/runs/<run-id>/
```
Important files include immutable plan revisions, Assignment transcripts, retained prototype reports and screenshots, `result.json`, and the terminal Markdown report. Report headings use the readable label and include the full canonical Run ID as explicit metadata. Completed worktrees remain available for manual inspection and integration.
## Reload after exposure
Repository-managed extension links are controlled through `config/pi-links.json`. Run `/reload` after the managed link is synchronized so Pi discovers `workflow`.
+284
View File
@@ -0,0 +1,284 @@
# workflow popup prototypes
**Status:** Direction C accepted
These static terminal frames compare popup directions for `/workflow`. They are prototype evidence, not production screenshots or manual validation of the implemented extension. All variants use Pi theme tokens, keyboard-visible focus, one border at most, and no animation.
Representative run: `workflow-usability-resume`, waiting at Plan Approval after Discover and Design.
## A. Centered compact modal
A small modal preserves the surrounding conversation and keeps one decision in focus.
```text
┌──────────────────────────────────────────────────────────────────────┐
│ │
│ ╭─ workflow ──────────────────────────────╮ │
│ │ workflow-usability-resume │ │
│ │ WAITING · Plan Approval · revision 12 │ │
│ │ │ │
│ │ ✓ Discover ✓ Design · Prototype │ │
│ │ · Implement · Verify · Review │ │
│ │ │ │
│ │ > Review plan │ │
│ │ Approve plan │ │
│ │ Request revision │ │
│ │ Close │ │
│ │ │ │
│ │ ↑↓ navigate enter select esc close │ │
│ ╰─────────────────────────────────────────────╯ │
│ │
└──────────────────────────────────────────────────────────────────────┘
```
Strengths:
- Minimal visual interruption.
- Familiar one-step prompt behavior.
- Low chrome and clear focus.
Weaknesses:
- Long plans and detailed run state require repeated modal replacement.
- Context disappears quickly as the interaction deepens.
- Poor fit for browsing artifacts or transcripts.
### A at 60 columns
```text
╭─ workflow ───────────────────────╮
│ usability-resume · WAITING │
│ Plan Approval · r12 │
│ │
│ > Review plan │
│ Approve plan │
│ Request revision │
│ Close │
│ │
│ ↑↓ enter esc │
╰─────────────────────────────────────╯
```
## B. Near-full-screen workspace
A stable workspace keeps the run list, selected run, progress, and actions visible together.
```text
╭─ workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ workflow-usability-resume WAITING │
│ │ feature/workflow-usability-resume · r12 │
│ > usability-resume │ │
│ auth-cleanup │ Progress │
│ cache-audit │ ✓ Discover ✓ Design · Prototype · Implement │
│ │ · Verify · Review │
│ │ │
│ │ Open Gate │
│ │ Plan Approval │
│ │ Review the implementation plan before work begins. │
│ │ │
│ │ > Review plan │
│ │ Approve plan │
│ │ Request revision │
│ │ Browse artifacts │
│ │ Close │
│ │ │
│ ↑↓ run tab focus │ ↑↓ action enter select esc back │
╰──────────────────────────────────────────────────────────────────────────────╯
```
Strengths:
- High information density with stable spatial context.
- Fast comparison between several active runs.
- Actions and state remain visible together.
Weaknesses:
- The permanent left pane spends space on uncommon multi-run comparison.
- Focus management and responsive collapse are more complex.
- At 80 columns the content pane becomes cramped; below 80 it must become a different UI.
### B at 80x24
```text
╭─ workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ usability-resume · WAITING · r12 │
│ > usability │ ✓ Discover ✓ Design · Prototype │
│ auth-cleanup │ · Implement · Verify · Review │
│ cache-audit │ │
│ │ Plan Approval │
│ │ > Review plan │
│ │ Approve plan │
│ │ Request revision │
│ │ Browse artifacts │
│ │ │
│ tab focus │ ↑↓ action enter select esc back │
╰──────────────────────────────────────────────────────────────────────────────╯
```
### B at 60 columns
The workspace must collapse to a single run-detail pane. The run list becomes a prior drill-down view, effectively converging on direction C.
## C. Drill-down overlays with dedicated readers
Direction C uses shallow browser-style navigation. Each overlay does one job. Escape always returns one level.
### C1. Run list popup
```text
╭─ workflow ─────────────────────────────╮
│ > usability-resume WAITING Plan Approval│
│ auth-cleanup RUNNING Implement │
│ cache-audit DONE report ready │
│ │
│ ↑↓ navigate enter open esc close │
╰────────────────────────────────────────────╯
```
### C2. Run detail popup
```text
╭─ usability-resume ───────────────────────────────────╮
│ WAITING · Plan Approval · revision 12 │
│ │
│ ✓ Discover ✓ Design · Prototype · Implement │
│ · Verify · Review │
│ │
│ > Review plan │
│ Record Gate Decision │
│ Browse prototype evidence │
│ Browse Assignment transcripts │
│ Show worktree path │
│ │
│ ↑↓ navigate enter select esc runs │
╰──────────────────────────────────────────────────────╯
```
### C3. Plan reader at wide width
The reader uses the whole overlay. The terminal edge is the outer frame, so there is no decorative full-screen border. The left outline tracks the heading containing the top visible document line.
```text
workflow plan · usability-resume line 42/216
Outline Plan
───────────────────────────── ─────────────────────────────────────────────
workflow usability update # workflow usability update plan
Locked decisions
> Implementation phases ## Implementation phases
Prototype overlays
Session lifecycle ### 2. Session lifecycle and recovery
Worktree safety
Popup TUI - Route the dashboard's fresh-session action
Progress widget through the existing continuation path.
Design regression
Acceptance criteria - Atomically rotate lease and context owners
during absent/dead adoption.
Primary files: dashboard.ts,
context-transition.ts, continuation.ts,
engine.ts, and focused tests.
↑↓ scroll pgup/pgdn page home/end document esc back
```
### C3 at 80x24
```text
workflow plan · usability-resume row 42/216
Outline Plan
────────────────────── ─────────────────────────────────────────────
Locked decisions ## Implementation phases
> Implementation
Prototype overlays ### 2. Session lifecycle and recovery
Session lifecycle - Route the dashboard's fresh-session action
Worktree safety through the existing continuation path.
Popup TUI
Progress widget - Atomically rotate lease and context owners
Acceptance criteria during absent/dead adoption.
↑↓ scroll pgup/pgdn page home/end document esc back
```
### C3 at 60 columns
The outline hides and the document becomes the only pane. The current heading remains visible in the header.
```text
workflow plan · Implementation phases · row 42/216
## Implementation phases
### 2. Session lifecycle and recovery
- Route the dashboard's fresh-session action through the
existing continuation path.
- Atomically rotate lease and context owners during
absent/dead adoption.
↑↓ scroll pgup/pgdn page home/end document esc back
```
### C3 at 47x11
```text
terminal too small
workflow plan needs 48x12
current terminal is 47x11
resize the terminal or press esc
```
Strengths:
- Each screen has one dominant task and a complete local keymap.
- Best responsive behavior because narrow layouts remain single-pane.
- Long plans and transcripts get dedicated virtualized readers.
- The shallow stack preserves context without permanent side-panel cost.
Weaknesses:
- Comparing several runs takes more navigation than direction B.
- Back-stack state and overlay focus/disposal require careful implementation.
## Persistent progress widget
The widget is independent of the selected popup direction and stays above Pi's editor while the newest attached run is active.
Standard:
```text
workflow usability-resume DESIGN 2/6 Gate: Plan Approval
```
Narrow:
```text
workflow usability-resume DESIGN 2/6
```
Terminal runs disappear rather than leaving a stale receipt above the editor.
## Recommendation
Use direction C. It has one border only on bounded popup cards, no redundant frame around the full-screen reader, keyboard-visible selection, and the most truthful 80-column and 60-column degradation. Direction B spends too much space on multi-run comparison, while direction A does not provide enough stable space for plans and evidence.
## Production mapping
The accepted direction maps to `extensions/workflow/tui.ts` and `dashboard.ts`. The implementation uses popup overlays for bounded selections and text entry, then switches to the full-screen reader for verified plans and retained evidence. `progress.ts` owns the separate one-line widget. Pure renderer tests cover the wide, 80-column, 60-column, and below-48x12 contracts; interactive Pi validation remains a separate manual step.
## Interaction contract
- Arrow keys navigate every selection surface; Enter selects; Escape cancels or returns one level.
- Page Up/Page Down and Home/End apply only to long-document readers.
- Text inputs use Pi's `Input` or `Editor` components and propagate focus for IME positioning.
- The current selection uses position plus selected background or reverse video, never color alone.
- TUI overlays are never opened in RPC, print, or JSON mode.
- Every rendered line is truncated or wrapped by terminal cell width rather than JavaScript string length.
- No continuously repainting animation is used.
+707
View File
@@ -0,0 +1,707 @@
# workflow Design
**Status:** Accepted
**Date:** 24AUG2026
## Purpose
`workflow` coordinates feature planning and implementation through selected Markdown-defined agents, persisted human gates, isolated Pi child sessions, and mandatory independent review.
The extension is based on `extensions/_workflows`, but it is a new extension rather than a rename. The existing extension remains an inactive reference until `workflow` is verified and explicitly exposed.
## Goals
- Load bundled Workflow Agent Profiles plus configured standard subagent definitions from the active `pi-interactive-subagents` package, the global agent directory, and trusted project overrides.
- Adapt standard definitions through explicit workflow role overlays, then select agents automatically using deterministic eligibility followed by planner selection with recorded rationale.
- Pause after discovery for unresolved questions and after design for user approval.
- Require at least three prototype candidates and explicit user acceptance for non-trivial UI or UX work.
- Prevent an implementation agent from reviewing its own work.
- Support configurable concurrency with a user-controlled safety ceiling.
- Retain a restricted JavaScript DSL for custom feature and read-only analysis workflows.
- Run every feature in one dedicated Git worktree.
- Let the user choose a fresh plan-seeded session, smart compaction with normal-compaction fallback, or unchanged current context before implementation.
- Recover safely after process interruption without replaying potentially mutating work automatically.
## Non-goals
- Replacing the outer nono sandbox or granting capabilities beyond it.
- Allowing child agents to ask the user directly.
- Supporting arbitrary workflow graphs that can bypass required gates.
- Automatically merging a completed worktree into its source branch.
- Adding a general plugin framework for custom stages, policies, or persistence backends.
- Inferring workflow roles or mutability from arbitrary standard-agent names or prompt prose.
## Language
**Agent Profile:** A versioned Markdown definition containing an agent's purpose, instructions, model preferences, tools, roles, and Eligibility Criteria.
**Eligibility Criteria:** Machine-readable conditions that determine whether an Agent Profile may be considered for an Assignment.
**Assignment:** One stage-specific task executed by one Agent Profile in a fresh child session.
**Workflow Run:** The persisted execution of one feature or analysis request.
**Stage:** A named unit of workflow progress controlled by the engine.
**Gate:** A persisted point where the Workflow Run waits for a valid Decision.
**Decision:** A revision-checked user or policy response that satisfies or rejects a Gate.
**Prototype Candidate:** One throwaway design option produced for user comparison.
**Review Assignment:** A fresh-session Assignment whose Agent Profile differs from every implementation Assignment it reviews.
**Implementation Context Choice:** The user's persisted selection of a fresh plan-seeded session, compacted current session, or unchanged current session before implementation starts. The compacted strategy prefers `smart_compact` and falls back to normal Pi compaction only when that tool is unavailable.
## External Interface
The extension exposes one state-changing tool and one workflow command.
```ts
type WorkflowInput =
| {
action: "start";
request: string;
featureName?: string;
workflow?:
| { mode: "feature" }
| {
mode: "feature-script";
insertionPoint: "before-design" | "after-design" | "before-review";
source: string;
args?: string;
}
| { mode: "analysis-script"; source: string; args?: string };
concurrency?: number;
background?: boolean;
allowDirtySource?: boolean;
idempotencyKey: string;
}
| {
action: "decide";
runId: string;
gateId: string;
expectedRevision: number;
decision: GateDecision;
idempotencyKey: string;
}
| { action: "inspect"; runId: string }
| {
action: "abort";
runId: string;
expectedRevision: number;
idempotencyKey: string;
};
```
Gate Decisions use closed, gate-specific schemas:
```ts
type GateDecision =
| {
kind: "answer-questions";
answers: Record<string, string>;
}
| {
kind: "approve-plan";
approved: true;
acceptedUiImpact: "none" | "minor" | "non-trivial";
comment?: string;
}
| {
kind: "revise-plan";
feedback: string;
}
| {
kind: "accept-prototype";
candidateId: string;
candidateRevision: number;
browserReviewed: true;
feedback?: string;
}
| {
kind: "refine-prototypes";
feedback: string;
}
| {
kind: "select-implementation-context";
strategy: "fresh-session" | "smart-compact" | "current-session";
}
| {
kind: "report-context-preparation";
preparationId: string;
planRevision: number;
method: "smart_compact";
outcome: "unavailable" | "succeeded" | "no-op";
}
| {
kind: "report-context-preparation";
preparationId: string;
planRevision: number;
method: "smart_compact";
outcome: "failed";
error: string;
}
| {
kind: "recover";
resolution: "retry" | "inspect" | "abort";
};
```
Feature and feature-script starts require `featureName` as a concise lowercase kebab-case name that describes what the feature does, such as `searchable-workflow-dashboard`. Analysis starts omit it. The host validates the name before persisting launch intent.
Human-facing dashboard, selector, notification, handoff, compaction, tool, and report prose uses a shared presentation label. It prefers `featureName`; otherwise it normalizes the request to one line and bounds it to 48 characters, preserving whole words where possible and adding `…` when truncated; only a missing request falls back to `runId`. When derived labels collide within an available run list, only those labels receive ` · <prefix>`, where the run-ID prefix is the shortest unique prefix with a minimum of eight characters. This label is never persisted as identity or accepted as a lookup alias. It requires no schema migration and does not change persisted paths. The complete `runId` remains canonical for snapshots, structured fields, command arguments, paths, receipts, leases, and idempotency. Copyable `/workflow continue <run-id>` and `/workflow stop <run-id>` commands retain it, and reports include it as `Run ID` metadata beneath the readable heading.
The `workflow` tool calls a single internal `execute(command)` interface. `/workflow` opens a drill-down TUI dashboard and may accept a run ID for direct inspection. Run selection, actions, Gates, confirmations, questions, and feedback use bounded popup overlays. Verified plans, reports, prototype evidence, and Assignment transcripts use a sanitized full-screen reader with H1-H3 outline navigation at widths of 80 columns or more and a single document pane from 60 through 79 columns. Below 48x12 it renders only a truthful minimum-size state. RPC, print, and JSON paths remain linear and do not call `ctx.ui.custom()`.
`/workflow start <message>` sends the initial request through the assistant so the normal `workflow` tool path owns feature naming and idempotency; in interactive TUI mode, omitting the message opens an input overlay. `/workflow continue` presents eligible pending context transitions for selection, while `/workflow continue <run-id>` continues one directly; `/workflow resume` is an alias for both forms. Selecting a fresh-session continuation from the dashboard routes directly through the same handler and calls `newSession()` without a second command. `/workflow stop [run-id]` aborts a non-terminal run owned by the active parent session and presents a selector when multiple owned runs are active. The misspelled `/worlflow` alias is intentionally unsupported. Continue and stop selectors require interactive TUI mode and provide direct-run-ID guidance otherwise.
Continuation performs only a pending fresh-session handoff or normal-compaction fallback after the run is safely waiting; it cannot approve plans, select prototypes, or make other Decisions. Stop treats `running` and `waiting` runs as active and excludes terminal runs and runs owned only by historical parent sessions.
When a run reaches a Gate, the tool returns a structured waiting view. The parent agent asks the user through its normal interaction tools, then calls `workflow` with `action: "decide"`. Child agents never receive `ask_user`.
Background runs return a structured run ID immediately. When they reach a Gate or settle, the extension sends one custom follow-up message with a stable delivery key to the active parent session and a readable run label in its prose.
After `start` creates the run lease, every subsequent state-changing parent operation is authenticated against its active parent-session ID. Session IDs retained in `parentSessionIds` are historical discovery links and permit inspection only.
## Agent Profiles
### Discovery and precedence
Profiles are loaded in this order:
1. Bundled workflow profiles from `extensions/workflow/agents/*.md`.
2. Configured standard definitions from `${PI_CODING_AGENT_DIR:-~/.pi/agent}/extensions/pi-interactive-subagents/agents/`.
3. Configured standard definitions from `${PI_CODING_AGENT_DIR:-~/.pi/agent}/agents/`.
4. Workflow profiles or configured standard definitions from the nearest `.pi/agents/*.md`, only when `ctx.isProjectTrusted()` is true.
Standard definitions become Workflow Agent Profiles only when `standardAgents.roles` explicitly maps their name to one or more workflow roles. Their prompt, description, model, thinking level, and declared tools remain the standard definition's values; workflow policy supplies stages and still intersects tools with the audited stage allowlist. Unmapped standard definitions are ignored rather than assigned a role from their name or prose.
Files are read in lexical order. The first duplicate within one source wins and emits a diagnostic. Later trusted sources replace earlier definitions with the same normalized name. Provenance and a digest over both definition content and role overlay are retained. Regular files and symlinks are accepted only when their resolved paths remain inside the selected profile root. When a configured standard profile is eligible for a role, bundled profiles for that role become explicit fallbacks and are ineligible; bundled profiles continue to supply roles such as Design, Verify, and Review when no standard mapping exists.
Profile contents are pinned into the Workflow Run before selection. Editing a Markdown file does not change an active run.
### Markdown schema
```md
---
name: frontend-prototyper
description: Produces structurally distinct browser-reviewable UI prototypes.
roles: [prototype]
model: anthropic/claude-opus-4-6
effort: high
tools: [read, grep, find, ls, edit, write]
selection:
stages: [prototype]
anyTags: [frontend, ui, ux]
allTags: []
pathGlobs: ["src/**/*.svelte", "src/**/*.tsx"]
keywords: [dashboard, page, component, responsive]
---
Agent instructions go here.
```
Required fields:
- `name`: lowercase kebab case, unique after precedence is applied.
- `description`: concise purpose used by selection and the planner.
- `roles`: one or more of `discover`, `design`, `prototype`, `implement`, `verify`, or `review`.
- `selection`: structured Eligibility Criteria with at least one stage; additional filters may be empty for a deliberate fallback profile.
- Markdown body: non-empty agent instructions.
Optional fields:
- `model`: bare model ID or `provider/model-id`.
- `provider`: accepted only with a bare `model` field.
- `effort`: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max`.
- `tools`: CSV or YAML string array.
Unknown fields produce diagnostics and are ignored. Malformed files are skipped independently so one profile cannot break the catalog.
### Eligibility and planner selection
The engine normalizes request and repository evidence into facts:
```ts
interface WorkflowFacts {
stage: StageKind;
taskKind: "feature" | "analysis";
requestTerms: string[];
candidatePaths: string[];
languages: string[];
tags: string[];
riskTags: string[];
}
```
Eligibility is deterministic:
- The profile must support the requested role and stage.
- Every `allTags` entry must be present.
- At least one `anyTags` entry must match when the list is non-empty.
- At least one `pathGlobs` entry must match when the list is non-empty.
- At least one normalized `keywords` entry must match when the list is non-empty.
Pre-discovery selection uses only facts available without a model call: workflow mode, requested stage, normalized request terms, repository language markers, and paths named by the request. Criteria that require unavailable discovery facts do not match. A bundled general discovery profile provides an explicit fallback.
The engine selects the initial discovery profile deterministically from eligible profiles using specificity and profile name as the stable tie-breaker. Empty and ambiguous selections fail clearly. After discovery, the selected planner receives only eligible profiles and chooses Assignments with a structured rationale. The host validates every choice and persists the eligible set, rejected profiles with reasons, selected profiles, and rationale.
## Configuration
Configuration sources are:
1. Bundled defaults.
2. `~/.pi/agent/workflow.json`.
3. Trusted `.pi/workflow.json`.
4. Per-run invocation values.
Invocation values may change requested concurrency but never the safety ceiling. A project may lower the global ceiling but cannot raise it.
```json
{
"concurrency": {
"default": 8,
"ceiling": 32
},
"maxAssignmentsPerRun": 128,
"maxReviewCycles": 3,
"analysisTools": ["read", "grep", "find", "ls"],
"standardAgents": {
"enabled": true,
"roles": {
"scout": ["discover"],
"worker": ["implement"]
}
},
"worktrees": {
"root": ".worktrees"
}
}
```
`32` is an immutable process-wide maximum, not merely a default. Global and trusted project configuration may lower it but cannot raise it. The scheduler uses one extension-wide semaphore so concurrent Workflow Runs cannot exceed the effective process ceiling in aggregate. Each run also has its requested or configured limit.
The first-version analysis and review tool sets are audited built-in allowlists. Configuration may remove tools but cannot add arbitrary extension tools by name.
Effective per-run concurrency is:
```text
min(requested or configured default, global ceiling, trusted project ceiling, 32)
```
Invalid, zero, non-integral, or out-of-range values fail before the run starts.
## Workflow State
```ts
type RunStatus =
| "running"
| "waiting"
| "completed"
| "failed"
| "aborted";
type AssignmentStatus =
| "queued"
| "running"
| "succeeded"
| "failed"
| "interrupted";
interface WorkflowRun {
runId: string;
revision: number;
mode: "feature" | "analysis";
status: RunStatus;
request: string;
featureName?: string;
parentSessionIds: string[];
planArtifact?: PlanArtifact;
implementationContext?: ImplementationContextState;
lease?: RunLease;
workspace: WorkflowWorkspace;
effectiveConfig: EffectiveWorkflowConfig;
pinnedProfiles: PinnedAgentProfile[];
facts: WorkflowFacts;
stages: Stage[];
gates: Gate[];
decisions: Decision[];
assignments: Assignment[];
prototypeCandidates: PrototypeCandidate[];
deliveries: DeliveryRecord[];
uiImpact?: UIImpact;
error?: WorkflowError;
}
```
Only the workflow engine may transition Stage, Gate, Assignment, context-preparation, or run status. Each accepted state-changing command increments `revision` and atomically replaces the persisted snapshot. Read-only inspection does not increment the revision. `ImplementationContextState` persists the Gate ID, plan revision, preparation ID, selected strategy, observed method/outcome, active parent-session ID, and any fresh-session or normal-compaction intent.
## Built-in Feature Pipeline
```text
Initialize
-> Discover
-> Questions Gate, when unresolved questions exist
-> Design
-> Plan Approval Gate
-> Prototype, only for non-trivial UI impact
-> Prototype Acceptance Gate
-> Implementation Context Gate
-> Implement
-> Verify
-> Review
-> Remediate -> Verify -> Review, when changes are requested
-> Complete
```
### 1. Initialize
- Resolve effective configuration, validate the feature name, and validate the repository without mutation.
- Load, validate, and pin Agent Profiles from the source checkout.
- Verify that eligible discovery, design, implementation, verification, and independent review profiles exist before mutating the repository.
- For feature mode, verify that the configured worktree root is ignored by Git. Capture at most 20 sorted path/status records plus an omitted count for staged, unstaged, or untracked source changes. Unmerged paths always block creation. Ordinary changes require explicit TUI confirmation or `allowDirtySource: true` from a noninteractive caller.
- Persist a run snapshot with workspace state `creating` before invoking Git.
- Create a distinct worktree transactionally, then persist workspace state `ready`.
- On creation failure, roll back what can be removed safely, persist the failure, and leave enough intent for startup reconciliation.
- Persist Assignment intent before starting every child.
### 2. Discover
Discovery Assignments inspect the repository and return structured facts, relevant files, risks, precedents, unresolved questions, and preliminary UI impact evidence.
If unresolved questions exist, the engine persists a Questions Gate and waits. Answers become a Decision and are included in every later planning prompt.
### 3. Design
The planner selects eligible Agent Profiles with recorded rationale and produces:
- Scope and acceptance criteria.
- Stage Assignments.
- Explicit file ownership for every mutating Assignment.
- Verification commands and expected outcomes.
- A structured UI impact classification: `none`, `minor`, or `non-trivial`, with affected surfaces and evidence.
- The independent Review Assignment target.
The engine combines planner output with objective UI signals from request terms, affected paths, routes, layout/navigation changes, accessibility, responsiveness, and user-flow changes. Objective signals of non-trivial UI impact cannot be downgraded by the planner. The approved design is written atomically to a bounded, versioned `plan.md` containing requirements, Decisions, selected Assignments, file ownership, verification commands, worktree details, and UI impact evidence. The Plan Approval view shows the classification and evidence, and the Decision explicitly accepts that classification. Implementation and prototyping cannot begin before approval.
### 4. Prototype
This Stage is required when UI impact is `non-trivial`.
- Produce at least three structurally distinct Prototype Candidates.
- Use separate fresh Assignments and candidate-specific paths. Profiles may repeat when only one prototyper is eligible.
- Prefer an existing host page and a `?variant=` switcher.
- Use realistic data and responsive layouts.
- Keep prototypes out of production behavior and mark them as throwaway.
- Return launch instructions, routes, candidate summaries, and artifact paths.
The engine opens a Prototype Acceptance Gate only after at least three candidates have unique IDs, revisions, paths, routes, structural rationales, responsive checks, and browser-launch evidence. The user reviews them in the browser or application and may accept one successful candidate revision, request refinement, or abort. The accepted candidate and feedback produce a new `plan.md` revision before implementation-context selection. Accepted prototype code is evidence, not production code; implementation rewrites the accepted direction to production standards. A post-acceptance cleanup Assignment removes prototype-only routes, losing candidates, and switchers before verification while retaining bounded artifacts outside the production tree.
### 5. Choose Implementation Context
Immediately before implementation, the engine persists an Implementation Context Gate referencing the final approved `plan.md` revision. For work without non-trivial UI impact this follows Plan Approval; for non-trivial UI work it follows Prototype Acceptance and the resulting plan revision.
The user chooses one strategy:
- `fresh-session`: the engine atomically persists a handoff intent bound to the Gate ID, plan revision, run revision, source parent-session ID, and unique preparation ID before `/workflow continue <run-id>` calls `ExtensionCommandContext.newSession()`. During the expected `session_shutdown`, the matching source session and `reason: "new"` atomically claim the event's `targetSessionFile` onto that intent and enter `claimed-target-awaiting-withSession`. The target's immediate `session_start` with `reason: "new"` and matching `previousSessionFile` suppresses recovery for that startup lifecycle only. Only the following replacement `withSession` callback for the claimed target may consume the intent: it attaches the new active parent-session ID, seeds the bounded `plan.md`, run ID, revision, worktree path, and continuation instruction, and then satisfies the Gate. Cancellation or failure before consumption keeps the Gate waiting with the original session active when possible.
- `smart-compact`: the engine persists a preparation ID bound to the Gate and final plan revision. When `pi.getActiveTools()` contains `smart_compact`, the parent invokes it with `plan.md` as the focus and reports `succeeded`, `no-op`, or `failed` through a `report-context-preparation` Decision carrying that preparation ID and plan revision. When the parent reports `unavailable`, the host accepts it only if `smart_compact` is absent from the active tool inventory, persists a normal-compaction intent, and directs `/workflow continue <run-id>` to invoke `ctx.compact({ customInstructions, onComplete, onError })` with equivalent plan-focused instructions. The invocation's intent-bound `onComplete` or `onError` callback consumes that exact intent and records the terminal method and outcome. A successful or no-op preparation satisfies the Gate; a failure remains visible and waiting. An available-but-failed `smart_compact` attempt never silently falls back.
- `current-session`: the Gate is satisfied immediately and the current context is retained unchanged.
Session replacement or compaction occurs only while the Workflow Run is waiting with no active child Assignments. Every callback, command, and event must match the active parent-session ID, Gate ID, preparation ID, and plan revision. A stale value, failed transition, or mismatched strategy leaves the Gate waiting and cannot start implementation.
### 6. Implement
Mutating Assignments run in the Workflow Run's worktree.
- Every Assignment has declared file ownership.
- All mutating Assignments are serialized in the first version. Concurrency remains available for read-only Assignments.
- Mutating child sessions do not receive `bash` or other process-execution tools. Assignment-scoped file operations reject symlink traversal and require canonical containment beneath both the worktree root and the Assignment's owned path roots.
- Plan-approved verification and generation commands run separately through a host executor using fixed executable/argument arrays, never agent-authored shell strings. The only accepted wrapper form is `env PI_OFFLINE=1 <executable> ...`; the executor unwraps it, sets that single variable, and applies the normal executable safety checks.
- The host executor sets `PYTHONDONTWRITEBYTECODE=1` so Python-backed checks do not create out-of-scope `__pycache__` artifacts.
- Every host command has a three-minute execution timeout and reports exit code `124` when terminated. Internal Git probes and worktree commands have a 30-second timeout. Process-tree termination, including Windows `taskkill`, has its own deadline and reports exit code `125` when cleanup cannot be completed.
- Every child Assignment has a five-minute execution deadline. Timeout aborts the child signal and persists the Assignment as `interrupted` with `assignment-timeout` evidence rather than reporting success.
- The engine records branch, HEAD, worktree identity, and Git diff state before and after every mutating Assignment and host command.
- Out-of-scope changes, branch movement, commits, or worktree metadata changes invalidate the Assignment and open a Recovery Gate before more mutation starts.
- The scheduler reserves capacity synchronously before launching children.
- Assignment intent is persisted before child execution.
- The extension does not commit, merge, reset, or remove work automatically in the first version.
### 7. Verify
Verification runs the focused tests, type checks, linting, builds, and browser validation required by the approved plan. Changed behavior must have focused tests. UI changes must be exercised in the application or browser with realistic data.
A failed verification returns to remediation or opens a Recovery Gate when automatic remediation is unsafe.
### 8. Review
The engine maintains a cumulative set of every Agent Profile that mutated the reviewed diff, including implementation, prototype cleanup, and remediation. Review selection excludes that complete set.
Each Review Assignment:
- Uses a fresh child session.
- Receives only an audited read-only tool allowlist plus an internal read-only diff tool.
- Records a zero-diff postcondition; any repository change invalidates the verdict.
- Receives the approved plan, accepted prototype Decision when applicable, verification evidence, and complete diff scope.
- Reports specification conformance and repository standards as distinct structured axes.
- Returns a structured verdict and findings.
`changes_requested` creates remediation Assignments whose profiles join the cumulative mutator set, then repeats Verify and Review in another fresh session. A reviewer profile may never remediate the work it reviews. If exclusions leave no eligible reviewer, the run fails closed before further mutation. After three unsuccessful review cycles by default, the engine opens a Recovery Gate for user direction. Completion requires an approved review verdict.
## Custom Script Modes
The existing restricted JavaScript runtime remains as defense in depth inside nono.
### Feature script
A feature script is bound by its closed `insertionPoint` input to run before Design, after Design, or before Review. It may request only custom read-only analysis Assignments at that point. Every pre-implementation custom Assignment uses the audited analysis tool allowlist. The host still injects and enforces Questions, Plan Approval, Prototype Acceptance, implementation verification, and independent review policy. Scripts cannot choose another insertion point at runtime, create mutating Assignments before approval, satisfy Gates, reorder mandatory Stages, or create child sessions directly.
### Analysis script
An analysis script may orchestrate read-only Assignments without feature Gates. Its effective tool set is the intersection of:
- The configured `analysisTools` allowlist.
- The selected Agent Profile's tools.
- Tools active in the parent session.
The fixed first-version allowlist excludes `bash`, mutation tools, recursive orchestration, user interaction, process execution, and unaudited extension tools. Configuration may only remove entries from that allowlist.
### Script-visible interface
```js
stage("Audit");
const results = await parallel([
() => assign("review", "Inspect persistence behavior"),
() => assign("review", "Inspect cancellation behavior"),
]);
return results;
```
`stage`, `assign`, `parallel`, and immutable `args` communicate through authenticated, bounded IPC. The script has no filesystem, network, process, import, timer, eval, or dynamic code-generation access.
## Worktree Policy
Every feature Workflow Run owns a distinct, exclusive worktree under:
```text
<repository>/.worktrees/workflow-<feature-name>-<run-id>/
```
The corresponding branch is:
```text
feature/<feature-name>
```
`<feature-name>` comes from the validated `featureName` start input and describes the feature rather than the workflow mechanism. Any existing branch with that name rejects a new start. If persisted state associates the branch with a Workflow Run, the error returns its run ID and directs the caller to continue it through `inspect` or `decide`; otherwise it directs the caller to choose another descriptive name. The extension never adds a numeric or run-ID suffix silently.
The configured worktree root must already be ignored by Git. The extension verifies this with Git before persisting creation intent and fails with setup guidance rather than modifying `.gitignore` automatically. A worktree is created from the pinned source `HEAD`; source-only staged, unstaged, and untracked changes are not copied. The engine persists bounded path/status evidence and whether omission was explicitly allowed. TUI callers must confirm a warning that states those changes are omitted. Noninteractive callers must set `allowDirtySource: true`. Conflicts and unmerged paths always block creation.
The engine records an ownership lease for the run and refuses to adopt or share another run's worktree. The completed worktree remains available for inspection and manual integration. Removal is explicit and never part of normal completion.
Read-only analysis runs use the parent cwd and do not create worktrees. All child sessions inherit the parent nono sandbox. The extension neither invokes nono nor widens filesystem or network permissions.
## Persistence and Recovery
Artifacts live under:
```text
~/.pi/agent/workflows/runs/<run-id>/
```
Files include:
```text
workflow.json
request.md
plan.md
config.json
profiles/
handoffs/
transcripts.json
result.json
artifacts/
```
Writes are atomic and mode `0600`. Serialization, transcript, source, argument, result, and IPC bounds from `_workflows` are retained.
The snapshot contains Decisions and prior Assignment outcomes, so a separate event store is unnecessary. Every `start`, `decide`, and `abort` command requires an idempotency key. The launch key and initial result are persisted before workspace creation. State-changing commands use revisions and idempotency keys to reject stale or duplicate transitions. Repeating a completed key returns its recorded result without another transition.
An active run owns a persisted lease containing process identity, active parent-session identity, heartbeat time, and worktree identity. The run retains every parent session ID attached through a handoff so `/workflow` can discover it from either session, but only the active ID may mutate the run. Startup or explicit Recovery may adopt a continuable run only when its recorded owner process is dead or its lease is absent. Adoption atomically rotates both `lease.activeParentSessionId` and `implementationContext.activeParentSessionId`, appends the adopting session to `parentSessionIds`, and preserves revision fencing. A live process or live Assignment blocks adoption even when its heartbeat is old. Startup and session recovery reconcile child processes, workspace-creation intent, Git identity, context handoffs, compaction intents, and assignments left `running`.
Fresh-session handoff intent is durable before `newSession()`. A `session_shutdown` with reason `new` bypasses ordinary interruption recovery only when its source session matches the pending intent; that handler atomically claims the event's `targetSessionFile` and marks the intent `claimed-target-awaiting-withSession`. The claimed target's immediately following `session_start` is exempt from recovery only when its reason is `new` and `previousSessionFile` matches the source. The replacement `withSession` callback must then match the claimed target before it atomically consumes the intent, rotates the active parent-session ID, records both session IDs, and resumes delivery. Any later `session_start` caused by `startup`, `reload`, `resume`, or `fork`, or a bounded claim expiry before consumption, follows normal recovery and leaves implementation blocked.
Every Gate and terminal background notification has a deterministic delivery key and persisted pending/sent state. Delivery uses a custom parent-session message containing that key in structured details. The parent session is the receiver-side receipt: recovery scans durable session entries for the key before retrying, then marks the outbox item sent. This closes the crash window between message persistence and sender-side state updates.
On process or session interruption:
- Active Assignments become `interrupted` idempotently.
- Potentially mutating Assignments are never replayed automatically.
- The run opens a Recovery Gate offering retry, inspect, or abort.
- Explicit retry resets failed verification commands to pending and clears their prior output before host execution.
- An interrupted mutating Assignment routes to remediation only while the Implement stage is incomplete; after remediation completes that stage, later retries continue into verification.
- Completed Assignments and accepted Decisions remain intact.
## Child Execution
Every Assignment creates a fresh in-memory Pi session using the parent model registry, Assignment cwd, resolved trust decision, settings, skills, extensions, and `AGENTS.md` context. Worktree trust is resolved with `resolveStandaloneChildProjectTrust`; an alternate cwd never inherits a session-only trust decision implicitly.
The effective model is resolved in this order:
1. Assignment override allowed by the workflow definition.
2. Agent Profile model/provider/effort.
3. Parent session model and thinking level.
Unknown or ambiguous models fail the Assignment before execution. The effective provider, model, effort, profile digest, child session ID, and context capacity are persisted.
Children cannot access recursive workflow or subagent tools or `ask_user`. Standard definitions are execution identities, not permission grants: `worker` may declare `bash` and nested subagents, but mutating workflow Assignments still receive only audited reads plus guarded `edit`/`write`, and read-only Assignments receive only audited reads. `workflow` is added to the shared child-tool exclusion policy used by Pi-subagent children so recursive orchestration remains unavailable. Each child tool call retains the shared timeout guard, including tools registered after startup. The first-response watchdog and bounded shutdown behavior from `_workflows` are retained.
## Internal Modules
`workflow` should remain a small set of deep modules:
- `index.ts`: Pi tool, command, lifecycle, and composition root.
- `engine.ts`: command handling, state transitions, gates, policies, and scheduling.
- `profiles.ts`: Markdown discovery, validation, eligibility, pinning, and diagnostics.
- `execution.ts`: fresh child sessions, assignment-scoped file operations, approved host commands, model resolution, structured output, transcripts, and timeouts.
- `script-runtime.ts` plus `sandbox-child.cjs`: restricted custom DSL and IPC.
- `store.ts`: atomic revisioned snapshots and bounded artifacts.
- `workspace.ts`: worktree creation, ownership conflict checks, and lifecycle.
- `context-transition.ts`: plan handoffs, new-session replacement, smart/default compaction callbacks, and session attachment.
- `dashboard.ts`: drill-down run actions, Gate orchestration, continuation handoff, and artifact selection.
- `tui.ts`: reusable popup inputs/selections and the full-screen verified-document reader.
- `progress.ts`: newest-attached-run projection and the bounded editor widget.
- `agents/*.md`: bundled default profiles.
Pure transition and eligibility logic stay inside the engine and profile modules rather than behind speculative adapter interfaces. Tests may inject filesystem, executor, decision, and script-runtime adapters at the composition root.
## Exposure and Migration
- Do not rename or activate `_workflows` during initial development.
- Add `extensions/workflow` tests to `package.json` explicitly.
- Typecheck through the existing `extensions/**/*.ts` configuration.
- Add `workflow` to `config/pi-links.json` only after focused tests, full tests, independent review, and manual TUI validation pass.
- Run the link reconciler in check mode before sync.
- Preserve unrelated managed links and require `/reload` after exposure.
## Implementation Phases
### Phase 1: Domain and profile catalog
Implement the Workflow Run model, configuration resolution, Markdown profile loader, deterministic Eligibility Criteria, and bundled profiles.
#### Phase 1 Success Criteria
- Configured standard package/global/trusted-project definitions override bundled fallbacks deterministically, while untrusted project profiles are never read.
- Standard definitions require explicit role overlays, preserve their model/prompt/tool identity, and cannot grant tools beyond the workflow stage allowlist.
- Profile files and symlinks resolving outside the selected bundled or trusted agent roots are rejected.
- Malformed profiles produce isolated diagnostics and cannot suppress valid profiles.
- Profile contents, provenance, and effective model settings are pinned by digest.
- Every profile has stage Eligibility Criteria, pre-discovery fallback is deterministic, and irrelevant profiles are excluded with recorded reasons.
- Configuration resolves default concurrency 8 and an immutable process-wide maximum of 32; project and run settings cannot raise that maximum.
### Phase 2: Engine, gates, and persistence
Implement the command interface, legal transitions, closed Gate Decisions, atomic revisioned snapshots, idempotency, leases, delivery state, recovery, transactional worktree creation scaffold, and the built-in feature state machine through Plan Approval using an injected scripted Assignment executor for tests.
#### Phase 2 Success Criteria
- An exhaustive legal and illegal Stage/Gate transition matrix passes through `execute(command)`; invalid transitions fail closed.
- `start`, `decide`, and `abort` require idempotency keys; launch intent is persisted before worktree creation, and a repeated completed key returns its prior result without a second transition.
- Stale revisions are rejected for `decide` and `abort`.
- Using the injected scripted Assignment executor, Questions and Plan Approval pause and resume across process restarts with the accepted UI classification intact and no dependency on live Pi child execution.
- Startup reconciliation detects absent or dead ownership and transitions abandoned `running` Assignments to `interrupted` exactly once.
- Potentially mutating interrupted Assignments require an explicit Recovery Decision; completed Decisions and Assignments are not replayed.
- Feature names are validated before launch persistence; worktree branches use exactly `feature/<feature-name>`, and every existing branch collision rejects new start with recorded-run `inspect`/`decide` guidance or descriptive-name rename guidance, never a silent suffix.
- Workspace creation intent and lease are persisted before Git mutation; creation succeeds transactionally or leaves a reconciled failure that startup can recover.
- Interrupted atomic writes leave a complete prior or next snapshot, never partial JSON.
### Phase 3: Child execution and selection
Implement the production Pi Assignment executor and eligible planner-selection path, then integrate child sessions, structured output, model selection, process-wide scheduling, transcript capture, trust resolution, and timeout behavior with the Phase 2 engine.
#### Phase 3 Success Criteria
- Live Discover and Design Assignments drive the built-in pipeline through Questions and Plan Approval using the production executor.
- Every Assignment uses a fresh child session and resolves worktree trust through `resolveStandaloneChildProjectTrust`.
- Planner choices are restricted to eligible profiles and persist selected, rejected, and rationale data.
- Aggregate running Assignments across all Workflow Runs never exceed 32 or a lower configured ceiling.
- Capacity is reserved synchronously; queued cancellation and bounded session shutdown release capacity exactly once.
- `workflow`, legacy workflow/subagent tools, and user interaction remain unavailable through both shared workflow-child and Pi-subagent child policies.
- A tool registered after child startup is still guarded by `extensions/shared/tool-call-timeout.ts`.
### Phase 4: Worktrees, implementation, verification, and review
Extend the Phase 2 worktree scaffold with the Implementation Context Gate, `/workflow continue`, and the production command/callback context-transition adapter, then add serialized mutation, canonical ownership and Git-state enforcement, verification evidence, independent review, and remediation cycles.
#### Phase 4 Success Criteria
- An unignored worktree root or unmerged source state blocks creation before Git mutation. Ordinary source changes require bounded evidence and explicit authorization, then create from the persisted `HEAD` without copying those changes.
- Workspace creation intent is persisted first; creation failure rolls back safely or remains reconcilable after restart.
- Every feature run receives a distinct leased worktree and worktrees are retained until explicitly removed.
- A versioned `plan.md` is persisted before the Implementation Context Gate and revised with an accepted prototype when applicable.
- Phase 4 registers `/workflow start`, `/workflow stop`, `/workflow continue`, and its `/workflow resume` alias. Start routes through the assistant's normal `workflow` tool path, stop is scoped to active runs owned by the current parent session, and continuation without a run ID selects from valid candidates. Its `ExtensionCommandContext` performs both fresh-session replacement and approved normal-compaction fallback rather than deferring either path to dashboard integration.
- `fresh-session` persists a Gate-, revision-, plan-, preparation-, and source-session-bound handoff intent before `newSession`; only the replacement `withSession` callback consumes it, attaches the new active parent session, seeds the bounded plan handoff, and resumes.
- `smart-compact` uses a Gate-bound `report-context-preparation` transition with distinct `unavailable`, `succeeded`, `no-op`, and `failed` outcomes; `failed` requires a non-empty actionable error. The host validates `unavailable` against `pi.getActiveTools()`; only that outcome permits plan-focused `ctx.compact({ onComplete, onError })`, whose intent-bound callback persists success or failure.
- An available-but-failed `smart_compact` call does not silently fall back and keeps the Implementation Context Gate waiting with an actionable error; `current-session` preserves context unchanged.
- Context transitions run only while no child Assignment is active. Every state-changing parent call must match the lease's active parent-session ID; historical IDs are inspection-only, and stale Gate, preparation, plan, or run revisions keep implementation blocked.
- The pending fresh-session intent survives its matching old-session `reason: "new"` shutdown and atomically enters `claimed-target-awaiting-withSession`; only the target's immediate matching `reason: "new"` `session_start` suppresses recovery before `withSession` consumes it. Later startup, reload, resume, fork, or expiry recovers an unconsumed claim without starting implementation.
- Mutating Assignments are serialized, receive no process-execution tools, reject symlink traversal, and require canonical write containment beneath both the worktree and owned path roots.
- Plan-approved host commands use fixed executable/argument arrays; out-of-ownership writes or branch, HEAD, commit, reset, clean, or worktree changes fail before another mutation begins.
- Review excludes the cumulative set of profiles that mutated the diff, including remediation and prototype cleanup, and fails closed when no independent reviewer remains.
- Review uses a fresh session, an audited read-only tool set, and a zero-diff postcondition.
- Review reports specification conformance and repository standards separately.
- Completion is impossible without focused behavioral tests, successful verification, and approved independent review.
### Phase 5: Prototype policy and custom scripts
Add objective UI-impact validation, three-candidate prototype handling, post-acceptance cleanup, Prototype Acceptance, and restricted feature/analysis script modes.
#### Phase 5 Success Criteria
- Objective signals of non-trivial UI impact cannot be downgraded, and Plan Approval explicitly accepts the displayed classification.
- Non-trivial UI work cannot reach implementation without three successful, structurally distinct candidate revisions and explicit acceptance of one.
- Prototype candidates use realistic host context, are browser-reviewable and responsive, and produce launch and validation evidence.
- Prototype-only routes, losing variants, and switchers are removed or isolated before verification while bounded artifacts remain inspectable.
- Analysis and pre-implementation feature scripts receive only the audited read-only tool allowlist.
- Feature scripts are bound to a validated closed insertion point and cannot reorder or bypass mandatory Gates, prototype policy, verification, or review.
- Script IPC tests reject malformed, duplicate, oversized, unauthenticated, and over-budget requests and prove cancellation terminates active work.
### Phase 6: Dashboard, integration, and exposure
Add the dashboard integration around the Phase 4 `/workflow continue` command, persisted notification outbox, reports, complete verification, documentation, and managed exposure.
#### Phase 6 Success Criteria
- Dashboard state is derived from persisted snapshots and active runs, prior supported snapshot versions remain readable, and continuation is presented only for a valid pending fresh-session or normal-compaction intent. Selecting a fresh-session continuation enters `newSession()` immediately.
- Bounded TUI interactions use responsive popup overlays. Verified documents use the dedicated sanitized reader with H1-H3 navigation, cell-width-safe viewports, and the locked 80-column, 60-column, and 48x12 behavior. RPC, print, and JSON remain linear.
- The widget above Pi's editor projects only the newest attached active run and clears after terminal persistence or session shutdown.
- Stable delivery keys, durable custom parent-session message receipts, and outbox reconciliation ensure each background Gate or terminal result is delivered once across reload and recovery.
- Focused tests, typecheck, full test suite, and manual Pi TUI validation of Gates, dashboard navigation, background delivery, and prototype handoff pass.
- Exposure is performed only through `config/pi-links.json`; unmanaged extension links are rejected and link reconciliation check passes before sync.
- `_workflows` remains available as an inactive reference until removal is separately approved.
## Verification Notes
- Test workflow and standard-profile trust, package/global/project precedence, explicit role overlays, malformed YAML isolation, unmapped-definition omission, and containment of regular files and symlinks.
- Test the exhaustive legal and illegal Stage/Gate transition matrix through the engine interface.
- Test stale revision, duplicate idempotency, lease reconciliation, and notification outbox handling.
- Test process-wide semaphore reservation races, queued cancellation, bounded session shutdown, and interrupted recovery.
- Test all three Implementation Context choices; Gate-bound `smart_compact` unavailable/succeeded/no-op/failed reports; required actionable failure errors; active-tool validation; intent-bound normal-compaction `onComplete`/`onError` callbacks; available-tool failure without fallback; and stale Gate, preparation, plan, run, and active-session identities.
- Test fresh-session intent persistence before `newSession`, exact shutdown claim, immediate target `session_start` exemption, `withSession` consumption, cancelled replacement, active-session rotation, old-session mutation rejection, and recovery of unconsumed claims on later startup/reload/resume/fork or expiry, plus the no-active-child transition precondition.
- Test cumulative reviewer profile/session exclusion, read-only postconditions, and failure when no independent reviewer exists.
- Test non-trivial UI classification cannot bypass structural candidate evidence, user acceptance, or prototype cleanup.
- Test analysis and pre-approval feature modes cannot activate mutation, recursive orchestration, interaction, process, or unaudited extension tools.
- Test malformed, duplicate, oversized, unauthenticated, and over-budget script IPC plus cancellation escalation.
- Test atomic persistence and backward-tolerant dashboard reads.
- Manually validate Gate dialogs, background delivery, dashboard navigation, browser prototype handoff, and responsive candidates in Pi TUI and the application.
## Precedents &amp; Lessons
- `_workflows` already proves bounded sandbox IPC, atomic artifacts, child-session execution, transcript capture, and dashboard rendering.
- `extensions/shared/child-session.ts` is the source of truth for project trust inheritance, recursive-tool exclusion, and bounded child teardown.
- `extensions/shared/tool-call-timeout.ts` must continue guarding tools registered after child startup.
- `extensions/subagents` demonstrates synchronous capacity reservation, normalized lifecycle state, and duplicate-delivery hazards.
- `skills/design/prototype/UI.md` requires structurally different variants, realistic host context, browser review, and throwaway cleanup.
- `skills/develop/code-review/SKILL.md` establishes independent standards and specification review as separate concerns.
- `config/pi-links.json` is the only approved exposure mechanism for repository-managed global extensions.
+101
View File
@@ -0,0 +1,101 @@
# workflow usability update plan
Status: manual recovery plan after managed Workflow Runs `512d6c31`, `51b0c1cb`, and `ecb11e1e` failed or were interrupted before implementation.
## Locked decisions
- The interactive dashboard automatically enters a fresh plan-seeded session. Tool and RPC callers receive `/workflow continue <run-id>` instead.
- Startup may adopt a continuable run only when its prior owner is stale or dead. A live owner remains fail-closed.
- The widget above Pi's editor shows only the newest attached active run.
- Dashboard navigation, action sheets, Gates, confirmations, questions, and feedback use popup overlays in TUI mode. RPC, print, and JSON paths remain linear.
- The plan reader is a full-screen overlay with an H1-H3 outline, current-section highlight, arrows, Page Up/Page Down, Home/End, and Escape.
- The outline is visible at 80 columns and wider, hidden from 60 through 79 columns, and replaced by a truthful minimum-size message below 48x12.
- Dirty source changes require a bounded TUI warning and explicit confirmation when `allowDirtySource` is omitted. TUI starts honor an explicit `allowDirtySource: true` without prompting. Non-TUI tool, RPC, print, and JSON starts require `allowDirtySource: true`. Approval is not tied to a later status digest recheck.
- Approved host commands retain a three-minute timeout. Internal Git commands receive a 30-second timeout. Process-tree termination is bounded on every platform.
- Prototype direction C, drill-down overlays with a dedicated full-screen reader, is the baseline after comparing A, B, and C.
## Failure evidence captured during this change
- Run `512d6c31-5bde-4e93-8164-5d31fb684b00` reached design, described a prototype phase, but emitted no `prototype` assignment. The engine terminated with `invalid-design-output: Design must select exactly one prototype Assignment`.
- Run `51b0c1cb-f5b2-47f9-8c0c-b323307b720b` was interrupted during discovery.
- Run `ecb11e1e-fe38-4076-862e-739498dbe33b` completed discovery, then remained in the feature-designer assignment for nearly five minutes until interrupted.
These failures are acceptance-test inputs for assignment timeout handling and designer guidance.
## Implementation phases
### 1. Prototype overlays
Own only `docs/workflow/dashboard-mocks.md` and isolated prototype artifacts. Compare:
- A: centered compact modal
- B: near-full-screen workspace with list/detail panes
- C: drill-down overlays with a dedicated full-screen plan reader
Validate wide, 80x24, 60-column, and 47x11 frames. Production TypeScript remains untouched until the prototype direction is accepted.
### 2. Session lifecycle and recovery
- Route the dashboard's fresh-session action through the existing `handleContinue()` and `ctx.newSession({ withSession })` path.
- Add an integration test proving a dashboard result triggers session replacement without a second command.
- During absent/dead startup adoption, atomically rotate both `lease.activeParentSessionId` and `implementationContext.activeParentSessionId`.
- Preserve live-owner, active-assignment, and historical-session fences.
Primary files: `dashboard.ts`, `context-transition.ts`, `continuation.ts`, `engine.ts`, and focused tests.
### 3. Worktree safety and command deadlines
- Return bounded dirty path/status evidence instead of rejecting all ordinary source dirt.
- Keep conflicts, unmerged entries, repository identity, ignored-root, branch collision, and target-path checks fail-closed.
- Create the worktree from the pinned `HEAD`; warning copy states source-only changes are omitted.
- Add `allowDirtySource` to tool/domain inputs and idempotency fingerprints.
- Apply 30-second timeouts to every internal Git invocation.
- Keep approved commands at three minutes and bound Windows `taskkill` itself.
- Preserve exit `124` for timeout and `125` for termination failure.
Primary files: `workspace.ts`, `domain.ts`, `tool.ts`, `engine.ts`, and focused tests.
### 4. Popup TUI and plan reader
- Add reusable, modeless overlay components with one earned border, visible selection, keyboard hints, width-safe rendering, and focus propagation for embedded `Input` or `Editor` children.
- Use a drill-down stack: run list to run detail to action/Gate overlay. Escape always returns one level or closes.
- Parse Markdown H1-H3 headings into a pure outline model.
- Render only the current plan viewport, not the entire artifact.
- Sanitize untrusted transcript/plan control sequences before rendering.
- Keep `ctx.ui.custom()` guarded by `ctx.mode === "tui"`.
Primary files: new `tui.ts` and tests, plus orchestration changes in `dashboard.ts`.
### 5. Persistent progress widget
- Add a pure projection for readable label, active stage, completed/total core stages, and open Gate.
- Refresh from persisted attached runs after `afterRunPersist` and `session_start`.
- Clear after terminal state and `session_shutdown`.
- Render one bounded line at narrow widths.
Primary files: new `progress.ts` and tests, plus registration in `index.ts`.
### 6. Design-contract and timeout regression
- Strengthen the bundled feature-designer instructions so non-trivial UI plans explicitly select exactly one eligible prototype assignment with isolated ownership.
- Add a focused test for the exact missing-prototype failure and guidance contract.
- Ensure assignment execution cannot wait forever; surface timeout/interruption evidence without falsely reporting success.
- Record any behavior that cannot be safely fixed in this slice in `docs/todo.md` with the three run IDs above.
Primary files: `agents/feature-designer.md`, engine/execution tests, and related runtime code.
### 7. Documentation, verification, and review
Update the README, design document, dashboard mocks, and a superseding ADR. Run focused tests, typecheck, full tests, and manual Pi validation at wide, 80x24, 60-column, and 47x11 sizes. An agent that did not implement the change performs the final standards and specification review.
## Acceptance criteria
- Fresh-session selection continues automatically in interactive Pi without restart or a second command.
- A new Pi process can adopt an absent/dead continuable run but cannot steal one from a live owner.
- Exactly one newest active-run widget is visible above the editor and clears promptly.
- Every bounded TUI interaction is an overlay; RPC/print/JSON remain usable and never call unsupported custom overlays.
- The full-screen plan reader meets the locked outline, navigation, responsive, and width contracts.
- Dirty source starts are warned and explicitly authorized while conflicts remain blocked.
- No internal Git or approved host subprocess can wait indefinitely, and process cleanup is bounded.
- The designer contract prevents the missing-prototype-assignment failure, while assignment execution has a bounded failure path.
- Focused tests, typecheck, full tests, manual Pi validation, and independent review pass.