A self-hosted personal organiser you talk to. Say "gym Monday, Wednesday and Friday at three, and remind me to call the dentist tomorrow" and a language model running on your own hardware turns it into tasks, events, journal entries, expenses, weigh-ins and meals. Anything it is sure about happens straight away and can be undone. Anything ambiguous waits as a card you approve, edit or throw out. Reminders reach your phone with the app closed.
![]() |
![]() |
There is no chat window, no web search and no memory beyond your own data. The model reads what you said and proposes rows; the app checks every one of them before anything is written, and each card quotes the words it came from.
It runs on one machine, for one person, out of a single SQLite file. Nothing leaves the box except what you point it at.
voice ──▶ faster-whisper ──▶ transcript ─┐
├─▶ extraction (your model) ──▶ actions
typed text ──────────────────────────────┘ │
┌──────────────────────────┴──────┐
▼ ▼
execute → database confirm → a card
(always undoable) (approve / edit / dismiss)
│
▼
reminders: WebSocket · Web Push · Google Calendar
The extraction prompt (prompts/extract_v1.md) asks for JSON under a schema
the model server enforces. Python then validates every action by type: dates
have to parse, recurrence rules have to be legal, categories have to come
from your own list, required fields have to be present. Anything that fails
becomes a confirmation card carrying the reason instead of a row in the
database. A 93-case regression suite guards the prompt, and a harness runs
that suite against any model so you can see how it does before trusting it
with your notes.
| Area | |
|---|---|
| Today | what needs a look, what is next, open tasks, the month's spend, your weight, the week's consistency |
| Life | tasks, recurring events (RRULE, with DST handled by the zone), a rolling agenda, a journal with mood and tags |
| Money | expenses in a closed category vocabulary, standing and monthly budgets, income, transfers, savings goals with pace, month-by-month history |
| Health | weigh-ins with trend, weight goals, calories in (a bundled USDA subset plus your own presets), calories out (a MET table plus your own activities), the day's energy balance |
| Reminders | a durable ledger with three senders: the open app, Web Push to the installed phone app, and an optional Google Calendar projection |
| The app | installable PWA, phone and desktop layouts, four accents in dark and light, search, a skippable first-run setup, edit wherever approve exists |
- Python 3.11 or 3.12. Not 3.13 yet: CTranslate2 has no wheels for it.
- An OpenAI-compatible chat endpoint.
llama-server, LM Studio, Ollama, vLLM or a hosted API. The reference model is Qwen3.8-27B at Q8, which wants roughly 30 GB of VRAM. Its results ship as the baseline, and the harness will tell you what a smaller model gives up. - Speech-to-text needs nothing extra.
faster-whisperruns on CPU, and an NVIDIA GPU makes it quick. Typing works as well as talking, so you can skip voice entirely. - HTTPS if you want it on your phone. Browsers only expose the microphone
and allow an installable app on a secure origin. One
tailscale servecommand is the documented route; any reverse proxy with a certificate does the same job. - No Node required. The built web app ships in the repository.
git clone https://github.com/Inovello/lifeos.git && cd lifeos/backend
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -e .
python -m alembic upgrade head
cp ../config.local.example.yaml ../config.local.yaml # then set timezone, token, model endpoint
python -m lifeos.mainOpen http://127.0.0.1:8080, enter the token, and type a note. docs/setup.md covers the rest, including how to reach it from a phone and how to run it as a service.
lifeos-harness serveThat opens a page on http://127.0.0.1:8090. Give it an endpoint and a model name, run the 93 cases (roughly ten minutes on a 27B model, less on a small one), and read what the model actually produced next to what the case expected. Any run can be compared against the saved baseline.
Strict APIs reject the extra sampling fields llama.cpp accepts, so those need
the openai compat profile. An HTTP 400 on the very first case is usually
that rather than the model. See docs/harness.md.
Read SECURITY.md before you expose the app beyond your own
computer. In short: there is one shared token, the app binds to loopback
until you open it, and it refuses to listen on the network without a token
set. Your notes travel to whatever llm.base_url points at, so that choice
is yours to make deliberately. Nothing the model returns is trusted; it is
validated first and stays reversible afterwards.
config.yaml every key, documented; overlay it rather than edit it
config.local.example.yaml copy to config.local.yaml (gitignored)
prompts/ the extraction prompt, versioned
backend/lifeos/ FastAPI + SQLAlchemy + faster-whisper
api/ routes
pipeline/ audio → transcript → actions → database
services/ LLM client, extraction + validation, executors,
reminders, Google Calendar, Web Push
harness/ the model qualification harness and its cases
alembic/ migrations
frontend/ Vite + React + TypeScript + Tailwind; dist/ is committed
tests/ unit, API, live-LLM and acceptance suites
scripts/ deploy, publish
docs/ setup, deploy, harness, engineering notes
backend/.venv/bin/python -m pytest -q -m "not live_llm and not live_stt and not live_gcal"
backend/.venv/bin/python -m ruff check backend tests
cd frontend && npm test && npx tsc --noEmitThe live_llm tests run the extraction suite against your configured
endpoint and skip with a reason when it is unreachable. The phone verifier
(frontend/scripts/verify-record-mobile.mjs) walks every surface at 390 px
with a touch profile, populated, in both themes. Every check in it was made
to fail on purpose before it was allowed to count, which
docs/engineering.md explains along with the rest of
what building this cost.
- docs/setup.md: clean machine to working install
- docs/harness.md: qualifying a model
- docs/deploy.md: systemd, HTTPS, push-to-deploy, Google Calendar
- docs/engineering.md: the rules, and what they cost
- SECURITY.md: the threat model
- ROADMAP.md and CHANGELOG.md
LifeOS is free software under the GNU Affero General Public License, version 3 or later. Running it for yourself carries no obligation to anyone, whether you have modified it or not. The Affero clause only applies if you modify LifeOS and then let other people use your modified version over a network: those users have to be able to get your changes under the same licence.
Bundled third-party material and the licences of every dependency are listed in NOTICE. The fonts are under the SIL Open Font License and the USDA FoodData Central subset is public domain.

