Files
Maven/docs/plans/01-email-reader.md
T
kami 5fe8f228c1 feat(mavweb): /ecosystem page consuming Nexus/Praxis/Hexis + shell fixes
Add a read-only /ecosystem page that consumes the sibling services'
JSON APIs (Nexus entities, Praxis attention, Hexis capabilities),
fetched concurrently with honest per-panel error states. Siblings stay
headless — mavweb is their human surface (arch §16). Wired via mavweb
-nexus/-praxis/-hexis flags; mavweb joins the ecosystem compose network.

Fix mobile horizontal overflow across all pages: .content is a flex
child with default min-width:auto, so it refused to shrink below the
tables' intrinsic width. min-width:0 lets wide tables pan inside .scroll
instead of dragging the page sideways. Verified via CDP geometry check
(scrollWidth === clientWidth at 430px).

Also includes in-progress Ethos UI redesign, ecosystem deploy compose,
and planning docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 22:04:23 +04:00

2.5 KiB

Plan: Background Email Reader

Goal: Maven periodically polls configured IMAP mailboxes, extracts structured items (tasks, reminders, calendar events, important facts) via LLM, and writes them into the store through ipc.CoreAPI — discarding spam, newsletters, and noise.

Done when:

  • internal/email/ package exists with IMAP idle+poll loop
  • New email block in config.Config (mailboxes, poll interval, extraction model)
  • Extracted items land as WriteFact/CreateReminder/WriteNote via ipc.Client
  • Spam/promotions/social are silently dropped (Gmail X-GM-LABELS or IMAP keyword check)
  • Integration test with a throwaway mailbox verifies the round-trip

Scope:

  • New internal/email/ package — IMAP client (stdlib net/mail + github.com/emersion/go-imap or raw net/textproto)
  • Config extension: config.Config.Email block with PollInterval, Accounts[] (host, username, password/app-password, folders)
  • LLM extraction prompt (shared internal/llm.Client) classifies each unseen message as task|reminder|event|fact|junk and fills slots — same GBNF-constrained pattern as internal/router/llmrouter.go:routeGrammar
  • Extracted items written through ipc.CoreAPI interface (same seam internal/voice/reactiveHandler uses)
  • Daemon lifecycle: wired in cmd/mavend/main.go alongside the tick loop, starts after unlock
  • deploy/mavend.json gets the email block

Steps:

  1. Add EmailConfig struct to internal/config/config.go (accounts, poll interval, folders to scan)
  2. Create internal/email/ with Poller — IMAP connect, IDLE for push, fallback to periodic SELECT INBOX + SEARCH UNSEEN
  3. Implement message → plaintext conversion (text/plain body, strip HTML from text/html via golang.org/x/net/html or simple regex)
  4. Add LLM extraction via internal/llm.Client.Complete() with a GBNF grammar that outputs {"type":"task|reminder|event|fact","key":"...","value":"...","when":"..."} — mirroring internal/router/llmrouter.go:routeGrammar
  5. Map extracted items to ipc.WriteFactReq / ipc.CreateReminder / ipc.WriteNote calls
  6. Wire Poller into cmd/mavend/main.go — start on unlock, stop on context cancel
  7. Test with a throwaway mailbox (Gmail app password or a self-hosted Dovecot); verify extraction accuracy
  8. Add models/seeds/email_*.txt seed examples for the extraction classifier
  9. Log poll stats (seen, extracted, junk, errors) through log.Printf (consistent with existing pattern in cmd/mavend/tick.go)