Technical Report — 8 April 2026 | Prepared by Luci
The Auth Portal is a Flask web app running on Luci (Hetzner) at http://100.118.207.3:8788, accessible via Tailscale. It manages OAuth tokens for four cloud services so Elmar can re-authenticate from his phone or laptop without terminal access.
| Service | Auth Flow | Token File | Status |
|---|---|---|---|
| M365 (Safair) | Device Code Flow | ~/.graph-api-token.json |
Active |
| Google Workspace | OAuth2 Authorization Code | ~/.config/gws/credentials.json |
Active |
| Personal OneDrive | Device Code Flow | ~/.graph-api-token-personal.json |
Needs Auth |
| Dropbox | OAuth2 Code (no redirect) | ~/.dropbox-api-token.json |
Just Authenticated |
/oauth2/v2.0/devicecode to get a user code + verification URLmicrosoft.com/devicelogin/oauth2/v2.0/token every 5s until user completes sign-inaccess_token + refresh_token + expires_on to the token JSON filegraph_api.py or the auth portal calls the refresh endpoint automaticallyM365 Safair uses tenant-specific authority (/common as of today). Personal OneDrive uses /consumers authority with Files.ReadWrite.All scope only.
http://localhost:1 with an auth code in the URLoauth2.googleapis.com/token~/.config/gws/credentials.jsondropbox.com/oauth2/authorize with token_access_type=offlineapi.dropboxapi.com/oauth2/token using Basic auth (app key:secret)access_token + refresh_token to ~/.dropbox-api-token.json_dbx_refresh_token() when access token expiresThe portal exposes GET /api/status which returns health for all four services. Each service's health check:
graph_api.py refresh-tokengws drive about get)/v1.0/me/2/users/get_current_account, auto-refreshes on 401A scheduled health check (oauth_health_check.py) runs periodically and writes status to ~/workspace/data/oauth-health-status.json.
Searches all four cloud drives in parallel via their respective APIs:
| Drive | API Used | Capabilities |
|---|---|---|
| M365 Work OneDrive | MS Search API (/search/query) |
Full-text content search, ranked results, content snippets |
| Personal OneDrive | Graph API (/me/drive/search) |
Filename + content search |
| Google Drive | Drive API v3 (fullText contains) |
Full-text content search inside docs, PDFs, etc. |
| Dropbox | Dropbox API (/2/files/search_v2) |
Filename + content search with match highlights |
python ~/workspace/scripts/search_all.py "fleet plan" python ~/workspace/scripts/search_all.py "FICA" --drive onedrive_work python ~/workspace/scripts/search_all.py "budget" --top 10 --json
Three search modes available locally:
| Mode | What It Searches | How |
|---|---|---|
| Gety.ai (MCP) | Inside file content (semantic + full-text) | mcp__gety__Search — searches PDFs, DOCX, PPTX, images via OCR |
| Catalog (CLI) | Filenames + paths across all drives | search_files.py — 121K+ files indexed, keyword + LanceDB semantic |
| Google Drive API | Inside Google Drive files | --gdrive-content flag on catalog search |
/consumers authority, separate token file (~/.graph-api-token-personal.json), auto-refresh supportredirect_uri=http://localhost:1 parameter (wasn't registered in the Dropbox app), switched to no-redirect flow| # | Improvement | Where | Impact |
|---|---|---|---|
| 1 | Deploy search_all.py on local machine — give Lucienne the same unified cloud API search that Luci has | Local Mac | High |
| 2 | Add search_all.py to file-search skill — integrate as a 4th search mode alongside Gety, Catalog, and GDrive content search | Skill | High |
| 3 | Add Dropbox & Personal OneDrive tokens on local — copy auth_portal.py or just the token files so Lucienne can search these drives too | Local Mac | Medium |
| 4 | PKA Dashboard integration — add a "Cloud Search" widget to the PKA dashboard that calls search_all.py and displays results | Dashboard | Medium |
| 5 | Search as MCP tool on Luci — expose search_all.py as an MCP tool so any Claude instance can call it remotely, not just Luci | Luci MCP | Future |
| 6 | Content extraction — after finding a file via API search, add ability to download + extract content (currently search_all.py only returns metadata/snippets) | Both | Future |
| Scenario | Best Tool | Why |
|---|---|---|
| "Find a PDF that mentions FICA on page 3" | Gety.ai (local only) | Semantic search inside document content, OCR for scanned docs |
| "Find my budget spreadsheet" | File Catalog (local) or search_all.py | Filename search — fast, broad coverage |
| "Find documents about Heron project in Dropbox" | search_all.py (Luci or local) | Dropbox API does content search server-side |
| "Search across everything — OneDrive, GDrive, Dropbox" | search_all.py + Gety in parallel | API search covers cloud-only files; Gety covers local+OCR |
| File | Location (Luci) | Purpose |
|---|---|---|
| auth_portal.py | ~/workspace/scripts/auth_portal.py | OAuth token management web UI (port 8788) |
| search_all.py | ~/workspace/scripts/search_all.py | Unified cloud file search CLI |
| graph_api.py | ~/workspace/scripts/graph_api.py | MS Graph API client (email, calendar, OneDrive) |
| file-search skill | ~/.claude/skills/file-search/SKILL.md | Local file search (Gety + catalog + GDrive) |
| google-drive skill | ~/.claude/skills/google-drive/SKILL.md | Google Drive API client (drive.py) |
| m365 skill | ~/.claude/skills/m365/SKILL.md | MS365 integration (email, calendar, OneDrive) |
Report generated by Luci | MC-393 | 8 April 2026