What it does, every morning
- Ingest. Mail, calendar and meeting recordings since the last run.
- Rank. Every relationship scored, so the list is a standing agenda rather than a fresh guess each day.
- Decide. A review board of independent voices argues over the top of the board and decides who to contact and what to say.
- Draft. Emails in your voice, written from an evidence bundle the model is not allowed to go outside of.
- Lint. Anything stating a fact the evidence does not support is blocked before you ever see it.
- Deliver. Into your Gmail drafts.
- Brief. What it did, what it decided against, and what it cost.
Then it watches what you do with each draft. Sent as written, sent after edits, or deleted. That verdict is the training signal, and it is the one thing here that cannot be reconstructed later.
Why the ranking is not a CRM score
Eff = max(1, Ease - Cost)
t = (Eff - 1) / 9
PS = 1.5·Eff + (2 - t)·Impact + (1 + t)·Urgency
Ease dominates. A quick win beats a slightly more valuable slog, because the list you actually work through beats the list that is theoretically optimal and sits untouched.
Urgency counts for more on easy things, impact counts for more on
hard ones. That is the t term. A two-minute reply
that is time-sensitive should jump the queue. An expensive move should be
justified by what it is worth, not by the fact that it is nagging you.
Decay follows a logistic curve rather than a linear one, because relationships do not cool at a constant rate. They are fine, and then suddenly they are not.
Plugs into what you already have
| Source | What it contributes |
|---|---|
| Gmail | Correspondence, reply detection, the delivery target |
| Google Calendar | Meetings held and booked, identity discovery from invites |
| Fireflies | Meeting summaries. Not transcripts, deliberately |
| Notion | One-way CRM import: contacts, notes, page bodies |
A source writes rows into two tables. Everything downstream reads those and nothing else, so adding one is self-contained and cannot break ranking.
Built in public
The interesting parts are the bugs, and they are written up in the code rather than tidied away. A poller that read its own cleanup as a rejection. A dry run that advanced a cursor and ate the real run's work. A batch retry at the wrong level that discarded two thirds of its input while reporting success.
Every one is a comment explaining what happened, because the reasoning is worth more than the fix.