A local, Graph-backed mail client + cache + agent.
This repo is a single repo (monorepo) containing three apps:
sync-app/: builds/updates a local SQLite cache from Microsoft Graph (folders + date range + attachments)agent-app/: intent→safe query templates over the local cache, plussync now/sync statusweb-server-app/: local 3-pane mail UI + chat grounded in the cache; shells out toagent-appfilesearch-app/: Windows-only filesystem search agent powered by Voidtools Everything SDK
Background scripts report live progress to a shared sync_status.json file.
progress_monitor.py reads it every 2 seconds and shows an always-on-top desktop UI.
.\.venv\Scripts\python.exe .\progress_monitor.pySee MONITOR_ARCHITECTURE.md for the full architecture, the
StatusWriter API, all registered task IDs, and the pattern for adding new tasks.
Secrets live in a repo-root .env file (never committed). Each app sub-folder contains an
identical env_loader.py that loads them into os.environ at startup. An age-encrypted
.env.enc backup is safe to commit and restore on new machines via sops.
See SECRETS_ARCHITECTURE.md for the full loading chain, candidate
file search order, encrypted backup workflow, and the pattern for adding env_loader.py to new
apps.
- Linux + system Python 3.10+
- APT packages (no pip/venv assumed):
python3-msalpython3-requestspython3-yaml- Optional for PDF text extraction:
poppler-utils(providespdftotext)
TENANT_IDCLIENT_IDCLIENT_SECRETMAILBOX_UPNOPENAI_API_KEY(needed for chat; optional for agent planning)
Preferred local source:
- Store these in repo-local
.env. - The app env loaders now check repo-local
.envbefore older hidden-file locations.
- Copy the example config:
cp sync-app/config.example.yaml sync-app/config.yaml
- Edit
sync-app/config.yaml:
- Adjust
sync.cache_range.start_date/end_date - Confirm
sync.folders.names - Leave secrets as env-var references
From repo root in pwsh:
- Create config once if needed:
Copy-Item sync-app/config.example.yaml sync-app/config.yaml - Put secrets in repo-local
.env - Safe Graph verification:
./.venv/Scripts/python.exe ./sync-app/mailboxsync.py --config ./sync-app/config.yaml --sqlite "$env:TEMP\ai_exchange_mailboxsync_dry.sqlite" dry - Build/update cache:
py -3 sync-app/mailboxsync.py --config sync-app/config.yaml sync - Agent search:
py -3 agent-app/cache_agent_cli.py --config sync-app/config.yaml "pdfs from annie" - Agent sync controls:
py -3 agent-app/cache_agent_cli.py --config sync-app/config.yaml "sync now"py -3 agent-app/cache_agent_cli.py --config sync-app/config.yaml "sync status"
- Start mail web UI:
./web-server-app/restart_mail_web_server.ps1 - Test Graph mail sending (standalone):
.\.venv\Scripts\python.exe .\web-server-app\send_mail_cli.py new --to "you@example.com" --subject "test" --body "hello" - Start filesystem search server:
./filesearch-app/scripts/start_filesearch_server.ps1 -WaitForHealth -WaitTimeoutSec 10
Then open:
- Mail UI:
http://127.0.0.1:8001/ - Filesearch UI:
http://127.0.0.1:8712/
python3 sync-app/mailboxsync.py --config sync-app/config.yaml sync
python3 agent-app/cache_agent_cli.py --config sync-app/config.yaml "pdfs from annie"python3 agent-app/cache_agent_cli.py --config sync-app/config.yaml "sync now"python3 agent-app/cache_agent_cli.py --config sync-app/config.yaml "sync status"
cd web-server-app && bash restart_mail_web_server.sh
Then open:
http://127.0.0.1:8001/
Everything uses a Windows DLL, so SDK calls must run in a Windows process.
Recommended workflow (WSL + Windows together):
- Start the Windows server (from WSL, recommended):
cd filesearch-app/scripts && ./wsl_start_server.sh --wait --wait-timeout 10 - Use the HTML UI:
http://127.0.0.1:8712/ - Or call from WSL:
python3 filesearch-app/filesearch_wsl_client.py --limit 20 "recent txt files"
UI notes (keyboard-first):
ArrowDownfrom query moves into results;ArrowUpfrom the first row returns to query.Enteron a selected row opens an action menu (includes Copy Full Path → Windows clipboard).Shift+Arrowsupports multi-select; Copy copies all selected paths (newline-separated).
Content search (opt-in):
- Content scanning is disabled unless you include the explicit marker
content:. - Example:
python3 filesearch-app/filesearch_wsl_client.py --limit 20 "ext:pdf content:insurance premiums"
Health/readiness:
http://127.0.0.1:8712/health(includeseverything_db_loadedandopenai_available)
OpenAI model:
- Default model is
gpt-5.2, but the UI allows switching models.
Agent notes / full runbook:
- See
filesearch-app/README.md→ Agent runbook (do not reinvent) for exact commands, flags, endpoints, and test cases. - Large-result-set behavior and timeout tuning are documented there as well (see “everything query timed out”).
OpenAI key note:
- If
OPENAI_API_KEYis set in your WSL environment and you start via the WSL wrapper scripts, it is forwarded into the Windows server process automatically (viaWSLENVenvironment passthrough).
The sync-app/archive_ews_sync.py script pulls the Exchange Online In-Place Archive directly via EWS (Microsoft Graph does not expose the archive mailbox). It writes into the same mail_cache.sqlite.
Requires the full_access_as_app Application permission granted in your Azure App Registration.
Key commands (from repo root in pwsh):
# One-shot sync (picks up from the oldest already-synced date and works backwards)
.\.venv\Scripts\python.exe .\sync-app\archive_ews_sync.py --config .\sync-app\config.yaml sync
# Unattended auto-restart loop (stops when target year is reached)
.\sync-app\scripts\run_archive_sync_loop.ps1 -TargetYear 2017
# Extract text from attachment blobs (run after sync is complete)
.\.venv\Scripts\python.exe .\sync-app\archive_ews_sync.py --config .\sync-app\config.yaml extract
# Combined terminal status report (process + DB stats)
.\.venv\Scripts\python.exe .\sync-app\archive_ews_sync.py --config .\sync-app\config.yaml statusProgress monitor — always-on-top desktop widget (bottom-right corner):
.\.venv\Scripts\pythonw.exe .\progress_monitor.pyReads sync_status.json (written by status_writer.py) every 2 seconds. Any script can report progress by importing StatusWriter from status_writer.py.
Full details: sync-app/README.md → EWS Archive Sync and Progress Monitor sections.
- The web server and the agent both default to
sync-app/config.yaml. - The agent emits cache coverage warnings for date-based queries and can kick off a full sync.
- Microsoft Graph access has been verified directly through
mailboxsync.py dryin PowerShell. - The mail UI reply composer supports rich text editing (bold/italic/underline, lists, font controls), To/CC/BCC address fields that auto-populate on reply/reply-all/forward, per-email draft memory across message selections, and an amber tab indicator when a draft is present.
web-server-app/send_mail_cli.pyis a standalone Graph mail send test tool (reply, reply-all, forward, new). RequiresMail.Sendapplication permission with admin consent in Azure AD.
- Encrypted
.envbackup workflow is documented inSECRETS.md. - Plaintext
.envstays local; commit.env.encand.sops.yaml. - Windows age private key location:
%APPDATA%\sops\age\keys.txt.
git clone <REPO_URL>