What This Builds
A minimal embedded-agent program. It uses the app-facing lash-runtime facade, one provider handle, the default standard mode, and in-memory runtime facets.
lash-runtime is published under that crate name because lash is owned by another project on crates.io. The Rust library import is still use lash::....
Before You Start
This page keeps the host deliberately small: one provider, one core, one session, one collected turn.
The example uses OpenRouter through the OpenAI-compatible provider. Substitute any provider crate and model id your host already uses.
The first run uses in-memory runtime facets. Add Persistence when the same session id must survive process restart.
Streaming, RLM, tools, background work, and traces are linked after the minimal example instead of being mixed into it.
Add The Crates
Pin the alpha pre-release explicitly and add the provider crate you actually use.
[dependencies]
lash-runtime = "=0.1.0-alpha.84"
lash-provider-openai = "=0.1.0-alpha.84"
anyhow = "1"
tokio = { version = "1", features = ["full"] }
For ordinary projects the facade and provider crates are enough. Drop down to lash-core only for custom runtime hosts, explicit process registries, store implementations, or diagnostics that need internal state.
Minimal Example
Build one core, open one session, run one turn, print the committed assistant prose.
This example uses an OpenAI-compatible provider through OpenRouter. Substitute the provider crate, base URL, model id, and API key for your deployment.
use std::sync::Arc;
use lash::{LashCore, TurnInput, provider::ProviderHandle};
use lash_provider_openai::{OPENROUTER_BASE_URL, OpenAiCompatibleProvider};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// build a provider handle. substitute your own creds + base URL.
let api_key = std::env::var("OPENROUTER_API_KEY")?;
let provider = ProviderHandle::new(
OpenAiCompatibleProvider::new(api_key, OPENROUTER_BASE_URL).into_components(),
);
// one LashCore per app, cloned freely.
let core = lash::LashCore::standard_builder()
.provider(provider)
.model(
lash::ModelSpec::from_token_limits("anthropic/claude-sonnet-4.6", None, 200_000, None)
.expect("valid model metadata"),
)
.effect_host(Arc::new(lash::durability::InlineEffectHost::default()))
.attachment_store(Arc::new(lash::persistence::InMemoryAttachmentStore::new()))
.build()?;
// one session per chat / task.
let session = core.session("hello-1").open().await?;
// run one turn; read settled prose from the terminal result.
let result = session
.turn(TurnInput::text("Say hi in one short sentence."))
.run()
.await?;
let prose = result.assistant_message().unwrap_or_default();
println!("{prose}");
Ok(())
}
Common Tasks
The quickstart intentionally leaves most host features out. Add them one at a time.
Use TurnBuilder::stream_to(&sink) instead of run() to emit TurnActivity items as the model produces them. The Lash API · turns guide covers the full event taxonomy.
Implement ToolProvider, hand it to .tools(Arc::new(MyTools)) on the builder. See the Tools guide.
Pass a SessionStoreFactory to .store_factory(...) so sessions survive process restarts. See the Persistence guide.
Attach a TraceSink via .trace_sink(Arc::new(sink)) for JSONL traces of every turn. See the Tracing guide.
Use LashCore::rlm_builder(factory) for Lashlang-driven agentic turns with structured finish / AgentFrame switch semantics. See the RLM protocol guide.
Wire up MCP via McpPluginFactory::new(servers).await? and pass it to .plugin(...). See MCP Servers in the Lash API guide.
Failure Modes
Most first-run failures are missing host facets, provider configuration, or context/model metadata.
build() requires explicit effect, Lashlang artifact, and attachment stores. Use in-memory facets for local tests; use file/SQLite stores when sessions must survive restarts.
Check API key, base URL, model id, and token limits. Provider failures surface as turn errors or TurnStop::ProviderError depending on where the failure occurs.
Without .store_factory(...) or a per-session .store(...), the session is in-process only. A restart starts from empty state for that id.
Where Next
Choose the next page by the job you are adding to this minimal host.