diff --git a/docs-ai/063-agent-workflows/000-plan.md b/docs-ai/063-agent-workflows/000-plan.md index ef53ed20..bc699940 100644 --- a/docs-ai/063-agent-workflows/000-plan.md +++ b/docs-ai/063-agent-workflows/000-plan.md @@ -2,7 +2,7 @@ | | | | --- | --- | -| **Status** | In progress — R1 foundations C0/A1/A1b implemented; A2 implemented in PR #714 | +| **Status** | In progress — R1 foundations C0/A1/A1b/A2 and 064-S1 merged; 064-S2 is next | | **Anchor date** | 2026-08-21 | | **Primary PRs** | R1 foundations: #709 (C0), #710 (A1), #713 (A1b), #714 (A2); B1–D3 TBD | | **Related** | [047 cross-agent-handoff](../047-cross-agent-handoff/000-plan.md), [049 agents-toolbar-entry](../049-agents-toolbar-entry/000-plan.md), [053 agent-profiles](../053-agent-profiles/000-plan.md), [055 agent-profile-runtimes](../055-agent-profile-runtimes/000-plan.md), [059 agent-transcript-snapshots](../059-agent-transcript-snapshots/000-plan.md), [060 cli-targeting-and-contract-governance](../060-prowl-cli-targeting-and-contract-governance/000-plan.md), [061 native-toolbar-controls](../061-native-toolbar-controls/toolbar-controls.md), [064 agent-completion-signals](../064-agent-completion-signals/000-plan.md) (signal bus, `agents signal` / `agents wait`), [#699 `prowl create pane`](https://github.com/onevcat/Prowl/issues/699), [PR #651 (direction reference, not merged)](https://github.com/onevcat/Prowl/pull/651), [DSL spec (living)](dsl-spec.md), [release plan (living)](release-plan.md), `docs/components/handoff.md`, `docs/components/agent-profiles.md`, `docs/components/cli.md` | @@ -593,6 +593,9 @@ attaches hooks through A2's launch boundary. ## Amendments +- Updated 2026-08-23: 064-S1 merged in #715 and the owner locked S2's paired dispatch and + evidence-wait contract, leaving S2 as the next R1 critical-path PR — see + [064.003](../064-agent-completion-signals/003-s2-dispatch-wait-design.md). - Updated 2026-08-22: Shipped C0 with the Agents sidebar group, Profiles page, and Command Line Tool page; Workflows remains deferred to D1 — see [002-settings-agents-group.md](002-settings-agents-group.md). - Updated 2026-08-22: Implemented A1 with the direct anchored split primitive and schema-governed `prowl create pane` command — see [003-cli-create-pane.md](003-cli-create-pane.md). - Updated 2026-08-22: Implemented A1b — `PROWL_PANE_ID` in every pane's environment, manual identity section, and the `prowl-cli` skill rewritten around it — see [004-pane-identity-env.md](004-pane-identity-env.md). diff --git a/docs-ai/063-agent-workflows/release-plan.md b/docs-ai/063-agent-workflows/release-plan.md index 2f79aa78..6a6fbda3 100644 --- a/docs-ai/063-agent-workflows/release-plan.md +++ b/docs-ai/063-agent-workflows/release-plan.md @@ -24,7 +24,7 @@ that 063-B3 consumes; 064-S3 attaches launch-scoped hooks through 063-A2's launc PRs merge to `main` one at a time (each keeps `main` shippable); engine PRs without a user-facing surface may merge before "their" release and stay dormant. Three releases: -### Current R1 status (2026-08-22) +### Current R1 status (2026-08-23) | Slice(s) | State | PR / next action | | --- | --- | --- | @@ -32,14 +32,14 @@ user-facing surface may merge before "their" release and stay dormant. Three rel | A1 | Merged | #710 | | A1b | Merged | #713 | | A2 | Merged | #714 | -| S1 | In progress | `feat/agent-completion-signal-bus`: bus, multicast observer, `agents signal` | -| S2 | Planned | Follows S1: atomic dispatch ID → completion receipt → `agents wait` path and honest heuristic fallback | +| S1 | Merged | #715: bus, multicast observer, `agents signal` | +| S2 | Design locked; next | [064.003](../064-agent-completion-signals/003-s2-dispatch-wait-design.md): paired dispatch receipt, strict ID wait, generic evidence wait | | S3 wave 1 | Planned | Follows A2 + S1: tier-A launch hooks | | 065-S0/K1 | Planned, parallel | Skill-target spike + bundled-skill registry | | 065-K2/K3 | Planned | Follow S0/K1 inside R1 | -A2 completes 063's R1 implementation work. The orchestration critical path now moves to -064-S1 → S2 → S3 wave 1; 065-S0/K1 may proceed independently in parallel. +A2 completes 063's R1 implementation work, and S1 is now on `main`. The orchestration +critical path is S2 → S3 wave 1; 065-S0/K1 may proceed independently in parallel. ### R1 — CLI orchestration primitives + completion signals @@ -52,7 +52,7 @@ A2 completes 063's R1 implementation work. The orchestration critical path now m | 2 | **A2** profile launch boundary + `create tab\|pane --profile

--prompt -` + `profiles list` | 063 | A1 | CLI launches a profile with a kickoff prompt and gets the pane back | | 2 | **S1** signal bus + `ObservedAgentState` multicast observer + `prowl agents signal` (`turn-ended`, needs-input/session/progress, bounded detail) | 064 | — | layer-0 signals for every runtime | | 2 | **065-K2** shared `SymlinkInstaller` + `prowl skills list\|install\|uninstall\|path` | 065 | 065-K1 | one command installs Prowl's skills into agent skill folders | -| 3 | **S2** atomic dispatch pairing (`create` dispatch ID, cooperative `dispatch-complete --detail`, bounded receipt retention, `agents wait --dispatch` with overflow resnapshot) + `source`/`confidence`, `--include-screen`, `agents` `signals`, and skill rubric | 064 | S1 | no hand-written polling or stale completion; heuristic results are labelled | +| 3 | **S2** prompted-profile dispatch pairing (`create` dispatch ID, required `dispatch-complete --outcome ... --summary`, 256-entry receipt retention, strict ID-only `agents wait --dispatch`) + generic evidence wait, `source`/`confidence`, `--include-screen`, live `agents.signals`, and skill rubric | 064 | S1 | no hand-written polling or stale completion; deterministic task receipts stay separate from labelled heuristics | | 3 | **065-K3** Agent Skills section on Settings › Command Line Tool | 065 | 065-K2 | GUI users install skills without a terminal | | 4 | **S3 wave 1** launch-scoped hooks for tier-A runtimes (Claude Code, Codex `notify`, Copilot, Droid, Qoder, Pi, OMP, OpenCode) + self-check | 064 | A2, S1 | `agents wait` is deterministic for Prowl-launched agents | @@ -107,6 +107,10 @@ R3+: V2 / S5 rest; delete HANDOFF_RETIRED stubs ## Change log +- 2026-08-23 — S1 merged in #715. Owner review then locked S2: prompted launches always + create a dispatch, completion has an immutable succeeded/failed summary receipt, strict + dispatch waits never accept heuristic completion, and generic waits retain honest auto + fallback. See [064.003](../064-agent-completion-signals/003-s2-dispatch-wait-design.md). - 2026-08-22 — S1 started on `feat/agent-completion-signal-bus`; owner review moved the complete dispatch-ID issuance/receipt/wait protocol into S2, renamed the runtime edge to `turn-ended`, retained bounded detail, and required explicit overflow resnapshot. diff --git a/docs-ai/064-agent-completion-signals/000-plan.md b/docs-ai/064-agent-completion-signals/000-plan.md index 1ecc0ab5..fdd68c0f 100644 --- a/docs-ai/064-agent-completion-signals/000-plan.md +++ b/docs-ai/064-agent-completion-signals/000-plan.md @@ -2,9 +2,9 @@ | | | | --- | --- | -| **Status** | In progress — S1 implementation on `feat/agent-completion-signal-bus` | +| **Status** | In progress — S1 merged in #715; S2 design locked for implementation | | **Anchor date** | 2026-08-22 | -| **Primary PRs** | S1 TBD | +| **Primary PRs** | #715 (S1); S2 TBD | | **Related** | [063 agent-workflows](../063-agent-workflows/000-plan.md) (consumer; defines the `ObservedAgentState` observer this entry feeds), [030 agent-status-detection](../030-agent-status-detection/000-plan.md), [045 native-agent-session-detection](../045-native-agent-session-detection/000-plan.md), [055 agent-profile-runtimes](../055-agent-profile-runtimes/000-plan.md), [059 agent-transcript-snapshots](../059-agent-transcript-snapshots/000-plan.md), [060 cli-targeting-and-contract-governance](../060-prowl-cli-targeting-and-contract-governance/000-plan.md), [#473](https://github.com/onevcat/Prowl/issues/473), [#676](https://github.com/onevcat/Prowl/issues/676), `docs/components/agent-detection.md`, `docs/components/cli.md` | ## Background @@ -119,9 +119,11 @@ prowl agents wait --until idle|blocked|changed|exit [--timeout 1…600] 059 result state — everything an orchestrating agent needs to judge a heuristic result in one call. - Prowl-dispatched work uses an opaque `dispatch_id`, not timestamps, to exclude stale - completion. S2 ships `create` issuance, `dispatch-complete --detail`, bounded receipt - retention, and `agents wait --dispatch` atomically. Receipts survive pane closure but not - app restart; surface generation is only the unpaired fallback. + completion. S2 ships `create` issuance, required `dispatch-complete --outcome + succeeded|failed --summary`, bounded receipt retention, and ID-only `agents wait + --dispatch` atomically. Receipts survive pane closure but not app restart; surface + generation is only the unpaired fallback. The finalized contract is + [003-s2-dispatch-wait-design.md](003-s2-dispatch-wait-design.md). - `removed` / `surfaceClosed` → `AGENT_GONE` (unless `--until exit`); timeout → `WAIT_TIMEOUT` with the last known status/source. The 600 s cap matches typical agent tool timeouts; the skill documents "re-arm on timeout". @@ -131,7 +133,8 @@ prowl agents wait --until idle|blocked|changed|exit [--timeout 1…600] When a Prowl-launched runtime declares a `sessionStart` hook, the launch boundary expects the corresponding signal within a grace window; if it never arrives the pane is marked `signals: none` (hooks did not load) instead of silently pretending. `prowl agents` -JSON gains `signals: {channels: [hook, transcript, osc], last: {...}}` per pane, and the +JSON gains `signals: {channels: [...], last: {...}}` per pane, where channels describe only +live observed or verified evidence rather than theoretical runtime support. The Active Agents panel shows a small "exact" badge for panes with a live deterministic channel. ### Judging heuristic results (skill, not code) @@ -166,7 +169,7 @@ interleaves with 063's slices, is owned by the shared living | Slice | Depends | Contents / expectation | | --- | --- | --- | | **S1** | — | Signal bus state + the `ObservedAgentState` multicast observer (snapshot / changed / removed / surfaceClosed / `.signal`; first specified in 063, delivered here so it ships first) + `prowl agents signal` for `turn-ended`, `needs-input`, session, and progress events (CLI four layers, bounded detail). Layer 0 works for every runtime immediately; 063-B3 later consumes the same observer. | -| **S2** | S1 | One atomic paired-dispatch path: `create --profile --prompt` returns `dispatch_id`; cooperative `dispatch-complete --detail`; bounded non-destructive in-memory receipts; `prowl agents wait --dispatch` with automatic overflow resnapshot; `agents` `signals` field; `--include-screen`; skill rubric. Route B usable; heuristic fallback honest. | +| **S2** | S1 | One atomic paired-dispatch path: every `create --profile --prompt` appends the completion protocol and returns `dispatch_id`; cooperative `dispatch-complete --outcome succeeded|failed --summary`; 256-entry non-destructive in-memory receipts; ID-only strict `prowl agents wait --dispatch`; generic `wait --until` with automatic overflow resnapshot and honest heuristic fallback; `agents` live `signals` field; `--include-screen`; skill rubric. Route B becomes usable without polling or stale completion. | | **S3 wave 1** | 063-A2, S1, research matrix | Launch-scoped hook injection (adapter `signalHooks`, self-check) for tier A of the research matrix (flag/env per launch, live-verified): Claude Code `--settings`, Codex `-c notify=[…]` (native `agent-turn-complete` maps to `turn-ended`; hook trust bypass is never passed), Copilot `--plugin-dir`, Droid `--settings`, Qoder `--settings`, Pi `-e`, OMP `--hook`, OpenCode `OPENCODE_CONFIG_CONTENT`. `agents wait` becomes deterministic for Prowl-launched agents on these runtimes. | | **S3 wave 2** | S3 wave 1, 053 dedicated homes | Tier B (`configDirOnly`: Gemini, Qwen, Grok, Cline, Kimi) for dedicated-home profiles only; tier C (Cursor, Amp: project files) is not attached. | | **S4** | S1 | Transcript file-watch and OSC producers — layer 2 without hooks. | @@ -232,6 +235,10 @@ opencode; partial for qodercli/qwen/amp; docs/bundle for the rest). Key conclusi ## Amendments +- Updated 2026-08-23 after S1 merged in #715: owner review locked S2's paired dispatch, + receipt lifecycle, exact-versus-heuristic wait policy, CLI outcomes, trust boundary, and + verification scope — see + [003-s2-dispatch-wait-design.md](003-s2-dispatch-wait-design.md). - Updated 2026-08-23 before merge: owner raised bounded signal `--detail` from 4 KiB to 32 KiB (32768 UTF-8 bytes). The larger bound remains well below the 32 MiB socket frame and macOS argument budget, accommodates useful completion summaries, and preserves the rule diff --git a/docs-ai/064-agent-completion-signals/001-action.md b/docs-ai/064-agent-completion-signals/001-action.md index 09abd7fc..6931a701 100644 --- a/docs-ai/064-agent-completion-signals/001-action.md +++ b/docs-ai/064-agent-completion-signals/001-action.md @@ -2,7 +2,7 @@ ## Status -Complete on `feat/agent-completion-signal-bus`; PR #715 is ready for merge. +Complete and merged in PR #715. ## Slice objective @@ -19,7 +19,9 @@ S1 does not add `agents wait`, launch-scoped runtime hooks, workflow completion, - Continue the 064 path before the 063 workflow runner. `prowl workflow done` remains the only command that completes a workflow step; agent signals are observation/control-plane evidence. - Rename the runtime edge from ambiguous `turn-complete` to `turn-ended`. A runtime hook can prove that a turn ended, not that an assigned task completed. -- Reserve `dispatch-complete` for S2's paired dispatch protocol. S2 must ship the entire path atomically: `create` returns a `dispatch_id`, the agent reports `dispatch-complete --detail`, a bounded in-memory receipt survives pane closure (but not app restart), and `agents wait --dispatch` consumes it without destructive read semantics. +- Reserve `dispatch-complete` for S2's paired dispatch protocol. S1 recorded the provisional + shape; the final owner-reviewed command and receipt contract is in + [003-s2-dispatch-wait-design.md](003-s2-dispatch-wait-design.md). - Keep bounded `--detail` in S1 so a cooperative producer can attach a short result/reason without forcing another CLI command. The owner raised its limit from 4 KiB to 32 KiB before merge: this remains small relative to the 32 MiB socket frame and 1 MiB macOS argument budget while accommodating useful completion summaries. Detail is caller-authored metadata, never logged, never raises confidence, and is not a replacement for large transcript/workflow output channels. - Public `--origin` is only a claimed origin. It cannot mark a channel as verified, raise confidence, or satisfy future hook self-checks. S3 may upgrade provenance only through a Prowl-configured launch-scoped capability; this is a correctness boundary, not a heavyweight security boundary. - Each observer has bounded buffering. State churn may be recovered by a newer snapshot. Signal/lifecycle loss is never silent: overflow terminates with an explicit internal error, and S2's waiter must re-subscribe/resnapshot before exposing a failure. diff --git a/docs-ai/064-agent-completion-signals/002-s1-work-note.md b/docs-ai/064-agent-completion-signals/002-s1-work-note.md index fac95ddd..ad08d660 100644 --- a/docs-ai/064-agent-completion-signals/002-s1-work-note.md +++ b/docs-ai/064-agent-completion-signals/002-s1-work-note.md @@ -45,6 +45,10 @@ This note tracks the authorized S1 execution. Durable design decisions belong in ## Deferred S2 contract (must not be lost) +This was the provisional S1 handoff. The owner-reviewed S2 command spelling, outcomes, +receipt lifecycle, and wait semantics are finalized in +[003-s2-dispatch-wait-design.md](003-s2-dispatch-wait-design.md). + S2 owns one atomic paired-dispatch slice: ```text diff --git a/docs-ai/064-agent-completion-signals/003-s2-dispatch-wait-design.md b/docs-ai/064-agent-completion-signals/003-s2-dispatch-wait-design.md new file mode 100644 index 00000000..730b862d --- /dev/null +++ b/docs-ai/064-agent-completion-signals/003-s2-dispatch-wait-design.md @@ -0,0 +1,288 @@ +# 064.003 — S2 Paired Dispatch and Agent Wait Design + +## Context + +S1 merged in #715 and delivered the per-surface signal state, `ObservedAgentState` +multicast observer, lifecycle events, and cooperative `prowl agents signal` ingress. S2 is +the first consumer-facing slice: it must replace hand-written polling with an atomic, +stale-safe dispatch receipt while also making generic state waits honest about their +evidence. + +This amendment records the final owner review completed on 2026-08-23. It supersedes the +provisional S2 command spelling in `002-s1-work-note.md`; S1's shipped `agents signal +--detail` contract is unchanged. + +## Starting state and confirmed seams + +- `supacode/Features/Terminal/BusinessLogic/AgentObservationStore.swift` provides + snapshot-first, independently buffered multicast observation and retains only the latest + signal per live surface. It is the right state/signal wait source but cannot retain a + task receipt after surface closure. +- `supacode/CLIService/AgentSignalCommandHandler.swift` already attributes cooperative + events through the socket peer's process ancestry. Dispatch completion reuses that trust + boundary rather than focus or caller-provided pane identity. +- `supacode/Domain/AgentProfile/AgentProfileLaunchPlan.swift` distinguishes child command + environment from surface shell environment. Only the former is safe for a launch-scoped + dispatch id. +- `supacode/CLIService/LifecycleCommandHandler.swift` already returns typed profile-launch + metadata, but prompted launches have no task identity or receipt today. +- `supacode/CLIService/ReadCommandHandler.swift` owns stable viewport capture behavior that + can supply optional post-wait evidence without redefining completion. +- `supacode/CLIService/CLISocketServer.swift` allows an async handler to suspend while other + requests are accepted. S2 is the first long-lived CLI wait, so disconnect cancellation + must be propagated instead of leaving a subscription alive until timeout. +- `supacode/CLIService/Shared/CommandResponse.swift` currently carries only error code and + message. S2 needs an optional structured error-details field for receipts and last-known + observation; omitting that field preserves existing wire responses. +- `supacode/CLIService/Shared/AgentsCommandPayload.swift` exposes detected state but no + signal evidence. S2 adds live observed/verified signal visibility. + +Consequently, S2 needs a separate dispatch store and subscriber path while consuming the +S1 observer for status, signal, and lifecycle evidence. Reusing the existing signal record +as receipt storage would lose the result on pane closure and allow unrelated later signals +to overwrite it. + +## Scope + +S2 ships three connected surfaces in one PR: + +1. `create tab|pane --profile ... --prompt ...` becomes an atomic paired dispatch and + returns an opaque dispatch id. +2. The launched agent reports one immutable terminal outcome through + `prowl agents dispatch-complete`; `prowl agents wait --dispatch` consumes the resulting + non-destructive receipt. +3. Generic `prowl agents wait --until ...`, `--include-screen`, and the `agents` + `signals` field expose deterministic observations where available and labelled + heuristics otherwise. + +S2 does not install runtime hooks, watch transcript files, infer completion with an LLM, +persist receipts across app restarts, or change `prowl workflow done` semantics. Those +remain owned by S3/S4, the orchestrating skill, and 063 respectively. + +## Two planes, one observer context + +Signals and dispatch receipts are deliberately separate: + +| Plane | Answers | Scope | Storage | Consumer | +| --- | --- | --- | --- | --- | +| Signal observation | What just happened to this agent/runtime? | Surface | Latest in-memory observation; ends with the surface | `wait --until ...`, later watchdogs | +| Dispatch receipt | Did this exact assigned task reach a terminal outcome? | Opaque dispatch id | Bounded immutable in-memory receipt; survives surface closure | `wait --dispatch ` | + +`turn-ended` is a runtime edge, not task completion. `dispatch-complete` never fabricates or +maps to `turn-ended`; a normal run may record the dispatch receipt first and receive an +independent runtime `turn-ended` signal afterward. Conversely, a deterministic terminal +signal while a receipt remains pending is actionable evidence that the completion protocol +was not fulfilled, not permission to synthesize success. + +## Paired dispatch protocol + +Every prompted profile launch is a dispatch. S2 intentionally has no `--no-dispatch` path: + +```text +create --profile --prompt + -> mint pending dispatch + -> append the versioned Prowl completion instruction to the effective prompt + -> launch the runtime with child-only PROWL_DISPATCH_ID + -> return pane identity plus dispatch.id +``` + +Launch failure removes the pending record and returns the existing typed launch error. The +capacity check and id issuance happen before starting the runtime; binding the returned +surface and completing the create response remain one main-actor lifecycle transaction. + +An unprompted `create --profile` remains an interactive launch without a dispatch. A caller +that needs byte-for-byte prompt delivery can create an interactive pane and use the existing +`send` command. + +The id must be passed through the launch plan's child-process command environment, not the +surface shell environment. The latter outlives the launched runtime and could let a later, +manually started agent inherit a stale dispatch id. The effective prompt contains the +protocol command but never the id itself. + +The injected instruction tells the agent to choose one terminal outcome and make the +completion command its final tool action: + +```bash +prowl agents dispatch-complete \ + --outcome succeeded \ + --summary "Implemented the requested change; all tests pass." +``` + +or: + +```bash +prowl agents dispatch-complete \ + --outcome failed \ + --summary "The required SDK is unavailable on this deployment target." +``` + +`--outcome succeeded|failed` and a non-empty `--summary` are required. Summary is capped at +32 KiB of UTF-8 and is the concise result retained with the receipt, not a transcript or +artifact transport. S1 keeps optional `agents signal --detail`: signal detail is event +context or a reason, whereas dispatch summary is the required terminal delivery synopsis. + +The completion command accepts no public dispatch-id option. It reads the child-only +`PROWL_DISPATCH_ID`; the app independently resolves the socket peer's process ancestry and +requires the caller pane to match the dispatch-bound surface. Missing launch context fails +with `DISPATCH_CONTEXT_REQUIRED`; a mismatched caller fails with +`DISPATCH_SOURCE_MISMATCH`. + +## Receipt lifecycle and idempotency + +The terminal manager owns a separate dispatch store with a maximum of 256 records: + +- pending records are never evicted; +- creating a dispatch evicts the oldest terminal record first; +- if all 256 records are pending, creation fails before launch with + `DISPATCH_CAPACITY_EXCEEDED`; +- succeeded, failed, and gone receipts survive agent and pane closure; +- app restart clears the store, after which an old id returns `DISPATCH_NOT_FOUND`; +- there is no disk persistence or TTL in S2. + +Completion is first-write-wins. Retrying the same id with the same outcome and summary is +idempotent and returns the original receipt. A later completion with different content +returns `DISPATCH_ALREADY_COMPLETED` and cannot mutate the recorded outcome seen by existing +or future waiters. + +## Wait contracts + +### Exact dispatch wait + +Dispatch identity is sufficient; a pane argument would be redundant and would stop working +after surface closure: + +```bash +prowl agents wait --dispatch [--timeout 1...600] +``` + +Only the matching receipt can return task success. Idle state, screen content, and +`turn-ended` never substitute for it. The outcomes are: + +- succeeded receipt: successful command with the immutable summary; +- failed receipt: nonzero exit and structured `DISPATCH_FAILED`, including the receipt; +- exact/high `needs-input`: nonzero `DISPATCH_NEEDS_INPUT`, receipt remains pending; +- exact/high stable `turn-ended` without a receipt: nonzero `DISPATCH_INCOMPLETE`, receipt + remains pending; +- session end, agent removal, or surface closure before completion: `AGENT_GONE` backed by + a retained gone record; +- timeout: `WAIT_TIMEOUT` with the last observation and evidence. + +Before surfacing `DISPATCH_INCOMPLETE`, the waiter gives a 300 ms coalescing grace period for +independently delivered receipt and signal events. This is an event-ordering allowance, not +screen stabilization. `needs-input` and disappearance remain immediate. A completed receipt +returns immediately unless the caller explicitly requests stable screen evidence. + +The receipt read is non-destructive: any number of concurrent or later waiters observe the +same outcome. Socket-client disconnect or CLI cancellation must cancel the server-side wait +subscription rather than leave a waiter alive until the timeout cap. + +### Generic observation wait + +```bash +prowl agents wait --until idle|blocked|changed|exit \ + [--timeout 1...600] [--min-confidence exact|high|heuristic] \ + [--include-screen ] +``` + +The default confidence policy is `auto`: + +- when a live exact/high channel is verified, only deterministic evidence resolves the + requested condition; heuristic changes update diagnostics only; +- without such a channel, an already-stabilized screen/process observation may resolve the + wait with `confidence: heuristic`; +- `changed` requires a post-baseline normalized state or signal change and is never + satisfied by the initial snapshot; +- `exit` accepts removal or surface closure; disappearance is `AGENT_GONE` for other + requested conditions. + +An exit-zero heuristic result means only that the requested observable condition matched. +It never means the assigned task completed. The bundled `prowl-cli` skill teaches the +orchestrating agent to inspect `agents read`, optional screen evidence, and task context +before it decides to proceed, nudge, retry, or ask the owner. + +`--include-screen` is explicit and diagnostic. After the matching event it reuses the stable +read/capture boundary for a short bounded settle so trailing terminal rendering can arrive; +it never changes the receipt or confidence decision. Existing detector stabilization remains +the heuristic gate instead of adding a universal multi-second delay to exact signals. + +Observer overflow is never ignored. The waiter re-subscribes and evaluates a fresh snapshot; +if lost signal history prevents a safe conclusion, it surfaces a structured failure instead +of guessing. + +## Signal visibility + +`prowl agents --json` reports current evidence, not runtime marketing or theoretical +capability: + +- cooperative CLI is listed only after it has been observed on that pane; +- a future S3 hook is listed as verified only after launch injection and self-check succeed; +- the latest signal retains event, source, confidence, timestamp, and optional detail; +- screen/process state remains heuristic observation evidence and does not masquerade as a + deterministic signal channel; +- no observed or verified deterministic source means an empty `channels` array, enabling + the generic wait's honest auto fallback. + +## Error and response model + +The common CLI error envelope gains optional structured details so timeout, protocol, and +task failures can return their last observation or immutable receipt without encoding data +into error strings. Existing errors omit the field and remain wire-compatible. + +`create` adds a dispatch object alongside existing launch information. Wait success includes +the dispatch id, outcome, summary, target metadata, completion timestamp, waited duration, +and observation provenance. `DISPATCH_FAILED`, `DISPATCH_NEEDS_INPUT`, +`DISPATCH_INCOMPLETE`, `AGENT_GONE`, and `WAIT_TIMEOUT` use distinct nonzero errors. + +## Implementation boundaries + +The PR changes the existing launch planner and lifecycle handler under +`supacode/Domain/AgentProfile/` and `supacode/CLIService/`, adds the dispatch store beside +the observation domain under `supacode/Domain/AgentDetection/`, and adds governed wire, +parser, renderer, router, schema, and handler coverage through `ProwlCLI/`, +`supacode/CLIService/Shared/`, `ProwlCLITests/`, and `supacodeTests/`. + +The same PR updates the normative contracts under `docs-ai/013-prowl-cli/contracts/`, the +current CLI and agent-detection manuals under `docs/components/`, and the bundled +`prowl-cli` skill. S3 runtime adapter hook injection is explicitly excluded. + +## Verification plan + +- Dispatch store: issuance, binding, both outcomes, identical retry, conflicting retry, + two waiters, terminal eviction, all-pending capacity, pane closure, and app-lifetime reset. +- Launch: child-only id propagation, no surface-shell leakage, prompt protocol rendering, + atomic cleanup on launch failure, and unprompted launch parity. +- Completion ingress: missing context, caller ancestry mismatch, wrong pane, validation, + summary UTF-8 bounds, and immutable receipt behavior. +- Dispatch wait: already completed, delayed completion, failed outcome, needs input, + terminal signal grace, gone surface, timeout evidence, cancellation, and concurrency. +- Generic wait: initial snapshot, transition, post-baseline `changed`, exact/high gating, + auto heuristic fallback, stable screen evidence, overflow resnapshot, and target exit. +- Four CLI layers: parser, shared wire models, router/handler, text/JSON rendering, + executable schema, raw socket fixtures, and current manuals/skill. +- Required gates before PR: CLI build, smoke and integration tests, format/lint, app tests, + app build, and live prompted-profile checks for the paired route and heuristic fallback. + +## Owner decision record + +1. Every prompted profile launch appends the documented completion protocol. +2. Dispatch completion and runtime `turn-ended` remain separate facts and stores. +3. `wait --dispatch` is strict and never accepts an idle or heuristic substitute. +4. Exact/high stable signals may accelerate attention or failure transitions; heuristic + changes are evidence for the orchestrating agent only. +5. Dispatch uses required `summary`; S1 signal keeps optional `detail` because their content + roles differ. +6. Completion is first-write-wins with idempotent identical retries. +7. Terminal outcomes are explicitly `succeeded` or `failed`. +8. The store is memory-only, bounded to 256 records, and survives pane closure but not an + app restart. +9. Generic wait uses deterministic evidence when present and honest heuristic auto fallback + otherwise. +10. `wait --dispatch` is addressed only by dispatch id. +11. A failed receipt makes wait return nonzero `DISPATCH_FAILED` with structured receipt + details. +12. The prompted-profile dispatch path has no opt-out in S2. +13. Completion accepts only implicit launch context plus verified caller-pane ancestry. +14. `agents.signals` reports only live observed or verified channels. + +No product-level questions remain open for S2. Internal type names and small payload-layout +choices may be refined during RED/GREEN implementation without changing these contracts.