ChooseEnterOpenEscBack

DELAMAIN

A personal AI operating system whose backend owns the entire agent loop — state, tools, routing, and streaming stay coherent across reconnects, restarts, and provider failures.

LivePython · TypeScript · SwiftFastAPI · Next.js · React 19 · LiteLLM · SQLite (WAL)

Solo — designed, built, and operated end-to-end. In production on my own infrastructure since spring 2026; open-sourced (MIT) June 2026.

The problem

Most "AI assistants" are a browser talking directly to a model API. That architecture quietly owns nothing: drop the connection mid-run, refresh the tab, or restart the server, and the run is lost or corrupted. The moment an agent can also read files, patch code, run shell commands, and touch your email, that fragility stops being an inconvenience and becomes a liability.

DELAMAIN’s design bet is that the backend must be the single source of truth for the entire agent loop. That one decision forces the hard problems into one place: streaming has to be replayable, tool execution has to be deterministic and gated, model access has to degrade gracefully across providers, and a decade of private notes has to be usable as context without ever leaking into a prompt by accident.

The thread through all of it is cross-system correctness — policy, orchestration, and state that stay coherent across reconnects, restarts, provider failures, and privacy boundaries.

Technical approach

A user message becomes a run. The HTTP request persists the message, queues the run, and returns immediately; RunManager executes it under a per-conversation lock, streaming every event through a bus that writes to SQLite before fan-out. Clients consume Server-Sent Events with Last-Event-ID replay — reconnection is gap-free by construction, not by luck. On restart, orphaned runs are marked interrupted and queued work resumes.

The model boundary is deliberately paranoid: LiteLLM calls run in a spawned child process with a hard timeout, isolating provider-SDK side effects from the server. A route maps to an ordered, deduplicated fallback chain (requested → high-volume → cheap → paid), with per-attempt cost accounting and a monthly premium-request budget that blocks routes rather than silently overspending.

Tools are a typed, deterministic registry — 31 tools with per-tool risk levels and persisted approval gating. File patches are sha256-guarded with automatic backups; shell is structured-argv only; Gmail and Calendar mutations are two-phase (the model stages, the human approves). A self-config group lets DELAMAIN reconfigure DELAMAIN through a strict settings whitelist.

The Obsidian vault is a context source, not an auto-context dump. Sensitivity is decided from a bounded frontmatter pre-scan before any note body is read; private notes are never indexed, summarized, or embedded; the Sensitive root cannot be unlocked by any model tool — only per-conversation, by the human. Semantic memory is local-only (sqlite-vec + FTS5 with Ollama embeddings) and degrades to lexical search if unavailable.

Around the core: an /ops control plane (projects, schedules, briefings, Discord), worker orchestration that runs CLI coding agents as tmux sessions across three machines, and a separable health module fed by a native iOS HealthKit companion.

Architecture — the module map

  • Client shell

    Next.js / React 19 shell — sidebar, docked conversation, command palette. Owns no state: it replays runs from the backend by event cursor and reconnects without losing a token.

    talks to API surface

  • API surface

    One FastAPI app, ~30 routers under /api — conversations, runs, streams, vault, ops, workers, integrations, settings, health. Cloudflare Access JWT gating in production.

    talks to Agent loop · /ops control plane · Worker orchestration · SQLite spine · Security + privacy

  • Agent loop

    RunManager — the core. Owns runs, turns, tool iterations, approval gating, cancellation, and restart recovery. Runs in a conversation execute serially under a per-conversation lock.

    talks to Tool registry · Model client · Routing + budget · Event bus + SSE · SQLite spine · Context builder

  • Context builder

    Assembles each run’s context — system context, continuity, pinned notes, explicit selections — privacy-filtered against the vault graph before any note body is read.

    talks to Vault index · SQLite spine

  • Model client

    The LiteLLM boundary, run in a spawned child process with a hard timeout so provider-SDK side effects never touch the server. Normalizes every provider to one stable result shape.

    talks to Routing + budget

  • Routing + budget

    Route strings map to API families and a deduplicated fallback chain (requested → high-volume → cheap → paid). Monthly premium-request budgets block routes instead of silently overspending.

    talks to SQLite spine

  • Tool registry

    31 typed tools with per-tool risk levels and persisted human-approval gating — file reads/patches (sha256-guarded), structured-argv shell, vault search, propose-only mail/calendar, self-config.

    talks to Vault index · Integrations · Security + privacy

  • Event bus + SSE

    Persist-before-fanout pub/sub. Every event is written to SQLite before any subscriber sees it; streams replay from Last-Event-ID, so a reconnecting client loses nothing and duplicates nothing.

    talks to SQLite spine · Client shell

  • SQLite spine

    aiosqlite in WAL mode — one locked write connection, one read connection, 36 ordered migrations. The single source of truth for every subsystem.

  • Vault index

    Obsidian vault as a policy-bounded context source: structural graph index, local-only embeddings (sqlite-vec + FTS5, Ollama), LLM memory capsules. Private notes are never indexed; Sensitive unlocks only per-conversation, by the human.

    talks to SQLite spine

  • /ops control plane

    Projects, phases, gates, scheduled tasks, daily briefings, Discord notifications, self-maintenance. Read-mostly and policy-bound — no raw shell or secrets exposed.

    talks to SQLite spine · Worker orchestration · Integrations

  • Worker orchestration

    CLI coding agents (codex / claude / opencode / gemini) as socket-isolated tmux sessions across three hosts, with startup reconciliation and a v2 workflow engine of phases, gates, and evaluators.

    talks to SQLite spine

  • Integrations

    Gmail, Calendar, iCloud CalDAV. Reads return bounded snippets; every mutation is two-phase — the model can only stage operations the operator explicitly approves.

    talks to SQLite spine

  • Security + privacy

    Path policy confining all file access to one root, structural vault privacy, Cloudflare Access auth, log/error redaction, and a Fernet-encrypted secret store that returns references, never values.

    talks to Vault index

  • Health module

    Separable health/fitness workspace — HealthKit ingest via a native iOS companion, workout and nutrition history, an evidence-backed coaching engine. Talks to the core only through the tool registry.

    talks to Tool registry · API surface

Technical highlights

  • Persist-before-fanout event bus — every event is durable before any subscriber sees it; SSE replay makes mid-run reconnects exactly-once.
  • Model calls execute in a spawned child process with a hard timeout; a boot guard refuses known-bad LiteLLM versions.
  • Deduplicated multi-provider fallback chain with per-attempt cost rows — one exhausted provider degrades a run instead of breaking it.
  • Structurally-enforced vault privacy: frontmatter is never sent to a model to classify, the graph loader re-applies path policy node-by-node, and every Sensitive access (allowed or denied) is audited.
  • Cross-machine, cross-CLI worker orchestration — four coding-agent CLIs, three hosts, socket-isolated tmux, startup reconciliation, and a v2 workflow engine with gates and evaluators.
  • Two-phase mutating integrations everywhere: nothing sends, creates, or deletes without explicit human approval.
  • 36 ordered database migrations; ~30 API routers; runs with zero providers configured via a deterministic stub client.

Media

Sanitized screen recordings of the live instance are in preparation. The live deployment at term.danielju.com is gated (it operates on private data); the repository is fully public and runnable.

What I learned

Server-authoritative state is a discipline, not a feature — every subsystem (streaming, tools, budget, privacy) got simpler once the backend was the only writer of truth.

Privacy that holds is structural. Conventions leak; invariants enforced at the loader and pre-scan level do not.

Building for one operator is a superpower: the system can be opinionated, auditable, and honest about scope instead of diluted for multi-tenancy.

Current status / future work

  • Workflows v2 live cross-CLI execution (currently gated behind a flag).
  • An "Atlas" spatial graph view over the vault index.
  • Deploying the health/fitness workspace to the production host.

Why it matters here

For ML/AI and systems audiences: this is production agent infrastructure — the unglamorous correctness work (replayable streams, deterministic tools, budget-aware routing, structural privacy) that separates an agent platform from a demo.

danielju.com

Daniel Ju

I build and operate ML research pipelines, agent infrastructure, and the self-hosted platform behind this site.

RésuméLegal & technical · PDF

Los Angeles, CA · open to relocation

The full site is a 3D menu built for a desktop window, with a keyboard and a pointer. Open danielju.com on a laptop or desktop to walk it.