TODO.md had reached 1050 lines and 72 open items across 28 sections, read mostly on a phone. It is now a directory: todo/<theme>/<item>.md, one card per file, with frontmatter carrying id, status, created date and order, and the prose body copied across verbatim. TODO.md becomes a generated index (bun run todo:index). Dates: where an item's prose stated one it is used; otherwise its old section's; otherwise 2026-08-20, floored at the day before the split rather than invented. date_source records which. Shaped for a two-way Kanban board, filed as todo/tooling — a card is a file, id is the identity, frontmatter is the machine's half and the body is the owner's. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1.5 KiB
id, title, theme, status, created, date_source, order
| id | title | theme | status | created | date_source | order |
|---|---|---|---|---|---|---|
| plugin-system/the-platform-still-knows-email-s-on-disk | The platform still knows email's on-disk vocabulary, deliberately, and it is untested by anything | plugin-system | open | 2026-08-13 | stated | 3 |
The platform still knows email's on-disk vocabulary, deliberately, and it is untested by anything.
findEmailAccountName in data-path.ts reads DATA_PATH/<user>/email_accounts/*/emails.db and picks
the newest by mtime. Two core callers use it: user-instance.ts (OFFICER_EMAIL_DB, for the agent's
email_db MCP tool) and chat/websocket.ts (resolveEmailCwd, for a chat opened against a mailbox).
ChatPanelWrapper.tsx hardcodes workspace.id === 'email' to trigger the second.
This traded a CODE dependency for a CONVENTION, which was the right trade at the time — the code
dependency is what put officer-agent into a restart loop on 2026-08-13 (fbb6d6c7). But the
convention has no enforcement on either side: if the plugin ever renames emails.db, moves to one
database per folder, or nests differently, core silently points the agent at a path that does not
exist. No import breaks, no type fails, no test covers it. The tool just goes quiet.
The clean version needs two things the platform does not have: a way for a plugin to ship an MCP tool, and a way for a plugin to declare a chat context. Until both exist this stays — but it should be a decision someone re-takes, not one that is inherited.