How Lisa is put together.
Distilled from docs/PLAN.md §4–§5. The shape in one sentence: shell surfaces and apps talk through a portal trust boundary to a small set of single-purpose daemons, everything is recorded in an append-only Ledger, and the daemons that hold your data have no network access.
The daemons
| Daemon | Role | Spec |
|---|---|---|
lisa-inferenced | Model runtime & scheduler — the one process that owns compute. Supervises engine children (llama.cpp et al.), arbitrates RAM/VRAM, QoS scheduling (interactive preempts background), guided generation (JSON Schema → GBNF grammar). Exposes D-Bus dev.lisaos.Inference1 and OpenAI-compatible HTTP on 127.0.0.1:7777. | PLAN §5.1 |
lisa-modeld | Model catalog & store — blake3 content-addressed store, pinned-hash downloads, hardware profiler. The only component allowed network access for model traffic. | PLAN §5.2 |
lisa-contextd | Context fabric — the personal context index (SQLite FTS5 + vectors) with provenance tags and per-chunk ACLs, plus namespace-isolated per-app durable memory. D-Bus dev.lisaos.Context1. | PLAN §5.3 |
lisa-agentd | Agent Bus — apps are MCP servers; the bus holds the tool registry, enforces confirmation tiers (read → silent, write → chip, destructive → modal) at the bus, keeps the undo journal. D-Bus dev.lisaos.Agent1. | PLAN §5.4, ADR-0009 |
lisa-remoted | Egress broker — the single ledgered path to BYO remote model providers, with per-scope offload consent (default: nothing leaves). D-Bus dev.lisaos.Remote1. | ADR-0010, PLAN §5.11 |
The portal boundary
xdg-desktop-portal-lisa (PLAN §5.5, ADR-0008) is the trust boundary: sandboxed apps never talk to daemons directly. The portal attaches per-app identity, runs first-use consent (fail-closed), enforces quotas, and writes Ledger attribution. Interfaces: dev.lisaos.portal.{Inference, Context, Memory, Agent}.
dev.lisaos.Inference1. The shell consent dialog and Settings surface are still open (M2/M4 work; see docs/STATUS.md).The Ledger
An append-only SQLite audit log (libs/lisa-ledger) where UPDATE and DELETE are aborted by triggers. It is enforced, not advisory — dataflow rule 4: the ledger entry precedes the action; no ledger entry, no inference. Append failure returns 503, and the inference daemon refuses to start without a ledger. Context searches, tool calls, and remote egress are ledgered the same way. Read it with lisa ledger or the first-party Ledger app.
Egress rules
Egress is architecture, not policy (PLAN §5.10):
lisa-inferenced,lisa-contextd, andlisa-agentdrun with no network access (systemd sandboxing; verified zero egress in CI).- Only
lisa-modeldgets network for model downloads, and onlylisa-remotedbrokers traffic to remote providers — every remote request is ledgered with aremote.*kind and rendered in the dedicated egress color. - Per-scope offload consent (
prompt,files,mail,calendar,screen,memory) defaults to off — even prompts don't leave until you say so.
Provenance
Every context chunk carries a provenance tag (user, app:<id>, file, screen, web). Untrusted-provenance content is data, never instructions: a privileged tool call whose trigger chain includes untrusted provenance escalates one confirmation tier, fail-closed. A seeded injection suite gates merges on zero unconfirmed privileged calls.
Decisions (ADRs)
Every non-obvious decision is written down in docs/adr/:
| ADR | Title |
|---|---|
| ADR-0001 | Fork Arch Linux; ship an immutable, atomic, image-based OS via mkosi |
| ADR-0002 | Rust with zbus + axum for system daemons |
| ADR-0003 | Two-track delivery — Lisa Layer first, immutable image as the product |
| ADR-0004 | Flutter app lane + the Forge — superseded in part by ADR-0047 |
| ADR-0005 | License the project GPL-2.0-only |
| ADR-0006 | Monorepo with staged extraction |
| ADR-0007 | fcitx5-lisa is a C++ addon (thin), logic stays on the daemon side |
| ADR-0008 | The Lisa portal is a standalone session service, consent stays in the shell |
| ADR-0009 | Agent Bus core — D-Bus surface, tier enforcement at the bus, staged MCP transport |
| ADR-0010 | BYO remote model providers via a dedicated egress broker (lisa-remoted) |
| ADR-0011 | Lisa Ambient — the always-on, wake-word-free assistant |
| ADR-0012 | A native "Intelligence" panel in a forked gnome-control-center |
| ADR-0013 | The Lisa harness — Siri-style intents + a Claude-Code-level coding agent, on the existing substrate |
| ADR-0014 | lisa_ui becomes the kit Lisa apps import — superseded in part by ADR-0047 |
| ADR-0015 | A persistent Assistant chat window — the surface that makes the model usable |
| ADR-0016 | Reverse-DNS identifiers move to the real domains (dev.lisaos.* / app.lisaos.*) |
| ADR-0017 | Plymouth + the lisa theme move into the mkosi-initrd |
| ADR-0018 | /var is mounted by partition LABEL, not by UUID |
| ADR-0019 | A dedicated /home partition on fresh installs, weight-split with var |
| ADR-0020 | App updates decoupled from the OS image |
| ADR-0021 | aarch64 image lane on an Arch Linux ARM base |
| ADR-0022 | A user-survivable rescue boot path |
| ADR-0023 | Slim core, /var grows — apps and heavy payloads leave the image |
| ADR-0024 | ship an out-of-tree CS8409 codec module for Apple speakers |
| ADR-0025 | One agent loop — the Lisa harness |
| ADR-0026 | The native GPU driver + its firmware ride the initrd |
| ADR-0027 | the Flutter lane on-device — aarch64 SDK, and how a forged app gets launched |
| ADR-0028 | Files reach the default initrd through `io.mkosi.initrd`, not `mkosi.initrd/` |
| ADR-0029 | Hard guardrails for agent actions — policy outside the model |
| ADR-0030 | The guardrail boundary — probabilistic inside, logical outside |
| ADR-0031 | Server mode, the two edges, and artifact publishing |
| ADR-0032 | Construct and Lisa — one contract, two levels |
| ADR-0033 | Identity comes from the transport, not the message |
| ADR-0034 | `lisa dev` — developer tooling in the user's home, rootless |
| ADR-0035 | The desktop is a prompt — a floating dock-prompt, no top bar |
| ADR-0036 | An assistant that acts on its own — triggers, trust, and what happens when nobody is watching |
| ADR-0037 | Browser — the web becomes an agent surface, not a vendored binary |
| ADR-0038 | Lisa Desktop — a hard fork of GNOME Shell |
| ADR-0039 | The split, and the package index that makes it work |
| ADR-0040 | Docs live with the code — there is no docs repo |
| ADR-0041 | Package signing and the trust chain |
| ADR-0042 | The field device runs a blank login keyring |
| ADR-0043 | The model knows the OS through retrieval, never through the prompt |
| ADR-0044 | Retrieval receipts — contextd vouches for what it returned |
| ADR-0045 | CalVer for the image, SemVer for the contracts |
| ADR-0046 | Capability before storefront: what must be true before Lisa distributes somebody else's app |
| ADR-0047 | One toolkit: GJS + GTK4/Adwaita is the default, Flutter is parked |
| ADR-0048 | Lisa Desktop is a desktop, not a patched GNOME |
| ADR-0049 | Every app is an agent surface: install is the grant, the tier is the gate, the registry is the authority |
| ADR-0050 | App tooling is CLI verbs, and the scaffold carries the traps |