The Complaint That Created the Rule
Paraphrased from the message that became a decision record: “Everything I send you needs to result in something happening. I send you things over the day; I expect something to happen after. You might ask me about each one. I don’t want us to just ignore the messages. Even if you did act on them, I want to know.”
The system had been pulling messages. It had been logging them. Several had sat in the log for days, fetched and unprocessed, because nothing routed the backlog — the pull step lived inside the brief command and only ran when the brief ran. Messages were “pulled, not processed”, which to the person who sent them is indistinguishable from being ignored.
The Contract
Every inbound message must reach a terminal outcome — actioned, filed as a task, noted in the vault, answered, or answered with a question — and get a receipt back, threaded to the message, naming the outcome, before it is flagged processed.
The Dispatcher
A scheduled job every ten minutes:
- Pull new messages via the coordinator’s canonical pull script. New entries are appended to the history file before the platform offset is acknowledged, so a crash between the two loses nothing.
- If there is a backlog, launch a headless routing session. It sweeps every unprocessed message, routes each to an outcome — creating tasks with provenance, updating notes, drafting answers — and sends one receipt per batch, threaded to the oldest message, with a line per item.
- Mark processed only after the receipt is sent.
- Set reactions at each transition — 👀 on ingest, 🤔 while the session runs, 👍 on processed — from the deterministic code paths that own those transitions, never from an agent’s discretion.
A lock prevents two routing sessions from overlapping; the lock has a timeout, because a session that fans out to slow curators once held it for 57 minutes and the dispatcher double-processed a message when the lock expired mid-run. Locks need timeouts; timeouts need to exceed the longest legitimate run.
The Three Lessons That Cost Data
Respect retention timers. Bot-API polling endpoints often keep unfetched updates for only about 24 hours. If your poll cadence is “whenever the human runs a brief”, a quiet ten days silently discards everything. Rule: any surface with a retention timer gets a scheduled poll at least twice as fast as the timer, independent of anything the human does. “Embedded in another routine” is not “scheduled.”
The monitor needs a monitor. The scheduled poll later died silently — the job stopped, nobody noticed, a message was lost anyway. Every loss-sensitive scheduled job now needs a dead-man’s switch: an independent check that alarms when the job stops running. Silence from a monitor is not good news.
Pulled is not processed; routed is not done. A message can be fetched and logged and still never acted on. And — the later, sharper version — a request can be routed into a task, receipted, and still never executed, because nothing works the system’s own tasks. That produced the execution lane.
Report Loss Honestly
When messages age out, say so plainly — “messages between X and Y were lost to the retention window; please resend anything important” — and ask. Do not retry the API in the hope of finding what the contract says is gone.
Receipts That Don’t Mislead
A receipt is a claim, and claims need evidence. Lessons that shaped the wording:
- Name the exact artifact location. “Filed as task
abcin venture X; note added to the venture hub” — not “handled.” - A receipt that says “will surface in the brief on the 23rd” is only true if the mechanism exists. One did not (deferred tasks never woke), and the receipt was a promise the system could not keep.
- A blocked receipt — the session could not send — must not be silently retried later as if fresh, and must not starve the queue behind it. Surface the block where the human will see it, at the first tick, not the third.
Resuming Context
The newest refinement: a reply to a message the system sent resumes the session that sent it, instead of starting a fresh session that must re-read everything. The history log records which session produced each outbound message; the dispatcher routes a threaded reply to resume <that session>. Your reply is the instruction to continue, with the producing context intact.
Hand this to your chief of staff. Plain Markdown: /guides/every-message-gets-a-receipt.md. Tell it: "Read this guide and tell me what in our system it would change."
Also for your Claude: whole-site index · bootstrap prompt · guide feed