id: SMH-SPEC-SPEC0001 type: spec title: "Smith Specification" research: [SMH-RESEARCH-FNY87IGJ, SMH-RESEARCH-WASM0001, SMH-RESEARCH-AHDXRKXM, SMH-RESEARCH-EVY30PHD]
Smith Specification
Intent
Smith is a fast Rust coding-agent TUI with plugin-owned customization. It provides one provider-independent agent runtime across interactive, eval, JSON-RPC, and replay modes. A minimal semantic core and reusable native SDK facilities support a broad plugin ecosystem without special built-in tool paths.
Scope
Smith includes:
- terminal interaction,
- non-interactive evaluation,
- JSON-RPC over standard input and output,
- deterministic binary sessions and replay,
- provider and model selection,
- coding tools delivered as ordinary bundled plugins,
- sandboxed plugins,
- VCS-backed history and recovery,
- offline, retrievable documentation and generated reference for humans and agents.
Smith does not require a live provider for session storage, replay, tool execution, or interface testing.
Product boundaries
- Rust owns safety, persistence, concurrency, terminal primitives, model vocabulary, catalog schema, routing, credential mechanics, and bounded SDK effect mechanisms.
- Provider plugins own vendor adapters; vendor-specific knowledge lives exclusively in them.
- Sandboxed plugins own user extension, product layout, prompts, themes, keybindings, commands, and tool definitions, composition, and presentation.
- Built-in and user-visible extension behavior use the same plugin contracts.
- Provider details do not enter the agent, session, tool, plugin, or interface contracts.
- Interface modes share one runtime behavior rather than reimplementing the agent loop.
Runtime foundation
One durable session authority underlies agent policy, host embedding, all interface modes, and granted plugin operations. History, admitted input, work checkpoints, scoped state, and effect evidence share that authority; convenience APIs never introduce another runtime or authoritative store. Agent policy consumes recorded inputs and emits bounded state changes and effect requests; external execution is outside state transitions. Every nondeterministic input is recorded before authoritative state depends on it. Provider-specific behavior remains outside the shared foundation.
Embedding and frontends share session access, submission, inspection, observation, cancellation, fork, and close semantics. Durable admission and settlement are distinct; blocking conveniences compose them without another agent loop. Rust and plugin APIs expose their appropriate ownership and grant boundaries, not a requirement for identical syntax. These contracts require shared durable mechanisms, not a public generic task-definition engine, document database, or persisted execution stack.
Arrows show semantic dependencies, not prescribed crates or call signatures.
flowchart TB
clients["Frontends and embedding"] --> runtime["Shared runtime contracts"]
runtime --> agent["Agent policy"]
agent --> authority["Durable session authority"]
runtime --> effects["Granted effect execution"]
effects --> authority
plugins["Plugin resource contracts"] --> authority
Releases and dependencies
Smith app and workspace crates share one release version.
Before 1.0, Rust library APIs may break without stability guarantees.
From 1.0, every workspace library's public API and documented behavior follow ordinary SemVer; incompatible changes require a Smith major release.
Plugin-world versions and compatibility are independent of Smith releases, as defined in SMH-SPEC-PLUG0001.
Smith builds with latest stable Rust and promises no historical compiler support. Library consumers need a sufficiently current compiler regardless of their own crate edition. Built binaries and compiled plugins do not require a Rust toolchain to run.
Dependency requirements admit SemVer-compatible updates by default and declare meaningful minimums for required APIs, correctness, and security fixes. Narrower constraints require a concrete compatibility or tooling-coupling reason. The committed lockfile fixes the app's verified dependency graph; library consumers resolve their own graphs. Update detection surfaces both compatible releases and releases outside current requirements. Upgrades are deliberate and verified; coupled host and guest tooling is evaluated together. New dependency releases alone do not justify raising minimums or changing Smith's major version. Public dependency type and trait changes are evaluated as part of Rust API compatibility.
Release verification covers the locked graph, freshly resolved compatible dependencies, and declared dependency minimums. Engine and tooling upgrades also preserve supported compiled-plugin behavior, not merely successful guest rebuilds.
App reproducibility and downstream compatibility use distinct dependency graphs.
flowchart LR
requirements["Dependency requirements"] --> lock["Committed lockfile"]
lock --> app["Verified Smith app"]
requirements --> resolution["Consumer dependency resolution"]
resolution --> library["Smith library in consumer project"]
verification["Compatibility verification"] --> app
verification --> library
Shared structured data
Shared domain boundaries use Smith-owned data contracts; parser, codec, DOM, and engine error representations remain private. Tool arguments and tool schemas have distinct semantic contracts; plugin-defined arguments, schemas, and extension payloads remain extensible. Known session metadata and provider-effect records use typed records and reject invalid shapes at their owning boundary. Owned values and validated borrowed values expose equivalent bounded, fallible access and destination encodings without requiring an owned tree or JSON text as storage. Representation changes preserve existing JSON and session wire behavior, numeric kinds including negative zero, object ordering, escaping, and malformed-input handling. Secret substitution preserves its authorized-effect boundary across nested values and object keys. Serde remains supported; shared access does not mirror a parser or DOM API.
Agent behavior
The agent:
- accepts user input and delivers queued input at defined lifecycle events; queue policies are plugin contributions,
- streams normalized assistant output,
- validates and executes tool calls,
- records completed conversation-relevant events,
- continues until an explicit stop condition,
- exposes ordered lifecycle events,
- remains abortable during provider, tool, compaction, and plugin work.
Abort is cooperative inside the core: every awaitable checks cancellation at effect edges, preserving frame atomicity and three-state effect evidence; cancelled effects record not-applied or unknown, never silently.
Plugins may poll a cancellation API, but the host does not rely on plugin cooperation: after a short deadline it destroys the instance, leaving recorded evidence to speak for the effect.
A provider stream has explicit terminal success, tool-use, limit, abort, and error outcomes. Malformed or incomplete provider streams fail explicitly. A terminal event is emitted once.
Tool calls and results remain correctly paired and ordered. Injected messages never split a tool call from its result.
Plugin event boundary
Plugin handlers and their action semantics are specified in SMH-SPEC-PLUG0001.
The agent applies published actions only at the safe points defined here: between provider requests, after the current stream and complete tool-result batch.
sequenceDiagram
participant P as Provider round
participant A as Agent boundary
participant H as Ordered handlers
participant G as Runtime generation
P-->>A: Stream and complete tool batch
A->>H: Typed lifecycle events
H-->>A: Typed action batch
A->>A: Validate and reject conflicts
A->>G: Publish coherent runtime changes
G-->>P: Next request snapshot
Providers, models, and authentication
Smith supports Anthropic, OpenAI, Google, and OpenAI-compatible endpoints. Additional providers can be supplied through the plugin API. Vendor-specific knowledge — wire formats, endpoints, credential variable names, quirks — lives exclusively in provider plugins. The Rust core keeps vendor-agnostic provider concerns: model vocabulary, catalog schema, alias and group routing, and credential store mechanics.
Every provider normalizes:
- text and thinking deltas,
- tool calls,
- stop reasons,
- usage and cache accounting,
- provider errors,
- cancellation.
Network transport
One host-owned HTTP engine serves provider traffic and granted plugin net effects. It is synchronous and pure Rust: no async runtime, no system TLS library. TLS validates against bundled Mozilla roots.
Every exchange is bounded and observable:
- request bodies above 16 MiB are rejected before send,
- response bodies stop at 64 MiB,
- the response head arrives within 120 s or the exchange fails,
- a gap of 300 s between body chunks ends the body,
- body chunks are delivered as they arrive over a bounded channel, never buffered to completion,
- cancellation is observed at each chunk boundary; no chunk read after cancellation is delivered,
- every body ends with one explicit outcome: complete, truncated at the bound, cancelled, or failed; a consumer can never mistake a cut-off body for a complete one,
- non-2xx statuses are delivered as responses, never as transport errors.
Model capabilities
Model metadata states supported behavior explicitly, including:
- context and output limits,
- text and image input,
- tool use,
- thinking levels,
- strict or grammar-constrained tool input,
- cache behavior,
- pricing.
Provider requests use only advertised capabilities. Unsupported optional behavior degrades predictably or fails before dispatch. Family-name inference cannot override explicit provider evidence.
Catalogs
Smith ships a reviewed offline model catalog. Human configuration and checked-in data remain authoritative.
Provider or plugin catalogs may refresh at runtime when enabled. Refresh behavior must:
- remain cancellable,
- preserve a usable cached or bundled snapshot,
- prevent stale work from replacing newer state,
- publish coherent snapshots,
- expose source provenance and conflicts,
- never silently overwrite human configuration.
Catalog freshness cannot block normal offline startup.
Authentication
Credentials may come from environment variables, Smith auth data, explicit configuration, or provider plugins. Authentication is resolved before dispatch and can be checked independently of a model request. Concurrent credential changes cannot lose unrelated provider state. Expired renewable credentials refresh before use. Credential values never enter remote model context, logs, diagnostics, or replay output.
Failover
Model aliases, groups, and account buckets resolve deterministically. Resolution performs no network access. Cycles and ambiguity fail with complete diagnostics.
Rate limits may fail over immediately. Transient transport failures follow bounded retry policy before failover. Invalid requests and unavailable models do not retry indefinitely.
Dispatch identity
Selected model identity and dispatched provider/model identity are distinct. Aliases, groups, failover, and plugin routing may change dispatch without changing the user's selection. Every provider attempt records selection, physical dispatch, effective thinking level, routing provenance, and the catalog capabilities and plugin generation used. Request validation uses the dispatched model's limits and capabilities, never the selected label's assumed behavior.
Routing that needs external information obtains it through granted recorded effects; its decision enters the ordered event log before dispatch. Alias and group resolution remains network-free. A dispatched attempt retains its resolved identity through the response and complete tool-result batch; later attempts record their own decisions. Retries and failover within one provider round retain its initial plugin generation and tool loadout; a subsequent round may resolve a published replacement after preceding work settles. This contract does not require classifier-backed routing or a virtual-model API.
Sessions
A session is an append-only branching history with stable IDs, parent links, timestamps, and a selected leaf. Entries represent messages, tool activity, model changes, compaction, context edits, request provenance, secret registration, VCS operations, and replay-relevant metadata. Work ownership is independent of history ancestry; selecting a branch does not create another executor or transfer ownership. Independent sessions retain separate write and commit boundaries; no cross-session atomic commit or distributed merge is implied.
Committed changes
A committed change is one bounded, validated semantic transition within a session. Dependent history, state, checkpoint, queue, and receipt updates belonging to that transition publish and recover together, or none do. Submission admission atomically records its input, destination branch, queue placement, and initial work identity. Effect completion atomically records its output, outcome, mutation evidence, and corresponding work/state transition. Pure state preparation failure leaves the prior state intact; failure after an external effect cannot undo that effect.
Authoritative state adoption, settlement receipts, and effect eligibility require durable acknowledgement of their committed change. Complete but unacknowledged records are distinguishable from acknowledged durable state and cannot authorize effects or successful settlement. A lost caller acknowledgement does not prove rollback: recovery validates complete committed changes and establishes their persistence boundary before adopting or acknowledging them. Data outside a complete recoverable committed change is non-authoritative; a completion there is treated as missing under the durable effect boundary. An uncertain storage outcome stops further mutation and effect dispatch until recovery establishes a usable committed boundary; it never reports a guaranteed rollback. Readers, recovery, inspection, and replay recognize the same commit boundaries, including after a torn or corrupt tail. Commit size, record count, structured depth, and resident preparation are bounded before admission. Live-work count and ownership depth, and active scoped-state item and byte totals, have explicit limits; excess admission fails without partial changes. Archived history and terminal receipts remain retrievable in bounded batches; cache eviction never erases their durable meaning.
Submission and receipts
Submission returns a stable identity after durable admission, not after its work finishes. A receipt distinguishes admitted/queued work from a terminal outcome and remains retrievable after reopen. Transport request IDs and process-local handles do not substitute for durable submission identity. Caller-supplied deduplication keys are scoped to stable session identity; repeated accepted input with the same key returns the original submission, not another execution. Conflicting content or explicitly different destination for that key fails without new work. Deduplicated admission does not promise exactly-once external effects.
Read-only access rejects admission and work-abort requests before mutation or effects.
Cancelling a wait or subscription stops only that observation; aborting work is a separate authorized operation with recorded cancellation intent.
Abort acknowledgement does not imply terminal settlement or that a started effect was not applied.
Queue delivery and withdrawal retain the lifecycle policy in SMH-SPEC-PLUG0001.
Admission, execution, and observation have separate outcomes.
sequenceDiagram
participant C as Caller
participant R as Runtime
C->>R: Submit input and key
R-->>C: Durable admission receipt
C->>R: Inspect or observe receipt
R-->>C: Pending work or terminal outcome
C->>R: Cancel observation
R-->>C: Observation ends, work unchanged
Work and recovery
Admitted work has stable identity, explicit ownership, bounded durable checkpoints, and a terminal receipt. Checkpoints describe recoverable state and required provenance, not a live thread, future, closure, or guest stack. A parent settles only after work it owns reaches terminal outcomes; ordinary child work cannot silently detach or become background work. Waiting work and unavailable execution dependencies remain distinguishable from successful completion. Work outcomes and external effect mutation evidence are separate; failure or cancellation may retain applied or unknown effects.
Reopen reconstructs admitted input, checkpoints, ownership, and receipts from the same session authority. Inspection and read-only observation never schedule execution. Continuation uses recorded state and resolved execution prerequisites; it never re-executes effects merely to reconstruct state. Missing completion follows the durable effect boundary below, not an automatic retry rule for interrupted work. Missing or incompatible code or required authorization blocks the affected continuation with a diagnostic; no silent name-based rebinding or evidence deletion. Closing seals new mutation admission, settles admitted commits, and stops execution before releasing writer ownership. Close alone never fabricates a terminal receipt or discards recovery evidence.
Scoped state
Durable state declares its owner, version, value bounds, retention, and branch/fork behavior. Core state uses typed records; plugin-defined payloads follow the shared structured-data and session encoding laws. Changes and work checkpoints belonging to one transition use the same committed change. Historical state is reconstructed from recorded state, never today's plugin implementation or configuration. Forked history does not resume or duplicate the source's live work; state copying or fresh initialization follows its declared contract. Effect intents and evidence visible at the fork point remain historical, including unknown outcomes; later source completions do not silently enter the fork. Inherited work and receipts retain source attribution, never authorize fork execution, and are not fork-owned admissions; new fork work receives its own identity. Transient render and guest scratch remain transient; semantic ownership is not allocation-scope accounting.
Observation
Observation attaches to one coherent committed revision plus its continuation position, without a gap between baseline and later changes. Positions identify the session and committed order, not process-local offsets; incompatible positions fail explicitly rather than skipping history. Every frontend's durable transcript sequence and reconnect contract uses these positions; connection-local progress counters cannot substitute for them. Branch navigation and file maintenance cannot silently mix view boundaries or invalidate active observations. Snapshots, pending updates, and retained views have byte and item bounds; exact history can be read in bounded batches without whole-history snapshots. Transient progress may coalesce or drop per the UI degradation law. Backpressure or reconnect never loses durable transcript entries: continuation retrieves missing committed history or reports an explicit recovery requirement. A replacement presentation snapshot does not substitute for omitted durable history when exact resumption is requested.
Effective request context
Durable session history is authoritative for provider context; transient agent state cannot replace it implicitly. Effective context follows the selected branch, compaction boundary, applicable context edits, and accepted prompt/context transformations.
Recorded inputs reconstruct each request's exact ordered messages, effective instructions, advertised tool definitions, model dispatch, and generation provenance in secret-safe form. Reconstruction preserves recorded redactions and secret references; it never restores credential plaintext for context inspection or replay. The request's effective context is fixed before its provider effect starts; later changes affect subsequent requests only. Runtime prompt/tool changes are durable request history, not implicit writes to user configuration. Resume and ordinary replay reconstruct prior request context from recorded data, not current configuration or freshly executed transformations. Projection and provenance obey bounded working-set and encoding laws; they do not require a second authoritative history or whole-history residency.
Provider context is a projection; raw history remains intact.
flowchart TB
h["Durable branch history"] --> c["Compaction boundary"]
c --> e["Applicable context edits"]
e --> t["Accepted prompt and context transforms"]
t --> r["Recorded effective request"]
d["Tool definitions and dispatch provenance"] --> r
r --> p["Provider effect"]
h --> u["Raw history and accounting"]
Context edits
An append-only context edit omits or replaces the model-visible content of an earlier message on its branch. It never changes the target's identity, role, lineage, raw content, effect evidence, or usage. Unknown targets and targets outside the active ancestry fail explicitly. The latest applicable edit wins; navigating before the edit restores the earlier projection, and unrelated branches remain unchanged.
Edits apply only to targets contributing to retained context; they do not resurrect compacted entries or silently regenerate summaries. An edit batch publishes atomically only when the resulting context preserves valid tool-call/result pairing and ordering. Invalid batches leave the previous projection unchanged. Raw transcript and export views retain original messages; projected context is distinguishable from that history. Readers preserve unsupported records losslessly but reject request reconstruction requiring unknown edit or provenance semantics rather than silently ignoring them.
Storage and encoding
Each session has one self-contained append-only binary data file identified by its stable session ID. Default runs create distinct sessions; attaching or resuming selects an existing identity explicitly. Session discovery requires no shared catalog or separately synchronized index. Independent sessions support concurrent writers in separate Smith processes.
Known entry metadata and typed content use a custom versioned binary encoding. Fixed metadata identifies entries, parents, timestamps, kinds, pairing IDs, and payload locations without decoding content. Text and tool output are byte payloads; arbitrary structured values use canonical CBOR within explicit bounded payload spans, preserving numeric kinds and negative zero through semantic round trips. The format specifies field widths, byte order, tags, lengths, and offsets independently of Rust memory layout. Raw Rust memory images are not a persistence format.
Length-prefixed, checksummed frames support deterministic, transparent compression for eligible payloads. Allocation bounds apply before decoding and throughout decompression. Compression preserves independent metadata traversal, frame-level recovery, and byte-preserving round trips of unknown frames.
Persistence guarantees:
- deterministic encoding and complete semantic roundtrips,
- bounded frame allocation and validated offsets, lengths, tags, and parent references,
- recovery of complete committed changes before a truncated tail, without publishing partial changes,
- bounded skipping of corrupt frames with intact lengths,
- preservation of unknown future frames during round trips,
- explicit failure for unrecoverable framing ambiguity,
- atomic publication of newly created, forked, or repaired sessions,
- at most one writer per session.
Publication distinguishes complete visible records from acknowledged durable records. Readers never consume partial appends; durability acknowledgements require the platform persistence boundary, not merely userspace flush. An incomplete tail of a live writer is pending input, not permission for readers to repair or truncate it. Maintenance coordinates with writers and observers so replacement or truncation cannot invalidate active reads or mix file generations.
Checkpoints and integrity
Derived lookup indexes and checkpoints reside inside the session file and are reconstructible from authoritative records. Incomplete or invalid checkpoints cannot hide otherwise recoverable history. Checkpoint discovery follows unambiguous structural boundaries; checkpoint-shaped bytes inside payloads are never authoritative. Fast opening does not claim full historical integrity: records are validated on access, and explicit full-file verification reports damage. Bounded working memory does not imply constant reopen work; discovery and recovery costs remain explicit.
Working sets
Opening, browsing, resuming, and forking do not require a whole-session payload arena or whole-history resident index. Storage workers fetch bounded record batches and prepare immutable views for consumers. Render code never reads files or accesses storage that can fault in file-backed pages. Initial storage uses explicit reads, not mmap.
Consumers retain distinct bounded working sets.
flowchart TB
F["Session file"] --> W["Storage worker"]
W --> U["Visible transcript chunks"]
W --> A["Effective agent context"]
W --> R["Replay or export batches"]
Views borrow validated resident chunks, including bounded decompression buffers, without allocating intermediate content trees; structured-value spans are validated before borrowed access and support inspection and serialization without materializing owned trees. Chunk lifetimes outlive their views; cache eviction never invalidates active references. Owned content is materialized only at explicit consumer boundaries that require it. UI retention follows visible content and bounded scrollback caches, not total history size. Replay, export, search, and fork traversal stream bounded batches; accumulated semantic state is accounted separately. Agent context follows the selected branch and compaction boundary without decoding unrelated branches; paging does not eliminate the effective-context working set.
Resuming, cloning, forking, and branch navigation preserve the selected history and compaction boundary. Externally managed entries can initialize a session view without changing their order or IDs. Session dumps use JSONL for inspection and interchange, never authoritative persistence.
Access ownership
Opening a session already owned by another writer yields read-only observer access rather than indefinite writer-lock waiting. Observer navigation and inspection never mutate source history or acquire writer ownership implicitly. Requests requiring mutation fail explicitly before provider or tool execution when access is read-only. Writer exit never silently promotes an observer. An explicit fork creates a new independently writable session.
Compaction, cost, and secrets
Compaction reduces provider context without deleting durable history. It preserves required lineage, recent context, tool ordering, secret registrations, and the active branch boundary. It never persists a summary known to be truncated or incomplete. Queued input resumes after compaction according to its original delivery mode.
Cost accounting includes provider responses, tool-reported usage, compaction, and branch summaries when usage is available. Usage and pricing follow the physical model serving each operation, including routed, retried, and nested requests. Aggregates count each recorded usage observation once; parent reporting cannot double-count recorded child work. Unknown usage remains unknown rather than becoming zero.
The secret proxy replaces registered secrets before remote dispatch and restores them only for authorized local effects. Secrets remain local plaintext under the user's filesystem permissions. Mechanics are core: registration records, reference-based consumption, substitution at the effect boundary after record redaction, and one-time handoff from creating plugins. Secret routing and authorization policy is plugin-contributed.
Tools
Core dispatches registered tools generically; it contains no hardcoded built-in tool definitions, name-based special execution paths, or privileged native fallback. Bundled defaults and user tools are ordinary sandboxed plugins under the same registration, grants, SDK, and lifecycle contracts. Plugins own tool names, input schemas, descriptions, composition, and output presentation. Disabling all tool-contributing plugins leaves no hidden core tools available.
Native SDK facilities provide reusable filesystem, search, structured evaluation, and process mechanisms, not a second agent-facing tool registry. Ordinary filesystem, search, and data transformations execute in process; they do not spawn a shell or helper program merely to implement a tool call. Explicit external-program execution remains a supervised process effect. Plugins can compose facilities directly; using an interpreter is not required for every tool. Default contributions cover file reading, writing, editing, traversal, search, and Nushell evaluation.
Tool definitions and native effect mechanisms remain separate.
flowchart TB
core["Generic agent runtime"] --> tools["Registered wasm tools"]
tools --> sdk["Granted SDK facilities"]
sdk --> host["Native host mechanisms"]
All tools use provider-neutral definitions, bounded output, explicit errors, cancellation, and recorded lifecycle events. Provider-specific constrained sampling is an optional transport capability, not a separate tool contract.
Durable effect boundary
Every invoked SDK host effect is durable, including reads, searches, mutations, processes, provider operations, and VCS operations. An effect record contains its bounded canonical input and full bounded output, outcome, plugin generation, stable effect ID, and explicit causal parent. Secret plaintext is replaced before persistence.
Effect intent becomes durable before execution.
An intent-recording failure prevents execution.
Completion records mutation state as applied, not-applied, or unknown.
A missing completion or uncertain partial effect recovers as unknown and is never retried automatically.
Completion-recording failure is terminal and reports the best known mutation state outside the failed record.
stateDiagram-v2
[*] --> Intent: persist intent
Intent --> Running: begin bounded effect
Running --> Completed: persist outcome
Running --> Unknown: completion missing or uncertain
Completed --> [*]: applied, not-applied, or unknown
Unknown --> Reconciled: explicit reconciliation
Reconciled --> [*]
File effects
- Read supports bounded line windows and identifies unsupported binary content.
- Write creates parent directories when permitted and replaces files atomically.
- Edit applies exact replacements, rejects missing or ambiguous matches, detects stale input, and writes atomically.
- Find, grep, and list return deterministic bounded results and respect configured ignore behavior.
- File tools resolve paths against the invocation context, not process-global startup state.
Process and evaluation effects
External programs execute in an explicit working directory with bounded output, timeout, exit status, and cancellation. Process termination includes descendants started by the invocation where the platform permits it. Process output arriving immediately after exit is not silently truncated. In-process Nushell evaluation and its packaged language documentation are specified in SMH-SPEC-ZVMD_XYT.
Mutation completion records the observed outcome even when execution fails. No successful or uncertain mutation is presented as unrecorded success.
Compatibility adapters may translate external tool names only when semantics are equivalent. Fuzzy edits, freeform patches, terminal sessions, plans, subagents, permissions, MCP, and semantic search remain plugin behavior.
Replay and VCS
Replay reconstructs runtime state from recorded events without a provider. It supports real-time playback, accelerated playback, turn ranges, and comparison of re-executed tool effects. Replay preserves source event order and reports divergence explicitly.
Smith provides VCS-backed snapshots, diffs, undo, redo, restore, and time travel through one structured SDK boundary. Normal operation does not require an external VCS executable. Mutating VCS operations validate their target and remain attributable to session events.
Plugin system and configuration
The plugin system is specified in SMH-SPEC-PLUG0001; engine mechanics in SMH-SPEC-WASM0001.
Plugin events respect the agent lifecycle boundary defined there.
Plugins contribute configuration values per the precedence below.
Configuration
Configuration is expressed in KDL. Configuration has deterministic precedence:
- product defaults,
- built-in plugin defaults,
- plugin contributions,
- user configuration,
- trusted project configuration,
- environment variables,
- explicit command-line overrides.
Each option is declared once across its command-line and environment surfaces. Resolved values report their source.
Invalid values fail with their source and field path. Unknown values follow the owning schema's explicit policy. Handler-requested configuration changes are runtime-only; only explicit user commands persist configuration.
User interface abstraction
Interface modes are frontends over one core: terminal today; graphical, web, and mobile remain possible on the same crates. Plugins never query which frontend is active. They emit semantic UI intents whose unsupported behavior is defined per intent — drop, refuse with an event, or persist — never discovered at runtime. Transcript appends are durable session events; presentation is frontend detail. Frontend-specific escape hatches, where unavoidable, are manifest-declared capabilities.
Terminal interface
Smith uses a fullscreen TUI by default. Version 1 has no regular terminal-scrollback mode. The TUI presents messages, thinking, tool activity, errors, input, status, model, cost, and context use through an independently scrollable transcript.
Required interaction behavior:
- input remains responsive during provider and tool work,
- scrolling away from the bottom does not jump on new output,
- users can return to the latest message explicitly,
- search and selection target stable visible content,
- overlays own focus explicitly,
- resize and focus changes preserve valid layout,
- shutdown restores terminal state after normal exit, error, abort, or signal.
Rust supplies deterministic widgets and layout primitives. Plugins select product layout and presentation. Structured render descriptions cannot emit arbitrary terminal control sequences.
Terminal capabilities are detected conservatively and can be overridden explicitly. Unsupported hyperlinks, color, keyboard, mouse, or image features degrade to plain terminal behavior. Capability probing cannot indefinitely delay startup.
Interface modes
Interactive
Interactive mode supports new, attach, continue, resume, branch, compact, replay, model selection, plugin management, help, and shutdown behavior. User-visible commands are plugin-registered unless they are required to enter or recover the runtime.
Observer mode visibly identifies read-only access and writer ownership. It permits transcript navigation, search, export, and explicit fork; prompt submission, tool execution, and source-session mutations are disabled. Navigation changes only local presentation, never the writer's persisted selection. Follow-live is an explicit toggle that consumes complete published records without disrupting users browsing older content. Observer navigation and session inspection are read-only storage operations, not agent tool execution.
Session inspection
Session inspection works without the TUI or provider credentials:
smith sessions liststreams session identities and summary metadata without decoding complete histories.smith sessions grep <pattern>searches recorded content incrementally and identifies each match by session and entry.smith sessions get <id>reads one identified session through bounded traversal.
Human-readable output is the default; --json emits LF-delimited JSON records for scripts and agents.
Standard output contains data only; diagnostics use standard error; piped output contains no terminal escape sequences.
Inspection is read-only and respects secret redaction; it never repairs, truncates, or runs tools.
Active-session inspection uses a complete-record snapshot boundary; continuous following requires explicit selection.
CLI help defines search syntax, branch scope, ordering, exit statuses, broken-pipe behavior, and handling of damaged sessions.
Eval
Eval accepts a prompt, runs the same agent behavior without the TUI, and can emit human-readable or structured output.
It auto-creates a distinct named session by default; separate invocations never implicitly resume a shared fixed filename.
--no-session runs effects against a temporary session store removed on clean exit and retained after abnormal termination.
Effects never execute without a durable recording destination.
JSON-RPC
RPC uses standard input and output with strict LF-delimited messages. Standard output contains protocol records only. Requests and responses preserve request IDs. Unknown commands return correlated errors.
Streaming message updates are ordered deltas between start and end events. The end event is authoritative. Clients can inspect sessions, observe tool and compaction lifecycle, manage queued input, abort active work, and wait for the runtime to settle. Admission responses identify durable submissions; later inspection and events identify their settlement independently of transport correlation IDs. Session access mode is exposed to clients; read-only access rejects mutation requests explicitly.
Replay
Replay operates without provider credentials. Structured replay output is deterministic for the same session and trace inputs.
Model Context Protocol
smith mcp serves MCP over stdio as a client-spawned frontend.
It consumes the smith-ui intent vocabulary: progress maps to progress notifications, sessions to resources, built-in tools to MCP tools.
Intents without an MCP translation degrade per the intent law.
Remote serving and OAuth flows belong to the remote-frontends spec.
Documentation and help
All Smith user and developer documentation is retrievable through smith docs, friendly to humans and agents.
Documentation covers everything needed to use, configure, and extend Smith: supported workflows, settings, command and protocol interfaces, plugin development, and public Rust and plugin SDK APIs.
The corpus includes reference, guides, tutorials, and complete tested example projects.
Documentation matches the installed Smith version and is available offline without a repository checkout, provider credentials, or an active session.
Retrieval
Readers can list, search, filter, and retrieve selected documents or source ranges without dumping the whole corpus. Results have stable document identities, deterministic ordering, bounded output, and explicit continuation when truncated. Readable terminal output and structured machine output expose the same content. Local documentation references resolve within the installed corpus. Agent bootstrap instructions identify the documentation entry point; documentation enters model context on demand, not wholesale.
Reference authority
Normal command help and documentation command reference derive from the same authoritative command declarations; no independently maintained duplicate reference.
Settings reference follows the owning configuration schemas, including types, defaults, constraints, and precedence.
Plugin SDK declarations are the source for generated plugin help and reference.
Every public event and function has one discoverable usage description.
Generated reference is checked against its exposed commands, configuration, and APIs so neither can silently drift.
Plugin deprecation migration guidance and examples derive from authoritative API metadata and enter built Smith documentation, per SMH-SPEC-PLUG0001.
Examples
Example projects ship as documentation source, not automatically loaded or bundled executable extensions. Examples satisfy the same build, lint, test, and sandbox contracts as bundled plugins. Shipped examples include the source, manifests, and interface definitions needed to build outside Smith's checkout. Documentation refers to those tested sources rather than independently maintained copies of example code.
Security
The remote model and provider response content are untrusted. Project-local executable behavior is untrusted until approved. Installed user plugins are user-approved but remain sandboxed.
Security guarantees:
- only active tools can be invoked,
- tool arguments are validated before effects,
- secrets are removed before remote dispatch,
- plugin effects pass through Smith SDK boundaries,
- project trust gates local executable behavior,
- path and package installation cannot escape owned roots,
- diagnostics do not expose credentials.
Smith does not depend on confirmation dialogs as its primary security boundary.
Performance and portability
Target behavior:
- help output starts within 100 ms on supported desktop systems,
- normal TUI frames complete within a 16 ms budget,
- encoding 1,000 representative session entries completes within 5 ms,
- large sessions use bounded record reads without requiring whole-file residency or a whole-history index,
- transcript work scales with visible content rather than complete history where practical,
- long-running network and filesystem work never blocks input rendering.
Memory accounting
Every allocation, including engine allocations, is attributed to the innermost active lifetime scope on its thread: process, session, turn, kernel call, frame, or io request. A scope is entered by a guard; a thread with no guard is in the process scope. A block is charged to the scope that allocated it for its whole life, so releasing it in another scope keeps live and peak accounting exact. Per scope Smith reports allocation count, allocated bytes, live bytes, and peak live bytes. Accounting never allocates, never locks, and never aborts; ceilings are recorded and reported. For a deterministic path with isolated state, counts are identical across runs; allocation-count tests assert exact counts and bounds only tighten.
Smith supports current Windows, macOS, and Linux on x86_64 and ARM64 where Rust and required native dependencies support the target. OpenBSD x86_64 is best effort. Release archives include versioned binaries and SHA-256 checksums.
Diagnostics
Every user-facing error and warning states what happened, why, and the next corrective action. Diagnostics steer: they name the offending value, the surface that supplied it, and where possible a concrete fix or example. Bare codes without prose are forbidden; errors never expose secret material. This law covers the CLI, the plugin API, RPC, and all developer tooling at every stage of the project.
Acceptance criteria
Smith is acceptable when:
- all modes and embedding use one provider-independent runtime and durable authority,
- rejected or torn committed changes expose no partial dependent state, queue, checkpoint, or receipt,
- repeated admission keys recover the original submission across restart; conflicting reuse creates no work,
- admitted input, work ownership, checkpoints, and terminal receipts reconstruct without re-executing recorded effects,
- cancellation of observation leaves work unchanged; work settlement waits for owned children and preserves effect evidence,
- missing execution dependencies block continuation without silent rebinding or erasing durable state,
- forked history preserves source effect evidence without adopting live work or authorizing duplicate execution,
- admission over live-work, ownership-depth, or active-state limits fails without partial changes,
- coherent bounded observation and sequence recovery preserve durable transcript history under backpressure and reconnect,
- a mock provider completes a tool-using turn with ordered durable events,
- sessions survive truncation, preserve unknown frames, and replay deterministically,
- independent sessions remain writable concurrently; second-writer access is read-only and cannot mutate source history,
- interrupted appends, checkpoint publication, and maintenance do not silently corrupt or hide recoverable history,
- observer UI and session inspection expose complete records without loading whole histories or leaking secrets,
- provider catalogs remain usable offline and reject stale refresh publication,
- model requests never use unadvertised capabilities,
- branch-relative context edits preserve raw history and accounting; invalid pairing or targets leave the projection unchanged,
- resume and replay reconstruct recorded effective instructions, messages, tool definitions, and dispatch provenance without current configuration,
- routing and failover retain selection separately from physical dispatch; capability checks and usage attribution follow each actual attempt,
- nested usage contributes once to totals; missing usage remains unknown,
- plugin system acceptance is defined in
SMH-SPEC-PLUG0001, - every SDK effect has durable intent, completion, causal attribution, and three-state mutation evidence,
- replay exposes incomplete effects as unknown and never retries them automatically,
- compressed session frames remain bounded, recoverable, traversable, and deterministic,
- terminal shutdown restores host state across supported exit paths,
- RPC consumers can assemble complete messages from ordered events,
- app and workspace crate releases are version-aligned; stable Rust library changes satisfy SemVer,
- dependency update detection reports compatible and breaking releases; locked, compatible-resolution, and minimum-version verification satisfy declared contracts,
- required quality, architecture, documentation, and release gates pass without warnings.