diff --git a/README.md b/README.md
index 20c8584..6e839d8 100644
--- a/README.md
+++ b/README.md
@@ -7,34 +7,59 @@ replies, and answers the Hub.
The build spec is [`AGENTS.md`](AGENTS.md). `ORIGINAL_NOTES.md` is archived
pre-planning material and is not authoritative.
+## Architecture
+
+```mermaid
+flowchart LR
+ SAM["Sam phone or desktop browser"] --> CADDY["Caddy on .35 mail.lab.audasmedia.com.au"]
+ CADDY --> UI["HTMX dashboard login, inbox, rules, reports"]
+ UI --> DB[("SQLite email_agent_data")]
+ UI --> GMAIL["Gmail IMAP :993 / SMTP :587 (IPv4)"]
+ UI --> JEV["JEV / TypeSafe classify"]
+ UI --> OMNI["OmniRoute :20129 draft reply"]
+ UI --> APPRISE["Apprise :8210 summary email"]
+ HUB["Central AI Hub :8788"] --> API["Hub API /capabilities /ask /notify"]
+ API --> DB
+ N8N["n8n schedule"] --> JOBS["CLI jobs -fetch -classify -summary-send"]
+ JOBS --> DB
+```
+
+Sources: [`docs/email-agent-architecture.mmd`](docs/email-agent-architecture.mmd)
+and [`docs/email-agent-map.html`](docs/email-agent-map.html). Interactive map:
+.
+
## Status
-**Phase 7 — Summary and Hub; retention.** The Go skeleton, session login,
-and HTMX dashboard (Phase 1), real mail over **IMAP with an app password,
-forced to IPv4** (Phase 2), **JEV classification** (Phase 3), **bulk triage
-actions** (Phase 4), **reply drafts** (Phase 5), and now **unsubscribe
-detection and the rules editor** (Phase 6). Open a message to read it, draft a
-reply with the LLM through **OmniRoute** from a template, edit it, and send it
-over Gmail SMTP (IPv4 + STARTTLS). A reply is sent **as the address the mail
-arrived at** (`X-Pm-Original-To`, FR-15) and returns to the original sender; the
-reply sets `In-Reply-To`/`References` so Gmail keeps the thread, and the
-original is filed under its `Replied-to/
` label. Sending is a
-deliberate UI action with a confirmation — there is no auto-send (§10). The
-**rules editor** (`/rules`) saves and versions the plain-text rules that JEV and
-the reply model read. **Unsubscribe detection** (`/unsubscribe`) finds RFC
-2369/8058 links and body links, keeps a domain ignore list, and records what Sam
-marks — it **never follows a link**. Every action, including drafts, sends,
-rules edits, and unsubscribe marks, is appended to `actions_log` (FR-13).
-**Phase 7** adds the daily **summary** (`-summary`, `-summary-send`; delivered
-by email through Apprise) and the read-only **Hub API** (`/capabilities`,
-`/ask`, `/notify`). **Retention** (AGENTS.md §7) is enforced by the bounded
-`-retain` job: it clears message bodies older than one month, keeps metadata,
-and caps the append-only `actions_log`; see
-[`docs/retention.md`](docs/retention.md). See
-[`docs/phase7-summary-hub.md`](docs/phase7-summary-hub.md) for Phase 7,
-[`docs/phase6-unsubscribe.md`](docs/phase6-unsubscribe.md) for the phase evidence,
-[`docs/phase5-replies.md`](docs/phase5-replies.md) for Phase 5, and
-[`docs/phase4-triage.md`](docs/phase4-triage.md) for Phase 4.
+**Complete and deployed.** All eight AGENTS.md §11 phases are done. The Go
+skeleton, session login, and HTMX dashboard (Phase 1), real mail over **IMAP with
+an app password, forced to IPv4** (Phase 2), **JEV classification** (Phase 3),
+**bulk triage actions** (Phase 4), **reply drafts** (Phase 5), **unsubscribe
+detection and the rules editor** (Phase 6), and the **daily summary by email plus
+the read-only Hub API** (Phase 7) run on `.13` behind Caddy. Phase 8 documents
+the project across Gitea, Obsidian, Outline, Vikunja, and the architecture map.
+
+Open a message to read it, draft a reply with the LLM through **OmniRoute** from
+a template, edit it, and send it over Gmail SMTP (IPv4 + STARTTLS). A reply is
+sent **as the address the mail arrived at** (`X-Pm-Original-To`, FR-15) and
+returns to the original sender; the reply sets `In-Reply-To`/`References` so
+Gmail keeps the thread, and the original is filed under its
+`Replied-to/` label. Sending is a deliberate UI action with a
+confirmation — there is no auto-send (§10). The **rules editor** (`/rules`)
+saves and versions the plain-text rules that JEV and the reply model read.
+**Unsubscribe detection** (`/unsubscribe`) finds RFC 2369/8058 links and body
+links, keeps a domain ignore list, and records what Sam marks — it **never
+follows a link**. Every action, including drafts, sends, rules edits, and
+unsubscribe marks, is appended to `actions_log` (FR-13). **Phase 7** adds the
+daily **summary** (`-summary`, `-summary-send`; delivered by email through
+Apprise) and the read-only **Hub API** (`/capabilities`, `/ask`, `/notify`).
+**Retention** (AGENTS.md §7) is enforced by the bounded `-retain` job: it clears
+message bodies older than one month, keeps metadata, and caps the append-only
+`actions_log`; see [`docs/retention.md`](docs/retention.md). Phase evidence:
+[`docs/phase7-summary-hub.md`](docs/phase7-summary-hub.md),
+[`docs/phase6-unsubscribe.md`](docs/phase6-unsubscribe.md),
+[`docs/phase5-replies.md`](docs/phase5-replies.md),
+[`docs/phase4-triage.md`](docs/phase4-triage.md), and
+[`docs/phase8-documentation.md`](docs/phase8-documentation.md).
## Layout
@@ -52,6 +77,10 @@ internal/unsubscribe/ RFC 2369/8058 + body unsubscribe-link detection (no netw
internal/version/ build metadata (set via -ldflags)
web/static/ embedded design tokens, Inter fonts, htmx, app.css
web/templates/ embedded server-rendered HTML
+docs/ phase evidence, retention, AI context, map, diagrams
+docs/outline/ AI-context documents (system, config, code, runbook)
+docs/archify/ Archify JSON spec for the architecture map
+docs/diagrams/ rendered Mermaid PNG
Dockerfile multi-stage, CGO-free build
docker-compose.yml this project's own container and image
```
@@ -280,6 +309,12 @@ Caddy on `.35` proxies `mail.lab.audasmedia.com.au` to this port.
| `POST` | `/unsubscribe/ignore` | session + CSRF | Adds a domain to the ignore list |
| `POST` | `/unsubscribe/unignore` | session + CSRF | Removes a domain record |
| `POST` | `/unsubscribe/mark` | session + CSRF + confirm | Records a domain for unsubscribe; never contacts the link |
+| `GET` | `/reports` | session | Reports screen: build, send, and delete a daily summary (FR-10) |
+| `POST` | `/reports/generate` | session + CSRF | Builds and stores today's summary; sends nothing |
+| `POST` | `/reports/send` | session + CSRF + confirm | Delivers today's summary by email via Apprise |
+| `POST` | `/reports/delete` | session + CSRF | Deletes a stored summary |
+| `GET` | `/capabilities` | Hub bearer | Hub capability list (FR-12) |
+| `POST` | `/ask` | Hub bearer | Read-only short answer (FR-12); never writes |
| `GET` | `/static/…` | public | Embedded `tokens.css`, `app.css`, Inter fonts, `htmx.min.js` |
Unauthenticated requests to `/` and `/partials/…` redirect to `/login?next=…`.
@@ -300,3 +335,24 @@ folders; migration v5 adds `messages.message_id_header` (reply threading) and
`drafts.sent_at`; migration v6 adds `messages.list_unsubscribe` and
`messages.list_unsubscribe_post` and extends `unsubscribe` with `url` and
`updated_at`.
+
+## Documentation
+
+Phase 8 recorded the project in five places.
+
+| Surface | Location |
+|---|---|
+| Gitea | This README, `docs/phaseN-*.md`, `docs/outline/`, `docs/email-agent-architecture.mmd`, `docs/email-agent-map.html` |
+| Obsidian | Note `Email Agent — Family Inbox Triage` in `010 inbox` on `.27` (the sorter files it) |
+| Outline | Collection `Email Agent` (`00-index`, system overview, config, code map, runbook) |
+| Vikunja | Project `Email Agent` (human milestones) |
+| Map | `central_ai_llm_master/docs/hub-architecture-map.html` and this repo's map, published to |
+
+Rebuild the map:
+
+```sh
+mmdc -i docs/email-agent-architecture.mmd -o docs/diagrams/email-agent-architecture.png --scale 2 -b white
+~/.agents/skills/project-docs/scripts/publish-maps.sh /home/sam/paseo/projects/email_agent
+```
+
+See [`docs/phase8-documentation.md`](docs/phase8-documentation.md) for the evidence.
diff --git a/docs/archify/email-agent.architecture.json b/docs/archify/email-agent.architecture.json
new file mode 100644
index 0000000..7bea33c
--- /dev/null
+++ b/docs/archify/email-agent.architecture.json
@@ -0,0 +1,58 @@
+{
+ "schema_version": 1,
+ "diagram_type": "architecture",
+ "meta": {
+ "title": "Email Agent — One-Page Family Inbox Triage",
+ "output": "docs/email-agent-map.html",
+ "quality_profile": "showcase",
+ "viewBox": [1780, 1000],
+ "views": [
+ {
+ "id": "triage-loop",
+ "label": "Triage loop",
+ "focus": ["sam", "caddy", "ui", "gmail", "db"],
+ "note": "Sam opens one page. The app reads Gmail and stores every message."
+ },
+ {
+ "id": "classify-reply",
+ "label": "Classify and reply",
+ "focus": ["ui", "jev", "omni", "gmail"],
+ "note": "JEV labels each message. OmniRoute drafts the reply. SMTP sends it."
+ },
+ {
+ "id": "hub-summary",
+ "label": "Hub and summary",
+ "focus": ["hub", "api", "db", "jobs", "apprise", "n8n"],
+ "note": "The Hub asks read-only questions. CLI jobs send the daily summary."
+ }
+ ]
+ },
+ "components": [
+ { "id": "sam", "type": "frontend", "label": "Sam", "sublabel": "phone or desktop browser", "pos": [60, 460], "size": [150, 64] },
+ { "id": "caddy", "type": "security", "label": "Caddy on .35", "sublabel": "mail.lab.audasmedia.com.au", "pos": [330, 460], "size": [170, 64] },
+ { "id": "ui", "type": "frontend", "label": "HTMX dashboard", "sublabel": "login, inbox, rules, reports", "pos": [640, 440], "size": [200, 80], "tag": "port 8790" },
+ { "id": "db", "type": "database", "label": "SQLite", "sublabel": "email_agent_data volume", "pos": [1300, 460], "size": [180, 80] },
+ { "id": "api", "type": "backend", "label": "Hub API", "sublabel": "/capabilities /ask /notify", "pos": [1300, 120], "size": [180, 64], "tag": "read-only /ask" },
+ { "id": "hub", "type": "backend", "label": "Central AI Hub", "sublabel": "hear-route-answer :8788", "pos": [980, 120], "size": [180, 64] },
+ { "id": "jobs", "type": "backend", "label": "CLI jobs", "sublabel": "-fetch -classify -summary-send", "pos": [1300, 800], "size": [180, 64] },
+ { "id": "n8n", "type": "external", "label": "n8n schedule", "sublabel": "scan and summary runs", "pos": [1580, 800], "size": [170, 64] },
+ { "id": "apprise", "type": "backend", "label": "Apprise", "sublabel": "summary email :8210", "pos": [1000, 800], "size": [170, 64] },
+ { "id": "gmail", "type": "cloud", "label": "Gmail", "sublabel": "IMAP :993 / SMTP :587, IPv4", "pos": [240, 800], "size": [180, 64] },
+ { "id": "jev", "type": "cloud", "label": "JEV", "sublabel": "TypeSafe System One", "pos": [500, 800], "size": [170, 64] },
+ { "id": "omni", "type": "cloud", "label": "OmniRoute", "sublabel": "reply drafts :20129", "pos": [760, 800], "size": [170, 64] }
+ ],
+ "connections": [
+ { "id": "browser", "from": "sam", "to": "caddy", "label": "HTTPS" },
+ { "id": "proxy", "from": "caddy", "to": "ui", "label": "reverse proxy" },
+ { "id": "store", "from": "ui", "to": "db", "label": "store mail, triage, rules" },
+ { "id": "mail", "from": "ui", "to": "gmail", "label": "read + send", "fromSide": "bottom", "toSide": "top", "route": "orthogonal-v" },
+ { "id": "classify", "from": "ui", "to": "jev", "label": "classify", "fromSide": "bottom", "toSide": "top", "route": "orthogonal-v" },
+ { "id": "draft", "from": "ui", "to": "omni", "label": "draft reply", "fromSide": "bottom", "toSide": "top", "route": "orthogonal-v" },
+ { "id": "summary", "from": "ui", "to": "apprise", "label": "send summary", "fromSide": "bottom", "toSide": "top", "route": "orthogonal-v" },
+ { "id": "ask", "from": "hub", "to": "api", "label": "Bearer token" },
+ { "id": "read", "from": "api", "to": "db", "label": "read only", "labelAt": [1390, 340] },
+ { "id": "schedule", "from": "n8n", "to": "jobs", "label": "schedule" },
+ { "id": "run", "from": "jobs", "to": "db", "label": "fetch + classify" },
+ { "id": "jobs-summary", "from": "jobs", "to": "apprise", "label": "daily email", "labelAt": [1240, 878] }
+ ]
+}
diff --git a/docs/diagrams/email-agent-architecture.png b/docs/diagrams/email-agent-architecture.png
new file mode 100644
index 0000000..057dab5
Binary files /dev/null and b/docs/diagrams/email-agent-architecture.png differ
diff --git a/docs/email-agent-architecture.mmd b/docs/email-agent-architecture.mmd
new file mode 100644
index 0000000..3d36dfa
--- /dev/null
+++ b/docs/email-agent-architecture.mmd
@@ -0,0 +1,41 @@
+flowchart LR
+ SAM["Sam phone or desktop browser"]
+ CADDY["Caddy on .35 mail.lab.audasmedia.com.au"]
+
+ subgraph APP["Email Agent container on .13 (port 8790)"]
+ UI["HTMX dashboard login, inbox, rules, reports"]
+ API["Hub API /capabilities /ask /notify"]
+ JOBS["CLI jobs -fetch -classify -summary-send"]
+ DB[("SQLite email_agent_data volume")]
+ end
+
+ subgraph HOUSE["House services"]
+ HUB["Central AI Hub :8788"]
+ APPRISE["Apprise :8210 summary email"]
+ end
+
+ N8N["n8n schedule"]
+
+ subgraph CLOUD["External providers"]
+ GMAIL["Gmail IMAP :993 / SMTP :587 IPv4 only, app password"]
+ JEV["JEV / TypeSafe System One classification"]
+ OMNI["OmniRoute :20129 reply drafts"]
+ end
+
+ SAM --> CADDY --> UI
+ UI --> DB
+ UI --> GMAIL
+ UI --> JEV
+ UI --> OMNI
+ UI --> APPRISE
+ HUB --> API
+ API --> DB
+ N8N --> JOBS
+ JOBS --> DB
+ JOBS --> GMAIL
+ JOBS --> APPRISE
+ API -. notify .-> HUB
+
+ click CADDY "https://maps.lab.audasmedia.com.au/email_agent/docs/" "View Archify Map"
+ click UI "https://maps.lab.audasmedia.com.au/email_agent/docs/" "View Archify Map"
+ click DB "https://maps.lab.audasmedia.com.au/email_agent/docs/" "View Archify Map"
diff --git a/docs/email-agent-map.html b/docs/email-agent-map.html
new file mode 100644
index 0000000..0a1f600
--- /dev/null
+++ b/docs/email-agent-map.html
@@ -0,0 +1,13716 @@
+
+
+
+
+
+
+ Email Agent — One-Page Family Inbox Triage Diagram
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Visual identityS cycles
+
+
+
+
+
+
+
+
+
+
+
+
+
Export diagramPortable, clean outputs
+ E
+
+
+ Share
+
+
+
+
+
+
+
+ Image
+
+
+
+
+
+ Vector & motion
+
+
+
+
+
+
+
+
+
+
+
+
+
Email Agent — One-Page Family Inbox Triage
+
+
+
+
+
+
+
+
+
+ Guided views
+
+
+
+
+ Explore this system
+ Step through curated paths without changing the source diagram.
+
+
+ Beat
+
+
+
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ready
+ Chapter 01 / 01
+
+
+ Guided chapter
+
+
+
+
+
+
+
+
+ Diagram guide
+ Explore this system
+
+
+
+
Inspecting compiled semantics
+
+
+
+
+
+
+
+
+
+ E ExportT ThemeS Style0 Reset+ Zoom in- Zoom outEsc Close
+