- ADR-0003: modular monolith for Phase 0 with documented extraction triggers - ADR-0004: Auth.js + OIDC-shaped boundary; dedicated provider when mobile ships - ADR-0005: protobuf for events, OpenAPI for HTTP, schema-registry CI gate - New architecture docs: data-model, metrics (magic proxies), privacy (Phase-0 feature) - Prime directives updated: privacy-as-feature, modular-by-package-deployable-by-stage - Roadmap revised: Apple OAuth deferred to M1; web push in M1; k3s intermediate; tip-kind-aware UI - PLAN updated: Phase-0 deletion endpoint, metrics baseline, compose profiles, import-boundary lint - License decision in README (ARR with OSS plan in Phase 5)
7.1 KiB
oO
One tip. Right now. Feels like magic.
oO learns who you are from the apps you already use and surfaces one perfectly-timed suggestion — an advice or a todo — on a black page. No feed. No dashboard. One tip.
Why
Everyone has too many tasks, too many apps, too much noise. What people actually need is a single, well-chosen nudge at the right moment. oO is that nudge, powered by a recommendation engine that gets smarter the more of your life it sees.
Product principles
- One thing at a time. The UI is a black page with one tip. That's the product.
- We don't own your data, we understand it. Connect your apps; we read what we need, when we need it.
- Magic requires craft. Precision, timing, and restraint matter more than features.
- Private by default. Tokens are encrypted, models are per-user, deletion is one click.
Prototype scope (Phase 0)
Three pages. That's it.
| Page | What it does |
|---|---|
| Sign in | Google / Apple OAuth. No passwords. |
| Connect | A list of integrations. Tap "Todoist" → OAuth flow → token stored. |
| Tip | Black page. One tip. Tap to dismiss / done / snooze. |
Under the hood the "pick a tip" call already routes through a recommender service with a pluggable policy — so v0 is literally "random Todoist task" but every other version slots into the same contract.
Architecture at a glance
┌──────────┐ OAuth ┌────────────┐
│ Web / │──────────▶│ auth │
│ Mobile │ └─────┬──────┘
│ client │ │ JWT
│ │ REST/GraphQL ▼
│ │────────▶┌───────────────┐
└──────────┘ │ gateway │──┬──▶ profile
└───────┬───────┘ ├──▶ integrations ──▶ Todoist / Google / ...
│ └──▶ recommender ──▶ ml/serving (Python)
▼
┌───────────────┐
│ events │ ◀── integrations emit normalized events
│ (Kafka/NATS) │ ──▶ ml/pipelines (features, training)
└───────────────┘
More detail in docs/architecture/ and decisions in docs/adr/.
Monorepo layout
See CLAUDE.md for the full tree and conventions.
apps/ web, ios, android
services/ gateway, auth, profile, integrations, recommender, events, notifier
packages/ shared-types, sdk-js, ui
ml/ pipelines, features, registry, experiments, serving
infra/ docker, k8s, terraform, ci
docs/ architecture, adr, api
Roadmap
Phase 0 — Walking skeleton (M0)
Goal: a single user signs in with Google, connects Todoist, and sees one random Todoist task on a black page. Deletion works.
- Monorepo scaffold, CI skeleton, docker-compose dev env with
core/fullprofiles authon Auth.js with Google provider; OIDC-shaped boundary (ADR-0004)integrations/todoistOAuth2 flow + encrypted token vault + provider-side revocationrecommenderwithRandomPolicy; stablePOST /recommendcontractapps/web— three pages (sign-in, connect, tip); PWA manifest; offline reaction queue- ToS + Privacy Policy + consent capture on first sign-in
- Account-deletion endpoint: revokes providers, purges credentials, soft-deletes profile
- Metrics baseline: activation, first-tip reaction rate, dwell, retention (see
docs/architecture/metrics.md) - Deploy modular monolith +
ml/servingstub to a single VM via docker-compose + Caddy
Phase 1 — Real signal + in-the-moment delivery (M1)
Goal: tips are picked, not drawn from a hat — and they arrive at the right moment on the web.
- Event bus (NATS JetStream) with protobuf schemas (ADR-0005) + schema-registry CI gate
- Todoist event-driven sync (emit
signals.task.*) - Feature store skeleton + first five features (hour-of-day, overdue count, task age, priority, project)
ml/servingFastAPI scorer;RemotePolicywrapper in recommender- Global-then-personalize bandit: pooled LinUCB over shared features, per-user residual when data allows
- Shadow-deploy infra: every new policy logs what it would have picked; promotion requires reward-parity
- Feedback loop: reactions → rewards; delayed rewards for tasks completed in Todoist directly
- Web Push notifications (VAPID) so the "magic" shows up without opening the app
notifier(lite): web-push delivery, quiet-hours honoured, dedupe- Apple OAuth added (deferred from M0)
Phase 2 — Multi-source profile & trust (M2)
Goal: oO knows more than tasks, and users can see/control what we know.
- Integrations: Google Calendar, Apple Health (web import), generic webhook ingress
- Unified
Profilemodel (identity, preferences, contexts, consents) - Timing signals (Page Visibility, Idle Detection, coarse location) — opt-in, transparent
- Advice library + mixing policy (todo vs advice vs ambient)
- User-facing data dashboard: what's stored, what's computed, export, delete-by-category
- Cost/usage observability
Phase 3 — Native mobile (M3)
- iOS app (SwiftUI) with APNs push
- Android app (Compose) with FCM push
notifiergains APNs + FCM channels, per-device rate limits- Migrate auth from Auth.js to dedicated OIDC provider (trigger from ADR-0004)
- Decide-and-deliver scheduler: per-user "is this tip worth interrupting now?" threshold
Phase 4 — MLOps at scale (M4)
- Prefect/Airflow for batch feature materialization + retraining
- MLflow registry; shadow → A/B → launch pipeline as first-class
- Online experiments framework: deterministic assignment + bandit policies alongside fixed-split A/B
- Cross-user collaborative features (opt-in only); cohort slicing; fairness checks
- Drift monitoring (feature drift, prediction drift, reward drift); model cards per version
Phase 5 — Production hardening (M5)
- Audit logging, rotation of provider tokens + internal signing keys
- k3s on existing VM, then k8s + HPA once multi-node justified (no cliff)
- Multi-region failover, Postgres PITR, event-bus mirroring
- Public integration SDK; sandbox tenancy for third-party connectors
- Billing + subscription tiers
Contributing
This repo is split into independent modules; most tickets belong to exactly one. Pick an issue, check its milestone (= phase), read the service's README.md, ship.
Conventions and per-service guidance live in CLAUDE.md.
License
All rights reserved — 2026. Contact the owner for licensing inquiries. (We'll switch to an OSS license for non-sensitive packages once the public SDK lands in Phase 5.)