The v1.3 inboxos milestone closes on the 9/12 disposition: 9 ACCEPT candidates (REQ-INB-28, 29, 30, 31, 32, 33, 34, 36, 37) EXECUTED in v1.3 across 8 PRs / 8 commits; 3 DEFER candidates (REQ-INB-35, 38, 39) filed for v1.4+; 0 REJECT candidates. This commit updates REQUIREMENTS.md (the 9 ACCEPT candidates are now marked [CANDIDATE — EXECUTED in v1.3, commit <sha>]) and ROADMAP.md (the v1.3 EXECUTE block records the 8 commits, the 4-layer PASS verify, the PASS-with-NITS review, and the PASS audit). v1.1 backlog closures recorded in v1.3: P1-1 closed by REQ-INB-36, P1-2 closed by REQ-INB-37. P2-1 + P2-2 deferred to v1.4+ (REQ-INB-38, REQ-INB-39). Tag: v1.3.0. Ship pattern identical to v1.1 / v1.2: FF-merge phase/01-v1.3-execute → milestone/v1.3-initial → main, push tag, push milestone branch, create Gitea release. The cto-inboxos closure (T1.1, REQ-INB-28 + REQ-INB-37) is the same P0 class as the v1.1 P0 sweep (commits7c20d5d,d530921); the ci-pr test wiring (T1.2, REQ-INB-34) is the v1.3 highest-impact candidate. ---ci--- project: inboxos phase: 0 milestone: v1.3 status: complete requirements: covered: [REQ-INB-28, REQ-INB-29, REQ-INB-30, REQ-INB-31, REQ-INB-32, REQ-INB-33, REQ-INB-34, REQ-INB-36, REQ-INB-37] partial: [] deferred: [REQ-INB-35, REQ-INB-38, REQ-INB-39] rejected: [REQ-INB-26] # carry-forward from v1.2 backlog_closures: v1_1_P1_1: REQ-INB-36 v1_1_P1_2: REQ-INB-37 v1_1_P2_1: REQ-INB-38 (deferred to v1.4+) v1_1_P2_2: REQ-INB-39 (deferred to v1.4+) version: v1.3.0 branch: milestone/v1.3-initial commits: 17 execution_pass_commits: 8 verification: PASS (4 layers, 9 must-haves, 30/30 runnable tests, high confidence) review: PASS-with-NITS (0 P0, 2 P1, 3 P2) audit: PASS (17/17 ---ci--- blocks, file/commit discipline clean) ---/ci---
InboxOS
Self-hosted personal ERP / CRM pipeline. A single Gmail inbox, polled over IMAP, archived to SeaweedFS, classified and extracted by a local LLM (Ollama), and written to NocoDB as structured records. Curated attachments are mirrored to Papra. No third-party SaaS touches PII.
Where to start
- Operations runbook —
docs/operations-runbook.md. System overview, service inventory, workflow operations, observability, failure modes, security, cost, glossary. The first thing to read on day 1 of incident response. - Extraction contract —
docs/extraction-contract.md. How a raw email becomes a NocoDB record. Source of truth for theinboxos:classify+inboxos:extract-<module>prompt family. - NocoDB schema —
docs/schemas.md. The four module tables (finance,crm,intel,promotions) and the Message-ID idempotency contract. - Gitea Actions setup —
docs/gitea-actions.md. Runner provisioning (including the second runner for live + historical parallelism), repo secrets, the Basic Auth model. - Pipelines —
pipelines/README.md. Flow diagrams, idempotency model, rollback procedure for the live and historical pipelines. - Papra write policy —
docs/papra-write-policy.md. When the pipeline writes to Papra (attachments + selected bodies), and why the first ship is dry-run.
Quick layout
inboxos/
├── README.md # this file
├── .env.example # placeholder env (no real secrets)
├── docker/
│ └── docker-compose.yml # self-hosted stack: gitea, runners, nocodb, seaweedfs, papra, ollama
├── .gitea/workflows/
│ ├── live-pipeline.yml # cron */5 * * * *, polls IMAP
│ ├── historical-pipeline.yml # workflow_dispatch, streams .mbox
│ └── ci-pr.yml # fast-tests + 100MB e2e + live Ollama smoke
├── pipelines/ # shared Python: common.py, live_pipeline.py, historical_pipeline.py, mbox_stream.py
├── .opencode/commands/ # version-controlled extraction prompts (prompt-as-code)
├── config/ # n8n config (legacy, no longer in use)
└── docs/ # this runbook + schemas + contracts + reports
Status
Phase 5 — Full Deployment. Parent goal: INB-1. Current phase issue: INB-7. The runbook in docs/operations-runbook.md is the canonical reference for ongoing operation.
Historical archive (Google Takeout .mbox)
The full Google Takeout .mbox export lives in SeaweedFS at the canonical S3 URI:
s3://inboxos/eml/historical/all-mail.mbox
That is the value to pass as the mbox_object_key workflow_dispatch input to historical-pipeline.yml. To verify it exists, run from any host with mc configured against the inboxos bucket:
mc ls --recursive inboxos/inboxos/ | grep '\.mbox$'
The historical pipeline streams this object message-by-message, UPSERTs each into NocoDB on Message-ID, and writes the raw .eml backup under s3://inboxos/eml/historical/<yyyy>/<mm>/<dd>/<Message-ID>.eml. See docs/operations-runbook.md §3.2 for the dispatch recipe and §4.4 for the full bucket layout.