Agent inbox
Mail is a Markdown file. Deliver it with an atomic rename; the recipient reads it and archives it after handling it. Any agent with filesystem access can participate.
main checkout ----+--> shared .agents/inbox/<agent>/
linked worktree ---+
message: tmp/ --mv--> new/ --read + handle--> archive/
owner: sender recipient
Set up and discover
Pick a short, goal-oriented name such as auth-rewrite. Use lowercase kebab-case, check for an existing owner, and add a suffix if the name is taken. Keep your name for the session even if the task changes. One reader owns each inbox.
Set skill_dir to the directory containing this SKILL.md, then:
. "$skill_dir/scripts/lib.sh"
inbox_root=$(agent_inbox_root) || exit 1
export AGENT_INBOX_NAME=auth-rewrite
mkdir -p "$inbox_root/$AGENT_INBOX_NAME"/{tmp,new,archive}
ls "$inbox_root" # Discover peers; directories may belong to inactive sessions.
Share your name and resolved inbox root with collaborators. Directory existence does not prove an agent is running.
By default, all worktrees in a Git clone share .agents/inbox/ beside the common Git directory. This keeps discovery simple and mail independent of worktree deletion. Outside Git, the default is $PWD/.agents/inbox/; collaborators must use the same directory.
Set AGENT_INBOX_ROOT to an absolute path to override the default. Use a worktree-local .agents/inbox/ when isolation or filesystem permissions require it, and share that exact path with peers. A shared inbox may require access beyond an agent's worktree sandbox. Keep inbox contents ignored by Git; they are coordination state, not source code.
Send and reply
Use a unique filename and write in the recipient's tmp/, then rename into its new/. Both directories must be on the same filesystem. mktemp prevents concurrent senders from reusing a filename.
recipient=api-review
mkdir -p "$inbox_root/$recipient"/{tmp,new,archive}
draft=$(mktemp "$inbox_root/$recipient/tmp/$(date -u +%Y%m%dT%H%M%SZ)-auth-ready.XXXXXX") || exit 1
cat > "$draft" <<EOF_MESSAGE
---
from: $AGENT_INBOX_NAME
to: $recipient
reply_to: ../$AGENT_INBOX_NAME/tmp/
timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)
thread: auth-v2
---
Auth middleware is ready on branch feat/auth-v2. Please review the token validation.
EOF_MESSAGE
mv "$draft" "$inbox_root/$recipient/new/$(basename "$draft").md"
The body should state the result or request, relevant evidence or file/branch references, and the next action. Keep it short. Use a quoted heredoc for literal bodies containing shell syntax.
Messages have YAML frontmatter. from, to, reply_to, and timestamp are required; thread is optional topic grouping. Keep the same thread when replying. Filenames end in .md; a UTC timestamp, subject, and unique suffix make them easy to scan.
To reply, resolve reply_to relative to the recipient's inbox directory, not its new/ directory. It identifies the sender's tmp/; deliver to the sibling new/ using the same write-and-rename sequence. For separate inbox roots, use an agreed absolute reply_to path. Check that the path belongs to the intended peer before writing.
Read and archive
ls "$inbox_root/$AGENT_INBOX_NAME/new/"
cat "$inbox_root/$AGENT_INBOX_NAME/new/<file>.md"
# After handling the message or recording its follow-up:
mv "$inbox_root/$AGENT_INBOX_NAME/new/<file>.md" "$inbox_root/$AGENT_INBOX_NAME/archive/"
Read and archive only your own mail unless asked to act for another agent. Archiving acknowledges handling, not task completion. Send an explicit reply when the sender needs a result. Delivery does not guarantee an agent is awake or has read the message.
Optional notifications
Run scripts/check-inbox-hook.sh at a turn boundary for an unread count, or scripts/inbox-startup.sh at session start for a summary. Both are read-only and silent when empty.
Both use AGENT_INBOX_NAME, falling back to CLAUDE_SESSION_NAME for existing integrations. Safe legacy names, including uppercase letters, underscores, and spaces, retain their inbox identity. Unsafe legacy titles fall back silently to anonymous; invalid explicit inbox names are configuration errors. With no identity set, they report only the shared unread count. Export the name where the hook runs; setting it in a child shell does not configure the parent session.
Attach these scripts through your tool's hook configuration using their absolute install paths. Scheduling and waking agents belong to that tool; the inbox protocol only delivers files.
Existing inboxes
The message format is unchanged. Before moving an old worktree-local inbox, pause its readers and writers, resolve the shared root, and check for name and filename collisions. Merge messages deliberately; do not blindly move agent directories over existing inboxes. Verify the mail arrived and update collaborators' paths before removing the old copy.