# omp-mail โ federated agent mail for oh-my-pi
Inter-session messaging for `omp`: separate agent processes send each other mail
through a singleton mailbox daemon. Sessions are addressed by **session id**,
an **auto-generated slug**, or a **user alias** โ mail is delivered live when
the recipient is running, and stored for **inbox-on-resume** when it is not.
No core changes โ it is a plain [extension](https://github.com/can1357/oh-my-pi) plus a small Node daemon.
Install: `/marketplace add jokull/omp-mail` โ `/marketplace install omp-mail@omp-mail`.
## Sending mail
You are Agent A, the other agent is B. You type one line:
```
โโ omp ยท t1 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ /mail t2 hello-from-A first live mail โ
โ โ t2 ยท hello-from-A ยท delivered live โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
`/mail <to> <subject> <body>` โ recipient first, that's the whole syntax.
`to` is a slug (`t2`), an alias, a session id, or `all` for broadcast.
Across the room, B's terminal lights up:
```
โโ omp ยท t2 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ฌ Mail from t1: hello-from-A โ
โ โ
โ first live mail โ
โ โ
โ Reply with mail_send(to: "t1", โ
โ subject: ..., body: ...). โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
No human in the loop: B's agent wakes on the mail, replies with `mail_send`,
and the reply lands back in A. The daemon's log shows the whole round trip:
```
send "hello-from-A" 019ff693-โฆ -> t2 (1 mailbox(es), 1 live)
send "Re: hello-from-A" 019ff693-โฆ -> t1 (1 mailbox(es), 1 live)
```
## How it works
```
omp (agent A) omp (agent B) omp (agent C)
โ โฒ โ โฒ โ
โโโโผโโโโโโโโโโโโโโโโโโผโโโผโโโโโโโโโโโโโโโโโโโ
โ register / โ โ mail push
โ mail send โ โ
โผ โผ โ
[mail-daemon] โ singleton process
~/.omp/mail-daemon.sock
~/.omp/mail/<sessionId>.jsonl (mailboxes, append-only)
~/.omp/mail/agents.json (registry: slugs, aliases, cursor)
```
- **Daemon** (`daemon.mjs`) โ singleton over a Unix socket; auto-spawned
(detached) by the first extension that needs it, survives agent restarts.
Resolves slugs/aliases, persists mailboxes, pushes live.
- **Extension** (`omp-mail.ts`) โ loaded by every omp process. Registers on
`session_start`, re-registers on `session_switch`, unregisters on shutdown.
Injects incoming mail via `sendUserMessage` (starts a turn when idle). Falls
back to polling its own mailbox when the daemon is unreachable โ mail still
lands and is delivered on resume.
## Features
- **Live delivery** โ daemon pushes mail to connected sessions; the recipient
agent wakes and can reply via `mail_send` without a human.
- **Offline + inbox-on-resume** โ mail to an offline session is appended to its
mailbox and replayed on the next register (daemon cursor + per-session cursor
file dedupe).
- **Broadcast** โ `to: "all"` delivers to every registered session (sender
included).
- **Addressing** โ resolved as: exact session id โ slug โ alias โ unique id
prefix.
- **Auto-slug**: derived from the session name (cwd basename fallback;
content-derived title once OMP generates one), deduped `-2`, `-3` โฆ
- **Alias**: `/mail alias bb` pins a memorable address.
- **Agent tools** โ `mail_send` and `mail_agents`, so agents discover and
message each other without human help.
- **Human surface** โ `/mail` command: `whoami`, `alias`, `agents`, `inbox`,
`test`.
## Install
It's on a marketplace โ two commands:
```
/marketplace add jokull/omp-mail
/marketplace install omp-mail@omp-mail
```
(CLI equivalents: `omp plugin marketplace add jokull/omp-mail` then `omp plugin install omp-mail@omp-mail`.)
Prefer iterating on the code? Link the repo โ changes are live on the next omp start:
```
omp plugin link /path/to/omp-mail
```
### Raw install (no plugin system)
```sh
# 1) per-invocation
omp -e /path/to/omp-mail/omp-mail.ts
# 2) global โ loads in every omp session
cp omp-mail.ts daemon.mjs ~/.omp/agent/extensions/
# 3) project-local
mkdir -p .omp/extensions && cp omp-mail.ts daemon.mjs .omp/extensions/
```
The daemon auto-spawns on first use โ nothing else to start. Override the
daemon path with `OMP_MAIL_DAEMON=/path/to/daemon.mjs`.
## Commands
```
/mail t2 quick check all good # send: <to> <subject> <bodyโฆ>
/mail alias bb # pin an alias for this session
/mail agents # who's online (slug/alias/id)
/mail inbox # last 8 messages
/mail whoami # this session's address
```
Agents use the same surface via tools:
- `mail_send(to, subject, body)` โ `to` accepts slug, alias, session id, `"all"`
- `mail_agents()` โ listing with slug / aliases / id / live state
## Teach your agents to use it
`skills/omp-mail/SKILL.md` teaches the model the mail channel: reply by mail
when a task arrived by mail, reply in the TUI when driven directly, how to
address peers, and broadcast etiquette. It ships bundled with the plugin
(marketplace/link/npm installs discover it automatically). For raw file
installs, copy it alongside:
```sh
cp -r skills/omp-mail ~/.omp/agent/skills/
```
## Layout
```
daemon.mjs mailbox daemon (Node, no deps)
omp-mail.ts omp extension (tools + events + /mail command)
skills/omp-mail/ SKILL.md โ agent-to-agent mail etiquette
```
## Status
Working prototype. Known edges: `"all"` includes the sender; content-derived
slugs update only when OMP generates a session title (mail-driven sessions may
keep the cwd fallback); extension async jobs are still gated by core (#8322).
MIT.