@tranhoangnguyen0310/pi-flow-external 1.10.0-external.0 → 2.1.0-external.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -2,28 +2,30 @@
2
2
 
3
3
  ## pi-flow external contract
4
4
 
5
- This fork changes the original pi-flow contract: `Agent` is not a generic Pi subagent launcher. It delegates only to external Claude Code, Codex CLI, and Antigravity harnesses.
5
+ This fork changes the original pi-flow contract: `Agent` is not a generic Pi subagent launcher. It delegates only to external Claude Code, Codex CLI, and Antigravity harnesses, plus named Pi harness configurations (below) — in-process, per-model configs registered by the user, not a fourth CLI.
6
6
 
7
- - Ordinary driver tools: `Agent`, read-only `external_help`, and optional `workflow`. `pi_flow_profile_create` is active only inside `/external profile create`.
7
+ - Ordinary driver tools: `Agent`, read-only `external_help`, `external_runs`, and optional `workflow`. `pi_flow_profile_create` and `pi_flow_harness_create` are active only inside `/external profile create`.
8
8
  - User operations use `/external`; `/pi-flow-profile create` is a temporary deprecated alias.
9
- - Extension-owned concurrency, timeout, and global default-harness settings live in `$PI_CODING_AGENT_DIR/pi-flow-external/settings.json`. Profile backend/model/thinking metadata remains in `subagents/*.md`. A trusted project may override `defaultHarness` via `.pi/pi-flow-external/settings.json` (that key only, read-only to the extension); explicit call harness > project default > global default.
10
- - Every `Agent` call requires `description`, `prompt`, and either `role` with optional `harness` (`agy`, `claude`, or `codex`) or the legacy exact-profile `subagent_type`. The selectors cannot be combined. Without `harness`, use the global `defaultHarness` setting (initially `agy`).
11
- - Valid profiles come from `~/.pi/agent/subagents/*.md` and set `backend: claude`, `backend: codex`, or `backend: agy`. Use matching names such as `claude-*`, `codex-*`, or `agy-*`; the assisted creator enforces that convention.
12
- - A default roster ships with the extension and seeds once on session start: five code-oriented roles (explorer, planner, implementer, reviewer, qa) plus the generalist worker, one storage profile per backend (18 files, but six advertised roles). Seeding never overwrites existing files and respects later deletions. Roles outside the default roster (such as debugger) are user-created via `/external profile create`.
13
- - Profiles with `backend: pi` or a missing backend are filtered out and rejected; they belong to Pi's native subagent system and this extension never modifies them.
14
- - `/external profile clean-up` archives only this extension's own retired default profiles (currently the former `debugger` role) to `subagents/archive/` after user confirmation. Profiles tagged `owner: user` (stamped automatically by `/external profile create`) are the user's property and are never archived, nor are native Pi profiles.
9
+ - Extension-owned concurrency, timeout, and global default-harness settings live in `$PI_CODING_AGENT_DIR/pi-flow-external/settings.json`. Profile backend/model/thinking metadata remains in `subagents/*.md`. Named Pi harness configurations live in the sibling `$PI_CODING_AGENT_DIR/pi-flow-external/harnesses.json` registry (one shared file, `pi-<label>` keys pinning `model`/`thinking`). Registry writes are atomic per file, but there is no inter-process lock: concurrent writers adding distinct names from separate sessions are last-writer-wins and may drop one update. This is an accepted v1 limitation shared with `settings.json` and `subagents/*.md`, not a bug to re-report. A trusted project may override `defaultHarness` via `.pi/pi-flow-external/settings.json` (that key only, read-only to the extension); explicit call harness > project default > global default. `defaultHarness` may itself name a registered `pi-*` harness.
10
+ - Every `Agent` call requires `description`, `prompt`, and either `role` with optional `harness` (`agy`, `claude`, `codex`, or a registered `pi-*` harness name) or the legacy exact-profile `subagent_type`. The selectors cannot be combined. Without `harness`, use the effective default harness; if that default names a `pi-*` harness that is no longer registered, the call fails with an actionable error rather than silently falling back to `agy`.
11
+ - Valid profiles come from `~/.pi/agent/subagents/*.md` and set `backend: claude`, `backend: codex`, `backend: agy`, or (only when also declaring `harness: <registered pi-* name>`) `backend: pi`. Use matching names such as `claude-*`, `codex-*`, `agy-*`, or `<harness>-*`; the assisted creator enforces that convention.
12
+ - A default roster ships with the extension and seeds once on session start: five code-oriented roles (explorer, planner, implementer, reviewer, qa) plus the generalist worker, one storage profile per CLI backend (18 files, but six advertised roles). Seeding never overwrites existing files and respects later deletions. Roles outside the default roster are user-created via `/external profile create`. Every registered named Pi harness automatically and immediately gets the same six roles too, synthesized in-memory from the identical canonical role source — no per-harness file needed, and no on-disk seeding for pi harnesses.
13
+ - A `backend: pi` profile is external-delegation-eligible only when it also declares `harness: <name>` for a name present in the live `harnesses.json` registry; a bare `backend: pi` profile (no `harness`, or one naming an unregistered config) is filtered out and rejected exactly as before — it belongs to Pi's native subagent system and this extension never modifies it.
14
+ - **Named Pi harness configuration:** a `pi-<label>` entry in `harnesses.json` pinning a `provider/model` id (resolved through Pi's own model registry) and a thinking level (`off|minimal|low|medium|high|xhigh`, always persisted explicitly). It runs in-process via Pi's own SDK, not as a spawned CLI. A pi child loads no project/user extensions, skills, prompt templates, or themes — its entire tool surface is the SDK's own builtins (`read`/`bash`/`edit`/`write`, plus `grep`/`find`/`ls` where a tier's default allow-list adds them), curated but never claimed to be an OS sandbox: `danger` tier `bash` is exactly as exposed as on any external CLI. Retry is disabled per child (in-memory, call-scoped, never touching the user's real settings) to honor this extension's no-auto-retry contract, since the underlying SDK otherwise retries transient provider errors on its own. Pi children cannot resume (no persisted session) and have no enforced budget cap — both are deliberate v1 limitations, not oversights. Custom (non-canonical) roles are still authored per harness via `/external profile create`, not shared across harnesses automatically. Follow-up capability expansion (trusted extensions/MCP/skills, shared custom roles, resumable sessions, real budget controls) is tracked in issue #43.
15
15
  - Use Pi's native subagent system for Pi-backed scout/reviewer/planner/worker/oracle work.
16
- - External backends use their own tools and permission mechanisms. Codex tiers map to its `--sandbox` axis. Claude falls back to `--permission-mode auto` when its effective UID is 0 because Claude refuses bypass mode under root. Execution lanes (implementer, debugger, qa, worker) require shell command authority to inspect repositories and run tests; on Claude (where headless edit auto-denies all Bash commands), execution lanes maintain a danger floor so agents are not artificially handcuffed. Antigravity (`agy`) has no granular headless permission mode — its default sandbox denies even read-only tools — so every agy run is unsandboxed (`--dangerously-skip-permissions`) and `readonly`/`edit` on agy are advisory profile-body instructions, not a boundary. Run them only in trusted repositories and state whether the task is read-only or may edit files.
16
+ - External CLI backends use their own tools and permission mechanisms. Codex tiers map to its `--sandbox` axis. Claude falls back to `--permission-mode auto` when its effective UID is 0 because Claude refuses bypass mode under root. Execution lanes (implementer, qa, worker) require shell command authority to inspect repositories and run tests; on Claude and on pi harnesses (where `edit` tier excludes `bash`), execution lanes maintain a danger floor so agents are not artificially handcuffed. Antigravity (`agy`) has no granular headless permission mode — its default sandbox denies even read-only tools — so every agy run is unsandboxed (`--dangerously-skip-permissions`) and `readonly`/`edit` on agy are advisory profile-body instructions, not a boundary. Run them only in trusted repositories and state whether the task is read-only or may edit files.
17
17
  - Children receive no parent history by default. `Agent` and workflow `agent()` can opt into `context: {mode: "recent", turns: N}` (last N user turns, including the current one) or `{mode: "full"}` (available post-compaction conversation). Snapshots exclude system instructions, thinking, tool-result metadata, and pending calls; unsupported content/images and more than 1 MiB fail explicitly. Use the smallest sufficient snapshot plus a clear task, absolute paths, and read-only/edit intent. Shared context goes to the external harness and private local evidence; avoid unnecessary sensitive history. `resume` continues an existing child and cannot be combined with sharing. Workflow children select from one frozen parent snapshot, and replay fingerprints include the transferred context.
18
18
  - Backend-native nested agents may use a different workspace. Include explicit absolute paths and required context when asking an external backend to delegate further.
19
+ - `Agent` and `workflow` block by default; `background: true` returns a stable handle after validation/registration. Background work is owned by the originating session, not by the launching tool call or a daemon. Blocking-call interruption cancels work; wait interruption only stops waiting. Orderly session shutdown requests cancellation with bounded cleanup. A crash or unconfirmed shutdown leaves unfinished evidence interrupted/uncertain; restart never adopts live work.
19
20
 
20
21
  ## Delegation transparency invariants
21
22
 
22
23
  - Treat each `description` as a concise user-facing task label. Profile descriptions are also user-visible as the declared reason for profile selection.
23
- - `unsandboxed external CLI` and `external host access` disclose the real execution boundary. Never present a read-only prompt as permission enforcement: on agy every run is unsandboxed regardless of tier, so the profile body — not the tier — is what asks the agent to stay read-only.
24
+ - `unsandboxed external CLI` and `external host access` disclose the real execution boundary for CLI backends; a pi harness delegation discloses `Pi SDK child · host access · curated tools` instead — never call an in-process pi child an "external CLI". Never present a read-only prompt as permission enforcement: on agy every run is unsandboxed regardless of tier, so the profile body — not the tier — is what asks the agent to stay read-only; on pi, the curated tool table bounds which tool *names* exist, but does not make `bash` at `danger` tier any less exposed.
24
25
  - Keep direct intent visible during execution. Workflow access belongs once at the workflow level, not on every child row.
25
26
  - Parent-context sharing is a disclosure, not a silent optimization: the intent card names the mode before launch, and receipts name the mode and shared/requested turns. Shared conversation content leaves for the external harness and lands in local evidence, so never describe sharing as internal or free.
26
- - Keep default progress bounded and human-readable. Expanded output may reveal existing record paths, backend-event counts, workflow IDs, and journal paths.
27
+ - Keep default progress bounded and human-readable. Expanded terminal output shows bounded canonical output and a full-ID `/external runs` route; record paths, backend-event counts, workflow IDs, and journal paths remain advanced evidence.
28
+ - `/external runs` must use the same registry/readers as `external_runs`. Every hidden workflow child and truncated output/diagnostic page needs a cursor-backed navigation path; never add a silent hard cap.
27
29
  - Progress snapshots drive live presentation; persisted summaries and event logs remain the durable evidence source. Do not create a second UI-only record format.
28
30
 
29
31
  ## Receipt and evidence invariants
@@ -34,10 +36,13 @@ This fork changes the original pi-flow contract: `Agent` is not a generic Pi sub
34
36
  - Settings retention automatically prunes eligible completed records beyond `maxRunRecords`; active, interrupted, incomplete, and damaged records are not eligible.
35
37
  - Structured nested-agent activity may extend the wall-clock deadline once, by one fresh base timeout, capped at twice the original deadline.
36
38
  - Do not automatically retry failed or aborted external runs. Preserve the receipt and retry only when the user asks. Exception: the agy backend retries once on infrastructure-classified failures (auth, eligibility, network); the retry is disclosed in the receipt details (`retries`, `retryOf`) and never applies to agent-level failures, aborts, or timeouts.
39
+ - `external_runs` is session/project scoped. `list` pages runs and workflow roots; `inspect` pages summaries/output/diagnostics; `wait` returns outcomes only for the selected one/any/all target set and never cancels pending work; `cancel` targets one stable ID and preserves its reason. No routine run event sends a parent message or notification.
37
40
 
38
41
  ## Workflow contract
39
42
 
40
- `workflow` remains trusted JavaScript orchestration over the same external-only role roster. Every workflow `agent()` child uses the same `role`/optional `harness` resolution as `Agent`, with legacy exact-profile `subagent_type` available as an escape hatch.
43
+ `workflow` remains trusted JavaScript orchestration over the same external-only role roster, including registered named Pi harnesses. Its first statement declares `meta.apiVersion: 1`; missing/unsupported versions fail before child launch. Every workflow `agent()` child uses the same `role`/optional `harness` resolution as `Agent`, with legacy exact-profile `subagent_type` available as an escape hatch. A workflow run freezes one resolved profile (and model) snapshot up front — real on-disk profiles plus every registered pi harness's synthesized canonical roles — so a synthesized pi role executes exactly like a real file, and a `harnesses.json` edit mid-run cannot desync what the replay fingerprint recorded from what actually ran. Successful calls return their value; failed, cancelled, and timed-out calls throw structured catchable child errors. Explicitly handled errors permit siblings to finish; escaping errors fail the workflow and drain active siblings.
44
+
45
+ Replay is explicit through a persisted `scriptPath` plus `resumeFromRunId`. Reuse only the longest unchanged successful prefix; changed or unsuccessful calls and their suffix execute again. Never describe script recomposition as making child reruns free or side-effect-free. There is no live steering or automatic repaired-script retry.
41
46
 
42
47
  Use workflows for requested fan-out or multi-agent orchestration across Claude/Codex/Antigravity lanes. Do not route native Pi subagents through `workflow`.
43
48
 
@@ -47,7 +52,7 @@ Use workflows for requested fan-out or multi-agent orchestration across Claude/C
47
52
  - Test public contracts, trust/security boundaries, process lifecycle, cancellation/timeouts, profile rollback, workflow execution/resume, and receipt integrity.
48
53
  - Do not test cosmetic rendering variations, prompt prose fragments, trivial accessors, or a model's interpretation of instructions.
49
54
  - Do not repeat the same behavior at unit, integration, and E2E levels. A regression test must replace or extend overlapping coverage.
50
- - `npm test` must remain deterministic and offline. Real-provider E2E is opt-in and change-triggered through `npm run e2e -- --backend <claude|codex|agy> [--workflow]`.
55
+ - `npm test` must remain deterministic and offline. Real-provider E2E is opt-in and change-triggered through `npm run e2e -- --backend <claude|codex|agy> [--workflow]`, or `npm run e2e -- --backend pi --harness <registered-name> [--workflow]` for a named Pi harness the caller has already registered in their own real `harnesses.json` with real credentials configured.
51
56
 
52
57
  ## Verification and release
53
58
 
package/CHANGELOG.md CHANGED
@@ -4,6 +4,62 @@ All notable changes to pi-flow external are documented here.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [2.1.0-external.0] - 2026-09-15
8
+
9
+ Named Pi harness configurations (`pi-*`): a fourth delegation surface running in-process through Pi's own SDK, selectable exactly like `agy`/`claude`/`codex`. Design: `docs/plans/pi-named-configurations-design.md`; plan: `docs/plans/pi-named-configurations-implementation-plan.md`.
10
+
11
+ ### Added
12
+
13
+ - Named `pi-*` harness configurations: arbitrary labels pinning any `provider/model` resolvable through Pi's model registry (built-in, self-hosted, or OpenAI-compatible) plus an explicit thinking level, registered in `~/.pi/agent/pi-flow-external/harnesses.json`.
14
+ - `Agent({ role, harness: "pi-<label>" })` and workflow `agent()` treat `pi-*` names as first-class harnesses; the six canonical roles (`explorer`/`planner`/`implementer`/`reviewer`/`qa`/`worker`) are synthesized automatically for every registered pi harness with no per-harness files.
15
+ - A `backend: pi` profile is delegation-eligible only when it declares a registered `harness`; the registry stays authoritative for model/thinking (conflicting on-disk overrides fail rather than silently win).
16
+ - Profile creator gains a harness-declaration branch (`pi_flow_harness_create`) and role profiles targeting an existing pi harness, both smoke-tested through the real runtime with atomic staged writes.
17
+ - Pi runtime contract: curated built-in-only child tools (no extensions/skills/themes), synchronous model/auth/thinking preflights, tier→tool allow-lists, execution-role `edit`→`danger` floor, per-child in-memory retry disable (never touching user settings), observed non-retrying terminal-event + non-whitespace completion, thinking-clamp disclosure, and backend-aware permission labels that never call an in-process child an "external CLI".
18
+ - `/external settings`, `/external doctor`, and `external_help` disclose pi harnesses and their model/thinking; stale or deleted `defaultHarness` fails the delegation explicitly rather than silently rerouting to `agy`.
19
+ - Workflow replay fingerprints include the resolved backend/harness/model/thinking/profile body/tools/effective permission plus an SDK-version policy tag; each workflow freezes one complete profile snapshot (synthesized profiles included) for its run.
20
+
21
+ ### Limitations (v1)
22
+
23
+ - Pi children are built-in tools only; they do not load project/user extensions, skills, prompt templates, themes, or MCP tools. Expansion tracked in issue #43.
24
+ - Custom (non-canonical) pi roles are authored per harness in v1.
25
+ - Pi children cannot be resumed and enforce no hard budget cap; both are disclosed, not approximated.
26
+
27
+ ## [2.0.0-external.0] - 2026-09-14
28
+
29
+ Child observation and workflow-aware supervision. Full design: `docs/plans/2026-09-14-child-observation-and-supervision-design.md`.
30
+
31
+ ### Breaking
32
+
33
+ - Workflows must declare `meta.apiVersion: 1`. Unversioned or unsupported scripts are rejected before any child launches, with recomposition guidance; one current contract, no legacy failure mode.
34
+ - `agent()` throws a structured, catchable `ChildRunError` (outcome, run ID, reason, output/diagnostic references) for failed, cancelled, or timed-out children instead of returning `null`. Composition helpers no longer swallow child failures; unhandled errors terminate the workflow and cancel remaining children. Errors escaping user `catch` blocks propagate.
35
+ - Replay is a new explicit attempt with longest unchanged successful-prefix reuse; historical cancellations do not carry forward, and replay evidence from another project or an incompatible API contract is rejected.
36
+
37
+ ### Added
38
+
39
+ - Background (session-owned) `Agent` and `workflow` execution: runs survive tool-call returns and parent turns; interrupting a wait stops waiting only; closing the session cancels its work. Blocking calls keep interruption-cancels semantics.
40
+ - `external_runs` tool: `list` (session/project scoped), `inspect` (summary/output/diagnostics with bounded pages and opaque cursors), `wait` (one/any/all selected runs; outcome-only, no routine wake-ups; `all` escalates on unhandled workflow failure), `cancel` (scoped child/workflow, requested vs confirmed distinguished).
41
+ - Stable run IDs from queueing through evidence retrieval, including cancelled-while-queued runs.
42
+ - Readable partial and final child output recovered from run evidence across failure, cancellation, and timeout for all three backends, with preliminary/final/interrupted labels.
43
+ - Interactive `/external runs` navigation: run list, every workflow child, paged output/diagnostics, and selected-run cancellation; expanded receipts show bounded canonical output and freshness.
44
+ - Run listings show process-started vs first-activity, activity freshness, and interrupted/uncertain state for crashed or restarted sessions — never falsely `running`.
45
+ - POSIX process-tree termination on cancellation (group SIGTERM→SIGKILL regardless of leader exit) and bounded shutdown draining with honest uncertainty reporting.
46
+
47
+ ### Fixed
48
+
49
+ - Failed executable launches no longer recorded as `process started`; preallocated run records settle on resume-validation failure; discarded workflow chain rejections (including `undefined`) cannot yield successful completion; agy streamed deltas no longer duplicate the canonical result; live vs durable evidence states are reconciled for inspection; cancelled cleanup siblings remain discoverable in workflow journals.
50
+
51
+ ### Notes
52
+
53
+ - Windows process-tree termination is covered by mocked `taskkill` tests only. Real-provider field checks are opt-in per `docs/field-testing.md`.
54
+
55
+ ## [1.10.0-external.1] - 2026-09-12
56
+
57
+ Automated releases, adapted from [pi-bro](https://github.com/tranhoangnguyen03/pi-bro)'s pipeline.
58
+
59
+ ### Added
60
+
61
+ - Automated releases: PR CI validates release metadata (version bump, matching `release:` label, lockfile, CHANGELOG section), and merging a bump PR tags the commit, publishes to npm via OIDC trusted publishing, and creates the GitHub release. `release:none` skips. A daily sync-check watches for npm/GitHub drift.
62
+
7
63
  ## [1.10.0-external.0] - 2026-09-12
8
64
 
9
65
  Lets a trusted project pin its own default external harness, closing [#26](https://github.com/tranhoangnguyen03/pi-flow-external/issues/26).
package/CONTEXT.md CHANGED
@@ -4,15 +4,18 @@ This package is a fork of pi-flow whose `Agent` and `workflow` tools are reserve
4
4
 
5
5
  ## Domain language
6
6
 
7
- - **External profile:** A markdown file under `~/.pi/agent/subagents/*.md` whose filename and frontmatter select `backend: claude`, `backend: codex`, or `backend: agy`.
7
+ - **External profile:** A markdown file under `~/.pi/agent/subagents/*.md` whose filename and frontmatter select `backend: claude`, `backend: codex`, `backend: agy`, or (only alongside a registered `harness:`) `backend: pi`.
8
8
  - **Native Pi subagent:** A subagent exposed by Pi's native subagent system. This fork intentionally does not route it through `Agent`.
9
- - **Agent call:** A direct external delegation selected by `role` and optional `harness`, or by legacy exact-profile `subagent_type`.
9
+ - **Agent call:** A direct external delegation selected by `role` and optional `harness` (an external CLI or a registered named Pi harness), or by legacy exact-profile `subagent_type`.
10
+ - **Named Pi harness configuration:** A `pi-<label>` entry in `harnesses.json` pinning a `provider/model` id and a thinking level, run in-process via Pi's own SDK rather than as a spawned CLI. `harness` selects *which* configuration; `backend` (always the literal `"pi"` for these) selects the execution mechanism. The six default roles are synthesized automatically for every registered pi harness from the same canonical source the three CLI backends' default files already come from.
10
11
  - **Parent context:** An opt-in frozen text snapshot: `none` (default), `recent` with last N user turns including the current turn, or `full` available post-compaction conversation. It is background for a new external conversation, not a native session clone, system-prompt inheritance, or guaranteed cache reuse. Sharing excludes thinking and pending calls and cannot be combined with child `resume`. Workflow children share one invocation-time snapshot; prior child outputs remain explicit inputs.
11
- - **Workflow call:** Trusted JavaScript orchestration that may fan out several explicit external `agent()` calls.
12
+ - **Workflow call:** Trusted JavaScript orchestration beginning with `meta.apiVersion: 1` that may fan out several explicit external `agent()` calls. Each child returns a value or throws a catchable `ChildRunError`; escaping child errors fail the workflow and drain siblings.
13
+ - **Background run:** A validated, registered `Agent` or `workflow` invocation that returns a stable handle while work remains owned by the originating session. It is not a daemon or cross-session job.
14
+ - **Run supervision:** `external_runs` list/inspect/wait/cancel over stable IDs. Wait observes selected terminal outcomes without cancelling pending work; output and diagnostics use opaque cursors.
12
15
  - **Delegation intent:** The backend, profile, task label, profile purpose, and workspace shown to the user before and during direct execution.
13
16
  - **Access disclosure:** A visible statement of effective external CLI access and the external-host boundary; it does not create a sandbox or read-only guarantee.
14
17
  - **Evidence ID:** The short terminal reference to a persisted external run.
15
- - **Expanded receipt:** On-demand record or workflow-journal paths plus bounded evidence metadata.
18
+ - **Expanded receipt:** Bounded canonical output, full run navigation, and advanced record or workflow-journal evidence.
16
19
  - **Successful receipt:** A zero-exit run with a recognized backend terminal-success event and a non-empty result.
17
20
  - **Complete failure evidence:** The backend failed, but its event log and summary were persisted consistently.
18
21
  - **Incomplete record:** Local evidence is missing, malformed, or internally inconsistent; it must not be reported as trustworthy merely because the backend status says `done`.
@@ -21,29 +24,33 @@ This package is a fork of pi-flow whose `Agent` and `workflow` tools are reserve
21
24
  ## Routing rule
22
25
 
23
26
  - Native Pi work -> native subagent tool.
24
- - Claude Code / Codex CLI / Antigravity work -> this extension's `Agent` or `workflow`.
27
+ - Claude Code / Codex CLI / Antigravity work, and named Pi harness work -> this extension's `Agent` or `workflow`.
25
28
 
26
- The split is global and intentional to avoid tool ambiguity across projects. The ordinary driver sees `Agent`, optional `workflow`, and read-only `external_help`; the profile finalizer is activated only by `/external profile create`. External children start in the requested working directory, but backend-native nested helpers may create or use a separate workspace; prompts that request further nesting should include explicit absolute paths and all required context.
29
+ The split is global and intentional to avoid tool ambiguity across projects. The ordinary driver sees `Agent`, optional `workflow`, and read-only `external_help`; the profile finalizer is activated only by `/external profile create`. External children start in the requested working directory, but backend-native nested helpers may create or use a separate workspace; prompts that request further nesting should include explicit absolute paths and all required context. Named Pi harness children are the one exception to "backend-native nested helpers may use a different workspace": a pi child runs in-process with no extensions, skills, prompts, or themes loaded, so it structurally cannot itself launch a further nested agent.
27
30
 
28
31
  ## User control surface
29
32
 
30
- User operations are namespaced under `/external`: status, Doctor, settings, profiles, profile creation, profile clean-up, workflows, runs, and help. Extension-owned concurrency, timeout, and global default-harness settings live in `$PI_CODING_AGENT_DIR/pi-flow-external/settings.json`; profiles remain authoritative for downstream backend/model/thinking metadata. Project-specific default harnesses are deferred to issue #26.
33
+ User operations are namespaced under `/external`: status, Doctor, settings, profiles, profile creation, workflows, interactive run navigation, durable run summary/pruning, and help. `/external runs` uses the same registry/readers as `external_runs`, including every cursor-paged workflow child and output/diagnostic page. Extension-owned concurrency, timeout, and global default-harness settings live in `$PI_CODING_AGENT_DIR/pi-flow-external/settings.json`; profiles remain authoritative for downstream backend/model/thinking metadata. Named Pi harness configurations live in the sibling `pi-flow-external/harnesses.json` registry. A trusted project may override only `defaultHarness`, which may itself name a registered `pi-*` harness.
31
34
 
32
35
  ## Design stance
33
36
 
34
- Guardrails exist to keep lanes from bleeding into each other (a reviewer that edits, a debugger that fixes), not to constrain how a model works. Role bodies stay short: define the job, state the boundary, then get out of the way and trust the model's judgment on approach, depth, and method. The generic `worker` role covers non-coding tasks with no method constraints at all. The shipped default roster is five code-oriented roles (explorer, planner, implementer, reviewer, qa) plus `worker`; other roles such as `debugger` are user-created through `/external profile create` and still receive the name-based execution permission floor. External agents must not be arbitrarily handcuffed just to satisfy a theoretical safety checklist: what transpires on the ground is what matters. When an external agent needs heightened permissions to inspect, run tests, and execute tools, the system defaults to providing that authority rather than blocking execution.
37
+ Guardrails exist to keep lanes from bleeding into each other (a reviewer that edits, a worker that fixes), not to constrain how a model works. Role bodies stay short: define the job, state the boundary, then get out of the way and trust the model's judgment on approach, depth, and method. The generic `worker` role covers non-coding tasks with no method constraints at all. The shipped default roster is five code-oriented roles (explorer, planner, implementer, reviewer, qa) plus `worker`; other roles are user-created through `/external profile create` and still receive the name-based execution permission floor. External agents must not be arbitrarily handcuffed just to satisfy a theoretical safety checklist: what transpires on the ground is what matters. When an external agent needs heightened permissions to inspect, run tests, and execute tools, the system defaults to providing that authority rather than blocking execution.
35
38
 
36
39
  Role resolution is mechanical, not model-routed: a profile whose name begins with its declared backend plus `-` exposes the remaining name as its role (`agy-reviewer` -> `reviewer`). The selected role and harness must resolve to that exact profile; unavailable roles report their supported harnesses and never fall back. Nonstandard names remain available only through legacy exact `subagent_type`. The resolved profile stays authoritative for its instructions, model, and permissions.
37
40
 
38
41
  The always-visible parent guidance is limited to a compact role catalog and essential routing/safety facts. Catalog availability reflects configured profiles, not CLI installation or authentication. `external_help` supplies descriptions, permission details, workflow APIs/examples, and trust-aware saved-workflow discovery only when requested.
39
42
 
43
+ Workflow replay is explicit and successful-prefix-only. A persisted script resumed with `resumeFromRunId` reuses the longest unchanged prefix whose fingerprints and outcomes are successful; the first changed or unsuccessful call and its suffix run again. Script recomposition is cheap, but child execution can cost money or repeat side effects. There is no automatic repaired-script replay, completion-order winner selection, or live steering.
44
+
40
45
  Applied to Antigravity (`agy`), that stance is absolute: the harness offers no granular headless permission mode — its default sandbox (`proceed-in-sandbox`) hard-denies even read-only tools like `read_url_content`, and `--dangerously-skip-permissions` is the only unsandboxed mode. So every agy run is unsandboxed, and `readonly`/`edit` on agy profiles are advisory instructions carried by the profile body, never an enforced boundary. We disclose that plainly (`unsandboxed external CLI`) rather than pretend a read-only tier restrains what the harness will actually allow.
41
46
 
47
+ Applied to named Pi harness configurations, the same "get out of the way" stance takes a different, honestly-scoped shape: a curated, builtins-only tool surface (no project/user extensions, skills, prompts, or themes) genuinely bounds which tool *names* a pi child can reach — that claim is mechanically true because nothing else loads — but it is not a claim that `bash` at `danger` tier is any less dangerous than on an external CLI once it is granted. `readonly`/`edit` tiers get a real default tool allow-list (`read`/`grep`/`find`/`ls`, plus `edit`/`write` at `edit`) so those tiers are actually usable, not just technically restrictive. Execution-lane roles requested at `edit` are still elevated to `danger` (the same floor as Claude), because `edit` excludes `bash` entirely and an execution lane without shell access cannot do its job.
48
+
42
49
  ## Known inelegance
43
50
 
44
51
  <!-- ponytail: one-backend-per-file profile format forces role x backend file duplication; extend src/profiles.ts with multi-backend profiles (e.g. backends: [claude, codex, agy] plus per-backend model map) if maintaining N copies of identical role bodies ever hurts -->
45
- A standardized role roster needs one file per role per backend (e.g. `claude-qa`, `codex-qa`, `agy-qa` with identical bodies) because the profile format binds `backend:` and `model:` to a single file. The duplication is accepted for now; a future format extension could let one role file cover all backends. The same applies to `permission:` tiers: one tier per profile, but backends interpret tiers differently (Claude denies Bash at anything below `danger`), so command-running roles declare `danger` and maintain `danger` as their floor even if an explicit `edit` override is requested. Custom profiles outside the role-name convention get that floor only by declaring `permission: danger`; an undeclared custom profile that meets an `edit` tier still hits headless Bash denials, so `permission: danger` doubles as the lane's "needs shell" capability declaration.
52
+ A standardized role roster needs one file per role per backend (e.g. `claude-qa`, `codex-qa`, `agy-qa` with identical bodies) because the profile format binds `backend:` and `model:` to a single file. The duplication is accepted for now; a future format extension could let one role file cover all backends. Named Pi harnesses partially resolve this for the six canonical roles specifically (synthesized once from a single shared source, applied identically to every registered `pi-*` config, with zero files written) — but a *custom* role outside the six still needs one file per pi harness, exactly like the three CLI backends; a user with several registered pi harnesses wanting the same custom role on all of them still duplicates one file per harness. The same applies to `permission:` tiers: one tier per profile, but backends interpret tiers differently (Claude and pi deny Bash at anything below `danger`), so command-running roles declare `danger` and maintain `danger` as their floor even if an explicit `edit` override is requested. Custom profiles outside the role-name convention get that floor only by declaring `permission: danger`; an undeclared custom profile that meets an `edit` tier still hits headless Bash denials (or, on pi, a curated tool set without `bash`), so `permission: danger` doubles as the lane's "needs shell" capability declaration. Named Pi harnesses also ship with no resume and no enforced budget cap in v1 — both deliberate limitations, tracked alongside the shared-custom-role gap in issue #43, not oversights.
46
53
 
47
54
  ## Evidence boundary
48
55
 
49
- Normal external runs write best-effort local records under `~/.pi/agent/pi-flow-external/runs/` unless `PI_FLOW_EXTERNAL_RUNS_DIR` overrides it. The TUI shows short evidence IDs by default and exposes record/journal paths only through expanded output. Redaction is best-effort. Settings retention automatically prunes eligible completed records while preserving active, interrupted, incomplete, and damaged records. Failed/aborted runs are not retried automatically, except one agy retry for infrastructure-classified failures (disclosed via receipt `retries`/`retryOf`).
56
+ Normal external runs write best-effort local records under `~/.pi/agent/pi-flow-external/runs/` unless `PI_FLOW_EXTERNAL_RUNS_DIR` overrides it. The TUI shows short evidence IDs by default and exposes bounded output, full run navigation, and record/journal paths through expanded output. Redaction is best-effort. Settings retention automatically prunes eligible completed records while preserving active, interrupted, incomplete, and damaged records. Failed/aborted runs are not retried automatically, except one agy retry for infrastructure-classified failures (disclosed via receipt `retries`/`retryOf`). Blocking-call interruption cancels owned work; wait interruption does not. Graceful session shutdown requests cancellation with bounded drain. Crash/unconfirmed shutdown leaves unfinished records interrupted or uncertain, with no restart takeover or guaranteed retrospective process termination.
package/README.md CHANGED
@@ -5,14 +5,16 @@ External agent delegation for [pi](https://github.com/earendil-works/pi) through
5
5
  - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) profiles with `backend: claude`
6
6
  - [Codex CLI](https://github.com/openai/codex) profiles with `backend: codex`
7
7
  - Antigravity profiles with `backend: agy`
8
+ - Named Pi harness configurations (`pi-<label>`) — in-process, per-model configs you register yourself, not a spawned CLI
8
9
 
9
- The ordinary driver has three tools (`workflow` can be disabled):
10
+ The ordinary driver has four tools (`workflow` can be disabled):
10
11
 
11
12
  - `Agent` resolves and runs one external role.
12
13
  - `workflow` orchestrates multiple external roles with trusted JavaScript.
13
14
  - `external_help` returns role details, permission behavior, or workflow guidance on demand.
15
+ - `external_runs` lists, inspects, waits for, and cancels session-owned runs.
14
16
 
15
- `Agent` and `workflow` accept external roles with an optional harness override. Use pi's native subagent system for Pi-backed agents. The `pi_flow_profile_create` finalizer is active only during `/external profile create`.
17
+ `Agent` and `workflow` accept external roles with an optional harness override — one of the three CLIs, or a registered named Pi harness. Use pi's native subagent system for Pi-backed agents. The `pi_flow_profile_create` and `pi_flow_harness_create` finalizers are active only during `/external profile create`.
16
18
 
17
19
  ## Install
18
20
 
@@ -55,10 +57,11 @@ External agents use the effective permission tier and each harness's native mech
55
57
  - Claude: `--permission-mode plan`, `--permission-mode acceptEdits`, or `--dangerously-skip-permissions`
56
58
  - Codex: `--sandbox read-only`, `workspace-write`, or `danger-full-access`
57
59
  - Antigravity: always `--dangerously-skip-permissions`
60
+ - Named Pi harnesses: a curated `tools:` allow-list (`read`/`grep`/`find`/`ls` at `readonly`; those plus `edit`/`write` at `edit`), or the SDK's own default active tools (`read`/`bash`/`edit`/`write`) at `danger`
58
61
 
59
- Claude refuses bypass mode when its effective UID is `0`; in that case the extension uses `--permission-mode auto`. External execution lanes (like `implementer`, `debugger`, `qa`, and `worker`) require shell execution to inspect repositories, run tests, and verify code. On Claude Code, headless `edit` mode (`acceptEdits`) auto-denies all shell commands; therefore, execution lanes maintain a `danger` floor so the model is not artificially handcuffed by permission blocks. Run external agents only in repositories you trust and state whether each task is read-only or may edit files.
62
+ Claude refuses bypass mode when its effective UID is `0`; in that case the extension uses `--permission-mode auto`. External execution lanes (like `implementer`, `qa`, and `worker`) require shell execution to inspect repositories, run tests, and verify code. On Claude Code and named Pi harnesses, headless/`edit`-tier access excludes shell entirely; therefore, execution lanes maintain a `danger` floor so the model is not artificially handcuffed by permission blocks. Run external agents only in repositories you trust and state whether each task is read-only or may edit files.
60
63
 
61
- The TUI labels a direct run with its effective access, including `unsandboxed external CLI` for danger and all Agy runs, and shows `external host access` while workflow work is active. These labels disclose actual execution authority; they do not turn a read-only prompt into an enforced permission boundary.
64
+ The TUI labels a direct run with its effective access, including `unsandboxed external CLI` for danger and all Agy runs, `Pi SDK child · host access · curated tools` for a danger-tier named Pi harness, and shows `external host access` while workflow work is active. These labels disclose actual execution authority; they do not turn a read-only prompt into an enforced permission boundary.
62
65
 
63
66
  ## Quick start
64
67
 
@@ -94,9 +97,10 @@ All user commands use the `/external` namespace:
94
97
  | `/external settings` | Show the default harness and effective runtime settings |
95
98
  | `/external profiles` | List configured external profiles |
96
99
  | `/external profile create` | Create and smoke-test a profile |
97
- | `/external profile clean-up` | Archive retired pi-flow default profiles |
98
100
  | `/external workflows` | List saved workflows |
99
- | `/external runs` | Summarize recorded external runs |
101
+ | `/external runs` | Interactively browse current-session runs, every workflow child, paged output/diagnostics, and cancellation |
102
+ | `/external runs summary` | Summarize durable run records |
103
+ | `/external runs --prune` | Prune eligible completed run records |
100
104
  | `/external help` | Show the command reference |
101
105
 
102
106
  `/external doctor` verifies CLI availability, not provider authentication.
@@ -109,7 +113,7 @@ Profiles live in:
109
113
  ~/.pi/agent/subagents/<name>.md
110
114
  ```
111
115
 
112
- Names may contain lowercase letters, numbers, and hyphens. A profile must declare `backend: claude`, `backend: codex`, or `backend: agy`, and its name should start with the matching backend name.
116
+ Names may contain lowercase letters, numbers, and hyphens. A profile must declare `backend: claude`, `backend: codex`, `backend: agy`, or (alongside `harness: <a registered pi-* name>`) `backend: pi`, and its name should start with the matching harness name.
113
117
 
114
118
  Example Claude profile, `~/.pi/agent/subagents/claude-explorer.md`:
115
119
 
@@ -136,16 +140,46 @@ backend: agy
136
140
  model: gemini-3.7-flash-high
137
141
  ```
138
142
 
139
- Profile instructions become the external agent's system instructions. A profile's `description` is also shown as the user-visible reason for its selection, so keep it concise and concrete. External CLIs use their own tools, so a profile's `tools:` field does not control them. Profiles with `backend: pi` or no backend are not available to this extension; they belong to Pi's native subagent system and are never modified by it. `/external profile clean-up` archives only profiles this extension itself shipped and later retired (currently the former `debugger` role) to `~/.pi/agent/subagents/archive/` after confirmation — moved, never deleted.
140
-
141
- Profiles created through `/external profile create` are stamped `owner: user`, and clean-up never archives `owner: user` profiles. When writing a profile by hand, add `owner: user` to its frontmatter to protect it from clean-up.
143
+ Profile instructions become the external agent's system instructions. A profile's `description` is also shown as the user-visible reason for its selection, so keep it concise and concrete. External CLIs use their own tools, so a profile's `tools:` field does not control them; a pi profile's `tools:` field does apply, intersected with its permission tier's curated tool table. A `backend: pi` profile is only available to this extension when it also declares `harness: <name>` for a name registered in `harnesses.json` (see below); a bare `backend: pi` profile, or no backend at all, belongs to Pi's native subagent system and is never modified by this extension.
142
144
 
143
145
  ### Default profiles
144
146
 
145
- On first session start the extension seeds a default roster — five code-oriented roles (explorer, planner, implementer, reviewer, qa) plus the generalist worker — as one storage profile per backend (18 files). The compact agent catalog advertises each role once rather than presenting 18 choices. Seeding happens once: it never overwrites existing files, and profiles you delete or customize afterwards stay that way. Default profiles leave `model` and `thinking` unpinned so they track the CLI's own model and the current Pi thinking level. Roles not in the default roster, such as debugger, can be added with `/external profile create`.
147
+ On first session start the extension seeds a default roster — five code-oriented roles (explorer, planner, implementer, reviewer, qa) plus the generalist worker — as one storage profile per backend (18 files). The compact agent catalog advertises each role once rather than presenting 18 choices. Seeding happens once: it never overwrites existing files, and profiles you delete or customize afterwards stay that way. Default profiles leave `model` and `thinking` unpinned so they track the CLI's own model and the current Pi thinking level. Roles not in the default roster can be added with `/external profile create`.
146
148
 
147
149
  Project-local profiles are not supported; global profiles are used for both global and project-only package installations.
148
150
 
151
+ ## Named Pi harness configurations
152
+
153
+ A named Pi harness runs in-process through Pi's own SDK rather than as a spawned CLI, letting you delegate to any model Pi can already resolve (built-in, self-hosted, or a custom-registered provider) without an external CLI. Register one via `/external profile create` (choose the "declare a new named Pi harness" branch): give it a `pi-<label>` name, a `provider/model` id, and an optional thinking level. Registration is smoke-tested against the real pi runtime before it is saved, exactly like a CLI profile, into:
154
+
155
+ ```text
156
+ ~/.pi/agent/pi-flow-external/harnesses.json
157
+ ```
158
+
159
+ ```json
160
+ {
161
+ "version": 1,
162
+ "harnesses": {
163
+ "pi-deepseek": { "model": "deepseek/deepseek-chat", "thinking": "high" }
164
+ }
165
+ }
166
+ ```
167
+
168
+ The moment a harness is registered, all six default roles (explorer, planner, implementer, reviewer, qa, worker) become available on it automatically — no per-role file to write. Delegate to it exactly like any other harness:
169
+
170
+ ```ts
171
+ Agent({
172
+ description: "Cheap repository review",
173
+ prompt: "Review this diff read-only.",
174
+ role: "reviewer",
175
+ harness: "pi-deepseek",
176
+ });
177
+ ```
178
+
179
+ A custom (non-canonical) role still needs its own profile file per harness, the same as for the three CLI backends: `~/.pi/agent/subagents/pi-deepseek-security-reviewer.md` with `backend: pi` and `harness: pi-deepseek`. That file's body/permission/tools may be customized; its `model`/`thinking` are not — they always come from the harness's registered config, and a file that tries to override them to a different value is rejected rather than silently honored.
180
+
181
+ **v1 scope, by design:** a pi child's entire tool surface is the SDK's own builtins (`read`/`bash`/`edit`/`write`, plus `grep`/`find`/`ls` at `readonly`/`edit` tiers) — no project/user extensions, skills, prompt templates, or themes load into it. This bounds which tool *names* exist; it does not make `bash` at `danger` tier any less exposed than on an external CLI. Retry is disabled per pi child (in-memory, never touching your real Pi settings) so a transient provider error fails immediately rather than silently retrying. Pi children cannot resume a prior conversation and have no enforced budget cap. Expanding this capability set (trusted extensions/MCP/skills, a shared custom-role format, resumable sessions, real budget controls) is tracked in [issue #43](https://github.com/tranhoangnguyen03/pi-flow-external/issues/43).
182
+
149
183
  ## Agent usage
150
184
 
151
185
  A direct tool call requires `description`, `prompt`, and either `role` or legacy exact-profile `subagent_type`. With `role`, `harness` is optional and defaults to the global `defaultHarness` setting:
@@ -205,18 +239,43 @@ Workspace /path/to/project
205
239
 
206
240
  The `Context` line appears only when the parent shares conversation content, so extra data leaving for the external harness is visible before the run. Completed rows summarize what was actually shared (`context recent 4/5 turns`).
207
241
 
208
- Completed rows show a short evidence identifier and result preview. Press **Ctrl+O** (the default tool-expansion binding) to reveal the local record path plus structured backend-event count:
242
+ Completed rows show a short evidence identifier and result preview. Press **Ctrl+O** (the default tool-expansion binding) to reveal bounded canonical output, its full run ID, a `/external runs` navigation hint, and advanced local evidence details:
209
243
 
210
244
  ```text
211
245
  ✓ Claude Code(claude-explorer, Map repository architecture) 42s evidence 8f21a004 -> Architecture mapped.
246
+ Final output
247
+ Architecture mapped.
248
+ Run run_... · /external runs for full paged output and diagnostics
212
249
  Evidence ~/.pi/agent/pi-flow-external/runs/run_... · 15 backend events
213
250
  ```
214
251
 
215
- Workflows show access once at the workflow level, retain done/active/queued/failed counts, and expose child evidence plus the workflow journal when expanded. Raw backend events remain in local records rather than flooding the default terminal view.
252
+ Workflows show access once at the workflow level, retain done/active/queued/failed counts, and expose bounded final output plus the workflow journal when expanded. Hidden child rows remain reachable through `/external runs`. Active rows report last-activity freshness independently of the spinner. Raw backend events remain in local records rather than flooding the default terminal view.
253
+
254
+ ## Background runs and supervision
255
+
256
+ `Agent` and `workflow` are blocking by default. Add `background: true` to return a stable `run_...` or `wf_...` handle after validation and registration while the originating Pi session continues to own the work:
257
+
258
+ ```ts
259
+ Agent({
260
+ description: "Long repository audit",
261
+ prompt: "Audit /absolute/repo read-only.",
262
+ role: "reviewer",
263
+ background: true,
264
+ });
265
+ ```
266
+
267
+ Use `external_runs` with these actions:
268
+
269
+ - `list`: current session/project runs; use `cursor` for run pages and `workflowCursor` for workflow pages. `workflowRunId` filters children of one workflow.
270
+ - `inspect`: `runId`, `view: "summary" | "output" | "diagnostics"`, and optional opaque `cursor`/`limitBytes`. Follow `nextCursor` to avoid truncation.
271
+ - `wait`: one `runId` or selected `runIds`, with `mode: "any" | "all"`. It returns terminal outcomes plus still-pending IDs; an unsuccessful workflow returns early even in `all` mode. It never chooses a winner or cancels pending work.
272
+ - `cancel`: one `runId` and optional reason. Whole-workflow cancellation stops active children; targeted child cancellation remains a catchable workflow outcome. Cancellation does not roll back edits or other side effects.
273
+
274
+ Interrupting a blocking `Agent`/`workflow` call cancels its work. Interrupting `external_runs wait` stops only that wait. Background work survives its launching tool return and ordinary parent turns, but not the owning session: orderly session shutdown requests cancellation and waits for bounded cleanup. This is not a daemon. After a host crash or unconfirmed shutdown, unfinished evidence is `interrupted_or_uncertain`; restart restores evidence access, never live ownership or guaranteed retrospective process termination. No routine activity wakes the parent, and live steering is not supported.
216
275
 
217
276
  ## Workflow usage
218
277
 
219
- The `workflow` tool runs trusted JavaScript that calls one or more external roles and returns a JSON-serializable result. Every `agent()` child uses the same `role`/optional `harness` resolution as direct `Agent` calls, with legacy exact `subagent_type` also supported.
278
+ The `workflow` tool runs trusted JavaScript that calls one or more external roles and returns a JSON-serializable result. Its first statement must be the current declaration `export const meta = { apiVersion: 1, name, description }`; missing or unsupported versions fail before any child launches. Every `agent()` child uses the same `role`/optional `harness` resolution as direct `Agent` calls, with legacy exact `subagent_type` also supported.
220
279
 
221
280
  Saved workflows are discovered on demand through `external_help({ topic: "workflow" })`; project `.pi/workflows` entries are included only when Pi reports the project trusted.
222
281
 
@@ -226,7 +285,9 @@ Example request:
226
285
  Use the workflow tool to ask role "explorer" on harness "claude" for an architecture map and role "reviewer" on harness "codex" for a risk review, then synthesize their findings.
227
286
  ```
228
287
 
229
- Direct `Agent` calls and workflow children share the same concurrency and timeout controls. Workflow `agent(prompt, { role, context: { mode: "recent", turns: 5 } })` accepts the same context modes. Every child selects from one parent snapshot frozen at workflow invocation; earlier child results must still be passed explicitly. Replay fingerprints include the transferred context, so changes invalidate cached results.
288
+ Direct `Agent` calls and workflow children share the same concurrency and timeout controls. Workflow `agent(prompt, { role, context: { mode: "recent", turns: 5 } })` accepts the same context modes. Every current-version `agent()` returns its value or throws a catchable `ChildRunError` with `runId`, `outcome` (`failed`, `cancelled`, or `timed_out`), `message`, and output/diagnostic references. Catch an optional failure explicitly; an uncaught child error fails the workflow and drains active siblings. `parallel` and `pipeline` preserve this contract and never convert failure to `null`.
289
+
290
+ Every child selects from one parent snapshot and effective settings frozen at workflow invocation; earlier child results must still be passed explicitly. `resumeFromRunId` is explicit replay for a persisted `scriptPath`: it reuses only the longest unchanged prefix of successful child calls. The API version, transferred context, prompt, selection, and relevant options participate in fingerprints. The first changed, failed, cancelled, or timed-out call and everything after it executes again. Recomposition is cheap, but rerun children may cost money or repeat side effects; the runtime never retries or replays a repaired script automatically.
230
291
 
231
292
  ## Permission tiers, budgets, and resume
232
293
 
@@ -320,7 +381,10 @@ A failed backend can still have complete diagnostic evidence. Treat `incompleteR
320
381
  - **Claude rejects `--dangerously-skip-permissions` under root:** reload the current extension version; root runs use Claude's `auto` permission mode.
321
382
  - **Nested agent cannot find the repository:** include the repository's absolute path and required context in the prompt.
322
383
  - **Child is missing earlier decisions:** share the smallest sufficient parent context (`context: { mode: "recent", turns: N }` or `{ mode: "full" }`), or restate the missing decisions in the prompt.
323
- - **Run failed with complete records:** inspect the run's `summary.json` and `events.ndjson`; do not retry automatically unless requested.
384
+ - **Workflow rejected before any child launched:** the script is missing or using an unsupported `meta.apiVersion` declaration. Recompose it starting with `export const meta = { apiVersion: 1, name, description }`; nothing ran, so nothing needs cleanup.
385
+ - **Run shows `interrupted_or_uncertain`:** the host exited before the run's termination was confirmed. Treat its evidence as interrupted — partial output may be readable via `/external runs` — but never resume live ownership after restart; start a new run or replay explicitly.
386
+ - **Inspection cursor fails as stale:** the run's content changed while paging (live updates or registry handoff). Restart the inspection from the first page; cursors are single-sequence continuation tokens.
387
+ - **Run failed with complete records:** read its output and diagnostics via `/external runs`, or inspect `summary.json`/`events.ndjson` directly; do not retry automatically unless requested.
324
388
  - **Sensitive content appears in evidence:** remove the affected run directory. Local redaction is not a secrecy boundary.
325
389
 
326
390
  ## Development
@@ -338,9 +402,15 @@ export PI_CODING_AGENT_DIR="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
338
402
  npm run e2e -- --backend claude
339
403
  npm run e2e -- --backend codex
340
404
  npm run e2e -- --backend agy
405
+ npm run e2e -- --backend claude --workflow
341
406
  npm run e2e -- --backend codex --workflow
407
+ npm run e2e -- --backend agy --workflow
408
+ npm run e2e -- --backend pi --harness pi-deepseek
409
+ npm run e2e -- --backend pi --harness pi-deepseek --workflow
342
410
  ```
343
411
 
412
+ The `pi` backend requires a harness you have already registered yourself in your real `harnesses.json` with real credentials configured; the script never registers or pays for one on your behalf.
413
+
344
414
  See [`docs/field-testing.md`](docs/field-testing.md) for provider checks and [`docs/releasing.md`](docs/releasing.md) for the release process.
345
415
 
346
416
  Run directly from a checkout with:
@@ -39,15 +39,40 @@ Defaults:
39
39
 
40
40
  Override with `--model`, `--thinking`, `--root-model`, or `--root-thinking`. Use `--keep` only when evidence inspection is necessary; it preserves sensitive output and the temporary profile path printed by the runner.
41
41
 
42
- ## Workflow receipt
42
+ ### Named Pi harness receipt
43
43
 
44
- When workflow runtime, scheduling, or tool integration changes:
44
+ Run only when the pi runtime contract (§7 of the design), harness registry, or canonical role synthesis changes, and only if you have already registered a real `pi-*` harness in your own `harnesses.json` with real credentials configured:
45
45
 
46
46
  ```bash
47
+ npm run e2e -- --backend pi --harness pi-deepseek
48
+ ```
49
+
50
+ This lane never registers a harness or writes a temporary profile — canonical synthesis already provides the `worker` role for any registered harness — it only delegates to the harness you name and requires the same one complete `done` receipt.
51
+
52
+ ## Supervised workflow receipt
53
+
54
+ When workflow runtime, scheduling, supervision, or tool integration changes, run the affected backend; run all three before release:
55
+
56
+ ```bash
57
+ npm run e2e -- --backend claude --workflow
47
58
  npm run e2e -- --backend codex --workflow
59
+ npm run e2e -- --backend agy --workflow
60
+ npm run e2e -- --backend pi --harness pi-deepseek --workflow
61
+ ```
62
+
63
+ Each command declares `meta.apiVersion: 1`, starts a two-child workflow with `background: true`, waits for the selected workflow through `external_runs`, inspects its summary/output, requires two complete child receipts, and verifies the read-only fixture stayed clean. Forced multi-page cursor behavior remains covered by deterministic offline tests; this check exercises real workflow child handling without duplicating those semantics.
64
+
65
+ ## Change-triggered interruption and output check
66
+
67
+ When adapter cancellation, process-tree termination, partial output, or supervision changes, run the affected backend:
68
+
69
+ ```bash
70
+ npm run e2e -- --backend claude --interrupt
71
+ npm run e2e -- --backend codex --interrupt
72
+ npm run e2e -- --backend agy --interrupt
48
73
  ```
49
74
 
50
- This runs two children through one workflow and requires two complete receipts. One backend is enough because direct backend checks validate adapter-specific transport.
75
+ The runner starts a background `Agent`, cancels its stable ID with an explicit reason, waits for its `cancelled` outcome, and asks `external_runs` for every available output and diagnostic page. A very early cancellation may legitimately have diagnostics but no assistant text; the durable receipt must still be `aborted`/`cancelled` with the exact reason. Do not retry a failure automatically. Use `--keep` for one deliberate evidence inspection, then remove the printed run root and temporary profile.
51
76
 
52
77
  ## Natural-language routing smoke
53
78
 
@@ -90,7 +115,8 @@ Before a runtime release:
90
115
 
91
116
  1. Run `npm run check`.
92
117
  2. Run all three direct backend receipts.
93
- 3. Run one workflow receipt.
94
- 4. Run the natural-language routing smoke only if role discovery, tool descriptions, or coordinator guidance changed.
95
- 5. Run the nested timeout check only if nested detection or timeout behavior changed.
96
- 6. Remove temporary evidence and profiles.
118
+ 3. Run all three supervised workflow receipts.
119
+ 4. Run interruption checks for adapters whose cancellation/output path changed.
120
+ 5. Run the natural-language routing smoke only if role discovery, tool descriptions, or coordinator guidance changed.
121
+ 6. Run the nested timeout check only if nested detection or timeout behavior changed.
122
+ 7. Remove temporary evidence and profiles.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tranhoangnguyen0310/pi-flow-external",
3
- "version": "1.10.0-external.0",
3
+ "version": "2.1.0-external.0",
4
4
  "description": "External Claude Code, Codex CLI, and Antigravity delegation for pi.",
5
5
  "type": "module",
6
6
  "main": "./index.ts",