-
Notifications
You must be signed in to change notification settings - Fork 18
Architecture
TinyAgents is a small, provider-neutral agent harness for Rust, plus a durable
typed state-graph runtime. It takes its shape from LangChain (models, tools,
middleware, structured output, streaming, usage/cost) and LangGraph
(START/END, nodes, conditional edges, channels/reducers, checkpoints,
interrupts, subgraphs, time travel), rebuilt as ordinary, typed Rust.
This page shows how the crates layer together.
| Crate | Path | Owns |
|---|---|---|
| Harness | crates/tinyagents-harness/ |
provider-neutral model calls, typed tools, middleware, structured output, streaming, usage/cost, retry/limits, cache, memory, sub-agents, steering |
| Graph runtime | crates/tinyagents-graph/ |
durable typed state graphs: START/END, nodes, edges, conditional routing, commands, Send fanout, reducers/channels, checkpoints, interrupts, subgraphs, child-task orchestration, streaming, observability, time travel |
| Registry | crates/tinyagents-registry/ |
named capability catalog (models, tools, agents, graphs, routers, reducers) that .rag binds by name |
Expressive .rag |
crates/tinyagents-language/ |
declarative, side-effect-free blueprints that compile into the same graph/harness types as hand-written Rust |
| Session | crates/tinyagents-session/ |
durable SQLite-backed session history and a run ledger, separate from harness and graph durability |
| Tracing | crates/tinyagents-tracing/ |
shared, feature-gated tracing macros used by the other crates |
There is no facade crate: a consumer depends directly on the crates it needs. See Quick Start for the dependency snippet and feature flags, and Capabilities for a full index of what each crate exposes.
tinyagents-tracing
^
|
tinyagents-harness --------+
^ |
| v
tinyagents-language tinyagents-session
^
|
tinyagents-graph
^
|
tinyagents-registry
tinyagents-tracing has no internal dependencies and compiles to no-op macros
unless the tracing feature is enabled. tinyagents-harness depends only on
tracing. tinyagents-language depends on harness (it compiles a .rag
blueprint into harness/graph types). tinyagents-graph depends on harness,
language, and tracing. tinyagents-registry depends on graph, harness, and
language, since it is the layer that binds a .rag blueprint's capability
references against real, registered Rust values. tinyagents-session depends
only on harness (for its sqlite feature) and tracing; nothing in harness
reads from session, and session is not required to run a harness or a graph at
all — it is a separate persistence domain for history and search.
Both tinyagents-graph and tinyagents-registry also depend on a vendored,
provider-neutral inference crate, tinyinference
(vendor/tinyinference/crates/tinyinference), and tinyagents-harness
depends on a vendored tool-schema crate, tinytools
(vendor/tinytools/crates/tinytools).
+-------------+ +-------------------------------------------+
| Application |------->| Capability Registry |
| Rust code | | models | tools | agents | graphs | routers |
+------+------+ +---------------------+---------------------+
| |
| v
| +-------------------------------------------+
+------------->| Durable Graph Runtime |
| typed state | nodes | edges | checkpoints |
+---------------------+---------------------+
|
v
+-------------------------------------------+
| Agent Harness |
| prompts | tools | middleware | usage/cost |
+----+--------------------------+-----------+
| |
v v
+------------------+ +------------------+
| Model Providers | | Typed Tools |
| OpenAI and | | local functions |
| compatible hosts | | external systems |
+------------------+ +------------------+
A graph node can call into the harness to run a model or a tool. The harness does not depend on the graph: it runs standalone as a single agent loop, or as one node's implementation inside a larger graph.
Optionally, a workflow can be authored as a .rag blueprint instead of Rust:
the blueprint compiles (lexer, parser, compiler) into a Blueprint, which the
registry binds by name into the same GraphBuilder/CompiledGraph and
harness types a hand-written graph would use. See
Expressive Language .rag.
Two composition features let larger systems be built out of the same typed pieces, rather than a separate execution model:
-
Sub-agents.
tinyagents_harness::subagent(SubAgent,SubAgentSession,SubAgentTool) wraps a whole harness agent as an ordinaryTool. A parent agent calling a sub-agent is just a tool call; the child run gets its ownroot_run_id/parent_run_idand its usage and cost roll up to the parent. See Harness. -
Subgraphs.
tinyagents_graph::subgraph(adapter_subgraph_node,shared_subgraph_node) embeds one compiled graph as a single node inside another. The embedded graph's checkpoints are namespaced under the embedding node id, so durability composes the same way state does. See Graph Runtime.
tinyagents_graph::recursion (RecursionPolicy, RecursionStack,
RunTree) tracks parent/child run lineage for both of the above and enforces
a depth limit, so a chain of sub-agents or nested subgraphs stays bounded and
observable rather than growing without a cap. It is a safety and
observability mechanism, not a distinct architectural layer.
The harness owns nondeterministic agent work:
- model request construction and provider adapter calls
- tool registration and execution
- middleware hooks, structured output strategy, streaming deltas
- provider error normalization, usage and cost records
- retries, limits, cancellation, cache, memory/embeddings
- sub-agents (
tinyagents_harness::subagent): an agent exposed as a tool, run as a child at depth+1, capped by a run-limit policy and reported through sub-agent lifecycle events - deterministic model and tool test doubles (
tinyagents_harness::testkit)
See Harness.
The graph owns deterministic state movement:
- typed state, reducers/channels, and updates
- nodes, static and conditional edges, commands,
Sendfanout - checkpoints, interrupts, time travel, topology export, run status, observability
- child-task orchestration (
tinyagents_graph::orchestration): typed task controls (spawn/await/cancel/status/list/steer, and similar) exposed as harness tools, so an orchestrator agent manages concurrent child tasks by a stable task id - subgraphs (
tinyagents_graph::subgraph): a node embeds anotherCompiledGraph
See Graph Runtime.
The registry owns named capabilities, letting Rust code and .rag blueprints
refer to a model, tool, agent, graph, or router by a stable name instead of a
process global. Entries describe capabilities well enough that a .rag
blueprint's references can be validated and bound before it ever runs. See
Registry.
.rag is a declarative, side-effect-free blueprint format. It cannot embed
arbitrary code; it can only reference capabilities by name, which the
compiler binds and validates against a registry. Pipeline:
.rag source -> lexer -> parser -> compiler -> Blueprint
-> bind_capabilities (registry) -> build_graph -> run to END
Each crate keeps its contract narrow:
- the harness calls providers and tools
- the graph moves typed state through explicit topology
- the registry binds names to capabilities
-
.ragdescribes workflow source, and lowers into the same graph/harness types a hand-written Rust caller would build directly
No layer bypasses another layer's policy, observability, or validation
boundary: a .rag-authored blueprint, a sub-agent call, and a subgraph all
pass through the same registry binding, run-limit, and event machinery as a
top-level, hand-written run.
Provider-neutral agent harness and durable state-graph runtime for Rust.
Getting started
Concepts
Modules
Providers
Contributing