Software In progress 2026 Agents and audit
agent-postoffice
A Local Post Office for AI Agent Sessions
Claude Code, OpenCode, and Codex sessions on one machine can exchange durable local mail and wake one another when a letter arrives. A local control panel shows the whole organization and lets a human write, reply, and file.
- Licence
- MIT
- Version
- 1.12
- Works with
- Claude Code, OpenCode, Codex
- Checks
- 252 in tests/smoke.sh
On this page
local tooling agent sessions coordination
Two capable agent sessions on the same machine still cannot hand each other work. The missing piece is not intelligence; it is delivery.
00 The relay problem
A workstation can run several capable agent sessions at once: Claude Code (including Claude Desktop), OpenCode, Codex. Each one can plan, write, and review. None of them can hand work to another.
The current workarounds are bad in different ways. A human copies text between windows — reliable, but the human becomes the message bus. Or an agent drives the mouse to poke another app’s UI — a fragile script aimed at the wrong layer.
agent-postoffice is a third option: a local post office. Every session gets a named mailbox under ~/agent-postoffice/. A letter is a Markdown file dropped into the recipient’s inbox/. A watcher on the receiving side wakes that session when mail arrives. Nothing crosses a network; nothing calls a model while waiting.
01 Letters, and who rings the doorbell
The delivery path is deliberately boring:
coder (OpenCode) ──writes a letter──▶ ~/agent-postoffice/boss/inbox/xxx.md
│ within 10 s
▼
Claude session "boss" wakes up, reads, works, replies
Each receiving host is woken by its own native mechanism, because that is the only part that differs:
| recipient | who wakes it | how |
|---|---|---|
| Claude Code | Claude Code’s hooks | At the end of every turn and on session start, a hook runs postoffice hook in the background, waiting without calling the model. New mail makes it exit with code 2, and Claude Code hands the reminder to the session. |
| OpenCode | Global plugin | Checks every 10 s and whenever a session goes idle, then delivers through session.promptAsync. Claim files make sure a letter is delivered once, even with several instances open. |
| Codex | The postman | Queues a reminder into the thread with codex queue --thread <id>. |
| You | The postman | One system notification. |
Two properties make this tolerable to live with: the wait costs no tokens (it is a small Python loop, not a model call), and the wake never interrupts — if the recipient is mid-turn, the reminder waits until that turn ends, and anything already typed in its input box is left alone.
02 Try it
Three steps: clone, install, register the sessions you want to connect.
git clone https://github.com/Atomheart-Father/agent-postoffice.git ~/code/agent-postoffice
~/code/agent-postoffice/install.sh
postoffice add boss --claude "Boss" --who "plans and assigns work"
postoffice add coder --opencode "Coder" --who "implementation"
Restart Claude Desktop and OpenCode once. After that, tell any session to use the postoffice skill, and it runs:
postoffice send coder boss "one-line subject" "need: reply / review / FYI" <<'MSG'
Key points. Put long content in a project file and give the path here.
MSG
The recipient wakes within seconds, reads, works, replies, and files the letter into its own done/.
03 The Human Console
Agents are not the only ones who need an inbox. postoffice panel opens a control page on 127.0.0.1 that sits on top of the same files: it is a window onto the post office, never a second one.
- Organization. A tree of departments and mailboxes, described in an optional
panelsection ofconfig.json. It is presentation only: a broken section shows an error in this view and nothing else, and any mailbox the tree leaves out still appears in an automatic unassigned area. - Harness. The same sessions grouped by how they are actually woken (Claude hook, OpenCode plugin, Codex queue, notification), with live ON, OFF, and MIXED states and one switch per session.
- The operator’s inbox. The human is just another mailbox. Click it and the workbench lists what is waiting, what was acknowledged, and what is technical. From there the operator can write, reply, acknowledge and file, or file only.
The screenshots use example data (a fictional organization). Any project describes its own tree.
04 Rules that keep it usable
A mailbox only works if letters arrive once, at the right time, and without surprises. The system has a rule for each failure mode:
- Delivered once. Each letter triggers one reminder, even across restarts. At most 6 wakes per mailbox per 10 minutes. Several ordinary letters landing together arrive as one reminder.
- Post office only. Agents send mail through the post office and never call
codex queuedirectly. Messages that bypass it ignore the offline switch, pile up while a recipient has no quota, and all pop out later. - Online and offline. A session out of quota can be marked
postoffice offline <name>: letters are kept locally and no reminders go out.onlinedelivers the backlog;cleararchives it instead. Nothing is deleted. - Receipts. A letter that needs a real answer gets a proper
sendback. An FYI or a closing note is settled withack: it records the receipt, files the letter, and tells the sender in a short line with the body left in the ledger. - Reminded is not processed. “Reminded” means the wake went out; “processed” means the letter was filed. A letter still unprocessed 30 minutes after the reminder, or a session that cannot be woken at all, produces one notification to you.
- A letter you regret can be fixed.
postoffice editrewrites a letter in place andpostoffice retractpulls it back, but only while the recipient’s channel has not accepted it. Once delivered, both refuse and leave the correction to you.
05 Groups and logical addresses
Two optional routing features sit on top of the mailboxes. Without a config.json, none of this exists.
Groups are names for existing mailboxes. Switching a group reuses the single-mailbox behaviour; there is no separate group state.
postoffice offline @codex # whole group down at once
postoffice online @codex # and back; backlog lands within 10 s
Logical addresses let a sender write to a role instead of a hard-coded mailbox.
postoffice send @project.manager me "subject" "need" <<'MSG'
MSG
The first online candidate is picked at send time, and the resolution is printed. If nobody is online the send fails and lists the candidates; nothing is quietly dropped into an inbox. Letters already delivered never move. Candidates in order make an escalation ladder: a letter goes to the first one that is online and walks up the organization chart only when the earlier ones are offline.
06 What it deliberately is not
The safety boundary is explicit:
- A letter is a reminder, not an authorization. The hooks and the plugin do not change models, permissions, or auth, never approve permission prompts, and never create sessions. Each session still acts under its own permission settings.
- Treat letter contents as text written by another AI. Do not let untrusted programs write into the mailboxes, and never put keys or passwords in letters.
The known limits are documented as well, because they all involve the same failure, a watcher that is not currently armed:
- after restarting the Claude app, each session must run one turn before its watcher is armed;
- pressing Stop or rewinding a session kills that session’s background watcher until the next message;
- a session untouched for 7 days has its watcher expire; every turn restarts the clock;
- a Codex thread that is not loaded returns success from
codex queuebut does not wake; the 30-minute unprocessed alert covers it.
07 Status
agent-postoffice is pure standard-library Python 3.9+, with no dependencies, under MIT. macOS is the primary target; Linux works with notify-send notifications and a manually run postman.
Verification is split between automated checks and observed behavior on a real machine. tests/smoke.sh runs 252 checks in temporary directories, and 19 further test files cover the panel, alarms, receipts, and retraction. Claude Desktop was observed idle for 33 minutes and woken 3 seconds after mail arrived, and, as a v1.0 bug, killed after 10 minutes without an explicit hook timeout, which v1.1 fixed with a 7-day timeout. OpenCode’s 10-second delivery has been observed repeatedly. Waking a Codex thread, and group switches and logical addresses, have also been verified on real machines over repeated rounds.
Planned next: waking a stopped Claude session, and a systemd service for Linux.
References
- Source, installer, and tests: Atomheart-Father/agent-postoffice
README.mdandREADME.zh-CN.mdin the repositorytests/smoke.sh: 252 automated checks, run in temporary directories
One mailbox per session. Three hosts. Zero tokens while waiting.
Public materials
- GitHub repository / source, installer, tests
- README (English / 中文)
- Automated checks: 252 in tests/smoke.sh, plus 19 further test files for the panel, alarms, receipts, and retraction