Runtime architecture

Building an AI agent in Rust

A concrete tour of UIntellAgent's Rust stack, where type safety helps, where it does not, and how the runtime handles models, tools, state, and failure.

10 minute readUpdated July 25, 2026

Why Rust

A systems language fits the part of an agent that performs side effects

A coding agent is not only a model client. It manages terminal processes, asynchronous provider streams, filesystem state, database connections, user input, cancellation, and persisted checkpoints. These concerns look more like a systems runtime than a prompt wrapper, which makes Rust a practical choice for UIntellAgent.

Rust provides explicit ownership and error handling without requiring a garbage-collected runtime. More importantly for an agent, its type system makes data boundaries visible: a parsed tool request can be represented differently from an approved action, a completed tool result, or a durable run checkpoint.

One native process

The CLI, Ratatui interface, provider runtime, graph console, editor, tools, and HTTP gateway compile into the same Rust binary.

Explicit failure paths

Recoverable errors can cross typed results instead of becoming implicit exceptions at a tool or persistence boundary.

Composable subsystems

Model integration, graph memory, permissions, durable runs, and UI state remain separate modules with concrete contracts.

Predictable local footprint

A native terminal application avoids shipping a browser engine or language interpreter as part of its normal runtime.

Rust does not make an agent correct by itself

Memory safety is valuable, but model mistakes, unsafe policy choices, flawed queries, and incorrect business logic still require validation and testing.

Runtime stack

UIntellAgent uses focused Rust libraries for each boundary

The project does not implement model providers, terminal rendering, asynchronous I/O, or graph storage from scratch. It assembles established libraries and keeps product-specific behavior in its own state, policy, and workflow layers.

LayerRust componentRole in UIntellAgent
Model runtimeRigProvider integration, completion models, tool-call orchestration, and model-facing agent patterns.
Async runtimeTokioProvider streaming, background graph jobs, process I/O, gateway requests, signals, and cancellation coordination.
Terminal UIRatatui + CrosstermFive persistent workspaces, keyboard input, graph rendering, editor panes, tool events, and run status.
Graph memorySurrealDB 3Facts, datasets, typed relations, graph-operation journal, saved views, and metadata.
HTTP gatewayAxum + Tower HTTPAuthenticated readiness and chat endpoints, rate limiting, request IDs, timeouts, and CORS policy.
CLI and dataClap + SerdeCommand parsing and structured configuration, checkpoints, tool arguments, events, and API payloads.

The Rig dependency is pinned to a specific Git revision in Cargo.toml. Pinning prevents an upstream branch change from silently changing the agent at build time, although the project must deliberately update and retest that revision when adopting new Rig behavior.

Typed boundaries

Structured tools are safer than model-generated shell prose

A model can request a tool, but it should not decide how untrusted JSON becomes a privileged operation. Each UIntellAgent tool has a name, a declared argument shape, an implementation, and a permission classification. The shared policy engine receives the structured request before the tool executes.

01
Deserialize

Convert model-generated JSON into the tool's expected argument structure and reject malformed input.

02
Normalize

Resolve paths, commands, record identifiers, and other values into the representation used by policy checks.

03
Authorize

Classify the action as allowed, denied, or confirmation-required under the current permission mode.

04
Execute

Run the bounded implementation and retain its real output, status, or before-and-after file bytes.

05
Record

Return a structured result to the model and, for durable runs, append the outcome to the result ledger.

Types make these stages easier to distinguish in code, but validation remains necessary at every trust boundary. UIntellAgent's graph layer also validates SurrealDB record identifiers and serializes user-controlled text before building queries.

Concurrency

Streaming, tools, graph jobs, and input must stay responsive together

A terminal agent handles multiple timelines: model tokens arrive over the network, child processes produce stdout and stderr, graph operations can scan many records, and the operator may cancel or change workspaces at any time. Tokio provides the asynchronous tasks and channels used to coordinate those timelines.

Cancellation is a runtime behavior

Pressing Esc or Ctrl+G is not merely a visual state change. The active operation needs a cancellation signal, background work must stop at a safe boundary, and the UI must remain capable of receiving the resulting event. Durable runs checkpoint at defined stages so cancellation and later resume do not depend on reconstructing state from a transcript.

The graph console uses background jobs for refresh, layout, and SurrealQL operations. The TUI can continue drawing status and accepting cancellation while those jobs report phases and progress. This is a concrete benefit of designing the application as an event-driven runtime instead of a blocking prompt loop.

Performance discipline

Optimize the interaction path before making benchmark claims

Model latency often dominates an agent turn, but local responsiveness still matters. Large repository trees, streaming output, diff calculation, and graph rendering can make a terminal interface unusable if every frame performs unbounded work.

  • The graph explorer virtualizes its visible list instead of rendering every loaded fact.
  • Graph drawing uses viewport culling and indexed edge lookup for large interactive windows.
  • Analytics results are cached rather than recomputed on every key event.
  • Provider streams and child-process output are processed asynchronously so input remains responsive.
  • Workspace state is persisted separately from the model context, avoiding expensive conversational reconstruction.
No unsupported speed claim

UIntellAgent does not publish comparative performance benchmarks yet. Rust enables a controlled native runtime, but measured workloads are required before claiming it is faster than another agent.

This distinction is important for technical credibility. Architecture describes why performance can be managed; benchmarks demonstrate whether a particular build is faster under a defined workload.

Tradeoffs and setup

Rust improves the runtime boundary but raises the implementation bar

Compile times, asynchronous type errors, ownership design, and native dependency integration can make Rust feature work slower than scripting-language prototypes. A team benefits only when it maintains clear module boundaries, tests unsafe assumptions, and resists hiding everything behind untyped strings.

UIntellAgent publishes its Rust source under the MIT license and provides a checksummed Linux x86-64 archive for stable v1.0.2. Release artifacts include SHA-256 checksums and signed build provenance. Use Rust 1.94 or newer when building from source.

Build from source
git clone https://github.com/uintell/uintellagent.git
cd uintellagent
git checkout v1.0.2
cargo build --release --locked
./target/release/uintell-agent doctor
./target/release/uintell-agent --tui

The doctor command checks provider authentication, SurrealDB readiness and schema, workspace writes, tool policy, Bubblewrap, and advertised code runtimes before the interactive agent starts.

Use the real interface

Move from architecture to an inspectable run.

Open the complete command reference, configure a provider, and launch all five UIntellAgent workspaces.