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.