AnniLifeOS (ALOS) is a personal life OS — tasks, capture, reminders, finance, journal, goals, and AI assistant — built for self-hosting. It is part of a larger ecosystem of "Anni" projects all building toward an umbrella platform called YUME.
ALOS has two delivery surfaces that share one backend:
- Web app (
alos.yumehana.dev) — universal access, any device, any browser - Desktop app (Tauri, Win11 first) — same web frontend, but with a native window and access to local OS features: filesystem read/write, terminal commands, STT via local Whisper, tray icon, background processes
The distinction mirrors Claude.ai vs Claude desktop. Same brain, same features, but the desktop app can touch local system resources. Web is access everywhere, app is the power layer.
YUME (future umbrella — no code yet)
├── ALOS (this repo) — life OS
├── YUNA — notification backbone + Discord bot (separate repo: D:\.src\YUNA)
├── AnniWebsite — personal site (yumehana.dev, separate repo)
└── Other Anni projects (AnniWin11, AnniProxy, CZTimers, ...)
YUNA = "Your Unified Notification Assistant". Eventually ALOS sends events to YUNA, and YUNA decides how to deliver them (Discord DM, push notification, Win11 toast, Watch ping). For now, ALOS handles notifications itself — just keep the architecture clean enough that YUNA can be wired in later as a service.
Everything self-hosted. No external cloud services except Cloudflare Tunnel (no open inbound ports) and third-party APIs (Claude, ElevenLabs, OAuth providers).
Browser / Tauri app
└── Cloudflare Tunnel (HTTPS)
└── nginx on RPi4
├── alos.yumehana.dev → /opt/anni/alos/ (Vite build)
│ → 127.0.0.1:4100 (ALOS Express API)
└── (future: /api/whisper → ThinkPad Whisper service)
Storage: RPi4 with 2x 2TB hot-plug drives at /srv/storage
Auth DB: SQLite (shared with AnniWebsite)
ALOS DB: SQLite at /srv/storage/alos.db
The ThinkPad runs a Whisper STT service (FastAPI + faster-whisper). ALOS backend proxies STT requests to it. This is a future concern — scaffold the route but don't implement it in P0.
AnniWebsite already has working OAuth (GitHub, Discord, Google) with session cookies on .yumehana.dev. ALOS shares this.
- Session cookie domain:
.yumehana.dev - Auth routes live on the AnniWebsite backend (
yumehana.dev/api/auth/*) - ALOS backend validates sessions by calling
/api/auth/meon the AnniWebsite backend (internal network call on RPi4) GET /api/auth/mereturns{ id, username, email, role, avatar }or 401- Login flow: redirect to
https://yumehana.dev/#/login?returnTo=https://alos.yumehana.dev - After OAuth, user lands back on ALOS with a valid
.yumehana.devsession cookie
All ALOS API routes require auth. No public endpoints except health check.
| Layer | Tech | Notes |
|---|---|---|
| Frontend | Vite + Vanilla JS | Same as AnniWebsite — no framework |
| Backend | Node.js + Express | Port 4100 |
| Database | SQLite via better-sqlite3 | WAL mode, FK on |
| Desktop wrapper | Tauri (Rust) | Wrap the same Vite frontend |
| STT | Whisper (faster-whisper on ThinkPad, FastAPI) | Proxy via ALOS backend |
| AI | Claude API (claude-sonnet-4-20250514) | Anthropic SDK |
| Voice output | ElevenLabs API | Scaffold only in P0 |
| Reverse proxy | nginx | Same setup as AnniWebsite |
| Tunnel | Cloudflare Tunnel | Already running on RPi4 |
Port exactly from D:\.src\AnniWebsite\client\src\styles\global.css and components.css. Do not invent a new design language.
Key tokens:
--bg: #080c12 /* near-black */
--bg2: #0d1320
--bg3: #111927
--surface: rgba(255,255,255,0.04)
--surface-h: rgba(255,255,255,0.07)
--border: rgba(255,255,255,0.07)
--border-h: rgba(99,210,190,0.35)
--text: #dde6ef
--text-soft: #b0bec8
--muted: #627585
--accent: #63d2be /* teal — primary accent */
--accent2: #4fa8d8 /* blue */
--accent3: #a78bfa /* purple */
--radius: 14px
--radius-lg: 20px
--font-head: 'Syne', sans-serif /* headings */
--font-body: 'DM Sans', sans-serif /* body */
--font-mono: 'DM Mono', monospace /* code, numbers */Card style: background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); backdrop-filter: blur(12px); with hover lift.
Dark theme only for now. Custom cursor (dot + ring). Starfield canvas background.
AnniLifeOS/
├── client/ # Vite frontend (shared by web + Tauri)
│ ├── index.html
│ ├── package.json
│ ├── vite.config.js
│ └── src/
│ ├── main.js # Entry point
│ ├── lib/
│ │ ├── router.js # Hash-based SPA router (same pattern as AnniWebsite)
│ │ ├── api.js # All fetch calls to backend
│ │ ├── auth.js # Auth state, login redirect, /api/auth/me check
│ │ ├── toast.js # Toast notifications
│ │ └── theme.js # Theme helpers
│ ├── effects/
│ │ ├── starfield.js # Starfield canvas (port from AnniWebsite)
│ │ └── cursor.js # Custom cursor (port from AnniWebsite)
│ ├── components/
│ │ ├── nav.js # Top nav / sidebar
│ │ └── modal.js # Modal utility
│ ├── pages/
│ │ ├── home.js # Dashboard / today view
│ │ ├── capture.js # Quick capture
│ │ ├── tasks.js # Tasks + backlog
│ │ ├── finance.js # Finance tracker
│ │ ├── journal.js # Journal / daily notes
│ │ ├── goals.js # Goals
│ │ └── ai.js # AI chat
│ └── styles/
│ ├── global.css # Tokens, reset (ported from AnniWebsite)
│ ├── components.css # Buttons, cards, nav (ported from AnniWebsite)
│ └── alos.css # ALOS-specific styles
├── server/
│ ├── server.js # Express setup, middleware, routes
│ ├── db/
│ │ ├── db.js # SQLite singleton
│ │ └── schema.sql # Full schema
│ ├── middleware/
│ │ └── auth.js # Session validation (calls AnniWebsite /api/auth/me)
│ ├── routes/
│ │ ├── capture.js # POST /api/capture
│ │ ├── tasks.js # CRUD /api/tasks
│ │ ├── reminders.js # CRUD /api/reminders
│ │ ├── finance.js # CRUD /api/finance
│ │ ├── journal.js # CRUD /api/journal
│ │ ├── goals.js # CRUD /api/goals
│ │ ├── ai.js # POST /api/ai/chat (Claude streaming)
│ │ ├── stt.js # POST /api/stt (proxy to Whisper — scaffold only)
│ │ └── voice.js # POST /api/voice (ElevenLabs — scaffold only)
│ ├── .env.example
│ └── alos.service # systemd unit
├── app/ # Tauri wrapper
│ ├── src-tauri/
│ │ ├── Cargo.toml
│ │ ├── tauri.conf.json # Points webview at client dev server or built dist
│ │ └── src/
│ │ └── main.rs # Tauri commands: fs read/write, shell exec, STT
│ └── package.json
├── nginx/
│ └── alos.yumehana.dev.nginx
├── deploy.sh
├── deploy.ps1
└── README.md
-- Users are managed by AnniWebsite auth — store only what ALOS needs
CREATE TABLE users (
id TEXT PRIMARY KEY, -- matches AnniWebsite user id
username TEXT NOT NULL,
email TEXT NOT NULL,
created_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE captures (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
raw TEXT NOT NULL, -- original input
parsed TEXT, -- JSON: {type, title, due, priority, tags}
status TEXT DEFAULT 'inbox', -- inbox | processed | archived
created_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE tasks (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
title TEXT NOT NULL,
notes TEXT,
priority TEXT DEFAULT 'medium', -- low | medium | high
status TEXT DEFAULT 'todo', -- todo | doing | done
due_at INTEGER,
created_at INTEGER DEFAULT (unixepoch()),
updated_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE reminders (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
title TEXT NOT NULL,
body TEXT,
remind_at INTEGER NOT NULL,
recurring TEXT, -- null | daily | weekly | monthly (cron-style later)
done INTEGER DEFAULT 0,
created_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE finance_entries (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
amount REAL NOT NULL,
type TEXT NOT NULL, -- income | expense
category TEXT,
note TEXT,
date INTEGER NOT NULL,
created_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE journal_entries (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
date TEXT NOT NULL, -- YYYY-MM-DD
content TEXT,
mood INTEGER, -- 1-5
created_at INTEGER DEFAULT (unixepoch()),
updated_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE goals (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
title TEXT NOT NULL,
area TEXT, -- health | finance | growth | projects | social
horizon TEXT, -- week | month | quarter | year | life
status TEXT DEFAULT 'active',
progress INTEGER DEFAULT 0, -- 0-100
notes TEXT,
created_at INTEGER DEFAULT (unixepoch()),
updated_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE ai_messages (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
user_id TEXT NOT NULL REFERENCES users(id),
role TEXT NOT NULL, -- user | assistant
content TEXT NOT NULL,
context TEXT, -- JSON: injected context snapshot at time of message
tokens_used INTEGER,
created_at INTEGER DEFAULT (unixepoch())
);Goal: a working shell you can open, log into, and navigate. No broken state.
- Scaffold the monorepo with all folders and config files
- Port the design system CSS from AnniWebsite exactly
- Port
starfield.jsandcursor.jsfrom AnniWebsite effects - Build the SPA router (hash-based, same pattern as AnniWebsite)
- Build the auth flow — on load, call
/api/auth/me; if 401, show login screen with redirect to AnniWebsite OAuth; if authed, show app - Build the app shell — sidebar nav with all sections listed, top bar with user avatar, empty page stubs for each section
- Set up Express backend with SQLite, WAL mode, FK on, schema applied
- Implement the auth middleware (validate session via AnniWebsite
/api/auth/me) - Build the quick capture input — text field, Enter to submit, calls
POST /api/capture, drops item into DB asstatus: inbox - Build the inbox view — lists captures with status inbox, basic clear/archive actions
- Set up the Tauri project in
app/pointing at the Vite dev server for local dev - Write nginx config for
alos.yumehana.dev - Write systemd service file
- Write
deploy.sh/deploy.ps1
Do not build in P0: AI chat, STT, ElevenLabs, finance, journal, goals, recurring reminders, YUNA integration. Scaffold the routes and empty page stubs so the nav is complete, but implement only capture + tasks in P0.
- Model:
claude-sonnet-4-20250514 - Streaming responses via SSE (
text/event-stream) - Context injection: before each AI message, inject a JSON snapshot of the user's current tasks, reminders, recent captures, and goals. This is how the AI knows about your life.
- Token budget tracking per user — store
tokens_usedon eachai_messagesrow, aggregate per month - Quick capture AI parsing:
POST /api/captureshould optionally call Claude to parse raw input into structured{ type, title, due, priority, tags }JSON. In P0 just store raw input, add parsing in P1. - System prompt should be aware it is ALOS's embedded AI assistant, has access to the user's data, and should be concise and action-oriented
- All API routes behind auth middleware — no exceptions except
GET /health - Input validation on all routes (use zod or manual checks — no raw user strings into SQL)
- Parameterised queries only — no string concatenation in SQL
- Rate limiting on AI and STT routes
- CORS: only allow
alos.yumehana.devandlocalhostorigins - Session cookie:
httpOnly: true, secure: true, sameSite: 'lax', domain: '.yumehana.dev' - No secrets in client bundle — all API keys backend only
# Backend
cd server && npm install
cp .env.example .env
node server.js # → http://127.0.0.1:4100
# Frontend
cd client && npm install
npm run dev # → http://localhost:3100 (proxy /api/* to :4100)
# Tauri (desktop)
cd app && npm install
npm run tauri dev.env needs:
SESSION_SECRET=
ANNI_AUTH_URL=http://127.0.0.1:4000 # AnniWebsite backend internal URL
CLAUDE_API_KEY=
ELEVENLABS_API_KEY=
WHISPER_URL=http://thinkpad-local:8000 # Whisper service (future)
DB_PATH=/srv/storage/alos.db
PORT=4100
- Minimal working system over perfect system. Ship something usable fast, iterate.
- Every feature should be genuinely faster than doing it manually. If it's not, don't ship it.
- The quick capture is the hero feature. Everything else is secondary.
- Code should be clean and readable. Same patterns as AnniWebsite — consistent style matters because this will get big.
- Comments where intent isn't obvious. No comments for the obvious.
ALOS v0.1 — part of the YUME ecosystem