InitOrigin

01 / runtime · Rust 1.95 · Apache-2.0

io-harness

An embeddable agent runtime for Rust: any task, any provider, in your own process — with a permission boundary, a sandbox, and a durable trace you own. It is a library and nothing else; io-cli is one program built on it.

Embeddable, not hosted

Add it as a crate and call it in-process. No binary to install, no daemon, no UI, no account and no telemetry — the default build compiles no optional dependency at all.

Durable by the step

After every completed step the trace, the budget draw and a checkpoint commit in one transaction. A crash resumes the whole tree without re-running steps or double-charging.

Any provider

OpenRouter, Anthropic and OpenAI over the crate's own HTTP+SSE client, one Compatible provider for any OpenAI-shaped endpoint, 21 vendor presets, and fallback between them.

The boundary, traced

Layered, deny-first rules over read, write, exec and network. Every refusal is in the trace, attributed to the rule and the layer that produced it.

A durable conversation about one repository

src/main.rs
use io_harness::{ApproveAll, OpenRouter, Policy, Session, Store};

let provider = OpenRouter::from_env()?;
let store = Store::open("runs.db")?;

let policy = Policy::default()
    .layer("app")
    .allow_read("*")
    .allow_write("src/*")
    .deny_read("secrets/*")
    .allow_exec("cargo test*")
    .deny_exec("cargo publish*");

let mut session = Session::open(&store, "/path/to/repo")?;
let turn = session
    .turn("the test suite is failing; why?", &provider, &store, &policy, &ApproveAll)
    .await?;

println!("{}", turn.reply.unwrap_or_default());

Releases and stability

Nowio-harness on crates.io. io-cli as checksum-verified binaries on every GitHub Release — macOS, Linux, Windows, and it pins the harness release it was built against.
Pre-1.0A minor release may change what a session looks like. Every one of those is in CHANGELOG.md, and a configuration file written for an older release keeps working.
1.0When the owner says so, and not before. Until then CONTRACT.md is what a script may depend on: the argv surface, the exit codes, the configuration keys and the paths io writes.

What arrives with the crate

Orchestration loop

Observe, reason, act, check, stop — driven by a TaskContract or by a conversation.

Permission boundary

Layered, deny-first rules over read, write, exec and network. Every refusal is in the trace, attributed to the rule and the layer.

Human approval

Approve, deny, or defer past the end of the process and resume on a decision made later.

Plan gate

The agent reads, writes nothing, and exits only through an ordered plan you approve, correct or cancel.

Command execution

The project’s own build, test, lint and package-manager commands, checked on the whole argv and never as a shell string.

Containment

Commands run inside the sandbox backend the host offers, writing to the workspace and nowhere else, with per-host egress.

Execution sandbox

Model-produced code in an ephemeral workdir, with caps that kill rather than throttle and network denied by default.

Environment scrub

The harness’s own provider credentials are removed from every contained child, on every rung. A named variable survives only because the contract declared it.

Verification

Any language’s own test command, a second model against a rubric, or no gate at all.

Structured output

OutputSchema demands a shape of the final answer — a closed JSON Schema subset, validated here whatever the vendor did with it.

Budgets

Steps, wall-clock and token spend, from one ledger a whole tree of agents shares and no child can raise.

Durable runs

Trace, budget draw and checkpoint commit in one transaction after every completed step. A crash resumes the whole tree.

One driver per run

Every run and resume takes a lease; a second driver is refused by name before it can interleave its steps into the trace.

Composition and the mailbox

Nested sub-agents over a shared workspace, inherit-and-narrow. Every agent has an address, and siblings send findings exactly once.

Context and memory

Per-turn assembly to a stated budget share, compaction, invalidation, and durable memory kept by evidence rather than recency.

Accounting

Input, output, cache-read, cache-write and reasoning tokens per call, with latency and TTFT; cost derived on read from a price table you own.

Observability

An observer called as the run happens, a recorded provider that replays identically, an in-crate eval suite, and OTLP spans behind otel.

Extensibility

The Tool trait in-process, MCP over stdio and streamable HTTP, and markdown skills.

Reach

A browser under the policy, LSP navigation, provider-executed web search, documents, images and fixed-argv git.

Which model a run asks

NativeOpenRouter, Anthropic and OpenAI, over the crate’s own HTTP+SSE client.
CompatibleAny OpenAI-shaped endpoint from a base URL, an auth style, a key and a model.
13 hosted presetsGroq · xAI · Mistral · DeepSeek · Together · Fireworks · Cerebras · Perplexity · Gemini (compat) · Moonshot · Zhipu · Qwen · MiniMax
8 local runtimesOllama · llama.cpp · vLLM · LM Studio · LocalAI · Jan · SGLang · KoboldCpp
RoutingEscalate after repeated gate failures, downshift while the change is small, and refuse to start when the primary reports it is unreachable.

Platform support

macOSNative, sandbox-exec. Egress scoped to the proxy’s address exactly.
LinuxNative chain: Landlock, bwrap, namespaces, floor. The Landlock rung scopes egress to a port.
Windows · defaultJob Object — memory, CPU, process count, tree kill. Resources only: no filesystem or network boundary, and the proxy is advisory.
Windows · opt-inAppContainer inside a Job Object: writes confined to the paths the run resolved. Egress is the capability — all of the network, or none.
Portable floorWhatever the host allows, recorded as the floor. What a run reports about its boundary is probed, not assumed.

Feature flags

Everything below is off by default, and the default build compiles no optional dependency at all. The last four add no crate — they are features because a build that did not ask for a browser, an outbound telemetry writer or a door onto its own tools should not compile one.

media

Images to providers that accept them; BMP, TIFF, ICO, TGA and PNM converted to PNG at the door.

documents

Umbrella over the five below.

xlsx

Spreadsheet read, generate, and a single-cell edit that keeps the rest of the workbook.

docx

Word read and generate. No in-place edit, deliberately.

pptx

PowerPoint text extraction. Read-only; there is no writer.

pdf

Generate, extract text, watermark, and fill AcroForm fields by name.

barcode

Barcode and QR decoding from an image. No encoder.

browser

Driving an already-installed browser over a pipe, under the run’s own policy. No debugging port.

otel

Exporting a run as OpenTelemetry spans over OTLP/HTTP. Structure and numbers, never transcript content.

mcp-server

Serving this crate’s own tools over MCP on stdio, under its policy, gate and trace.

codeact

One contained Python program in place of a chain of calls, run by a host interpreter that is found rather than downloaded.

(none)

The default build: the loop, the boundary, the sandbox, the providers, the store and the trace, with no optional dependency compiled at all.

It runs your toolchain

Not a set of parsers: a shipped table mapping a marker file to that ecosystem's own commands, every one of them overridable in io.toml. Markers are tried in order and the first match wins. Each row also carries install, build, lint, format and run.

Cargo.toml

cargo test

deno.json

deno test

package.json

<bun|pnpm|yarn|npm> test

go.mod

go test ./...

pyproject.toml

uv run pytest

pom.xml

mvn -B test

build.gradle

gradle test

mix.exs

mix test

Gemfile

bundle exec rake test

composer.json

composer test

Package.swift

swift test

CMakeLists.txt

ctest --test-dir build

*.csproj

dotnet test

Makefile

make test

Measured cost

Numbers this repository has actually measured, on an Apple M1 in release. None of them is a gate: no test asserts a duration, because a duration asserted on a CI runner is a flake waiting to be written.

5.832 msRemoving one session of 1,000 steps from a store — and a sweep of ten sessions is ~4–5× cheaper than ten deletions.
1.106 msRanking a turn’s memory recall at the default 64 entries — linear in entries, flat in the recall table.
0.965 msA capped memory write that evicts, at 64 entries; ~73 ms at 4,096, which is why the cap is the operator’s.
1.75–2.55 msConverting an image at the door on a 512×512 image. A pass-through is 0.01–0.14 ms.
303.8 ms savedStarting a read before the completion ends, on a 400 ms window and a 300 ms read.
0.677A whole live run’s cache hit rate over six calls: 5,430 cache-read tokens on every step after the first, against a prompt that grows. A longer run of the same shape reports less.

Guides

Twenty-six pages, one per capability, each carrying the limits that capability actually has.