Architecture chapter 02

modules/crates

The workspace is split by responsibility: pure protocol, async runtime, mode drivers, provider transports, plugin/tool surfaces, host UI, trace/export utilities, and benchmark runners.

Crate Families

These are the high-value ownership groups to inspect before changing behavior.

Pure protocol

lash-sansio

Owns TurnMachine, Effect, Response, ModePreamble, prompt templates, messages, attachments, the TurnOutcome::{Finished, Handoff, Stopped} contract, and tool definitions/output contracts. Top-level files cover turn, mode, prompt, plugin, attachment, session, and tool surfaces; the sansio/, session_model/, and llm/ subdirectories hold the state machine, durable model, and provider request types.

lash-sansio/src/{turn,mode,prompt,plugin,tool_surface,session,attachment}.rs, sansio/, session_model/, llm/
Async runtime

lash-core

Owns LashRuntime, Session, SessionGraph, and the RuntimePersistence contract, plus tool dispatch, provider registry, OAuth, attachments, tracing, runtime controls, the built-in tool-output budgeting plugin, and handoff-following turn execution. No knowledge of MCP, user config files, or any host concerns — those live in higher layers.

lash-core/src/runtime/*, lash-core/src/session.rs, lash-core/src/store.rs, lash-core/src/plugin/*
Facade

lash

App-facing API on top of lash-core. Provides LashCore, LashCoreBuilder, LashSession, SessionBuilder, TurnBuilder, mode presets, and typed-plugin binding helpers. Host applications use this crate (not lash-core directly) for runtime construction, chat/task sessions, persistence wiring, and semantic turn streaming.

lash/src/lib.rs, lash/src/core.rs, lash/src/session.rs, examples/*
CLI runtime + config

lash-cli

Hosts the lash binary plus a [lib] half that owns LashConfig, provider spec parsing, and credential bootstrap. Bench runners and lash-harness-opt consume the lib half to share the same config loader. The bin handles resume/fork, --print, interactive TUI flows, and assembles the plugin factory chain (providers, MCP, mode presets) before constructing LashCore.

lash-cli/src/config.rs, lash-cli/src/bootstrap.rs, lash-cli/src/main.rs, lash-cli/src/interactive
Mode plugins

standard + rlm

Standard drives native provider tool calls. RLM extracts lashlang code fences, runs persistent REPL state with read-only host bindings projected into scope (history and any host-supplied globals), masks fence streaming, owns the continue_as handoff control tool, and records the RLM trajectory.

lash-mode-standard, lash-mode-rlm, lashlang, lash-rlm-types
Provider plugins

OpenAI, Codex, Anthropic, Google

Each provider implements state, auth, readiness, transport, and model policy components behind ProviderHandle.

lash-provider-*, lash-providers-builtin
Tool plugins

default tools + subagents + LLM helpers + MCP + tool-output budgeting

Default tools, subagents, llm_query, monitors, plan mode, prompt context, observational memory, rolling-history compaction, UI activity, tool discovery, MCP servers (via lash-plugin-mcp, rmcp-based, Stdio + Streamable HTTP + SSE), and the built-in tool-output budgeter all register through plugin factories. Discovery remains split across catalog projection, provider execution, lexical/BM25 ranking, LLM rerank, and schema indexing.

lash-standard-plugins, lash-subagents, lash-llm-tools, lash-plugin-*, lash-core/src/plugin/tool_result_projection_builtin.rs
Persistence

lash-sqlite-store

The concrete SQLite implementation persists session heads, graph nodes, blobs, checkpoints, usage ledgers, tombstones, and vacuum metadata behind the runtime store contract.

lash-sqlite-store/src/lib.rs
Host UI

CLI, TUI, UI surfaces

The CLI bootstraps runtime, plugins, and providers, then renders the authoritative SessionReadView through ChronologicalProjection into UiTimeline.

lash-cli, lash-tui-extensions, lash-tui
Inspection tools

trace + export + file index

lash-trace defines standard and extended JSONL trace records. lash-export walks a tree of sessions joined by continue_as handoffs and spawn_agent subagents, combining store state with provider traces to render chronological sessions, prompt snapshots, and token usage as a single HTML doc. lash-trace-viewer is a standalone tool that renders JSONL traces into a self-contained HTML browser. lash-file-index powers async fuzzy file completion.

lash-trace, lash-trace-viewer, lash-export, lash-file-index
Experimentation

benchmarks + harness optimization + autoresearch

Benchmark runners use Lash as an evaluated agent and follow handoff continuations between turns. lash-harness-opt owns generic optimization primitives (Candidate, HarnessProject, HarnessOptimizer, SqliteHarnessStore), the strategies::gepa reflective strategy, and a clbench project binding. Autoresearch adds off research tools and a UI extension.

bench/*/runner, lash-harness-opt, lash-autoresearch

Module Dependency Direction

Provider crates depend on runtime contracts; mode and plugin crates register behavior; the CLI composes the concrete app.

Crate families
flowchart TD CLI["lash-cli
bin + lib (LashConfig)"] --> Facade["lash (facade)"] CLI --> Core["lash-core (runtime)"] Examples["examples / agent-service"] --> Facade Bench["bench runners
clbench, longcot, longmemeval-rlm, swebench"] --> Facade Bench --> Core Bench --> CLI HarnessOpt["lash-harness-opt
Candidate, GEPA, SqliteHarnessStore"] --> Facade HarnessOpt --> Core Bench --> HarnessOpt CLI --> Tui["lash-tui-extensions / lash-tui"] CLI --> Builtins["lash-providers-builtin"] CLI --> Mcp["lash-plugin-mcp"] Facade --> Core Core --> Sansio["lash-sansio"] Core --> Lang["lashlang"] Core --> Store["lash-sqlite-store"] Core --> RlmTypes["lash-rlm-types"] Modes["lash-mode-standard
lash-mode-rlm"] --> Core Modes --> Sansio Modes --> RlmTypes Plugins["lash-plugin-*
lash-llm-tools
lash-standard-plugins"] --> Core Mcp --> Core Subagents["lash-subagents"] --> Core Subagents --> RlmTypes Autoresearch["lash-autoresearch"] --> Facade Autoresearch --> Core Providers["lash-provider-*"] --> Core Builtins --> Providers Export["lash-export"] --> Core Export --> TraceCore Export --> RlmTypes TraceViewer["lash-trace-viewer"] --> TraceCore["lash-trace"] Core --> TraceCore FileIndex["lash-file-index"] --> CLI