Email actions and storage
The root manual is the first-call router and the schema is authoritative. This
page covers action details that need care; action input objects remain closed.
Omitted optional values use defaults, and explicit null is omitted at the family
boundary.
Send
email(action="send", input={
"address": "peer", "subject": "status", "message": "ready",
"cc": ["human"], "bcc": [], "attachments": [], "delay": 0,
"mode": "peer", "type": "normal",
}, reasoning="report status")
address is a bare peer name, or an explicitly authorized absolute path with
mode="abs". CC is visible to recipients; BCC is stored only in the sender's
copy. attachments are source paths: for non-self POSIX delivery the adapter
validates every path before publishing that recipient's inbox entry, copies files
into recipient-local attachments/, and suffixes duplicate basenames. Source
paths are resolved/read at delivery time, so preserve their bytes until delivery;
there is no send-time frozen snapshot. No attachment-size or source-root-containment
limit is enforced: select only files you are authorized to share. A self-send bypasses this adapter
and does not validate or copy attachments; its inbox note can retain a missing
source path. Do not treat self-mail as an attachment backup. The message body is capped at 50,000 Unicode characters and is rejected,
not truncated, when oversized.
Each recipient's outbox is written before its thread starts; the unified sent
record follows all thread starts. status="sent" is scheduling, not acceptance.
Use a non-negative integer delay for one future attempt, not tool execution;
the schema does not enforce a non-negative bound. For partial failures and restart
limits read Notifications and delivery.
The duplicate guard compares recipient/body, not the whole message; see
Settings reference.
Check and search
check lists newest first from inbox; folder may be inbox, sent, or
archive, and n defaults to 10. Its only filter object supports:
sort:newest(default) oroldest;from,subject,contains: case-insensitive substrings;after,before: ISO 8601 timestamps;unread_only,has_attachments: boolean selectors;truncate: preview characters, default 500;0requests the full body.
Email may trim a large check result to its token budget and reports that fact.
search takes a regex query and optional folder, searches sender/subject/body,
and rejects invalid regex; it accepts neither filter nor n. With no folder,
search covers inbox + sent. Folder-less read searches inbox, sent, then archive;
only inbox records are marked read.
Read, mutate, and contacts
readtakes mailbox IDs, returns source records including attachments, and marks inbox IDs read.dismissmarks handled inbox IDs read without returning bodies.reply/reply_alltake one ID and a message; routing and subject derivation are in Addressing and replies.archivemoves inbox IDs tomailbox/archiveand removes them from the read set.deletepermanently removes inbox/archive IDs and refusessent.contactslists the private book;add_contactupserts;remove_contactdeletes;edit_contactchanges only supplied name/note fields. Contact writes use a temporary file and atomic replacement.
IDs must come from this agent's current notification or mailbox result. Stale or foreign-working-directory IDs have no meaning and produce a not-found hint.
Self-send and time capsules
An already-delivered self-note survives molt; dismiss/read clear unread status
but retain the message, archive moves it, and delete removes it. Before delivery,
a delayed self-note depends on the current mailman daemon thread staying alive;
outbox persistence does not make that timer survive process exit. Use it as a
one-shot time capsule, not delayed tool execution or a durable scheduler.
Recurring or restart-resilient work belongs to shell-manual.
Mailbox layout and retention
Paths are relative to the agent working directory:
mailbox/inbox/<id>/message.json received mail
mailbox/sent/<id>/message.json one sent record per call
mailbox/archive/<id>/message.json archived inbox mail
mailbox/outbox/<id>/message.json pending/delayed send
mailbox/read.json read-ID set
mailbox/contacts.json private contact book
.notification/email.json producer-owned unread mirror
Message JSON is UTF-8. Non-self POSIX recipient entries use staging + atomic
publication; self-inbox, outbox and unified sent records use direct writes.
read.json and contacts use temporary-file replacement. BCC is not exposed in
recipient payloads. Do not infer crash durability from these different write paths.
Cleanup / Footprint
Email leaves the paths above, recipient attachment snapshots, and ordinary Agent
logs/bounce events. Before mailbox retirement or when attachment growth matters,
inspect only this Agent's mailbox/ and .notification/email.json with the
shared read-only count/byte recipe in skills-manual →
reference/cleanup-footprint-contract.md#shared-footprint-check-recipe.
Inspect metadata without broadcasting private bodies/addresses. Keep sole copies
of decisions, handoffs, attachments, contacts and pending/evidence records.
Show a dry-run report listing what would stay or go, obtain explicit human consent,
then prefer authorized archive/delete actions over filesystem removal. Do not
clean active outbox state. Cleanup is optional; without consent stop at the report.
If recording the audit, separately opt into the shared logs/cleanup.jsonl append
(timestamp, Email label, dry-run/apply, count, bytes, non-secret path summary,
approval). Inspection alone writes nothing; approved apply records actual results.