localharness
A Rust-native agent SDK for Google's Gemini API.
Streaming text, custom tools, safety policies, hooks, background triggers, MCP bridge, context compaction -- one crate, zero external binaries. Compiles to native (tokio) and wasm32 (browser).
Quick start
use ;
async
[]
= "0.10"
= { = "1", = ["macros", "rt-multi-thread"] }
Get an API key from Google AI Studio.
No Python, no Go binary, no harness process -- cargo build and you have an agent.
Features
- Streaming. Independent cursors for text, thoughts, and tool calls -- safe to consume concurrently.
- Tools. 15 built-in tools (filesystem, shell, image gen, sub-agents, inter-agent RPC, in-browser Rust compiler) plus
ClosureToolfor custom tools. MCP stdio bridge for external tool servers. - Hooks and policies. Six hook points. Deny-by-default policy engine with
allow,deny,ask.workspace_only()sandboxes file tools. - Triggers. Background tasks that inject prompts on a schedule or condition.
- Wasm. Same
Agentloop compiles towasm32-unknown-unknown. File tools use OPFS. Onlyrun_commandand MCP are native-only. - Multimodal. Images, PDFs, audio, video via
Media/Partwith zero-copybytes::Bytesstorage.
Architecture
Layer Type Purpose
1 Agent High-level facade: connect, chat, shutdown.
2 Conversation / ChatResponse Stateful session, multi-cursor streams.
3 Connection Transport abstraction (swap backends).
aux Filesystem Pluggable FS for file tools (Native / OPFS / custom).
Cargo features
| Feature | Default | Description |
|---|---|---|
native |
yes | Tokio runtime, run_command, MCP stdio bridge, NativeFilesystem. |
wallet |
no | secp256k1 keypair, BIP-39, on-chain registry client. Works on every target. |
browser-app |
no | In-browser IDE as a wasm cdylib (wasm-pack). Enables wallet transitively. |
Built-in tools
Default config exposes the read-only subset; CapabilitiesConfig::unrestricted() enables all 15.
| Tool | Mode | Description |
|---|---|---|
list_directory |
R | Sorted children with name, kind, size. |
view_file |
R | UTF-8 read with optional line range; 256 KiB cap. |
find_file |
R | Glob-matched recursive name search; 1000-match cap. |
search_directory |
R | Regex content search with optional file glob; 500-match cap. |
create_file |
W | Atomic write via tempfile + rename; refuses to overwrite. |
edit_file |
W | Exact substring replace (or replace_all); atomic write. |
delete_file |
W | Remove file or directory (recursive). |
rename_file |
W | Rename/move; atomic on native. |
run_command |
W | Shell exec, 30s default / 600s max timeout. Native only. |
generate_image |
W | Image model call; returns base64 + MIME. |
ask_question |
I/O | No-op default; register a custom impl for interactive UI. |
start_subagent |
spawn | One-shot subagent with isolated context. |
call_agent |
RPC | Inter-agent message by subdomain name. |
compile_rustlite |
exec | Compile Rust-subset source to wasm and run it in-browser. |
finish |
term | Terminate turn + capture structured output. |
Custom tools with the same name as a built-in override it.
Examples
use ;
use json;
let weather = new;
let agent = start_gemini.await?;
use StreamExt;
let response = agent.chat.await?;
let mut tokens = response.text_stream;
while let Some = tokens.next.await
use ;
let policies = vec!;
// Or sandbox everything to a directory:
let agent = start_gemini.await?;
use every;
let watchdog = every;
use McpServerConfig;
let agent = start_gemini.await?;
Run in the browser
The same agent loop runs in a browser tab.
Live demo: localharness.xyz
&&
Links
docs.rs -- crates.io -- GitHub -- live demo