Roadmap phase sections now show shipped summaries only; open work lives in Gitea milestones. Eliminates duplicate source-of-truth between README and issue tracker. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
156 lines
8.7 KiB
Markdown
156 lines
8.7 KiB
Markdown
# 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/`](docs/architecture/) and decisions in [`docs/adr/`](docs/adr/).
|
|
|
|
## Monorepo layout
|
|
|
|
See [`CLAUDE.md`](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
|
|
```
|
|
|
|
---
|
|
|
|
## AI stack
|
|
|
|
oO is AI-native. Domain-specialized agents pre-compute snippets describing the user's state from one angle each; an orchestrator LLM reasons over the assembled snippets and produces one tip (ADR-0013). The orchestrator iterates a registry, not a hardcoded list (ADR-0014) — adding an agent is a manifest change, nothing else.
|
|
|
|
### Three-tier layout
|
|
|
|
| Tier | Service | Purpose | Where |
|
|
|------|---------|---------|-------|
|
|
| Inference | **Ollama** | Local LLM + embedding; no data leaves the host | `localhost:11434` |
|
|
| Routing | **LiteLLM** | Unified OpenAI-compatible API; model aliases; cloud fallback | `llm.alogins.net` (Agap shared) |
|
|
| Testing | **OpenWebUI** | Prompt iteration, model comparison, manual evals | `ai.alogins.net` (Agap shared) |
|
|
|
|
### Tip generation pipeline (ADR-0013, M2)
|
|
|
|
```
|
|
User signals Pre-compute agents (every 15 min)
|
|
(tasks, calendar, ──▶ ml/agents/{overdue-task, momentum, ──▶ agent_outputs
|
|
patterns, time) time-of-day, recent-patterns, (per-agent TTL)
|
|
focus-area, ...}
|
|
│
|
|
Eligibility filter: required consents + │
|
|
active context + per-user prefs (ADR-0014) ◀──┘
|
|
▼
|
|
Orchestrator prompt (`v4-orchestrator`)
|
|
= global prefs + active context + snippets
|
|
▼
|
|
LiteLLM ──▶ Ollama (local) / cloud fallback
|
|
▼
|
|
Tip shown to user
|
|
▼
|
|
User reaction (done / snooze / dismiss + dwell)
|
|
▼
|
|
Logged to tip_feedback for observability
|
|
(no online ML reward loop — see ADR-0013)
|
|
```
|
|
|
|
**Why LiteLLM as gateway:** All LLM calls use a single `LITELLM_URL` env var. Swapping from qwen2.5 to llama3.2, or routing a fraction to Claude for A/B, is a config change in LiteLLM — zero code change in oO. The model name in `tip_scores` tells you exactly which model produced each tip.
|
|
|
|
**Why Ollama first:** Tips contain personal context. Local inference means no user data leaves the host for the inference path. Cloud models (Anthropic, OpenAI) are opt-in fallbacks for evaluation and simulation only, gated behind `ANTHROPIC_API_KEY`.
|
|
|
|
### Models (planned; routes through LiteLLM)
|
|
|
|
| Alias | Model | Task |
|
|
|-------|-------|------|
|
|
| `tip-generator` | qwen2.5:1.5b (default) | Generate typed tip candidates from user context; local-first via Ollama |
|
|
| `embedder` | nomic-embed-text | Task clustering, semantic similarity for dedup; local via Ollama |
|
|
| `judge` | claude-haiku-4-5 (cloud, eval-only) | Offline sim judge; rates tip quality for A/B (requires `ANTHROPIC_API_KEY`) |
|
|
|
|
All model calls route through **LiteLLM** at `llm.alogins.net` (or `LITELLM_URL` env var) using model aliases. This decouples tip generation from model selection — swap the backend model in LiteLLM config without code changes. See ADR-0008.
|
|
|
|
---
|
|
|
|
## Roadmap
|
|
|
|
Issues and open work are tracked in [Gitea milestones](http://localhost:3000/alvis/oO/milestones). Pick an issue, check its milestone (= phase), read the service's `README.md`, ship.
|
|
|
|
### Phase 0 — Walking skeleton *(M0)* ✓ shipped
|
|
Single user signs in with Google, connects Todoist, sees one random task on a black page. Deletion works. Auth, integrations, recommender stub, PWA, feedback loop, ToS/privacy, metrics baseline.
|
|
|
|
### Phase 1 — Real signal + in-the-moment delivery *(M1)* ✓ shipped
|
|
Tips are picked, not drawn from a hat. Event bus, Todoist sync, task features, ε-greedy policy (v1 + v2), web push, NATS JetStream bridge, shadow-policy registry, offline sim framework, per-user profile features, admin + ML ops console (`apps/admin`).
|
|
|
|
### Phase 2 — AI tips + multi-source signals *(M2)* ✓ shipped
|
|
Tips are AI-generated from user context. Multi-agent pipeline (ADR-0013): five pre-compute agents (`overdue-task`, `momentum`, `time-of-day`, `recent-patterns`, `focus-area`) emit prompt snippets; orchestrator LLM produces one tip. Unified Profile + agent registry + auto-inference framework (ADR-0014). LLM output validation + fallback. LiteLLM gateway, model benchmarking, prompt research, MLflow tracing.
|
|
|
|
### Phase 3 — Native mobile *(M3)*
|
|
iOS (SwiftUI + APNs) and Android (Compose + FCM). `notifier` service gains APNs + FCM channels. Auth migrated from Auth.js to dedicated OIDC provider. Decide-and-deliver scheduler. See [M3 milestone](http://localhost:3000/alvis/oO/milestone/3).
|
|
|
|
### Phase 4 — MLOps at scale *(M4)*
|
|
Retraining pipeline, feature-to-prompt batch jobs, prompt optimization loop, LLM fine-tuning on reaction signals, modular-monolith import-boundary lint, online experiments framework, drift monitoring. See [M4 milestone](http://localhost:3000/alvis/oO/milestone/4).
|
|
|
|
### Phase 5 — Production hardening *(M5)*
|
|
Audit logging, key rotation, k3s → k8s, multi-region, public integration SDK, billing. See [M5 milestone](http://localhost:3000/alvis/oO/milestone/5).
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
This repo is split into independent modules; most tickets belong to exactly one. Pick an issue from [Gitea](http://localhost:3000/alvis/oO/issues), read the service's `README.md`, ship.
|
|
|
|
Conventions and per-service guidance live in [`CLAUDE.md`](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.)
|