11# MailSweep — Progress & Plan
22
33** Last updated:** 2026-02-25
4- ** Status:** All 6 phases implemented + extensive post-phase enhancements + full code review complete . App running. ~ 4,800 lines of Python. 56/56 tests passing. Published on GitHub. Release v0.2.0.
4+ ** Status:** All 6 phases + AI-powered analysis & reorganization implemented . App running. ~ 6,200 lines of Python. 74/74 tests passing. Published on GitHub. Release v0.2.0.
55
66---
77
@@ -30,13 +30,18 @@ mailsweep/ ← project root
3030│ ├── imap/
3131│ │ ├── connection.py ← connect(), find_trash_folder(), list_folders()
3232│ │ └── oauth2.py ← Gmail XOAUTH2, Outlook MSAL, token refresh
33+ │ ├── ai/
34+ │ │ ├── providers.py ← LLM abstraction: OpenAI-compat + Anthropic (stdlib HTTP)
35+ │ │ └── context.py ← DB→markdown context builder for LLM
3336│ ├── workers/
3437│ │ ├── scan_worker.py ← FETCH ENVELOPE+SIZE+BODYSTRUCTURE, batched
3538│ │ ├── qt_scan_worker.py ← QObject wrapper (moveToThread), incremental
3639│ │ ├── detach_worker.py ← FETCH→strip→APPEND→DELETE→EXPUNGE
3740│ │ ├── backup_worker.py ← RFC822→.eml→DELETE→EXPUNGE
3841│ │ ├── delete_worker.py ← Gmail-safe delete on background thread
39- │ │ └── incremental_scan.py ← get_new_deleted_uids(), CONDSTORE check
42+ │ │ ├── incremental_scan.py ← get_new_deleted_uids(), CONDSTORE check
43+ │ │ ├── ai_worker.py ← background LLM chat (moveToThread)
44+ │ │ └── move_worker.py ← IMAP MOVE (RFC 6851) with copy+delete fallback
4045│ └── ui/
4146│ ├── main_window.py ← QMainWindow, splitter layout, all wiring
4247│ ├── account_dialog.py ← add/edit account, OAuth2 on background thread
@@ -45,12 +50,14 @@ mailsweep/ ← project root
4550│ ├── filter_bar.py ← sender/subject/date/size/attachment filters
4651│ ├── treemap_widget.py ← squarify + QPainter, hover, click-to-filter
4752│ ├── progress_panel.py ← QProgressBar + status + Cancel
48- │ ├── settings_dialog.py ← batch size, max rows, save dir
49- │ └── log_dock.py ← live log viewer, per-level colour, dockable
53+ │ ├── settings_dialog.py ← batch size, max rows, save dir, AI settings
54+ │ ├── log_dock.py ← live log viewer, per-level colour, dockable
55+ │ └── ai_dock.py ← AI chat dock: provider selector, chat history, apply moves
5056└── tests/
5157 ├── test_db.py ← 22 tests: CRUD, queries, stats, message_id matching
5258 ├── test_scan_worker.py ← 17 tests: mock IMAP, BODYSTRUCTURE parser, message_id
53- └── test_mime_utils.py ← 11 tests: strip, save, path traversal
59+ ├── test_mime_utils.py ← 11 tests: strip, save, path traversal
60+ └── test_ai.py ← 18 tests: LLM providers, context builder, AI queries
5461```
5562
5663---
@@ -65,6 +72,7 @@ mailsweep/ ← project root
6572| 4 | Detach attachments + backup-delete | ✅ done |
6673| 5 | Gmail + Outlook OAuth2 | ✅ done |
6774| 6 | Incremental scan, settings, log dock, packaging spec | ✅ done |
75+ | 7 | AI-powered email analysis & reorganization | ✅ done |
6876
6977---
7078
@@ -104,6 +112,19 @@ Fix: `COPY` UIDs to `[Gmail]/Trash` before `\Deleted`+`EXPUNGE`. Applied to inli
104112Detach worker doesn't need this — it APPENDs a replacement message, so the old one should be removed.
105113` find_trash_folder() ` in ` connection.py ` detects Trash across providers (Gmail, Outlook, Apple Mail, generic).
106114
115+ ### AI-Powered Analysis (Phase 7)
116+ LLM integration via stdlib HTTP (` urllib.request ` ) — zero new dependencies.
117+ - ** Providers:** OpenAI-compatible (Ollama, OpenAI, Groq, Together) + Anthropic native API
118+ - ** Context builder:** Reads SQLite DB → markdown summary (folder tree with stats, top senders per folder,
119+ cross-folder sender overlap, dead folder detection). Capped at ~ 8K tokens.
120+ - ** AI dock:** ` QDockWidget ` with chat history, provider/model selector, quick-action buttons
121+ ("Analyze folders", "Find misfilings", "Find duplicates"), and "Apply Suggestions" for MOVE operations
122+ - ** Move worker:** IMAP MOVE (RFC 6851) with ` COPY ` +` DELETE ` +` EXPUNGE ` fallback, batched by source folder,
123+ updates local DB cache after each move
124+ - ** Threading:** ` AiWorker ` uses ` @pyqtSlot ` + ` moveToThread ` pattern (params via constructor, not lambda)
125+ to keep UI responsive during LLM calls
126+ - ** Settings:** Provider/URL/model persisted in ` settings.json ` ; API key stored in system keyring
127+
107128---
108129
109130## Bugs Fixed Post-Implementation
@@ -160,6 +181,11 @@ Detach worker doesn't need this — it APPENDs a replacement message, so the old
160181| ** Sender email dedup** | Sender treemap/summary groups by extracted email, not full "Name \< email\> " string |
161182| ** Message-ID matching** | ` message_id ` from ENVELOPE used for cross-folder dedup, unlabelled detection, and "View Headers → Labels" |
162183| ** Force Full Rescan** | Actions menu option to re-fetch all message metadata, bypassing incremental cache |
184+ | ** AI Assistant** | LLM chat dock for mailbox analysis — Ollama/OpenAI/Anthropic, zero new deps (stdlib HTTP) |
185+ | ** AI folder analysis** | Context builder: folder tree, top senders, cross-folder overlap, dead folder detection |
186+ | ** AI move suggestions** | LLM outputs ` MOVE: ` lines → user confirms → IMAP move worker executes |
187+ | ** IMAP move worker** | RFC 6851 MOVE with copy+delete fallback, batched by source folder, DB cache update |
188+ | ** AI settings** | Provider/URL/model in settings dialog + keyring for API key |
163189
164190---
165191
@@ -240,6 +266,10 @@ Outlook token refresh fix, README/LICENSE/.gitignore added, pyproject.toml metad
240266## Git Log
241267
242268```
269+ 5f8a4d0 feat: add AI-powered email analysis and reorganization
270+ 2b552f4 feat: add AppImage build to release workflow
271+ 994e9fa fix: build Linux binary on ubuntu-22.04 for GLIBC 2.35 compat
272+ 0b9d67d chore: bump version to 0.2.0, update PROGRESS.md for release
24327352a2a44 refactor: remove schema migrations, inline all columns and indexes
2442748fbdba4 feat: add Force Full Rescan option in Actions menu
2452752817424 feat: add message_id for cross-folder matching, fix unlabelled detection
0 commit comments