Luigit
repositories / smith

smith

There are many coding harnesses - but this one is fast

owned by admin

.system/specs/SMH-SPEC-SPEC0001-smith-specification/index.md

Raw
Rendered preview

id: SMH-SPEC-SPEC0001 type: spec title: "Smith Specification" research: [SMH-RESEARCH-FNY87IGJ, SMH-RESEARCH-WASM0001]

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.

Scope

Smith includes:

  • terminal interaction,
  • non-interactive evaluation,
  • JSON-RPC over standard input and output,
  • deterministic CBOR sessions and replay,
  • provider and model selection,
  • built-in coding tools,
  • sandboxed plugins,
  • VCS-backed history and recovery,
  • generated SDK help.

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 tool effects.
  • 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 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.

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.

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, secret registration, VCS operations, and replay-relevant metadata.

Session persistence uses length-prefixed CBOR frames with deterministic, transparent compression for eligible payloads. Allocation bounds apply before decoding and throughout decompression. Compression preserves frame traversal, frame-level recovery, and byte-preserving round trips of unknown frames.

It guarantees:

  • deterministic encoding,
  • bounded frame allocation,
  • recovery of all complete frames before a truncated tail,
  • 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,
  • serialization of concurrent writers.

Resuming, cloning, forking, and branch navigation preserve the selected history and compaction boundary. Externally managed entries can initialize an in-memory session without changing their order or IDs.

In memory a session is an index arena: each branch is a contiguous vector of fixed-size entry records over one contiguous payload arena per session. Entry content is canonical CBOR bytes at rest and in memory, decoded on demand into the consuming scope and never held decoded in the session. A record carries the entry identity, parent, timestamp, kind, and the pairing identifiers of its kind, so history traversal, tracing, forking, and compaction-boundary logic never decode content. An entry frame carries its content as an opaque canonical CBOR byte string; loading copies bytes, it does not parse them. Forking a session and loading its frames allocate a constant number of times beyond the frame reader, independent of entry count.

Session dumps use JSONL for inspection and interchange. JSONL is not the authoritative persistence format.

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. 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

Built-in tools are:

  • read,
  • write,
  • edit,
  • bash,
  • find,
  • grep,
  • ls.

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 effects

Bash executes 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. Shell output arriving immediately after process exit is not silently truncated.

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:

  1. product defaults,
  2. built-in plugin defaults,
  3. plugin contributions,
  4. user configuration,
  5. trusted project configuration,
  6. environment variables,
  7. 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.

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 named session by default. --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.

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

Public Rust and plugin SDK APIs are documented. Plugin SDK declarations are the source for generated plugin help. Every public event and function has one discoverable usage description. Generated help is checked against the exposed SDK so neither can silently drift.

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 load incrementally without requiring one contiguous file-sized string,
  • 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 use one provider-independent agent runtime,
  • a mock provider completes a tool-using turn with ordered durable events,
  • sessions survive truncation, preserve unknown frames, and replay deterministically,
  • concurrent or interrupted session operations do not silently corrupt history,
  • provider catalogs remain usable offline and reject stale refresh publication,
  • model requests never use unadvertised capabilities,
  • 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,
  • required quality, architecture, documentation, and release gates pass without warnings.
---
id: SMH-SPEC-SPEC0001
type: spec
title: "Smith Specification"
research: [SMH-RESEARCH-FNY87IGJ, SMH-RESEARCH-WASM0001]
---

# 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.

## Scope

Smith includes:

- terminal interaction,
- non-interactive evaluation,
- JSON-RPC over standard input and output,
- deterministic CBOR sessions and replay,
- provider and model selection,
- built-in coding tools,
- sandboxed plugins,
- VCS-backed history and recovery,
- generated SDK help.

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 tool effects.
- 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 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.

## 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.

```mermaid
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.

## 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, secret registration, VCS operations, and replay-relevant metadata.

Session persistence uses length-prefixed CBOR frames with deterministic, transparent compression for eligible payloads.
Allocation bounds apply before decoding and throughout decompression.
Compression preserves frame traversal, frame-level recovery, and byte-preserving round trips of unknown frames.

It guarantees:

- deterministic encoding,
- bounded frame allocation,
- recovery of all complete frames before a truncated tail,
- 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,
- serialization of concurrent writers.

Resuming, cloning, forking, and branch navigation preserve the selected history and compaction boundary.
Externally managed entries can initialize an in-memory session without changing their order or IDs.

In memory a session is an index arena: each branch is a contiguous vector of fixed-size entry records over one contiguous payload arena per session.
Entry content is canonical CBOR bytes at rest and in memory, decoded on demand into the consuming scope and never held decoded in the session.
A record carries the entry identity, parent, timestamp, kind, and the pairing identifiers of its kind, so history traversal, tracing, forking, and compaction-boundary logic never decode content.
An entry frame carries its content as an opaque canonical CBOR byte string; loading copies bytes, it does not parse them.
Forking a session and loading its frames allocate a constant number of times beyond the frame reader, independent of entry count.

Session dumps use JSONL for inspection and interchange.
JSONL is not the authoritative persistence format.

## 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.
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

Built-in tools are:

- `read`,
- `write`,
- `edit`,
- `bash`,
- `find`,
- `grep`,
- `ls`.

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.

```mermaid
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 effects

Bash executes 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.
Shell output arriving immediately after process exit is not silently truncated.

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:

1. product defaults,
2. built-in plugin defaults,
3. plugin contributions,
4. user configuration,
5. trusted project configuration,
6. environment variables,
7. 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.

### 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 named session by default.
`--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.

### 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

Public Rust and plugin SDK APIs are documented.
Plugin SDK declarations are the source for generated plugin help.
Every public event and function has one discoverable usage description.
Generated help is checked against the exposed SDK so neither can silently drift.

## 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 load incrementally without requiring one contiguous file-sized string,
- 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 use one provider-independent agent runtime,
- a mock provider completes a tool-using turn with ordered durable events,
- sessions survive truncation, preserve unknown frames, and replay deterministically,
- concurrent or interrupted session operations do not silently corrupt history,
- provider catalogs remain usable offline and reject stale refresh publication,
- model requests never use unadvertised capabilities,
- 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,
- required quality, architecture, documentation, and release gates pass without warnings.