5fe8f228c1
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>
30 lines
2.5 KiB
Markdown
30 lines
2.5 KiB
Markdown
# 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`)
|