oh-my-pi extension: calling pi.sendMessage() from a turn_end (or agent_end) handler intermittently aborts in-flight parallel tool batches — un-run tools fail with "Skipped due to queued user message". It also appeared to trigger a fake turn cycle (turn_start/turn_end recursion), which tempts a re-entrancy-guard workaround that doesn't fix the tool skips.
Root cause: turn_end/agent_end fire while session.isStreaming is still true, and sendCustomMessage with no deliverAs defaults to deliverAs: "steer" — i.e. agent.steer(). The agent loop's checkSteering() after each completed tool sees the queued message, sets interruptState, and skips the rest of the batch (createSkippedToolResult → "Skipped due to queued user message"). Dispatch is fire-and-forget with async image normalization first, so the steer lands at racy times — sometimes mid-batch (skipped tools), sometimes between turns (looks like a fake turn cycle). A re-entrancy guard treats the symptom only.
Fix: never use default-delivery sendMessage from turn_end/agent_end. Split into two channels:
Caveat: nextTurn-queued messages are in-memory; if the process exits before the next prompt (omp -p), the queued message is dropped. Verified: parallel sleep batches show zero skips; the hidden stamp is delivered verbatim to the model at the next prompt and persisted as a display:false custom_message.