# Message delivery and rendering

Pi Subagent requires **Pi 1.2.0 or newer**. Main ↔ Sub messages use `pi.sendMessage()` with `deliverAs: "followUp"` and `triggerTurn: true` in both directions:

- **Busy receiver:** Pi queues the custom message behind its current work.
- **Idle receiver:** Pi prepares and starts the run, including `before_agent_start`, the tool loadout, and prompt sections. The event has `messageType: "custom"`, with the starting `message` rather than a user `prompt`.

There are no synthetic user-role wake messages, version fallbacks, or patches to Pi internals. Custom messages do not pass through user-input processing or execute peer text as slash commands or templates.

## Sub talk and turn control

Sub's `talk` accepts an optional `endTurn` boolean, defaulting to `false`:

- Omitted or `false`: send the message and continue working. Use this for progress updates; no acknowledgement or "continue" reply from Main is required.
- `true`: send the message and end the current turn. Use this for completed work or a blocking question that requires Main's reply. Send a terminating `talk` on its own: Pi only ends the tool batch early when every tool result in it is terminating.

Ending a turn does not close the Sub or discard queued follow-ups. Main can still send further work through `talk`. Message text should make clear whether it reports progress, asks a blocking question, or delivers completed work; Main must not treat every message as task completion. Main's own `talk` does not end its turn.

## Delivery guarantees

- `content` carries the peer message and routing instructions; `details` carries rendering and receipt metadata and is not sent to the model.
- Custom cards retain their title, collapsed/expanded rendering, and saved-session rendering.
- A message file is removed only after its receipt appears in the receiving session. Existing user-message receipts remain recognized to avoid redelivery of saved messages; this is data compatibility, not support for older Pi runtimes.
- In-flight message IDs prevent duplicate submission. Synchronous submission failures leave the file retryable. Pi owns run preparation and queueing; the plugin does not keep a separate wake reservation or retry timer.

Pi 1.2.0 includes the native custom-message preparation fix in [#10739](https://github.com/earendil-works/pi/pull/10739), resolving [#5581](https://github.com/earendil-works/pi/issues/5581) and [#10267](https://github.com/earendil-works/pi/issues/10267). Real SDK regression tests require profile sections to remain present on the first idle delivery, subsequent turns, busy follow-ups, and after reload. No upstream TODO or workaround is retained.
