# LifeOS Architecture
LifeOS is a **local-first personal assistant** built for the Hugging Face
*Build Small* hackathon (Track 1 — Backyard AI). One small model, one shared
memory, three life domains, zero cloud calls.
**Stack:** NVIDIA Nemotron-3-Nano-4B (Q4_K_M GGUF, 2.84 GB) + nomic-embed-text
(146 MB GGUF), both running through the **llama.cpp** runtime
(`llama-cpp-python`), behind **Gradio 6 Server mode** with a hand-built
HTML/CSS/JS frontend. Runs on the HF Spaces free CPU tier.
## 1. System overview
```mermaid
flowchart LR
subgraph Browser ["Browser — static/ (hand-built, zero external requests)"]
UI["index.html + style.css + app.js
4 panels: Kitchen · Health · Money · Chat"]
end
subgraph Server ["app.py — gradio.Server (FastAPI + Gradio API engine)"]
API["@app.api endpoints
SSE streaming, queue, concurrency=1"]
UP["FastAPI routes
/upload/flyer · /upload/flyer_text · /upload/transactions"]
end
subgraph Features ["features/ — deterministic logic (no LLM)"]
FOOD["food.py
deal extraction · recipe scoring"]
HEALTH["health.py
weekly pattern aggregation"]
MONEY["money.py
recurring-charge detection"]
end
subgraph Engine ["engine.py — reasoning"]
PROMPT["build_prompt(domain, memory, input)"]
GEN["generate_stream — token streaming"]
end
subgraph Models ["llama.cpp runtime (100% local)"]
LLM["Nemotron-3-Nano-4B
Q4_K_M · 2.84 GB"]
EMB["nomic-embed-text-v1.5
Q8_0 · 146 MB"]
end
subgraph Memory ["memory"]
STM["memory.py — SHORT-TERM
data/memory.json (structured)"]
LTM["rag.py — LONG-TERM
data/longterm.json (notes + vectors)"]
end
UI -->|"fetch + SSE"| API
UI -->|multipart| UP
UP --> FOOD & MONEY
API --> FOOD & HEALTH & MONEY
API --> PROMPT --> GEN --> LLM
PROMPT --> STM
PROMPT -->|"recall(query, k=5)"| LTM
LTM -->|embeddings| EMB
API -->|"log / detect events"| STM & LTM
```
**Design principle — deterministic first, model last.** Parsing, scoring, and
detection are plain Python; the 4B model only does the judgment/explanation
layer on a small curated context. That division is what makes a 4B model on
2 vCPUs feel smart: short prompts, grounded outputs, no hallucinated data.
## 2. Request flow per feature
```mermaid
sequenceDiagram
participant B as Browser
participant S as gr.Server
participant F as features/*
participant M as memory (STM+LTM)
participant E as engine.py
participant L as llama.cpp
Note over B,L: 🍳 Kitchen — flyer → 3 recipe picks
B->>S: POST /upload/flyer (PDF/image)
S->>F: food.extract_deals (pdfplumber / pytesseract)
F-->>B: deals chips [{item, price}]
B->>S: call/food_recommend (SSE)
S->>F: shortlist(deals, recent meals, prefs) → top 6
S->>M: meals last 7d + RAG recall
S->>E: build_prompt("food") → generate_stream
E->>L: create_chat_completion(stream=True)
L-->>B: tokens stream into result card
Note over B,L: 💰 Money — CSV → cancel list
B->>S: POST /upload/transactions (CSV)
S->>F: parse → normalize merchants → detect_recurring (25–35d cadence, ±15% amount)
F->>M: set_subscriptions(detected)
F-->>B: subscription table
B->>S: call/money_review (SSE)
S->>E: income + budget + subs → stream CANCEL/KEEP/WATCH verdicts
```
Health follows the same shape (log → deterministic `weekly_pattern` →
model recommends tomorrow's session). Chat skips the feature layer: it gets
**all** memory slices plus conversation history.
## 3. Memory system — short-term + long-term
```mermaid
flowchart TB
subgraph Writes
W1["log meal / workout (UI)"]
W2["money: detected subscriptions"]
W3["chat: 'remember ...' statements"]
end
subgraph STM ["SHORT-TERM — memory.py (structured JSON)"]
S1["meals[] · workouts[] · finances{} · user_profile{}"]
end
subgraph LTM ["LONG-TERM — rag.py (local RAG)"]
L1["notes: {text, kind: fact|event|preference, vec}"]
L2["nomic-embed via llama.cpp (embedding=True)"]
L3["numpy cosine top-k (no vector DB)"]
end
subgraph Read ["Prompt assembly (every request)"]
R1["domain slice of STM
(food → meals, health → workouts, money → finances, chat → all)"]
R2["top-5 recalled LTM notes for the query"]
R3["[system: persona + domain task] + [user: memory + notes + request]"]
end
W1 --> S1
W2 --> S1
W1 -->|auto-summarized note| L1
W3 -->|explicit fact| L1
L1 --- L2 --- L3
S1 --> R1 --> R3
L3 --> R2 --> R3
```
- **Short-term** (`data/memory.json`): exact structured state — what you ate,
trained, pay for. Regenerated from a seed with **relative dates** so the
demo never goes stale.
- **Long-term** (`data/longterm.json`): durable facts, preferences, and events
("knee needs rest days between runs", "FitnessPal unused since March").
Embedded once at write time; retrieved by cosine similarity at prompt time.
At demo scale (10²–10³ notes) brute-force numpy beats any vector DB — and
it keeps the dependency count tiny.
## 4. Why these models
| | Model | Size | Role |
|---|---|---|---|
| Reasoning | [nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF](https://hf.co/nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF) Q4_K_M | 2.84 GB | All recommendations + chat |
| Embeddings | [nomic-ai/nomic-embed-text-v1.5-GGUF](https://hf.co/nomic-ai/nomic-embed-text-v1.5-GGUF) Q8_0 | 146 MB | Long-term memory recall |
Nemotron-3-Nano is a **hybrid Mamba-2** architecture (only 4 attention
layers): near-constant memory per token and strong CPU throughput, which is
exactly what the Spaces free tier (2 vCPU / 16 GB) needs. Reasoning traces
are disabled via system prompt to keep latency down; `max_tokens≈512`.
## 5. Hackathon badge map
| Badge | How |
|---|---|
| 📴 Off the Grid | No cloud APIs anywhere: local GGUFs, raw-fetch frontend, system fonts, no CDN |
| 🦙 Llama Champion | Both models run through the llama.cpp runtime |
| 🐜 Tiny Titan | 3.97B params reasoning model |
| 🎨 Off-Brand | gr.Server + 100% hand-built frontend, no Gradio components |