Files
oO/README.md
2026-04-15 14:08:20 +00:00

7.3 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

  1. One thing at a time. The UI is a black page with one tip. That's the product.
  2. We don't own your data, we understand it. Connect your apps; we read what we need, when we need it.
  3. Magic requires craft. Precision, timing, and restraint matter more than features.
  4. 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) ✓ shipped

Goal: a single user signs in with Google, connects Todoist, and sees one random Todoist task on a black page. Deletion works.

  • Monorepo scaffold, docker-compose dev env
  • auth — Google OAuth2/PKCE via openid-client v6; session cookie; Next.js middleware guard
  • integrations/todoist — OAuth2 flow, token stored in DB, disconnect supported
  • recommender with RandomPolicy; stable POST /recommend contract; 30s task cache
  • apps/web — sign-in, connect, tip pages; PWA manifest + icons
  • Feedback endpoint (done/dismiss/snooze); marks task complete in Todoist
  • Deploy modular monolith to Agap VM via Caddy at o.alogins.net
  • ToS + Privacy Policy pages (/legal/terms, /legal/privacy); implicit consent on sign-in
  • Account deletion: revokes tokens, purges data, soft-deletes profile; button on /connect
  • Metrics baseline: tip_views table (tip served) + tip_feedback (reactions) — activation + reaction rate queryable

Phase 1 — Real signal + in-the-moment delivery (M1) ✓ shipped

Goal: tips are picked, not drawn from a hat — and they arrive at the right moment on the web.

  • Event bus scaffold: typed in-process EventEmitter (services/api/src/events/bus.ts); subjects match future NATS JetStream — swap is mechanical
  • Todoist sync emits signals.task.synced; tip served/feedback emit signals.tip.*
  • Features extracted per task: is_overdue, task_age_days, priority; context: hour_of_day, day_of_week
  • ml/serving LinUCB bandit (d=5, alpha=1.0); per-user state persisted to disk; /score + /reward endpoints
  • RemotePolicy in recommender: calls ml/serving, falls back to RandomPolicy on timeout/error
  • Feedback loop: reactions mapped to rewards (done=+1, snooze=0, dismiss=-1) → online LinUCB update
  • Web Push (VAPID): SW, subscribe/unsubscribe API, "notify me" button on tip page
  • Quiet-hours + dedupe for push delivery
  • Delayed rewards: tasks completed directly in Todoist (requires webhook from Todoist)
  • NATS JetStream replacing in-process bus (when multi-process pressure arrives)
  • Apple OAuth (deferred to M2)

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 Profile model (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
  • notifier gains 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.)