Rapid iteration · APIs and docs may change
Liri Liri Build Log
Back to home
EN
BUILD LOG

A road that is still being built

From v0.1 to v0.5.22 — 156 days, 116 releases. This is not a feature list; it is the mistakes we made, the rules we earned, and the blanks we have not filled yet.

156 days
since first release
116
releases
9
architecture snapshots
20+
architecture checks

Data snapshot 2026-11-01 · numbers collected from the Liri repo by sync-facts and health:arch

Jump to the timeline

Origin

On 25 May 2026, Liri shipped v0.1: 100 commits and a terminal AI assistant that could actually run.

The problem was concrete — let the model sit in the terminal, read files, run commands and edit code, instead of chatting in a web input box. Local models first, because private files should not have to leave the machine; security by design, because the assistant is handed a real computer, not just an API.

Over the next three months, capability was added layer by layer: tools, 27 messaging channels, a desktop client, voice, a knowledge base. By August the repository held more than 4,000 files.

That is also when the problem was named out loud. The 18 June 2026 code review found LocalHTTPService at 7,200 lines and ChatManager at 3,263, with 150 test files against 3,742 source files. Two months later the first architecture health score came back: 10/40, grade D, with 105 oversized files, none of them registered.

The lesson: whether a project can be handed to someone else is decided not by how many features it has, but by the rules it grows after it hits a wall.

Five turning points

Ordered by cause, not by calendar — some periods overlap.

2026-05-25 → 2026-08

Ship capability first, boundaries later

Situation
v0.1 had 100 commits; shipping beat structure.
Decision
Fill in capability first: tools, channels, desktop, voice, knowledge — one at a time.
Cost
The first audit was ugly: LocalHTTPService at 7,200 lines, ChatManager at 3,263, a test-to-source ratio around 4%, and a first health score of 10/40 (D) with 105 unregistered oversized files.
Result
4,000+ files, 69 tools, 27 channels, 429 desktop components.

↳ Ways in — Adding capability? Start a module under app/src, not inside the kernel.

2026-08-09 → 2026-09-30

Learn to measure ourselves

Situation
Everyone could feel the problem; nobody could say how bad it was.
Decision
Turn architecture quality into a repeatable score with a register, and require every oversized file to be registered — giving up the assumption that cleanliness survives on discipline alone.
Cost
Registering is not splitting: ChatManager grew from 3,263 to 7,036 lines (it has since been split down to 2,570). The scoring itself kept changing, so it is a health check, not a KPI.
Result
Nine snapshots; unregistered oversized files went from 105 to 0 (later back to 2); the list became a traceable register.

↳ Ways in — Claim one oversized file to split (see Ways to help below).

2026-10-08 → 10-09

One bad delete bought us a deletion process

Situation
The codebase had accumulated a layer of apparently unused "dead surfaces". The v0.4.69 cleanup treated the sandbox and isolation subsystem as dead code: 170 files touched, +9,340 / −10,174 lines.
Decision
The next day, v0.4.71 rolled the whole thing back — 24 files restored (IsolationManager, EnhancedSandboxManager, PTYSandbox, SSHSandbox, docker/** and more, plus 5 test suites) and 21 live files reverted to match.
Cost
Deleting now takes longer: you write evidence first. Still cheaper than a rollback.
Result
v0.4.72 turned deletion into a process, code-deletion.md (CD01–CD07): collect evidence, detach entry points, then delete. "Nobody seems to use it" stopped being a reason.

↳ Ways in — Review one "dead code candidate" against CD01–CD07.

2026-10-10 → 10-22

Turn rules into gates

Situation
Rules lived in documents and relied on discipline; documents and code began to drift.
Decision
Every rule became a CI blocker rather than advice: five gates plus doc-gate and a required sandbox-negative job; 413 hardcoding baseline keys; a 34-value state vocabulary with 1,795 baseline pairs; startup-surface, critical-module and kernel-surface gates.
Cost
A few seconds per commit, and baselines must be regenerated with every vocabulary change — the point is that definitions can no longer drift silently.
Result
lint:arch violations at 0; tests grew from 3,029 to 7,488.

↳ Ways in — Run the local gates (bun run ci) before you push — fix whatever goes red.

2026-10-05 → 10-28

Shrink the kernel: from 5,336 lines to its own package

Situation
The core was both the entry implementation and everyone’s shared backyard — anyone could add to it.
Decision
Three steps: shrink (CoreAPIImpl 5,336 → 2,521 lines), extract (@openliri/kernel as its own package; core from 146 to 113 files with kernel gates K01–K08), then evict (37 modules failing the "zero I/O / zero upward dependency" rule moved into app/src, 470+ imports updated, five baseline families regenerated).
Cost
One large migration and full baseline regeneration; since 18 Oct work lands in batches and commit density is deliberately lower.
Result
The kernel now exposes a thin interface; external contributions finally have a boundary.

↳ Ways in — New capabilities live outside the kernel boundary and start in app/src.

Architecture: layered like an operating system

The architecture was not invented from scratch. A thin kernel, subsystem boundaries, one-way dependency direction, gates and observability come from decades of operating-system practice; the design-pattern and engineering guides published for agents over the last two years converge on the same questions — layering, boundaries, state, governance, evaluation. We constrain ourselves the first way and audit ourselves against the second.

OS concept → where Liri stands

Concept In Liri Status
Kernel @openliri/kernel as its own package with a thin public interface, guarded by K01–K08 Shipped
Subsystems Tools / channels / memory / routing / sandbox / tasks / voice / desktop — each with its own entry points and boundaries Converging
Drivers Provider adapters, channel adapters and 6 sandbox backends (Landlock / Docker / SSH / PTY / macOS / Windows) Shipped
Processes & scheduling Session execution, PDCA, Swarm, Cron Shipped
Permission model Five defense layers plus four approval stages (requested → presented → decided → recorded) Pending audit
Observability & audit Event log, cost ledger, evidence ledger Shipped
Maintainers Not established yet: no subsystem owners and no hand-over path Missing

What we compared against

We benchmarked ourselves item by item against publicly available agent design patterns and engineering guides: all 21 patterns have real implementations, but 3 of the key switches default to off — so we only claim "implemented", never "on by default". The engineering loop is audited the same way: architecture, build, run, govern, optimize.

Three blanks

Subsystem maintainers

Without owners there is no hand-over path. This is the most OS-like piece, and the one we lack.

Subsystem contracts

The contract design exists, but whether the ledger / LoopProfile landed is unverified — interface stability is not yet pinned down.

Coverage gate

About 4% at review time; CI runs 20+ architecture checks, but there is no coverage threshold yet.

To be honest: the architecture health score is still D (10/40); of 142 oversized files, 141 are still unregistered; the largest is still in chat (ChatManager has been split from 7,036 down to 2,570 lines). The kernel exists, boundaries are converging, maintainers do not exist yet — that is what "not finished" means.

Expand the current 8 functional layers

Architecture at a glance

8 functional layers from entry point to feedback; enforced in engineering by 6 dependency gates (entry > ui > app > service > infra > core)

L1

Multimodal entry layer

REPL terminal
A terminal UI built with React + Ink, with the Buddy companion system built in
Tauri desktop client
429 TSX components across 32 feature pages (Tauri 2.11 + React 19)
MCP / channel gateway
MCP Server plus 27 messaging channels (WeChat, DingTalk, Feishu, Telegram and more)
CLI / HTTP API
Three executables — Liri / liri-memory / liri-ink — plus an HTTP API
L2

Security first layer

Compile-time Rust AST analysis
The FFI layer parses the Bash AST against 37 dangerous-command rules
TypeScript semantic analysis
Compound read-only commands are judged segment by segment, with attributable rejection reasons
Guardrail rule engine
14 injection patterns + 10 shell-specific rules
AutoMode classifier
Scores task risk automatically and decides between allow, ask and deny
L3

Smart routing layer

19 task types detected
coding, writing, analysis, tools, translation, search, ideation, small talk and more
4 tiers
simple / medium / complex / reasoning
5-stage decision pipeline
switch → fast path → session stickiness → LLM judgment → tier resolution
FallbackChain
Ordered failover when the primary provider is unavailable, paired with RetryPolicy
L4

Second-brain injection layer

Knowledge base
Markdown on disk plus semantic indexing, with keyword / vector / RRF hybrid retrieval
Memory system
Tiered memory with a SQLite vector table and relevance-weighted recall
Session events
Append-only events.jsonl — replayable and auditable
DreamEngine
Consolidates knowledge while idle: collect → analyze → generate → write → index
L5

TAOR decision loop

Think
4 agent strategies: general / coding / exploration / planning
Act
69 built-in tools, registered dynamically per build variant
Observe
Result evaluation plus layered context windows and automatic compaction
Reason
Token budget management + checkpoint resume + per-round circuit breaking
L6

Execution sandbox layer

Linux Landlock
Kernel-level filesystem access restrictions
macOS / Windows
System sandboxes with Low IL / Job object as a fallback
Docker container
Full container isolation with resource limits and network policies
SSH / PTY
Clean remote execution environments and controlled pseudo-terminal paths
L7

Long-running task layer

PDCA pipeline
A Plan-Do-Check-Act loop that advances progress based on real artifacts
Swarm multi-agent
AgentSwarm with council-style orchestration and dynamic registry discovery
Cron scheduling
once / interval / cron expressions, time zones included
Task persistence
Session snapshots, breakpoint recovery and visible countdowns while waiting
L8

Feedback and evolution layer

Failure-pattern induction
Failure patterns are generalized back into prompts and skills, closing the improvement loop
Cost ledger
Billed against the database pricing table, recording the real model name echoed by the provider
Evaluation gates
Built-in baseline suites, pass^k reliability scoring and paired safety measurement
Event replay
The context of every model call can be reconstructed after the fact

Architecture philosophy

🛡️
Security built in
Security is not a plugin — it is the DNA of every layer
🏠
Local-first
Data stays local, works offline, privacy protected by default
🧠
Smart routing
19 task classes mapped to the right model tier
🧬
Second brain
Knowledge base, memory and event logs: three retrievable context layers
🔄
Verifiable loop
Lessons from failures feed back in, and gates block regressions
🔌
Unified multimodal
Terminal, desktop, IM and API all share one engine

Timeline

One entry per month — architecture and governance only, no routine commits.

  1. 2026-05-25 v0.1: 100 commits, the terminal assistant runs
  2. 2026-06-18 First code review: a 7,200-line monolith, ~4% test-to-source ratio
  3. 2026-08-09 First health score: 10/40 (D), 105 oversized files unregistered
  4. 2026-10-09 Sandbox deleted by a cleanup → full rollback; deletion process CD01–CD07 the next day
  5. 2026-10-20 State vocabulary gate ships: 34 values, 1,795 baseline pairs
  6. 2026-10-28 Kernel eviction lands; model-visible tools capped at 12 / 1,397 tokens
  7. 2026-10-28 Bilingual documentation site and this page go live

Monthly entries will be appended here.

Ways to help

This page is not a wrap-up report, it is an invitation. Three gaps, all of them need hands.

Security audit checklist

  • Dangerous-command rules: 37 rules — where they live, how they fire; build one case and check it hits the expected rule
  • Prompt-injection rules: 14 rules — feed a malicious document and see whether it is stopped
  • Shell rules: 10 allow / deny entries — try bypass paths (pipes, subshells, encoding)
  • Sandbox degradation: when each of the 6 backends degrades, and whether it fails closed
  • Approval stages: requested → presented → decided → recorded — look for missing or out-of-order stages
  • Privilege surface: can a tool call bypass the permission classifier and write or execute directly?

Entry points: app/src/security, app/src/sandbox, app/src/permission.

Report vulnerability details privately via SECURITY.md — do not open a public issue. Public issues are for audit process and coverage only.

Prefer to fund it? See the sponsor page