lash
A Rust runtime for durable LLM agents.
Most agent stacks treat the LLM as the runtime and stitch state around it — a database for memory, a queue for retries, a sandbox for code. lash inverts that. The runtime is the durable end of the pair; the LLM is the variable call. Your app owns the outer boundaries — storage, auth, transport, product state. lash owns the turn — model calls, modes, tools, plugins, semantic stream events, usage, and terminal outcomes.
Docs: https://lash.run/ — quickstart, embedding guide, plugins, persistence, durable-workflow integration, and architecture chapters.
Alpha: works today, API still moving fast — pin to an exact
=0.1.0-alpha.Nversion when you embed.
What's inside
- Durable per-turn commits — every completed turn lands as one atomic
RuntimeCommitagainst aSessionGraph. Effects are the replay boundary; turns are the semantic commit boundary. → persistence - Workflow-host integration — a sans-IO turn machine behind one
EffectHostboundary. The defaultInlineEffectHostruns in-process; the first-party Restate adapter replays effects from host history and retries the final idempotent commit. → durability - Two execution modes, one commit unit —
standarduses native provider tool-calling with concurrent dispatch;rlmrunslashlangprograms in a sandboxed VM where every effect crosses the host. → RLM - Plugin architecture — tools, prompts, planning, memory, subagents, history transforms, UI activity, and tool-output budgeting are all plugins; the execution mode is a plugin too. Hosts compose only what they embed. → plugins
- Provider portability — Anthropic, OpenAI Responses, any OpenAI-compatible Chat Completions endpoint, OpenAI Codex, and Google Gemini / Code Assist. MCP servers attach through
lash-plugin-mcp. → providers - Tracing as a first-class sink — attach a
TraceSinkfor structured turn, tool, LLM, prompt, and usage records. Bundled JSONL sink + self-contained HTML viewer; optional OpenTelemetry export. → tracing
Embed it
lash ships on crates.io as lash-runtime (the bare name is taken), but is still imported as lash. During the alpha the dep needs the explicit pre-release tag:
[]
= "=0.1.0-alpha.50"
= "=0.1.0-alpha.50"
= "1"
= { = "1", = ["full"] }
use Arc;
use ;
use ;
async
Full walkthrough in the quickstart; the complete facade API — session specs, plugin stacks, turn streaming, persistence, subagents, MCP, durable workflows — is in the embedding guide. To wrap Lash behind a service boundary (HTTP, queues, workflow handlers), use the canonical DTOs from lash::remote — see remote protocol.
Examples
Two runnable apps under examples/ drive the facade end-to-end — full hosts with a browser UI, real persistence, and optional durable execution. The docs walk through both at https://lash.run/examples.html.
# SQLite-backed chat app: RLM, app-owned tools, streaming, optional Restate turns
OPENROUTER_API_KEY=sk-or-...
# Adds durable background work: Lashlang processes, subagents, cron triggers (Restate required)
OPENROUTER_API_KEY=sk-or-...
See each example's README for environment knobs and Restate recipes.
The CLI
lash-cli is a first-party terminal frontend on top of the library — patch-based editing, shell execution, file/web search, planning, subagents, session resume, live token accounting. Not the product, but a fully featured way to drive the runtime and a useful end-to-end reference.

|
# or: cargo build -p lash-cli --release
CLI reference: https://lash.run/cli.html.
Contributing
Feature requests and bug reports welcome — open an issue. At this alpha stage detailed write-ups (what you tried, expected, and saw) help more than drive-by PRs — see CONTRIBUTING.md.
License
MIT