quick/start

The shortest path to a working Lash turn: add the crate, configure a provider, build a core, open a session, run one turn, and read the settled assistant message.

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.

provider key

The example uses OpenRouter through the OpenAI-compatible provider. Substitute any provider crate and model id your host already uses.

state

The first run uses in-memory runtime facets. Add Persistence when the same session id must survive process restart.

next features

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.

live streaming

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.

host tools

Implement ToolProvider, hand it to .tools(Arc::new(MyTools)) on the builder. See the Tools guide.

persistence

Pass a SessionStoreFactory to .store_factory(...) so sessions survive process restarts. See the Persistence guide.

tracing

Attach a TraceSink via .trace_sink(Arc::new(sink)) for JSONL traces of every turn. See the Tracing guide.

rlm core

Use LashCore::rlm_builder(factory) for Lashlang-driven agentic turns with structured finish / AgentFrame switch semantics. See the RLM protocol guide.

mcp servers

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.

builder error

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.

provider error

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.

no persistence

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.

read on ·