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
@@ -2,9 +2,9 @@
status: accepted
---
# Build pi-workflow around persisted policy gates
# Build workflow around persisted policy gates
`pi-workflow` will be a new extension rather than an activation or rename of `_workflows`. It will expose one command-style tool backed by atomic revisioned snapshots, Markdown Agent Profiles, deterministic eligibility followed by planner selection, a mandatory feature pipeline, and restricted feature or read-only analysis scripts. Every feature run receives a distinct exclusive worktree. Concurrency defaults to 8 under an immutable process-wide maximum of 32. Non-trivial UI work requires at least three structurally distinct prototypes and explicit user acceptance. Before implementation, the user chooses a fresh plan-seeded session, compaction of the current session that prefers `smart_compact` and falls back to normal Pi compaction when unavailable, or unchanged current context. Review uses a fresh session and excludes every Agent Profile that mutated the reviewed diff.
`workflow` will be a new extension rather than an activation or rename of `_workflows`. It will expose one command-style tool backed by atomic revisioned snapshots, Markdown Agent Profiles, deterministic eligibility followed by planner selection, a mandatory feature pipeline, and restricted feature or read-only analysis scripts. Every feature run receives a distinct exclusive worktree. Concurrency defaults to 8 under an immutable process-wide maximum of 32. Non-trivial UI work requires at least three structurally distinct prototypes and explicit user acceptance. Before implementation, the user chooses a fresh plan-seeded session, compaction of the current session that prefers `smart_compact` and falls back to normal Pi compaction when unavailable, or unchanged current context. Review uses a fresh session and excludes every Agent Profile that mutated the reviewed diff.
This keeps the caller interface small while making approval, prototype, recovery, and reviewer-independence rules enforceable in one workflow engine. We rejected unrestricted custom graphs because they could bypass policy, a general registry architecture because it adds speculative extension points, and event-sourced persistence because revisioned snapshots already provide the required recovery and audit data with less machinery.
@@ -1,3 +0,0 @@
# Reuse standard agents through workflow role overlays
`pi-workflow` will reuse standard `pi-interactive-subagents` definitions instead of duplicating their prompts and model settings in workflow-only agents. Explicit configuration maps standard agent names to workflow roles, while `pi-workflow` retains ownership, tool-intersection, Gate, verification, and reviewer-independence policy. The default maps `scout` to Discovery and `worker` to Implementation; bundled profiles remain fallbacks for roles without a standard mapping. This keeps one source of truth for agent identity without allowing arbitrary prompt prose or agent names to imply mutability or workflow authority.
@@ -1,11 +1,11 @@
---
status: accepted
supersedes: 0001-pi-workflow-architecture-24AUG2026.md
supersedes: 0001-workflow-architecture-24AUG2026.md
---
# Use drill-down overlays and bounded recovery
This decision supersedes the dashboard, dirty-source, execution-timeout, and startup-ownership assumptions in [ADR 0001](./0001-pi-workflow-architecture-24AUG2026.md). The persisted gated pipeline, worktree isolation, and independent-review decisions from ADR 0001 remain accepted.
This decision supersedes the dashboard, dirty-source, execution-timeout, and startup-ownership assumptions in [ADR 0001](./0001-workflow-architecture-24AUG2026.md). The persisted gated pipeline, worktree isolation, and independent-review decisions from ADR 0001 remain accepted.
## Context
@@ -39,7 +39,7 @@ Static prototypes compared a centered compact modal, a near-full-screen workspac
- Dead ownership can recover without manual state surgery. A running process or Assignment cannot be displaced based only on an old heartbeat.
- Users may proceed from a dirty source checkout without copying local changes into the worktree. Persisted evidence records what was knowingly omitted.
- Git, host-command cleanup, and child execution now have bounded failure paths rather than indefinite waits.
- Direction C has automated renderer and orchestration coverage. Its completed manual application validation is recorded below. The static frames in `docs/pi-workflow/dashboard-mocks.md` remain labeled prototype evidence, not production screenshots.
- Direction C has automated renderer and orchestration coverage. Its completed manual application validation is recorded below. The static frames in `docs/workflow/dashboard-mocks.md` remain labeled prototype evidence, not production screenshots.
## Manual application validation
@@ -0,0 +1,3 @@
# Reuse standard agents through workflow role overlays
`workflow` will reuse standard `pi-interactive-subagents` definitions instead of duplicating their prompts and model settings in workflow-only agents. Explicit configuration maps standard agent names to workflow roles, while `workflow` retains ownership, tool-intersection, Gate, verification, and reviewer-independence policy. The default maps `scout` to Discovery and `worker` to Implementation; bundled profiles remain fallbacks for roles without a standard mapping. This keeps one source of truth for agent identity without allowing arbitrary prompt prose or agent names to imply mutability or workflow authority.
@@ -0,0 +1,21 @@
# Package Pi extensions as a Bun workspace catalog
## Decision
Keep extension sources under `extensions/*` and make each maintained extension directory a Bun workspace with its own package manifest. Use the `@_jb/pi-*` namespace, a root Bun catalog for external dependency versions, and `workspace:^` for repository-owned libraries. The repository root is private and is no longer itself a Pi package.
Publish packages to the `jb` owner endpoint of the Gitea npm registry. Repository configuration maps `@_jb` to `https://git.jb.codes/api/packages/jb/npm/`; credentials remain in the user environment or user-level npm configuration and are never committed.
`extensions/shared` is the publishable `@_jb/pi-shared` library. Extensions that import it declare a normal runtime dependency so Pi's production package installation receives the required code.
`extensions/_workflows` is reference code, not a package or publishable extension. `@_jb/pi-workflow` remains a private workspace until the required reference runtime is merged under `extensions/workflow`; this prevents publishing two workflow packages or publishing an incomplete package.
The existing `config/pi-links.json` policy remains the authority for live-development exposure. Package boundaries and publication do not automatically enable extensions globally.
## Consequences
- Bun owns dependency installation and `bun.lock`; `package-lock.json` is removed.
- Catalog and workspace protocols require `bun publish` or `bun pm pack` before npm publication so concrete versions are written into package metadata.
- Shared libraries must be published before extensions that depend on the same new version.
- Pi packages continue shipping TypeScript source because Pi loads extension entrypoints directly.
- The `workflow` merge is an explicit blocker for its first release.
@@ -0,0 +1,25 @@
# Import external Pi packages as reviewed main-branch snapshots
## Decision
Import the tracked files from the `main` branch of these repositories into Bun workspaces:
| Source | Imported commit | Workspace | Package |
| --- | --- | --- | --- |
| `jb/pi-interactive-subagents` | `a3cd328edef59ad491d4f35f9fbadf8ec80cadc4` | `extensions/interactive-subagents` | `@_jb/pi-interactive-subagents` |
| `jb/pi-native-hooks` | `73fa3299bf30fd6da5abfc74a0ee7a36e0a07f0a` | `extensions/native-hooks` | `@_jb/pi-native-hooks` |
| `jb/pi-todo-herdr` | `d9e1ffec51e25238e0baec48ce1303893f13849f` | `extensions/todo-herdr` | `@_jb/pi-todo-herdr` |
Carry snapshots rather than submodules, subtrees, or unrelated Git histories. The monorepo owns package manifests, dependency normalization, compatibility changes, tests, and releases after import. Preserve source attribution in each package.
Record source URLs, branches, and commits in `config/imported-packages.json`. `bun run imports:check` compares those commits with current remote `main` heads. The staging command in `scripts/import-package-snapshots.mjs` clones fresh snapshots outside the repository for explicit review; it never overwrites the maintained workspaces.
Rename the private `pi-workflow` extension identity to `workflow`. Its workspace is `extensions/workflow`, its tool and user-facing runtime identifiers use `workflow`, and its configuration/state paths use the same name. The npm package remains `@_jb/pi-workflow` under the repository's `@_jb/pi-<name>` convention.
## Consequences
- The three imported extensions share the Bun lockfile and catalog with the rest of the monorepo.
- Published packages use the scoped Gitea registry instead of Pi-managed Git sources.
- Upstream movement is detected but never merged automatically; imported changes require reconciliation with monorepo-specific manifests and APIs.
- Only `main` is tracked. Source tags, branches, and historical commits are not copied.
- The renamed `workflow` extension remains private until its `_workflows` dependencies are merged and isolated packaging succeeds.
+13 -13
View File
@@ -94,7 +94,7 @@ Node/Bun Python/Rust/Go/Java local integrations child isol
| | | |
+--------------------+--------------------------+---------------------+
v
Slice 6B2: pi-workflow/toolchain broker
Slice 6B2: workflow/toolchain broker
|
v
Slice 7A: Docker/browser Slice 7B: release/production Slice 7C: maintenance
@@ -155,7 +155,7 @@ Slices in the same row may proceed in parallel after their listed dependencies a
- one selected provider route;
- no package registries, SSH, Docker, browser, microphone, deployment credentials, or broad localhost access.
4. Separate extension source from extension state. Confirm that normal sessions cannot modify global instructions, installed extension code, authentication state, other Pi profiles, or sibling repositories.
5. Materialize the normal in-process extension allowlist as a generated, isolated Pi `settings.json` under the selected personal/work state root. Its package/extension entries come only from `config/pi-package-lock.json` and the trusted repository map. Disable `pi-ask` arbitrary notification commands, `/update`, `pi-workflow`, background shell jobs, and any privileged direct spawn path until a controlled subprocess policy exists.
5. Materialize the normal in-process extension allowlist as a generated, isolated Pi `settings.json` under the selected personal/work state root. Its package/extension entries come only from `config/pi-package-lock.json` and the trusted repository map. Disable `pi-ask` arbitrary notification commands, `/update`, `workflow`, background shell jobs, and any privileged direct spawn path until a controlled subprocess policy exists.
6. Import the unmanaged `~/.pi/agent/extensions/lm-studio.ts` implementation into a repository-managed extension at `extensions/lm-studio/index.ts`, lock its source revision, and change its fixed base URL contract to `http://127.0.0.1:1234/v1`. Maintenance moves the old extension to the quarantined state store and removes its active settings entry. A duplicate-provider test fails if the old source, another `lm-studio` registration, or `localhost` base URL remains loadable.
7. Define and own stable profile fragments for `provider-lm-studio`, `provider-openai`, `provider-anthropic`, and `provider-morph`, granting only one route at launch. Prove nono 0.74's `tcp_connect_ports` behavior with real loopback fixtures listening on ports 1234 and 1235: the selected provider must connect to 1234 while 1235 and every other loopback port fail. Do not use hostname-only `allow_domain` as evidence of port restriction. If the fixture cannot prove exact enforcement, `provider-lm-studio` remains unavailable until a separately reviewed mediated relay is designed.
@@ -165,7 +165,7 @@ Slices in the same row may proceed in parallel after their listed dependencies a
- The selected provider works while non-selected provider hosts, raw key environment names, and credentials are absent from the environment and process table.
- Reads outside the exact Pi state, declared active-worktree access, and per-launch temporary paths fail; writes to a read-only active worktree fail; another session's temporary directory is inaccessible.
- LM Studio, when selected, reaches only `127.0.0.1:1234`.
- `/update`, `pi-workflow`, arbitrary notification commands, and unbrokered background shell jobs are unavailable.
- `/update`, `workflow`, arbitrary notification commands, and unbrokered background shell jobs are unavailable.
- The repository-managed LM Studio provider uses only the exact `127.0.0.1:1234` base URL, the old unmanaged source is quarantined, duplicate registration fails, and a real two-port fixture proves all other loopback ports are denied.
- All base and provider profiles pass strict validation and resolved-policy review.
@@ -342,7 +342,7 @@ A failed pilot returns to the owning slice. Do not compensate by broadening the
**Owner surfaces:** `profiles/nono/{node-npm,pnpm,bun}.json` and disjoint tests under `tests/nono/capabilities/{node-npm,pnpm,bun}/`.
**Work:** grant each command the active repository, exact cache/store paths, required registry and artifact hosts, and a token-free normal configuration. Separate install/build/test from publish. Cover lockfile-respecting commands used by the mapped repositories. Treat npm/pnpm/Bun lifecycle scripts and `npm test`, `npm run`, `pnpm run`, and equivalents as shell-spawning paths: prove their children inherit the package-manager command sandbox and cannot invoke SSH, Docker, browsers, deployment tools, sibling repositories, raw credentials, or an alternate package binary. Keep `pi-workflow` disabled until Slice 6B2 integrates its executor with these completed policies.
**Work:** grant each command the active repository, exact cache/store paths, required registry and artifact hosts, and a token-free normal configuration. Separate install/build/test from publish. Cover lockfile-respecting commands used by the mapped repositories. Treat npm/pnpm/Bun lifecycle scripts and `npm test`, `npm run`, `pnpm run`, and equivalents as shell-spawning paths: prove their children inherit the package-manager command sandbox and cannot invoke SSH, Docker, browsers, deployment tools, sibling repositories, raw credentials, or an alternate package binary. Keep `workflow` disabled until Slice 6B2 integrates its executor with these completed policies.
**Acceptance criteria:** installs, builds, and tests work in representative npm, pnpm, and Bun fixtures; adversarial lifecycle/run scripts remain inside the command policy; sibling repositories, unrelated caches, privileged commands, and raw credentials remain unavailable; publish credentials and commands are absent outside release mode.
@@ -381,32 +381,32 @@ A failed pilot returns to the owning slice. Do not compensate by broadening the
## Slice 6B1: Child-agent and background-task isolation
**Goal:** isolate spawned Pi, Claude, Codex, bounded background jobs, Herdr panes, and tmux panes without enabling repository toolchain execution or `pi-workflow`.
**Goal:** isolate spawned Pi, Claude, Codex, bounded background jobs, Herdr panes, and tmux panes without enabling repository toolchain execution or `workflow`.
**Owner surfaces:** `profiles/nono/{child-pi,child-claude,child-codex,background-jobs}.json`, new spawn-wrapper sources under `scripts/nono/child-agents/`, isolated child-state configuration, and `tests/nono/capabilities/child-agents/`. Coordinate with extension owners but avoid editing Slice 6A's socket fragments or shared extension files concurrently.
**Work:**
1. Inventory every spawn path in active subagent, `pi-ask`, update, and background-task extensions. Classify each in-process operation as safe UI/state access, disabled behavior, or a brokered subprocess. Keep `pi-workflow` absent from generated settings.
1. Inventory every spawn path in active subagent, `pi-ask`, update, and background-task extensions. Classify each in-process operation as safe UI/state access, disabled behavior, or a brokered subprocess. Keep `workflow` absent from generated settings.
2. Route child Pi, Claude, and Codex through command policies with isolated child state and the immutable provider selected by Slice 3.
3. Broker only named background jobs and notification commands that do not invoke repository toolchains; keep arbitrary commands, package updates, and direct privileged spawn paths disabled.
4. Define caller relationships and prohibit privileged-command escalation through child commands.
5. Verify Herdr and tmux targets launch under equivalent or narrower generated policies before enabling command delivery.
6. Add containment tests for nested children, background completion, cancellation, inherited environment, provider override denial, notification commands, package-update denial, and artifact paths.
**Acceptance criteria:** child commands receive no broader filesystem, network, credential, socket, environment, or provider access than declared; nested child tests prove containment; unsandboxed Herdr/tmux targets are rejected; bounded extension behavior remains functional without `pi-workflow` or toolchain execution.
**Acceptance criteria:** child commands receive no broader filesystem, network, credential, socket, environment, or provider access than declared; nested child tests prove containment; unsandboxed Herdr/tmux targets are rejected; bounded extension behavior remains functional without `workflow` or toolchain execution.
**Dependencies:** pilot acceptance. May run in parallel with Slices 5A, 5B, and 6A.
## Slice 6B2: `pi-workflow` and toolchain integration
## Slice 6B2: `workflow` and toolchain integration
**Goal:** enable `pi-workflow` only after every toolchain command it can invoke has a completed command policy.
**Goal:** enable `workflow` only after every toolchain command it can invoke has a completed command policy.
**Owner surfaces:** `profiles/nono/pi-workflow.json`, workflow spawn-wrapper sources under `scripts/nono/child-agents/pi-workflow/`, the generated extension allowlist entry, and `tests/nono/capabilities/pi-workflow/`.
**Owner surfaces:** `profiles/nono/workflow.json`, workflow spawn-wrapper sources under `scripts/nono/child-agents/workflow/`, the generated extension allowlist entry, and `tests/nono/capabilities/workflow/`.
**Work:** route `pi-workflow` executable resolution and every npm/pnpm/Bun/Python/Rust/Go/Maven/Gradle task through the completed Slice 5 policies. Include lifecycle/run scripts, nested package executables, verification commands, and cancellation. Any unmodeled executable or repository without the required toolchain fragment fails before workflow execution.
**Work:** route `workflow` executable resolution and every npm/pnpm/Bun/Python/Rust/Go/Maven/Gradle task through the completed Slice 5 policies. Include lifecycle/run scripts, nested package executables, verification commands, and cancellation. Any unmodeled executable or repository without the required toolchain fragment fails before workflow execution.
**Acceptance criteria:** adversarial workflow tasks cannot bypass toolchain policies, select another provider, invoke high-risk commands, read sibling repositories, or access raw credentials; repositories lacking a required toolchain capability do not load `pi-workflow`.
**Acceptance criteria:** adversarial workflow tasks cannot bypass toolchain policies, select another provider, invoke high-risk commands, read sibling repositories, or access raw credentials; repositories lacking a required toolchain capability do not load `workflow`.
**Dependencies:** Slices 5A, all applicable 5B language fragments, and Slice 6B1. It does not run in parallel with the toolchain policy it consumes.
@@ -479,7 +479,7 @@ To keep parallel work mergeable:
| Base filesystem | Active registered worktree has exactly its mapped read-only or read/write access; exact mutable Pi state and the per-launch temporary directory are writable | A read-only worktree cannot be written; broad `/tmp`, runtime parents, other sessions, sibling or unregistered worktrees, global instructions, extension source, other Pi state, `~/.ssh`, and `~/.config/gh` are inaccessible or read-only as designed |
| Temporary lifecycle | Normal exit and cancellation remove the private runtime directory; approved active use remains within its aggregate bound | Cleanup preserves a held lease, matching PID/start time, populated cgroup, live unit, or inconclusive identity; proven crash leftovers expire, unsafe paths survive for review, and an active session cannot exhaust `/run` |
| Worktree lifecycle | Broker creates, registers, resolves, and safely removes an external clean worktree | Broad worktree-root access, age-only deletion, dirty/untracked/unpushed removal, active-worktree removal, and linked-worktree confidentiality claims fail |
| Environment/extensions | Reviewed extensions and selected mediated provider credential work | Raw credential variables, old LM Studio source, duplicate providers, `/update`, `pi-workflow` before 6B2, arbitrary notification commands, and unbrokered shell jobs are absent |
| Environment/extensions | Reviewed extensions and selected mediated provider credential work | Raw credential variables, old LM Studio source, duplicate providers, `/update`, `workflow` before 6B2, arbitrary notification commands, and unbrokered shell jobs are absent |
| Provider | Trusted default or one pre-boundary approved flag selects the route; LM Studio reaches port 1234 | Ambiguous/post-boundary/child overrides, non-selected providers, LM Studio port 1235, and broad localhost fail |
| Git/SSH | Fetch/push uses the correct provisioned agent and immutable wrapper | Direct SSH, stale/substituted agent, bypass config, alternate binary, same-port host, wrong agent, wrong host, and wrong port fail |
| GitHub CLI | Active-repository operation succeeds through proxy | Real token exposure, cross-repository API, and unapproved endpoints fail |
+3 -3
View File
@@ -20,9 +20,9 @@ Captured for Slice 0 on 27AUG2026 with nono 0.74.0. This record contains no cred
| `pi-orca-local` | Symlink to `profiles/nono/pi-orca-local.json` | Approved drift imported, narrowed to read-only trusted-file access, and relinked on 27AUG2026. |
| `pi-harness-tools` | Symlink to `profiles/nono/pi-harness-tools.json` | Approved drift imported, narrowed to read-only trusted-file access, and relinked on 27AUG2026. |
The imported `pi-orca-local` drift is limited to exact read-only access for `$HOME/.pi/agent/AGENTS.md`. Its saved grant for `$HOME/.pi/agent/extensions/pi-workflow/index.ts` was not imported because the user removed that extension and deferred its replacement to a future skill. The imported `pi-harness-tools` drift is limited to exact read-only access for `$HOME/.pi/agent/extensions/pi-todo-herdr/index.ts` and `$HOME/.config/herdr/herdr.sock`. Its inherited `pi-local` policy already contains the Herdr Unix-socket grant. The active files used read/write `allow_file` saved grants; the repository deliberately narrows them to `read_file` because normal sessions do not need to modify trusted instructions or extension code. No other active saved grant was imported.
The imported `pi-orca-local` drift is limited to exact read-only access for `$HOME/.pi/agent/AGENTS.md`. Its saved grant for `$HOME/.pi/agent/extensions/workflow/index.ts` was not imported because the user removed that extension and deferred its replacement to a future skill. The imported `pi-harness-tools` drift is limited to exact read-only access for `$HOME/.pi/agent/extensions/pi-todo-herdr/index.ts` and `$HOME/.config/herdr/herdr.sock`. Its inherited `pi-local` policy already contains the Herdr Unix-socket grant. The active files used read/write `allow_file` saved grants; the repository deliberately narrows them to `read_file` because normal sessions do not need to modify trusted instructions or extension code. No other active saved grant was imported.
The `pi-workflow` extension was unlinked from active Pi state by the user during this slice. It is also absent from normal `config/pi-links.json` exposure so reconciliation will not recreate it. The future replacement is tracked in `docs/todos.md`.
The `workflow` extension was unlinked from active Pi state by the user during this slice. It is also absent from normal `config/pi-links.json` exposure so reconciliation will not recreate it. The future replacement is tracked in `docs/todos.md`.
## Draft disposition
@@ -53,7 +53,7 @@ The `.nono-pi-pack-marker` is package wiring, not a profile draft, and remains i
Only `@pi-kaush/pi-welcome-screen@0.1.3` is currently locked end to end. Bare npm sources, `@latest`, and Git URLs without revisions remain blocked even though their installed contents are identified. `nolabs-ai/pi` remains blocked because the nono lockfile records `pinned: false`.
The extension inventory records the active repository-backed links and their observed commits. Mutable checkout targets and unmanaged links remain blocked until maintenance installs immutable snapshots. The unmanaged active `lm-studio.ts` file is recorded by SHA-256 and remains blocked pending the Slice 1 import and quarantine. `update` remains actively linked at capture time but has been removed from normal link exposure. The active `pi-workflow` link was removed by the user and is not part of the current active inventory.
The extension inventory records the active repository-backed links and their observed commits. Mutable checkout targets and unmanaged links remain blocked until maintenance installs immutable snapshots. The unmanaged active `lm-studio.ts` file is recorded by SHA-256 and remains blocked pending the Slice 1 import and quarantine. `update` remains actively linked at capture time but has been removed from normal link exposure. The active `workflow` link was removed by the user and is not part of the current active inventory.
## Maintenance-only follow-up
+59
View File
@@ -0,0 +1,59 @@
# Bun workspace packages and Gitea npm publishing
The repository uses Bun workspaces under `extensions/*`. External dependency versions live in the root `package.json` catalog; repository-owned dependencies use `workspace:^`.
Publishable packages include the repository-native extensions plus the imported `@_jb/pi-interactive-subagents`, `@_jb/pi-native-hooks`, and `@_jb/pi-todo-herdr` snapshots. `config/imported-packages.json` records their source `main` commits; use `bun run imports:check` to detect upstream movement.
## Install and verify
```bash
bun install --frozen-lockfile
bun run typecheck
bun run test
```
Use plain `bun install` when intentionally updating `bun.lock`.
## Registry configuration
The tracked `.npmrc` routes only the `@_jb` scope:
```ini
@_jb:registry=https://git.jb.codes/api/packages/jb/npm/
```
Configure a Gitea personal access token with package permissions outside the repository:
```ini
//git.jb.codes/api/packages/jb/npm/:_authToken=${GITEA_NPM_TOKEN}
```
The token line may live in `~/.npmrc`, or `GITEA_NPM_TOKEN` may be supplied by the publishing environment. Never commit a token.
## Pack and publish
Bun must resolve `catalog:` and `workspace:` references before publication. From a publishable workspace:
```bash
cd extensions/shared
bun pm pack --destination ../../dist
bun publish
```
Publish `@_jb/pi-shared` before a new version of any extension that depends on it. Gitea rejects republishing an existing name/version, so bump the changed package version first.
`extensions/workflow` is intentionally private until the `_workflows` reference dependencies are merged into that package. `extensions/_workflows` must not be published.
## Install with Pi
After configuring the same scope and token in the npm configuration visible to Pi:
```bash
pi install npm:@_jb/pi-dictate
pi install npm:@_jb/pi-file-search
pi install npm:@_jb/pi-interactive-subagents
pi install npm:@_jb/pi-native-hooks
pi install npm:@_jb/pi-todo-herdr
```
Pi installs runtime dependencies from the same scoped registry. The repository's symlink-based development exposure remains controlled separately by `config/pi-links.json`.
+1 -1
View File
@@ -1,3 +1,3 @@
# TODO
- [ ] Make pi-workflow verification tolerate inaccessible sibling Git worktrees. `GitStateProbe.captureRepository()` currently enumerates every path from `git worktree list --porcelain` and fails the verification command before execution when any unrelated worktree cannot be inspected. Preserve detection of cross-worktree mutations without making unrelated worktrees a hard verification dependency. Add focused coverage for an inaccessible registered sibling worktree.
- [ ] Make workflow verification tolerate inaccessible sibling Git worktrees. `GitStateProbe.captureRepository()` currently enumerates every path from `git worktree list --porcelain` and fails the verification command before execution when any unrelated worktree cannot be inspected. Preserve detection of cross-worktree mutations without making unrelated worktrees a hard verification dependency. Add focused coverage for an inaccessible registered sibling worktree.
+6 -2
View File
@@ -1,5 +1,9 @@
# Todos
## Merge `_workflows` reference runtime into `workflow`
`extensions/_workflows` was retained only as a reference while `extensions/workflow` was developed, but `workflow` still imports its runner, model, prompt, and serialization modules. Move the required code under `extensions/workflow`, remove obsolete model-authored workflow surfaces, update tests and documentation, and then delete the reference directory. Until that work is complete, `@_jb/pi-workflow` must remain a private Bun workspace and `extensions/_workflows` must remain excluded from workspaces and publication. Acceptance requires `bun pm pack` for `workflow` to contain every runtime import without reaching outside the package root, followed by an isolated Pi package smoke test.
## Make `pi-links` checks work from linked worktrees
A Slice 0 `node scripts/pi-links.mjs prune --dry-run` from `.worktrees/nono-dynamic-permissions-slice-zero-direct` exited 2 and classified every active link into the primary checkout as an outside-repository conflict. The tool anchors ownership to the current worktree root, while active links correctly target the primary repository checkout. Teach check and dry-run planning to recognize canonical checkouts sharing the same Git common directory without broadening stale-link deletion to unrelated repositories. Add linked-worktree fixtures before changing prune behavior. Until fixed, run host reconciliation only from the integrated primary checkout.
@@ -8,9 +12,9 @@ A Slice 0 `node scripts/pi-links.mjs prune --dry-run` from `.worktrees/nono-dyna
Slice 1 found two Nono 0.74 limitations while building behavioral policy proofs. First, command-policy startup fails with `path must be shorter than SUN_LEN` when Nono creates its supervisor socket beneath a moderately long isolated `TMPDIR` such as `/tmp/nono-slice-one-*/sessions/personal/tmp`. Before broker profiles activate command policies, reproduce the maximum safe path, then have the launcher select a private short socket root or confirm an upstream fix. Second, `nono profile show --json` omits resolved `environment`, `command_policies`, `network.connect_port`, and `network.custom_credentials` fields even though strict validation and live enforcement accept them. Do not treat resolved JSON as complete evidence for these capabilities; retain behavioral `nono run` and `nono why --command` proofs until the output is complete and regression-tested.
## Replace `pi-workflow` with a skill-based orchestrator
## Replace `workflow` with a skill-based orchestrator
The strict `pi-workflow` extension repeatedly failed before implementation because planner output and persisted state-machine constraints were too brittle for adaptive subagent orchestration. In a separate session, design a repository-managed skill where the main Pi agent owns the plan, task tree, isolated worktree, explicit user approval gates, verification, and independent review while launching standard `scout` and `worker` subagents directly. Preserve file-ownership boundaries, no inferred approvals, review independence, and resumable repository evidence, but prefer native Pi primitives over a custom orchestration engine. Evaluate a small committed state manifest for crash recovery before retiring or archiving the extension. Use the abandoned `.worktrees/pi-workflow-plan-seed` implementation only as reference; do not integrate it by default.
The strict `workflow` extension repeatedly failed before implementation because planner output and persisted state-machine constraints were too brittle for adaptive subagent orchestration. In a separate session, design a repository-managed skill where the main Pi agent owns the plan, task tree, isolated worktree, explicit user approval gates, verification, and independent review while launching standard `scout` and `worker` subagents directly. Preserve file-ownership boundaries, no inferred approvals, review independence, and resumable repository evidence, but prefer native Pi primitives over a custom orchestration engine. Evaluate a small committed state manifest for crash recovery before retiring or archiving the extension. Use the abandoned `.worktrees/workflow-plan-seed` implementation only as reference; do not integrate it by default.
## Support subagent launches through `multi_tool_use.parallel`
@@ -1,6 +1,6 @@
# pi-workflow
# workflow
`pi-workflow` plans and implements feature work through persisted human Gates, isolated Git worktrees, focused verification, and independent review.
`workflow` plans and implements feature work through persisted human Gates, isolated Git worktrees, focused verification, and independent review.
## Start a feature
@@ -10,9 +10,9 @@ Start with:
/workflow start <message>
```
The command sends the message through the assistant, which chooses the descriptive feature name and idempotency key before invoking `pi_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.
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 `pi_workflow` with:
You can also ask the assistant to use `workflow` with:
- `action: "start"`
- `workflow: { mode: "feature" }` (or omit `workflow`)
@@ -37,9 +37,9 @@ The assistant must inspect the current run before each state-changing call and o
## Agent selection
`pi-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.
`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/pi-workflow.json` or trusted `.pi/pi-workflow.json`:
Configure or disable mappings in `~/.pi/agent/workflow.json` or trusted `.pi/workflow.json`:
```json
{
@@ -99,11 +99,11 @@ Interrupted work opens a Recovery Gate with retry, inspect, and abort choices. C
Run state and bounded artifacts are stored under:
```text
~/.pi/agent/pi-workflows/runs/<run-id>/
~/.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 `pi-workflow`.
Repository-managed extension links are controlled through `config/pi-links.json`. Run `/reload` after the managed link is synchronized so Pi discovers `workflow`.
@@ -1,10 +1,10 @@
# pi-workflow popup prototypes
# 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: `pi-workflow-usability-resume`, waiting at Plan Approval after Discover and Design.
Representative run: `workflow-usability-resume`, waiting at Plan Approval after Discover and Design.
## A. Centered compact modal
@@ -13,8 +13,8 @@ A small modal preserves the surrounding conversation and keeps one decision in f
```text
┌──────────────────────────────────────────────────────────────────────┐
│ │
│ ╭─ pi-workflow ──────────────────────────────╮ │
│ │ pi-workflow-usability-resume │ │
│ ╭─ workflow ──────────────────────────────╮ │
│ │ workflow-usability-resume │ │
│ │ WAITING · Plan Approval · revision 12 │ │
│ │ │ │
│ │ ✓ Discover ✓ Design · Prototype │ │
@@ -46,7 +46,7 @@ Weaknesses:
### A at 60 columns
```text
╭─ pi-workflow ───────────────────────╮
╭─ workflow ───────────────────────╮
│ usability-resume · WAITING │
│ Plan Approval · r12 │
│ │
@@ -64,9 +64,9 @@ Weaknesses:
A stable workspace keeps the run list, selected run, progress, and actions visible together.
```text
╭─ pi-workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ pi-workflow-usability-resume WAITING │
│ │ feature/pi-workflow-usability-resume · r12 │
╭─ workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ workflow-usability-resume WAITING │
│ │ feature/workflow-usability-resume · r12 │
│ > usability-resume │ │
│ auth-cleanup │ Progress │
│ cache-audit │ ✓ Discover ✓ Design · Prototype · Implement │
@@ -101,7 +101,7 @@ Weaknesses:
### B at 80x24
```text
╭─ pi-workflow ────────────────────────────────────────────────────────────────╮
╭─ workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ usability-resume · WAITING · r12 │
│ > usability │ ✓ Discover ✓ Design · Prototype │
│ auth-cleanup │ · Implement · Verify · Review │
@@ -127,7 +127,7 @@ Direction C uses shallow browser-style navigation. Each overlay does one job. Es
### C1. Run list popup
```text
╭─ pi-workflow ─────────────────────────────╮
╭─ workflow ─────────────────────────────╮
│ > usability-resume WAITING Plan Approval│
│ auth-cleanup RUNNING Implement │
│ cache-audit DONE report ready │
@@ -160,11 +160,11 @@ Direction C uses shallow browser-style navigation. Each overlay does one job. Es
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
pi-workflow plan · usability-resume line 42/216
workflow plan · usability-resume line 42/216
Outline Plan
───────────────────────────── ─────────────────────────────────────────────
pi-workflow usability update # pi-workflow usability update plan
workflow usability update # workflow usability update plan
Locked decisions
> Implementation phases ## Implementation phases
Prototype overlays
@@ -186,7 +186,7 @@ The reader uses the whole overlay. The terminal edge is the outer frame, so ther
### C3 at 80x24
```text
pi-workflow plan · usability-resume row 42/216
workflow plan · usability-resume row 42/216
Outline Plan
────────────────────── ─────────────────────────────────────────────
@@ -207,7 +207,7 @@ The reader uses the whole overlay. The terminal edge is the outer frame, so ther
The outline hides and the document becomes the only pane. The current heading remains visible in the header.
```text
pi-workflow plan · Implementation phases · row 42/216
workflow plan · Implementation phases · row 42/216
## Implementation phases
@@ -228,7 +228,7 @@ The outline hides and the document becomes the only pane. The current heading re
terminal too small
pi-workflow plan needs 48x12
workflow plan needs 48x12
current terminal is 47x11
resize the terminal or press esc
@@ -271,7 +271,7 @@ Use direction C. It has one border only on bounded popup cards, no redundant fra
## Production mapping
The accepted direction maps to `extensions/pi-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.
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
@@ -1,13 +1,13 @@
# pi-workflow Design
# workflow Design
**Status:** Accepted
**Date:** 24AUG2026
## Purpose
`pi-workflow` coordinates feature planning and implementation through selected Markdown-defined agents, persisted human gates, isolated Pi child sessions, and mandatory independent review.
`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 `pi-workflow` is verified and explicitly exposed.
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
@@ -58,7 +58,7 @@ The extension is based on `extensions/_workflows`, but it is a new extension rat
The extension exposes one state-changing tool and one workflow command.
```ts
type PiWorkflowInput =
type WorkflowInput =
| {
action: "start";
request: string;
@@ -152,13 +152,13 @@ Feature and feature-script starts require `featureName` as a concise lowercase k
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 `pi_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()`.
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 `pi_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.
`/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 `pi_workflow` with `action: "decide"`. Child agents never receive `ask_user`.
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.
@@ -170,7 +170,7 @@ After `start` creates the run lease, every subsequent state-changing parent oper
Profiles are loaded in this order:
1. Bundled workflow profiles from `extensions/pi-workflow/agents/*.md`.
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.
@@ -252,8 +252,8 @@ The engine selects the initial discovery profile deterministically from eligible
Configuration sources are:
1. Bundled defaults.
2. `~/.pi/agent/pi-workflow.json`.
3. Trusted `.pi/pi-workflow.json`.
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.
@@ -484,7 +484,7 @@ return results;
Every feature Workflow Run owns a distinct, exclusive worktree under:
```text
<repository>/.worktrees/pi-workflow-<feature-name>-<run-id>/
<repository>/.worktrees/workflow-<feature-name>-<run-id>/
```
The corresponding branch is:
@@ -506,7 +506,7 @@ Read-only analysis runs use the parent cwd and do not create worktrees. All chil
Artifacts live under:
```text
~/.pi/agent/pi-workflows/runs/<run-id>/
~/.pi/agent/workflows/runs/<run-id>/
```
Files include:
@@ -554,11 +554,11 @@ The effective model is resolved in this order:
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. `pi_workflow` is added to both the shared child-tool exclusion policy and the separate Pi-subagent child exclusion list alongside the legacy `workflow` name; implementation should consolidate the duplicate list onto the shared policy when possible. 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.
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
`pi-workflow` should remain a small set of deep 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.
@@ -578,9 +578,9 @@ Pure transition and eligibility logic stay inside the engine and profile modules
## Exposure and Migration
- Do not rename or activate `_workflows` during initial development.
- Add `extensions/pi-workflow` tests to `package.json` explicitly.
- Add `extensions/workflow` tests to `package.json` explicitly.
- Typecheck through the existing `extensions/**/*.ts` configuration.
- Add `pi-workflow` to `config/pi-links.json` only after focused tests, full tests, independent review, and manual TUI validation pass.
- 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.
@@ -627,7 +627,7 @@ Implement the production Pi Assignment executor and eligible planner-selection p
- 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.
- `pi_workflow`, legacy workflow/subagent tools, and user interaction remain unavailable through both shared workflow-child and Pi-subagent child policies.
- `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
@@ -640,7 +640,7 @@ Extend the Phase 2 worktree scaffold with the Implementation Context Gate, `/wor
- 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 `pi_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.
- 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.
@@ -1,4 +1,4 @@
# pi-workflow usability update plan
# workflow usability update plan
Status: manual recovery plan after managed Workflow Runs `512d6c31`, `51b0c1cb`, and `ecb11e1e` failed or were interrupted before implementation.
@@ -26,7 +26,7 @@ These failures are acceptance-test inputs for assignment timeout handling and de
### 1. Prototype overlays
Own only `docs/pi-workflow/dashboard-mocks.md` and isolated prototype artifacts. Compare:
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