c1c367456bf06d796804d5eaa57edf6245fb375c
c60e3d6 made every route able to name its mailbox and left the UI unable to.
`?account=<id>` names one and `?account=all` spans them; nothing on screen
passed either, so the list showed whichever account sorted first enabled.
The selection is a QUERY PARAM, the same as the folder beside it and for the
same reason — it is addressable state, so a reload, a shared URL and a
cmd-click all land where they were meant to. The pills are real links built from
the live params, so the folder and any open email survive a mailbox switch.
`account` is in the react-query key. Without it, switching mailbox would serve
the previous one's page from cache under the new selection, which reads as the
filter not working rather than as a caching bug.
Absent means `all` in the UI and only in the UI. The routes keep treating absent
as "first enabled" — mail-scope.ts does that deliberately, because the mobile app
and the agent's email_db tool call them and know nothing about accounts. That
default is right for a caller that cannot choose and wrong for a person looking
at a screen: three accounts and you want all of it, not whichever sorts first.
Hidden with fewer than two accounts. A control that can say one thing is noise in
a toolbar that is already tight on a phone.
NOT visually verified: this machine has no email accounts configured, so the
picker cannot render here. tsgo clean, prettier clean, the 16 mail-scope tests
pass. It needs a look on a host with two accounts before it is trusted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
IMAP and Gmail accounts, synced into a per-account SQLite store on your own machine and searchable offline.
- Your mail stays local. Each account gets its own
emails.dbunder the platform's data directory, with an FTS5 index and Gmail-style search operators. Nothing is sent anywhere to be indexed. - IMAP or Gmail. Generic IMAP over
imapflow, or Gmail's history API where an account is connected through the platform's Google integration. - Real-time. IMAP IDLE watchers push new mail as it lands, with a slow cron poll as a backstop.
- Composing and sending, with attachments, over the account's own SMTP.
Status — read this before installing
This plugin has never been run. It was extracted from the Officer platform on 2026-08-17, where it had been switched off since 2026-08-13 — its database table was commented out of the schema and therefore never created, so nothing has exercised sync, sending or the UI since. The code is believed good (the sidecar starts cleanly and typechecks) but that is not the same as working.
Treat the first install as the first test. docs/email-plugin-extraction.md in the platform repository
records what was moved and what was decided.
Known gaps
- Credentials are stored unencrypted.
email_accounts.credentialsis a jsonb blob holding the IMAP app password in the clear. The platform has a secret store with per-purpose keys and this plugin does not use it yet. Deliberately left alone during the extraction so that a first-install failure has exactly one possible cause; it is the first thing to fix afterwards. - The
email_dbagent tool is not part of this plugin. It is resolved at runtime fromPI_TOOLS_DIRSand the platform points it at the account's SQLite store. The email chat panel's prompt assumes it exists. - Account management placement is unsettled — see the extraction doc.
Languages
TypeScript
100%