A self-extending, agent-driven personal operating system - one place to manage learning, tasks, coding/projects, trading, social, marketing, and design (and anything else you add later: health, finance, …), backed by a single common database, controllable from Telegram even when the laptop is off, and able to build its own new features on request.
It is personal today but architected to become a multi-tenant SaaS with no rewrite.
This README is the canonical architecture document - a superset of the original plan. CLAUDE.md is the short working-rules companion.
git clone <this-repo> && cd life-os
./setup.sh # checks Rust/Node, builds services, installs frontend deps
./run.sh # API on :8080 + web app on :5173 (add --with-drain for jobs)Zero configuration needed: the API auto-creates and migrates a local
lifeos.db on first boot, and AI runs keyless through whatever coding
agent CLI is already on your PATH (Claude Code, Gemini CLI, Codex, OpenCode,
Hermes, Antigravity, ...) - switch agent/model on the go from the AI Console.
Every optional knob (Turso sync, Telegram bot, Nango OAuth, whisper, ...) is
documented in .env.example and docs/MANUAL-SETUP.md.
The web app is an installable PWA (Add to Home Screen / Install app).
Two problems drove it:
- Notion's free AI is too weak and forces manual database-building. Every tracker had to be hand-modeled, and the AI couldn't populate or evolve it. Life OS inverts this: a generic graph schema means you never hand-build a database per domain, and the agent reads/writes it directly.
- Tools and data were siloed - Postgres apps, broker APIs, JSON task files, a SQLite memory DB, markdown vaults, social accounts, Figma files - none talking to each other. Life OS unifies them under one database and one agent loop.
Four requirements reshaped the design:
- Mobile-first control with the laptop off - manage everything from a Telegram bot 24/7.
- Self-extension - an AI inside the app that, when asked, edits the codebase to add a brand-new module itself.
- Real-world integrations from day 1 - social (multi-account OAuth), marketing, and design are first-class, not "addable later."
- SaaS-ready - multi-tenant, secret-isolated, and billable if it ever leaves personal use.
The result is a generic multi-tenant entity-graph + a module/plugin system + a self-extension builder + the local Claude Code harness as the brain, with seven seed domains and infinite room to grow.
- One generic schema, specialized by declarative manifests. Storage is generic; per-domain behavior is metadata. The opposite of Notion's per-database modeling tax.
- Multi-tenant from the first commit. Every data row carries
workspace_id; personal use is just one workspace. No single-user assumptions anywhere. - Local-first, no lock-in. SQLite-compatible store; offline on the Mac; data is yours and portable.
- Codegen only on the trusted Mac. The always-on cloud surface can only enqueue; all file-writing and reasoning-heavy work happens locally.
- Auditability over speed; gate the irreversible. Append-only event log; outward/irreversible actions (social posts, trades) are human-gated; every self-built module is a revertable git commit.
- Minimum always-on context, token-disciplined. API-first thin tools over heavy MCPs; on-demand loading only.
- Reuse before build. Generalize the existing
knowledge-atlasapp, the existing harness, and existing skills (copywriting, figma-, mcp-).
┌─────────────────────────────┐
Telegram ──────────► │ Cloudflare Worker (free) │ LIGHT/MEDIUM brain
(laptop off-OK) │ bot — Claude Haiku │ full DB (workspace) +
│ full common-DB + memory + │ memory + audit;
│ audit; enqueues heavy → jobs│ gated outward actions
└──────────────┬──────────────┘
│ HTTPS (workspace-scoped, authed)
┌──────────────▼──────────────┐
│ Turso / libSQL lifeos.db │ CANONICAL, always-on
│ control-plane + data-plane │ multi-tenant,
│ entities·edges·events·jobs… │ SQLite-compatible
└──────────────┬──────────────┘
│ embedded replica (periodic sync)
┌────────────────────────────────────▼────────────────────────────────┐
│ MAC (when awake) │
│ • lifeos local API (single DB-token owner, 127.0.0.1, authed) │ HEAVY brain
│ • Life OS SPA (generalized knowledge-atlas, light theme) │ deep work
│ • Claude Code harness: module scaffolder, Eval, Release, deep agents│
│ • thin curl tools in ~/.claude/bin (allow-listed) + broker-guard │
│ • Nango (self-hosted): OAuth vault + proxy for social/Figma/Notion │
│ • integration callers: Figma, Higgsfield, social APIs (on-demand) │
└──────────────────────────────────────────────────────────────────────┘
Two brains, one database:
- Light/medium brain (cloud, always-on). A Telegram bot on Cloudflare Workers (scale-to-zero compute = free) running on Claude Haiku. It has full common-DB access scoped to its workspace (entities/edges/events/annotations RW), harness memory recall (shared-DB FTS5/vector), and audit logging (
events). It handles capture, queries, and medium actions, gates outward actions (social posts, trades) for approval, and enqueues anything heavy/codegen for the Mac. Works with the laptop off. (Compute is free; Haiku tokens are minimal.) - Heavy brain (Mac). The existing Claude Code harness (Claude) does deep work: study authoring, coding, trade analysis, the self-extension builder, integration-heavy design/marketing work, and the Eval/Release loop. Syncs to the same DB.
Why Turso/libSQL: SQLite wire-compatible (all existing FTS5 / memvec.py code ports unchanged), hosted and always reachable, and purpose-built for multi-tenant SaaS (cheap database-per-tenant when we scale). An embedded replica on the Mac preserves local-first/offline; the cloud copy is always awake for Telegram.
Key invariant: request/state is data in the synced DB (survives the Mac being off); codegen + heavy reasoning only ever run on the trusted Mac; the cloud surface stays trivial.
A task / trade / topic / post / campaign / asset are all rows in entities, distinguished by workspace_id + module + type + a flexible attrs JSON. New domains and fields need zero migration by default.
| Table | Purpose |
|---|---|
entities |
Every typed node: workspace_id, module, type (topic/task/project/trade/social_account/post/campaign/content/lead/design_file/asset/component/note/gap/…), parent_id hierarchy, status, tier, ts, attrs JSON (escape hatch), source. FTS5-backed. |
edges |
Typed cross-domain links (generalizes the atlas's connections): connection/depends_on/blocks/derived_from/owns/publishes_to/uses_asset/…; state (pending/accepted), created_by; nullable dst_id + dst_ref. |
events |
Append-only log: domain events (study.review, task.completed, trade.closed, post.published, campaign.sent) and harness run-rows (run_id, tier, model, tokens, cost, latency, error, outcome, eval_score, gated). Powers Observe/Eval/Release. |
annotations |
Reader notes (generalizes the atlas's localStorage comment/link/question layer). |
jobs |
Heavy-work queue: bot enqueues, Mac drains. |
module_requests |
Self-extension queue: survives the Mac being off. |
| Table | Purpose |
|---|---|
workspaces |
Tenant. Personal = one seeded row. Carries plan/limits. |
users |
Identity. Personal = one row (you). |
memberships |
user_id ↔ workspace_id + role (owner/admin/member). |
connections |
Per-workspace, per-account integration credentials: provider (instagram/x/whatsapp/slack/reddit/figma/notion/kite/…), account_handle, scopes, access_token_enc / refresh_token_enc (encrypted at rest), expires_at, status. Supports multiple accounts per provider. |
Billing removed by design (migration 0013_remove_billing.sql, issue #104): the subscriptions/plans billing seam from the original control-plane migration was dropped - DROP TABLE IF EXISTS on both, never read by any route. This is a self-hosted, bring-your-own-database-and-AI-model project; there is no product to meter or bill. workspaces.plan stays as a free-text label only, never checked by any route.
Tenancy strategy: schema is workspace_id-scoped everywhere; personal deployment uses one shared DB, and the API enforces workspace filtering (RLS-style). SaaS scales via Turso database-per-workspace - the local API abstracts "which DB" so this is a deployment swap, not a code change. Secrets are never synced into the agent context or the replica's reach of the bot; the API injects them at call time using a per-workspace envelope key.
- Lexical:
entities_fts(FTS5; triggers flattenattrs→attrs_text). - Semantic:
entity_vecreusing~/.claude/bin/memvec.py(MiniLM-384, sqlite-vecvec0); fuse with FTS5 via RRF like~/.claude/bin/memory-recall. The shared DB is the cross-tier memory the Haiku bot recalls from. - Derived state lives in a SEPARATE, never-synced database file. Turso/libSQL has no table-level "don't sync" flag - a synced embedded replica converges to the primary's schema, so a local-only table in the synced file would be clobbered. Derived state (FTS5 + sqlite-vec) therefore lives in
lifeos-derived.db(plain SQLite, nosyncUrl),ATTACH-ed at runtime. This is already howmemvec.pystores vectors, so it is reuse, not new work; physical separation enforces "never synced" instead of a flag that does not exist. - Keep sqlite-vec/memvec; do not switch to libSQL native vectors. Native vectors are beta with the weakest local path and would only help if vectors lived in the synced DB - which violates the rule above.
Hot query paths get additive GENERATED … VIRTUAL columns over attrs (e.g. due) - confirmed indexable (expression index) and addable via ALTER TABLE ADD COLUMN without a table rewrite; ~90% of new modules ship with no SQL.
Sync model (corrected against how libSQL actually behaves):
events/jobs/module_requestsare append-only → conflict-free.- Embedded-replica writes go to the remote primary by default; the Mac sets
offline: true(Turso Sync, public beta) so writes land locally first and sync bidirectionally - this is required for the local-first/offline premise, not optional. - Turso's default conflict resolution is last-push-wins (not LWW-on-
updated_at), at row granularity over the wholeattrsJSON blob. Mitigation, defense-in-depth: (1) single-writer-per-row discipline - the bot writes its lane (light/medium), the Mac writes its lane (heavy); make it an explicit invariant; (2) treat the append-onlyeventslog as the reconciliation source of truth - repair entity state from the event log on a detected row conflict rather than trusting the blind last-push outcome; (3) optionally a field-mergeconflictResolver(per-fieldupdated_atinsideattrs) when both tiers start mutating the same rows. - Derived state (FTS5/vectors) is rebuilt locally in
lifeos-derived.dband never participates in sync.
Each module ships modules/<id>/module.js calling osRegisterModule({...}) - the generalization of the knowledge-atlas's atlasAdd merge-by-id contract. A manifest is declarative: data + how to render generic entities, never DOM/router/DB code.
osRegisterModule({
id, name, icon, color /* light palette */, num, version,
entityTypes: { <typeId>: { label, plural, icon,
attrs: { <field>: { type:'text|number|date|enum|ref|bool|secret', enum?, ref?, required? } },
display: { title, subtitle?, badge? }, lifecycle: [/* statuses */] } },
views: [ { id, label, kind:'list|board|table|calendar|detail|graph|gallery', type, groupBy?, sortBy?, filter?, columns? } ],
events: [ /* emitted event types */ ],
botCommands: [ { cmd, help, handler } ], // Telegram surface
agentTools: [ { name, schema, impl, gated? } ],// harness surface; gated=true → draft/approve
integrations:[ { provider, scopes, onConnect } ],// OAuth/API providers this module uses
syncTargets: [ { kind:'notion', db, map } ], // optional outbound sync, no lock-in
seed: [ /* optional starter entities/edges */ ],
});- Learning / Study - the knowledge-atlas generalized to any subject: domains → topics → subtopics → resources, cross-domain edges, gaps inbox, spaced repetition, examiner/teach-back. Atlas data files wrapped via an
atlasAdd → osRegisterModuleshim. Telegram:add topic,quiz me,what's due. - Tasks / Productivity - tasks/projects/schedule; Kanban board + "today" list. Telegram:
/task,/done,/today. - Coding / Projects - seeded from a git scan of the ~27 repos in
04_Projects; status, gaps, CI/review state, harness links. Telegram: project status, what's blocked. - Trading - from scratch (not
ai-trade): trade journal (entry/exit/stop/target/R-multiple/PnL/emotion), reusable setups/playbooks, equity-curve fromevents.thesisedges to learning topics → journal and atlas are one graph. Broker read-only; logging/analysis only; order placement is human-gated and out-of-agent (see §7). Telegram:/buy(logs a planned trade),/close,/pnl. - Social - multi-account OAuth for Instagram, X, WhatsApp, Slack, Reddit, via self-hosted Nango (it is the encrypted token vault + OAuth dance + auto-refresh + ~800 providers). Nango's Proxy matches the security model exactly: the local API calls
nango.proxy({connectionId, endpoint}), Nango injects the live token server-side, and the agent only ever holds aconnectionIdhandle, never a secret. Each connected account is anentity(type=social_account) referencing a NangoconnectionId; you hold many accounts per platform natively. Kite (daily request-token) and WhatsApp Business Cloud are custom connectors Nango doesn't model cleanly. The AI can read (feeds, mentions, DMs, threads) freely and draft posts/replies/DMs, but publishing is human-gated (draft → Telegram approve → publish via the same proxied connection), because it is outward and irreversible. Posts/mentions/threads are entities; engagement isevents. Telegram:/inbox,/draft, approve/deny buttons. - Marketing - campaigns, a content calendar, audiences/segments, leads, channels, and analytics. Content is drafted with the
copywriting+marketingskills-ai-agentsskills, publishes via Social accounts (publishes_toedge), and uses Design assets (uses_assetedge); funnel/UTM metrics arrive asevents. Outward sends (broadcast email, ad launch, scheduled posts) are human-gated. Telegram: campaign status, draft content, approve sends. - Design - Figma (read+write) via
mcp-figma, image/video generation viamcp-higgsfield, plus a design-system/asset library. Entities:design_file(Figma ref),component,token,asset(exported media),brief. The AI can read/inspect Figma, generate assets, build/maintain a design system (figma-generate-library), and implement designs to code (figma-implement-design). Assets feed Marketing/Social via edges. Integration MCPs are loaded on-demand via mcp-multiplexer and unloaded after. Views include an asset gallery and a component library.
Future domains (health, finance, CRM, …) are added the same way - via the self-extension builder. You never enumerate domains up front.
An in-app "+ Ask AI to add a module" affordance grows the system by talking to it.
Mac online (synchronous):
POST /api/module-request { prompt, workspace_id }→module_requestsrow +events('module.requested').server/scaffold.jsdrives the Claude Agent SDK (@anthropic-ai/claude-agent-sdk,query({prompt, options})) - not a rawclaude -psubprocess - so tool-locking, structured output, and hooks are first-class. Restriction is defense-in-depth, 3 layers: (A)allowedTools/disallowedTools+permissionMode: "dontAsk"(hard-deny, headless-safe); (B) a PreToolUse hook that fails closed when aWrite/Editfile_pathescapesmodules/<id>/(the dir scopeallowedToolscan't express; a hook deny holds even under bypass); (C) the built-in macOS Seatbelt sandbox (failIfUnavailable: true) confining any Bash child - in a git worktree it auto-allows shared.gitwrites sogit commitworks.- The agent copies
modules/_template→modules/<id>/, fills the manifest, and emits the manifest summary as schema-validated structured output (outputFormat: {type:"json_schema", schema}from a Zod source of truth; the SDK re-prompts on mismatch - no hand-rolled ajv retry loop). - Two validators: structural (pure Node: manifest matches schema, no duplicate type ids, no dangling
view.type) + render (headless Playwright against a scratch derived/replica DB, 0 JS errors, asserts an app-emittedmodule-mounted:<id>event, one bounded retry). - Insert
modulesrow +events('module.installed'); SSE hot-reload - new tile appears, no restart. - On failure →
status='failed'surfaced in-app, one retry.
Mac offline (queued): Telegram /addmodule … → the bot writes module_requests(status='queued') to cloud Turso, replies "queued". A LaunchAgent poller on the Mac (modeled on ~/.claude/bin/route-daemon) drains on wake, runs the identical local build, commits to git, bot notifies "✅ live".
Safety: the cloud bot only enqueues; codegen only ever runs on the Mac; the agent writes only under modules/ (never core/); every install is a git commit → one git revert away.
One local lifeos API (extending the atlas's zero-dep Node server; FastAPI acceptable) owns the DB write token at 127.0.0.1 and enforces workspace scoping + auth. Agent tools are thin curl wrappers in ~/.claude/bin/ (lifeos entity|edge|event|job|config, tg send, social draft, design gen), allow-listed in settings.json. CRUD is never an MCP. mcp-multiplexer hot-loads heavy MCPs (Figma, Higgsfield, social) only when needed; a bounded UserPromptSubmit context-injection hook replaces always-mounted MCPs.
- Common DB: harness = full RW; Haiku bot = full RW within its workspace.
- Trading: read-only for any agent/bot. No order tool registered anywhere; fail-closed
broker-guardPreToolUse hook denies place/modify/cancel/GTT even if the Kite MCP is mis-loaded; broker keys read-scoped. Orders flow agent →proposed_orderentity → Telegram approve → separate interactivetrade-exec(never agent/hook/cron-callable, typed confirmation). No autonomous trading. - Outward actions (social/marketing publish):
gatedagent tools produce drafts only; publishing requires Telegram approval, then a worker/Mac executor calls the provider API. - Secrets: OAuth tokens live encrypted in
connections, never in agent context; the API injects them at call time. eventsappend-only: no UPDATE/DELETE route, so even the RW token cannot rewrite history.
- Event store - the
eventstable doubles as the harness run-log; alifeos-sync-eventsbridge in the existing Stop hook joins~/.claude/logs/route.jsonl+~/.claude/metrics/costs.jsonl+session-captureinto one append-only row per run. Cloud rows written by the Worker. - Eval + Gate - LLM-as-judge on the Mac via the existing
claude -p --model haikupattern (reusing archivedeval-harness/agent-evalrubrics), sampled + ship-class only + content-cached → cents/day.eval-gatewraps the commit/sync/job-complete boundary; below threshold →gated=1, ship blocked, rationale to Telegram. Trade analysis judged on data-grounding only, never PnL, never auto-acts. - Observe - a
harness observecase besideroute-stats; readsevents+ quotas, breaks down tokens/cost/latency/error/gated per tier/module/phase, with a cloud free-tier + Haiku-spend meter. - Release loop - a
lifeos-releaselearner turns logged outcomes into candidate versionedconfigs(incl. the "learned reranking prior" as a JSON bias onroute_core.py); shadow-replayed → Telegram-approved →config promote(human-gated) flips active atomically; rollback = one pointer flip; every flip is an event.
jobs table (kept in Turso - not Cloudflare Queues, whose free tier drops messages after 24h and splits the audit trail from events). No queue library (graphile-worker/pg-boss are Postgres-only; no mature libSQL queue exists). The atomic claim is a one-liner - UPDATE jobs SET status='running', claimed_by=:w WHERE id=(SELECT id FROM jobs WHERE status='queued' ORDER BY priority DESC, created_at ASC LIMIT 1) RETURNING … - plus a reaper that returns timed-out running rows to queued (handles a Mac crash mid-job). module_requests is the same pattern with its own lifecycle. Triggered by a launchd LaunchAgent poller (StartInterval + RunAtLoad, re-fires on wake). Turso is the only always-on piece.
A generalization of the knowledge-atlas SPA into a multi-module shell. Implemented as a React + Vite SPA under frontend/ (the original plan called for a vanilla-JS no-build core/; that prototype was superseded and removed - see frontend/FRONTEND.md for the authoritative status).
- Reuse (concepts carried over): the atlas router, SVG cross-module graph, markdown engine, search,
annotations,intelligence. - Implemented in
frontend/src/:lib/moduleRegistry.js(osRegisterModulecontract) +lib/moduleManifests.js,lib/db/lib/api.js(libSQL + workspace context), soft auth,core/renderers/{list,board,table,calendar,detail,graph,gallery,timeline,map}.jsx,index.cssdesign tokens, the seven manifests; plusserver/{scaffold,…}.jsfor self-extension.
Each module renders generically from its manifest's views + entityTypes.display: a trade → journal table + equity calendar; a task → Kanban board; a topic → atlas article + connection chips; a design asset → gallery; a campaign → calendar/funnel - all from the same entities/edges rows. You get cross-domain edges, one search index, one event log, and one graph across every module for free.
life-os/
frontend/ # React + Vite SPA - the implemented UI (supersedes the
index.html # original vanilla `core/` prototype, now removed)
src/ main.jsx App.jsx # entry + React Router routes
components/ pages/ # shell (Layout, AIConsole, CommandBar) + route pages
core/renderers/ # generic list/board/table/calendar/gallery/… views
lib/ # api client, module registry/manifests, ai, vcs
index.css # Neo-Brutalist design tokens (Tailwind v4 @theme)
modules/
learning/ module.js data/01_dsa.js … 13_gpu.js # migrated atlas data
tasks/ module.js
projects/ module.js # git-seeded
trading/ module.js # from scratch
social/ module.js # multi-account OAuth
marketing/ module.js
design/ module.js # Figma + Higgsfield
_template/ module.js views.md README.md # scaffold skeleton
services/ # Rust services (the heavy brain's native code), 9 crates
lifeos-agents/ lifeos-api/ lifeos-vcs/ lifeos-ingest/ lifeos-pipelines/
lifeos-actions/ lifeos-memory/ lifeos-drain/ lifeos-cli/ # binary name `lifeos`
server/ # Node glue where JS is required
scaffold.js memvec.py agent/ build/ validators/ lib/ evals/ test/
worker/ # Cloudflare Worker: Telegram bot (Haiku) + OAuth callbacks
migrations/ 0001_core.sql … 0019_memory_communities.sql # 19 migrations
infra/ # self-hosted Nango, etc.
external/ # vendored/forked deps (e.g. jj)
CLAUDE.md README.md
- Foundations - Turso project +
0001_core.sql+0002_control_plane.sql(workspace/users/memberships/connections); locallifeosAPI (single DB-token owner, workspace-scoped); embedded-replica sync; thin~/.claude/bin/lifeostool + allow-list; seed the personal workspace/user. → agent can CRUD the common DB, tenant-aware. - App shell + seed modules - generalize the atlas into
core/(light palette),osRegisterModule, genericviews/; ship Learning, Tasks, Projects, Trading, Social, Marketing, Design. → usable multi-module SPA over the DB. - Integrations - OAuth flows + encrypted
connectionsfor Instagram/X/WhatsApp/Slack/Reddit; Figma + Higgsfield via mcp-multiplexer; read paths live, write paths drafted. → real accounts/files connected, AI can read & draft. - Telegram lane (Haiku) - Cloudflare Worker bot on Claude Haiku with full workspace DB + memory recall + audit; capture/query/medium actions; gated approve/deny for outward actions; enqueue heavy →
jobs. → control + capture from phone, laptop off. - Self-extension builder -
/api/module-request,scaffold.js,_template/, two validators, SSE hot-reload, offline queued variant + drain poller. → "ask AI to add a module" works. - Harness loop - event-store bridge, Eval+Gate,
harness observe, Release loop,broker-guard+ read-only broker tools + gated executors. → everything logged, scored, auto-improved, boundaries enforced. - SaaS hardening (when needed) - real auth/sessions, database-per-workspace swap, plan/quota gating, billing. → flip from personal to multi-tenant product.
Each phase ships with tests (≥80%, TDD) and a conventional-commit history.
- DB/tools:
lifeos entity create … && lifeos event add …; assert rows + FTS5 hit + memvec recall; workspace isolation (a second workspace can't see the first's rows); kill cloud, write offline, reconnect, assert replica converges. - SPA: load offline then with the local API; each module's views render; cross-module graph draws from
edges; search works; manual light/minimalist UI check. - Integrations: connect a throwaway account per provider; AI reads feed/mentions; a draft post is created but not published until approved; tokens stored encrypted, absent from agent context/logs.
- Telegram (Haiku): with the Mac off, capture/query/
/pnl//inbox//addmodulerespond; outward action shows approve/deny and only acts on approve; heavy/addmoduleshowsqueued; wake Mac → drain builds + notifies. - Self-extension: "add a health tracker" → new tile after validators;
git logshows the commit; break the template → validator fails cleanly, no partial register. - Permissions (must-pass): order attempt via agent and via mis-loaded Kite MCP →
broker-guarddenies both; no order tool registered;eventsUPDATE/DELETE → 404; social publish blocked without approval; broker/social reads succeed. - Harness loop:
harness observeshows tokens/cost/latency/gated per tier/module; a low-quality run is Eval-gated + Telegram rationale;lifeos-release propose→ shadow-replayed candidate that only activates after humanconfig promote.
| Layer | Choice | Why |
|---|---|---|
| Canonical DB | Turso / libSQL | SQLite-compatible (reuse FTS5/memvec), always-on, embedded replica = local-first, built for multi-tenant SaaS |
| Always-on compute | Cloudflare Workers (free) | Scale-to-zero, webhook-shaped; hosts bot + OAuth callbacks |
| Bot LLM | Claude Haiku | Capable + cheap; full DB + memory + audit on the always-on lane |
| Heavy-lane LLM | Claude (existing Claude Code harness) | Deep reasoning, codegen, Eval/Release |
| Bot transport | Telegram | Free, ubiquitous, works laptop-off |
| Telegram framework | grammY (MIT) | Native Cloudflare Workers adapter (webhookCallback(bot,"cloudflare-mod")), inline approve/deny keyboards |
| DB access | Drizzle ORM + @libsql/client (MIT) |
Typed access to entities/edges/events; /web import on the Worker (no FS/TCP), embedded-replica syncUrl on the Mac |
| Frontend | React + Vite SPA under frontend/ (superseded the original no-build vanilla-JS plan); Refine (MIT) adopted, dataProvider proven |
The live generic views (list/board/table/calendar/gallery/…) are hand-built components in frontend/src/core/renderers/, not yet routed through Refine; frontend/src/lib/refineDataProvider.js is wired end-to-end against the real API and proven on one proof-of-concept page (frontend/src/pages/RefineDemo.jsx), not yet the app shell; bring-your-own graph (Cytoscape) |
| Local API | Node (extend atlas server) / FastAPI | Single DB-token owner, workspace-scoped |
| Semantic search | sqlite-vec + MiniLM-384 (memvec.py) in a separate un-synced lifeos-derived.db |
Reuse existing harness infra; native libSQL vectors rejected (beta, would couple derived state to the synced DB) |
| Self-extension | Claude Agent SDK (@anthropic-ai/claude-agent-sdk) |
First-class tool-locking, PreToolUse path hook, Seatbelt sandbox, worktree isolation, schema-validated structured output (Zod) |
| Integrations / OAuth vault | Self-hosted Nango (Elastic License 2.0) + Figma/Higgsfield via mcp-multiplexer | ~800 providers, encrypted tokens, auto-refresh, Proxy keeps secrets out of agent context; Kite + WhatsApp as custom connectors |
| Secrets | Nango-managed encrypted tokens + per-workspace envelope key for non-OAuth | SaaS-safe, never in agent context (agent holds only a connectionId) |
Hard rule: every third-party integration uses credentials WE own, never a claude.ai connector.
The Gmail/Calendar/Drive/Notion/Slack MCPs live inside a claude.ai lead account that is not ours; depending on them is fragile and not SaaS-ready.
Instead, self-hosted Nango is the OAuth vault for all API providers (Google, Notion, Slack, Instagram, X, Reddit, Figma, GitHub): it runs the OAuth dance, stores tokens encrypted, auto-refreshes, and its Proxy injects the live token server-side so the agent only ever holds a connectionId, never a secret.
Non-OAuth providers (Zerodha Kite daily-token, WhatsApp Business Cloud) are native custom connectors.
Anything with no API at all is driven by a browser actuator (fork of browser-use/browser-harness), Mac-only and fully gated.
MCPs are reserved for heavy on-demand capability tools (Figma, Higgsfield, game engines), never credentialed connectors.
Full detail: docs/INTEGRATIONS.md.
- Universal version control (
lifeos-vcs) - the headline differentiator: git-style history, branches, tags, semantic diffs, and time-travel over every file type (video, image, design, 3D, audio, docs), not just code. Content-addressed (BLAKE3 + FastCDC chunking), modeled on Jujutsu, with per-type semantic diff plugins. Version history is the append-onlyeventslog. A Rust service. Seedocs/VERSIONING.md. - Media intelligence (
lifeos-ingest) - "find the clip where I said X" across your library. memvec is text-only, so a Rust pipeline transcribes (whisper-rs), captions, and parses media into timestampedsegmententities that memvec embeds. Optional CLIP for true visual search. Seedocs/MEDIA-INTELLIGENCE.md. - GitHub connector + "Life OS Actions" - manage all repos (issues/PRs/CI/releases) as entities; event-triggered AI automation on any entity (
on asset.version_created → draft post), GitHub-Actions-style but for everything. - New modules - Email, Calendar, Files, Notion, Slack, Reading, Travel - all manifests over the existing schema, owned-OAuth via Nango. See
docs/MODULES.md. - Platform systems - universal command bar, user/module agent pipelines (DAGs via the Agent SDK), per-module dashboards derived from
events(zero new storage), a signed module marketplace (the SaaS seam), and a PWA. Seedocs/PLATFORM-SYSTEMS.md. - Game-dev connectors - Godot/Unity/Unreal via mcp-game-engines; Godot
.tscnscenes are text → first-class semantic diffs inlifeos-vcsfor free.
This README is the narrative superset. The deep, authoritative specification lives in docs/:
data model, every module, the owned-integration model, lifeos-vcs, media intelligence, self-extension, the harness loop, platform systems, the Rust component inventory, the security model, the phased build plan, and the licensing/reuse audit.
Status: implemented and tested through issue #140 - 9 Rust crates, a React SPA, a Cloudflare Worker, 19 migrations, roughly 1000 passing tests. See CLAUDE.md for working rules, docs/ for the full spec (each section annotated with what's actually built), and §10 / docs/BUILD-PLAN.md for the phased build.