cloudinit-bot d2f3bd561b docs(ideate): register 12 v1.3 candidates in REQUIREMENTS.md + ROADMAP.md
The IDEATE commit (946b744) recorded the v1.3 candidate set in
the ideation file. This commit registers the same 12 candidates
in REQUIREMENTS.md (v1.3 section, REQ-INB-28..39) and updates
ROADMAP.md (v1.3 ideation block) to reflect the 9/12 disposition
(9 ACCEPT, 3 DEFER, 0 REJECT).

Disposition by candidate:
- REQ-INB-28 ACCEPT (P0, gitea-actions.md:95 cto-inboxos drift)
- REQ-INB-29 ACCEPT (P2, runbook footer Next review → v1.3)
- REQ-INB-30 ACCEPT (P2, runbook §4.5 alerting forward-pointer)
- REQ-INB-31 ACCEPT (P2, papra-write-policy.md test count 13→15)
- REQ-INB-32 ACCEPT (P2, extraction-contract.md line-ref refresh)
- REQ-INB-33 ACCEPT (P2, .env.example 7-entry addition)
- REQ-INB-34 ACCEPT (P0, wire 6 v1.1 offline tests into ci-pr)
- REQ-INB-35 DEFER  (XS, .gitignore opencode.json shadow)
- REQ-INB-36 ACCEPT (P1, runbook §6 ordering, closes v1.1 P1-1)
- REQ-INB-37 ACCEPT (P1, setup_gitea_secrets.sh owner, closes v1.1 P1-2)
- REQ-INB-38 DEFER  (XS, apply_schemas.py papra_index --check test)
- REQ-INB-39 DEFER  (S, test_papra_link_parity imapclient shim)

CP files: docs/requirements.md and docs/roadmap.md are NOT
modified (CPO-owned, per board mandate b49cfb7). The 12
candidates remain [CANDIDATE] until the CPO authors matching
entries in docs/requirements.md.

---ci---
project: inboxos
phase: 1
milestone: v1.3
status: ideate
disposition:
  accepted: [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]
  deferred: [REQ-INB-35, REQ-INB-38, REQ-INB-39]
  rejected: []
  count: 12
files_added:
  - .ciagent/inboxos/ideation/v1.3-candidates.md (in 946b744)
files_modified:
  - .ciagent/inboxos/REQUIREMENTS.md (v1.3 section, REQ-INB-28..39)
  - .ciagent/inboxos/ROADMAP.md (v1.3 ideation block, 9/12 disposition)
---/ci---
2026-06-08 23:16:04 +00:00

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 the inboxos: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.

S
Description
InboxOS — self-hosted personal ERP/CRM pipeline. Prompts-as-code, Gitea Actions, NocoDB, Ollama, SeaweedFS, Papra.
Readme 1.8 MiB
Languages
Python 90.3%
Shell 9.7%