# pi-orca-messages

**Inter-session messaging for Pi coding-agent sessions.**

License: MIT

## Overview

This extension lets multiple Pi sessions running against the same project deliver messages to each other. A "primary" session can ask a "secondary" session a question, an agent can broadcast a status update, and so on. Messages arrive in the recipient's chat as if the user had pasted them in — the recipient's LLM responds on its own turn without manual prompting.

**Architecture in one screen:**

- **Store / inbox split.** Senders write the message body once to `~/.pi/agent/sessions/<project-slug>/orca/messages/store/<yyyy>/<mm>/<dd>/msg-<uuid>.md` and create a small `.ref` pointer in each recipient's `inbox/<recipient-session-id>/`. The store is immutable; the inbox is the work queue.
- **Registry.** Each running session registers itself in `<project-slug>/orca/registry.yaml` at `session_start` (and deregisters on shutdown), recording its UUID, optional human-friendly name, PID, and labels. Senders look recipients up here.
- **Delivery into the LLM.** Two paths, both atomic (deliver + consume in one shot):
  - **Idle push (`pi.sendUserMessage`)** — every `polling.idleIntervalSeconds` (default 30s) the extension peeks the inbox, and if the session is idle it renders all unread messages as a rich user prompt (sender name + UUID, sent-at, title, labels, body) and pushes them via `pi.sendUserMessage`. The agent responds as if the recipient typed a summary themselves.
  - **Context-hook inject** — when a turn is already starting (user typed something, or idle-push deferred because the session was busy), the `context` event hook injects the same rich prompt into the outbound `event.messages` array.
- Each path consumes only the refs it just delivered, so messages are never silently dropped.

See the [Pi Orca specification §4](../../docs/spec-v0.3.0.md) for full details.

## Tool

```jsonc
{
  "name": "message",
  "parameters": {
    "action": "send",          // send | broadcast | read | list | register | sessions
    "to": "primary",           // session UUID, name, or unique prefix of either
    "title": "Auth scan results",
    "body": "Found 3 files...",
    "labels": { "topic": "auth-refactor" }
  }
}
```

The `to` field is resolved through `resolveSession()` — exact UUID match wins, then exact name, then unique prefix on UUID, then unique prefix on name (case-insensitive). Ambiguous prefixes return an error listing the candidates.

## Slash commands

| Command | Description |
|---|---|
| `/messages` | Open the interactive overlay (inbox / detail / sessions / compose). |
| `/messages send <session> "<title>" "<body>"` | Send to a UUID, name, or unique prefix. Quotes preserve multi-word arguments. |
| `/messages broadcast "<title>" "<body>"` | Send to every registered session except yourself. |
| `/messages read` | Consume your inbox manually (turns refs into a one-shot dump). |
| `/messages list` | List all messages in the project store without consuming refs. |
| `/messages sessions` | List currently-registered sessions, leading with each session's display name. |

The `<session>` argument may be a UUID, a `/name`-set display name, or a unique prefix of either. Quoted args (`"…"` / `'…'`) preserve whitespace; backslash escapes work inside quotes.

## Naming sessions

Pi's built-in `/name <text>` slash command sets a display name on the current session. The messages extension records the name in the registry so other sessions can address you by name instead of UUID. Renames propagate immediately when you next interact with the messages extension (slash command, tool, or overlay) and within `polling.idleIntervalSeconds` otherwise.

## Logging / observability

The extension emits `info`-level entries to `~/.pi/agent/orca/log.jsonl` for every meaningful lifecycle event:

- `send: <from> → <to> "<title>" (<msg-id>)`
- `broadcast: <from> → N recipient(s) "<title>" (<msg-id>)`
- `idle-poll → sendUserMessage: N message(s) (<titles>)`
- `idle-poll: N unread, session not idle — deferring to context hook`
- `context-inject: N message(s) → <recipient> (<titles>)`

`debug`-level entries (one per `.ref` written or consumed) are emitted when `logLevel: debug` is set in `config.yaml`. Tail the log file to follow the flow end-to-end across multiple sessions.

## Configuration

`~/.pi/agent/orca/config.yaml` (or `<project>/.pi/orca/config.yaml`):

```yaml
polling:
  idleIntervalSeconds: 30   # how often the idle push checks the inbox
```

## Dependencies

- `@pi-orca/core` — shared types, utilities, `bindSession()`, `tokenizeArgs()`, registry helpers.

## License

MIT License — see [LICENSE](../../LICENSE) for details.
