CLI: mail
npx cyberlegion mail <send|inbox|read|ack|delete|await|watch|hook> ...mail is durable inter-agent messaging: the store and the universal return channel every unit
gets once it registers. It is the peer, non-authoritative plane; see Mail
Model for the full model and its contrast with the authoritative mux plane.
npx cyberlegion mail send --to <peer> [--from <id>] [--subject <s>] [--body <text> | --body-file <path>] [--thread <id>] [--reply-to <msg>] [--no-nudge]Send a message to a peer, by handle or id. Also available as the top-level alias cyberlegion send.
| Option | Meaning |
|---|---|
--to <peer> |
recipient handle or id (required) |
--from <id> |
sender id (else this session’s own identity) |
--subject <s> |
subject |
--body <text> |
message body |
--body-file <path> |
read body from a file, or - for stdin |
--thread <id> |
thread id |
--reply-to <msg> |
message id this replies to |
--no-nudge |
suppress the delivery doorbell (do not wake the recipient’s pane) |
Delivery is durable first; waking the recipient’s pane is a best-effort act on top and never fails
the send. A failed wake prints a warning instead. Output: sent (message id), to, subject,
rung (whether the doorbell fired), and spawned (the unit’s id) when the send spawned a presence.
A standing owner is woken in this order: its live presence (unit claim); else, when it has a
home (unit register --standing --home), a presence spawned in that home; else the hub’s bound
main pane, if it is focused. A spawn that cannot happen is a warning, and the wake falls back to the
main pane. A sender outside any multiplexer pane (a cron job, say) cannot open a pane, so it warns
instead. It can reach a running multiplexer by setting CYBER_MUX=herdr or CYBER_MUX=tmux in its
environment. tmux also needs a server already running, and opens the window in tmux’s current
session. --no-nudge spawns nothing.
npx cyberlegion mail inbox [--unread] [--from <id>] [--thread <id>] [--owner <ref>]List your mail. Also available as the top-level alias cyberlegion inbox (without --owner).
| Option | Meaning |
|---|---|
--unread |
only un-acked mail |
--from <id> |
filter by sender |
--thread <id> |
filter to messages carrying this thread id |
--owner <ref> |
target a standing owner’s mailbox (by handle) or a service endpoint’s (by id or unique handle) instead of this session’s own |
Output: a messages table (id, from, subject, read) with an aggregate <N> messages (<U> unread). Suggests mail read <id> on the first unread message as a next step.
npx cyberlegion mail read <msg-id> [--ack] [--owner <ref>]Read a message. Peeking alone does not consume it; --ack acknowledges it in the same step.
| Option | Meaning |
|---|---|
--ack |
acknowledge the message in the same step (idempotent, so no error if already acked) |
--owner <ref> |
read a standing owner’s or a service endpoint’s mailbox instead of this session’s own |
Errors if the message id isn’t in the resolved inbox. Without --ack, suggests mail ack <id> as
a next step.
npx cyberlegion mail ack <msg-id> [--owner <ref>]Acknowledge a message, moving it out of the unread set. --owner <ref> acks a standing owner’s or a service endpoint’s
mailbox instead of this session’s own.
delete
Section titled “delete”npx cyberlegion mail delete <msg-id>Permanently remove a message from your inbox, unread or already-acked.
npx cyberlegion mail await --thread <id> [--from <h>] [--timeout <ms>] [--max-wait <s>]Block until a thread-correlated reply arrives, print it, and ack it.
| Option | Meaning |
|---|---|
--thread <id> |
thread id to wait on (required) |
--from <h> |
only match a reply from this sender |
--timeout <ms> |
give up after this many ms with no match (0 = wait forever); exits non-zero on timeout. Default 600000 |
--max-wait <s> |
self-cap for one internal poll cycle, in seconds; returns the clean “waiting” sentinel at this cap so the caller can re-arm rather than blocking past a harness tool-timeout. Default 240 |
Three outcomes:
| Outcome | Exit | Behavior |
|---|---|---|
matched |
0 | the message is printed on stdout and acked |
waiting |
0 | a stderr “waiting” line and nothing on stdout. The per-call --max-wait cap was hit with no match yet; re-run the same command to keep waiting |
timed-out |
1 | a clear stderr message and nothing on stdout. --timeout elapsed with no match |
Prefer being woken over calling await. See Architecture: Delegation &
return.
npx cyberlegion mail watch [--thread <id>] [--from <h>]Stream new matching mail as it arrives. An observer only: it never acks. Ctrl-C to stop.
npx cyberlegion mail hook [--event <event>]Emit the harness hook injection payload (raw JSON on stdout, not TOON). --event takes only
SessionStart (the default). PostToolUse is retired and rejected: mail that arrives mid-turn
reaches a busy session through the mail send doorbell instead. This is the command the surfacing hook calls on every matching harness
event (the plugin’s own hook on Claude Code and Codex, the project hook init registers on Cursor).
It’s rarely invoked by hand.
Related
Section titled “Related”- Mail Model: the address/correlation model and why mail stays non-authoritative
- CLI: unit: registration is what mints a mailbox
- CLI: init: sets up the hook that calls
mail hook - Skill: manage-inbox: the human-facing wrapper for the owner mailbox