Core Contracts
These abstractions define the system more precisely than crate names do.
| Abstraction | Owner | Role |
|---|---|---|
TurnMachine, Effect, Response, EffectId, TurnCheckpoint | lash-sansio | Pure turn state machine and response protocol. Checkpoints are a sans-IO primitive for machine round-trips and tests; runtime crash recovery is owned by effect hosts and committed state stores. |
EffectHost, ExecutionScope, ScopedEffectController, RuntimeEffectEnvelope, RuntimeEffectLocalExecutor | lash-core | Typed durable effect boundary for LLM calls, direct completions, individual tool calls, durable tool steps and waits, process admin, retry sleeps, RLM exec, checkpoints, and execution-surface sync. Envelopes carry a serialized RuntimeInvocation with scope, subject, optional causal parent, and replay.key; durable hosts such as Temporal, Restate, or another workflow runtime own effect replay and timers. |
TurnOutcome, TurnFinish, TurnStop | lash-sansio | Three-class turn result: Finished{AssistantMessage|FinalValue|ToolValue}, AgentFrameSwitch{frame_id, task}, Stopped{Cancelled|Incomplete|InvalidInput|MaxTurns|ToolFailure|ProviderError|PluginAbort|RuntimeError|SubmittedError{...}|ToolError{...}}. |
ProtocolBuildInput, TurnDriverPreamble, ContextProjector, ProtocolDriverHandle | lash-core + lash-sansio + protocol crates | ProtocolBuildInput carries the effective tool catalog and generic prompt/protocol context from the runtime into mode preamble builders. Protocol-specific prompt surfaces, including RLM's Lashlang host environment, are built by the protocol/runtime crates. TurnDriverPreamble, projectors, and protocol drivers stay mode-agnostic in lash-sansio. |
LashCore, SessionBuilder, LashSession, TurnBuilder | lash | App-facing facade for shared core configuration, session opening/resume, the stable host-owned session handle, and semantic turn streaming. |
Session, AgentFrameRecord, SessionGraph | lash-core | Session is the durable work identity; AgentFrameRecord is the current agent assignment/execution frame inside that session; graph nodes carry agent_frame_id so export/debug can show frame boundaries without turning them into child sessions. |
SessionRelation::{Root, Child} | lash-core | How a new session relates to its parent: top-level root, or child session with optional typed CausalRef. continue_as appends an agent frame inside the same session instead of creating a related session. |
PluginOptions, RlmCreateExtras, RlmProjectedSeedSnapshot | lash-core + lash-rlm-types | Plugin-owned session-creation payloads. RLM carries a termination policy and an optional projected-binding seed for AgentFrame switches and spawned agents. |
PluginSessionContext, SubagentSessionContext | lash-core | Per-session context handed to plugin factories, plus the marker that identifies a session as a subagent and tracks parent session id, capability, and depth. |
SessionSnapshot, RuntimeSessionState | lash-core | Public serializable session snapshots and runtime-private mutable state: graph, current frame id, frame records, policy, turn index, usage, store refs, and store head metadata. Execution snapshots are frame-owned, not one global session VM blob. |
AgentFrameRun, stream_turn_with_agent_frames | lash-core | Internal AgentFrame switch-following runtime primitive used by the lash facade. App hosts normally use TurnBuilder::stream_to, TurnBuilder::run, or pull-style TurnBuilder::stream. |
ToolContext, RuntimeSessionServices | lash-core | The runtime-session boundary is an internal capability set (RuntimeSessionServices and its capability handles). Public tool code reaches the same powers through explicit ToolContext capability methods (sessions(), processes(), direct_completions(), attachments(), durable_effects()) instead of receiving the runtime handle. |
TurnBoundary, TurnCommitDraft, TurnGraphEditor | lash-core | Turn-scoped typed graph writes, checkpoint, usage, and read-state commit policy. |
SessionGraph, SessionReadView, ChronologicalProjection | lash-core | Durable event storage, public read seam, and semantic chronological projection, all in lash-core. The CLI's UiTimeline is a render projection downstream of ChronologicalProjection. |
RuntimePersistence, RuntimeCommit, GraphCommitDelta | lash-core | Runtime persistence contract for the per-session execution lease, fenced graph/head commits, current AgentFrame metadata, pending turn input, queued work, committed checkpoints, and final turn commit idempotency. The session execution lease is the normal concurrency primitive; head CAS is the stale-writer backstop inside the same commit transaction. |
RuntimePersistence implementations | host / store crates | The store contract is database-agnostic. First-party implementations include lash-sqlite-store for local durable hosts and lash-postgres-store for shared workers; hosts can provide another database-backed implementation when it preserves the same session-lease, CAS, queue, process, trigger, artifact, and blob semantics. |
ProcessStartRequest, ProcessService::start_from_request | lash-core | Canonical process-start request path. Facade, runtime, and tool controls pass a typed request into the service helper; only the service reconstructs the internal ProcessRegistration and ProcessStartOptions. |
ProcessCancelAbility, ProcessCancelRequest, ProcessCancelAllRequest | lash-core | Host-owned intentional cancellation seam. Single-handle and cancel-all requests carry a ProcessCancelSource plus reason, and cancel-all returns ProcessCancelSummary by cancelling each visible live handle through the same ability path. |
ProviderHandle, ProviderComponents | lash-core | Runtime-only provider handle split by state, auth, readiness, transport, and model policy. Session persistence records only provider_id and rebinds it to the live handle supplied by the host. |
ToolDefinition, ToolCatalog, ToolOutputContract, ToolCallOutput, ToolCallRecord | lash-sansio | Tool catalog membership (a tool is callable iff it is a catalog member), model schema, examples, compact docs, dynamic return contracts, and canonical tool-call output records. App-facing tool implementations return lash::tools::ToolResult / lash_core::ToolResult, which core converts into this canonical output shape. |
PluginFactory, SessionPlugin, PluginRegistrar | lash-core | Plugin lifecycle and hook registration for tools, prompts, modes, runtime events, and host-callable RPCs. |
LlmToolsPluginFactory, DirectCompletionClient::direct_completion | lash-llm-tools + lash-core | llm_query tool registration, output-schema handling, direct completion, and usage relay. |
RlmControlToolsProvider | lash-protocol-rlm | Mode-provided RLM control tools such as continue_as, which produces a TurnOutcome::AgentFrameSwitch. |
LashlangHostEnvironment, ModuleArtifact, ProcessDefinitionIdentity, compile_module | lashlang + lash-lashlang-runtime + lash-protocol-rlm | The linked host surface gates resource operations, process declarations/starts, process sleep/signals, trigger registry operations, and optional language features such as @label annotations. Disabled features parse but fail during linking before runtime side effects. Hosts compile modules through the facade/runtime integration to get content-addressed artifact refs, stable introspection, and exported process definition identities. Stored Lashlang process input is an opaque ProcessInput::Engine { kind: "lashlang", payload }; the Lashlang process engine loads the artifact by module_ref before compiling the selected process_ref. |
TriggerHostOperation, TriggerRegistrationRequest, ProcessDefinitionIdentity | lashlang + lash-lashlang-runtime + lash-core | Canonical trigger register/list/cancel contract. Lashlang owns operation strings, resource operation shapes, request decoding, process-definition identity, trigger compatibility checks, alias resolution, and event/input assignability; the Lashlang runtime bridges those operations to core's durable registration storage and source-key matched trigger delivery. |
RlmProjectedBindings, ProjectionRef, ProjectionResolver, ProjectionRegistry | lash-protocol-rlm | Public RLM projection API. Inline bindings carry JSON/lashlang values; lazy bindings carry stable refs that resolve to low-level projected values immediately before execution. |
ProjectedBindings, ProjectedValue, ProjectedHostDescriptor, ProjectedReadRequest, ProjectedReadResponse | lashlang | Low-level read-only Lashlang projection protocol. ProjectedValue can carry opaque projection-ref metadata for snapshot/seed rehydration; assignment over a projected name is rejected at runtime. |
ToolResultProjector, ToolOutputBudgetPluginFactory, ToolOutputBudgetConfig | lash-plugin-tool-output-budget | Single exclusive tool-result projector (registered via reg.tool_results().projector(...)) that derives the budgeted model-facing ModelToolReturn from each completed call's full ToolCallOutput, with ToolOutputBudgetMode::{Bytes, Tokens} limits (defaults: 16 KiB, 400 lines). |
ToolDiscoveryIndex, CatalogTool, llm_rerank_request | lash-cli MCP discovery example | Host-owned search/load tool discovery pipeline split across catalog preview, ranking, rerank, and schema-index modules. |
TraceSink, TraceEvent::LashlangExecution, OtelTraceSink | lash-trace + lash-core | Runtime observability contracts. Ordinary traces flow through the configured trace sink; Lashlang execution graphs use a separate opt-in sink with execution maps, node, branch, and child-link records. Static @label metadata is emitted once in execution-map node label_metadata; OpenTelemetry export is feature-gated. |
UiTimelineItem, ActivityBlock, TuiExtensions | lash-cli / lash-tui-extensions | CLI render projection, tool activity display, and host-provided surface slots. |
Plugin Registration
Plugins are assembled per session. Each plugin can contribute protocol drivers, native tools, tool-catalog entries, prompt text, lifecycle hooks, host-callable RPCs, and UI activity.
session + driver + native tools"] Registrar --> Tools["ToolProvider
ToolCatalogContributor"] Registrar --> Prompt["PromptContributor
context transforms"] Registrar --> Runtime["runtime events
plugin actions"] Registrar --> UI["UI activity / panels"] Mode --> Session["Session"] Tools --> Session Prompt --> Session Runtime --> Session UI --> CLI["lash-cli projection"]
Boundary Rules
The current codebase relies on these separations staying explicit.
-
No UI vocabulary in core runtime.
UiTimelineItemand rendering stay inlash-cli. -
Provider quirks stay at provider boundary.
OpenAI-compatible schema normalization belongs in request builders, not canonical tool definitions.
-
Graph storage is not chronological policy.
Dedupe and ordering live in projections such as
ChronologicalProjection. -
Background work is handle-shaped.
Started tool calls, including
spawn_agentfan-out, are rediscovered throughprocesses.list. -
Host bindings are projected, not copied.
RLM exposes
historyand any host globals to Lashlang viaRlmProjectedBindings. Lazy values are passed asProjectionRefs and resolved at execution time; snapshot restore rehydrates ref-backed projected values instead of copying or materializing them.