InitOrigin
io-cli · Apache-2.0 · open source

An agent that shows its work.

io-cli is a terminal agent that shows you what it is allowed to do, what it is spending and what it refused — while it works. io-harness is the embeddable Rust runtime underneath it. Both are Apache-2.0, both run on your own provider keys.

Every artifact is checked against SHA256SUMS before it is unpacked

io-cli · ~/scratchpad/demo-run3 · run 165done · 39s
The billing test suite has one failing test. Find the root cause, fix it in the source rather than in the test, and run the suite again to confirm all five tests pass.
· thought · 12.4s · 21 tok
List . · 3 entries · ~0ms
Search billing · 3 hits · ~0ms
List billing · 2 entries · ~0ms
List tests · 2 entries · ~0ms
Read billing/windows.py · ~0ms
Read tests/test_windows.py · ~0ms
· thought · 1.6s · 97 tok
· a sandbox was created · macos-sandbox-exec
Run · python unavailable · ~37ms
no python on PATH. This machine cannot run that command; try another, or carry on without it.
· thought · 3.8s · 385 tok
Run · python3 exit 1 · ~102ms
..F..
FAIL: test_heartbeat_run_collapses_to_one_window
AssertionError: 6 != 1
· thought · 1.7s · 81 tok
Edit billing/windows.py · edited · ~0ms
billing/windows.py · +1 -1 · edit_file
@@ -33,7 +33,7 @@
35 last = merged[-1]
36 - if window.start < last.end:
36 + if window.start <= last.end:
37 merged[-1] = Window(last.start, max(last.end, window.end))
· a sandbox was created · macos-sandbox-exec
Run · python3 exit 0 · ~62ms
..... Ran 5 tests in 0.001s OK
· thought · 13.4s · 371 tok · confirms it once more
Run · python3 exit 0 · ~57ms
..... Ran 5 tests in 0.001s OK
Fixed. The failing test was test_heartbeat_run_collapses_to_one_window, and the root cause was in merge_windows in billing/windows.py:42: the merge condition was window.start < last.end, so end-to-start touching windows (a 10-second heartbeat ending exactly when the next starts) were not collapsed.
· thought · 1.8s · 41 tok
Changed it to window.start <= last.end so touching windows merge into one. The suite now passes all 5 tests (python3 -m unittest discover -s tests → OK).
· run 165 · 9 steps · 11 tool calls · 85,694 tok · 51% cached · $0.0036 · 39s · exit 0
>
ready · deepseek/deepseek-v4-flash-0731 · openrouter39s
9 steps · 85.7k tok · ctx 37% · $0.0036 · boundary verified · / for commandsworkspace · workspace-write/macos-sandbox-exec

License

Apache-2.0

Core

Rust 1.95+

Pricing

Starts at ₹0

Keys

Keys stay local

Currently shipping

One runtime. One terminal on top of it.

We build the load-bearing layer and give it away. What you build on top is yours.

io-harness

on crates.io

The base. An embeddable agent runtime for Rust. You hand it a contract — the task, the workspace it may touch, and what it may read, write, run and dial — and it runs the loop and hands back an outcome.

  • One line in Cargo.toml: cargo add io-harness. No daemon, no account, no telemetry
  • OpenRouter, Anthropic and OpenAI natively, plus 21 OpenAI-shaped presets — 8 of them local runtimes
  • Every step, refusal and budget draw in a SQLite trace you own

io-cli

terminal

The terminal agent built on it. Every finished line goes into the terminal’s own scrollback; two sticky rows say what is happening now, what it has spent, and what it is allowed to do.

  • A write stops the run and shows the diff: y, a or n, then Enter — answered where it was asked
  • The posture is on the footer, and Shift+Tab changes it from the next turn
  • /resume reopens a session and answers whatever its last run stopped on

01 — harness

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.

02 — harness

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.

03 — harness

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.

04 — harness

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.

05 — cli

It never takes your terminal

No alternate screen and no mouse capture, in any mode, behind any flag. Your terminal's search, selection and tmux copy-mode keep working, and a test fails the build if that changes.

06 — cli

Approvals in place

A write stops the run and shows the diff it proposes. Answer y, a or n and confirm with Enter, where it was asked — so a letter inside a sentence cannot decide a write. Allow for this session remembers that act on that target.

07 — cli

Your key, never on screen

The wizard verifies a key against the live endpoint, writes the file at mode 0600, and writes no key at all when the provider's own environment variable is already set.

08 — cli

Spend, and whether it worked

/cost commits the money and the token split by run, session, model and day; /stats commits the outcomes, first-try counts, gate failures and latencies. Nothing is estimated.

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());

Thirty-six commands, in four groups

ioWith no subcommand, opens an interactive session in this repository
/modelChange the model the next turn is sent to — this session only
/resumeReopen an earlier session and answer whatever its last run stopped on
/statusCommit the whole session state into the scrollback: policy layers, sandbox backend, caps, budgets, connections

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.

India first

Built here. Priced here.

Most agent tooling is priced in dollars and tested only on gigabit English. We start from the other end: a student in Coimbatore on shared wifi, a four-person team in Indore on a ₹3,000 budget, a bank in Mumbai whose code cannot leave the building.

01 — Rupee-native

Billed in rupees, UPI at checkout. No FX markup on a dev tool.

02 — Thin-pipe tolerant

A stopped run is resumable: /resume answers what it stopped on and carries on from that step, not from the top of the turn.

03 — Indic in the loop

Prompt and eval packs that hold up on Hindi, Tamil and code-mixed English — being built now, in the open.

04 — Data stays home

Run fully local, or self-host in an Indian region. DPDP-aware defaults from day one.

Pricing · in ₹, not converted

Free is not a trial.

Connect your own providers and use everything. Apache-2.0, self-hostable, no seat count, no sign-up wall, no telemetry.

  • Bring your own keys — any provider, including local models
  • Unlimited sessions on your own machine
  • The full io-harness runtime, embeddable in your own code
  • A layered permission boundary and a SQLite trace of every run
  • Community support in GitHub Discussions

Will Free get worse when the paid plans ship?

No. Nothing that works today moves behind a paywall. Paid plans are hosting and team features, not the runtime.

Do I need an io account?

Not for Free. Install, add your provider key, run. No sign-up wall.

Are model costs included?

On Free you pay your provider directly — we never mark up tokens. Managed inference is what the Go plan adds.

Install

One command, on any of the four platforms.

Both scripts pick the right build for your machine, verify it against the published SHA256SUMS before unpacking, and install into a directory you own — no administrator rights, and no edit to your shell profile or PATH. The tap and the bucket live in this repository rather than in two of their own, which is why brew tap and scoop bucket add name a URL. There is no crates.io publish: Rust 1.95 or later to build from source.

macOS · Linuxcurl -fsSL https://raw.githubusercontent.com/initorigin/io-cli/main/install.sh | sh
Windowsirm https://raw.githubusercontent.com/initorigin/io-cli/main/install.ps1 | iex
Homebrewbrew tap initorigin/io-cli https://github.com/initorigin/io-cli brew install initorigin/io-cli/io
Scoopscoop bucket add io-cli https://github.com/initorigin/io-cli scoop install io
From sourcegit clone https://github.com/initorigin/io-cli cargo build --release · Rust 1.95+
cargo installNot a path — there is no crates.io publish. The channel is the GitHub Release
IO_VERSION · IO_INSTALL_DIRA specific version, and somewhere other than ~/.local/bin or %LOCALAPPDATA%\io\bin
aarch64-apple-darwinmacOS, Apple silicon · sandbox-exec
x86_64-apple-darwinmacOS, Intel · as above
x86_64-unknown-linux-muslLinux, static · Landlock, bwrap, namespaces, floor
x86_64-pc-windows-msvcWindows · Job Object, AppContainer opt-in
SHA256SUMSEvery artifact is checked before it is unpacked
io upgradePrints the command for the way you installed it. No auto-update, no version check

Thirty-six commands, four groups

Everything you can type.

Grouped by what you are doing rather than by which part of the harness answers, and each group is capped at ten. Eleven of them run while a turn is in flight and the rest are refused — the rule is what a command does, not how harmless it looks.

the session

/clear · /resume · /fork · /profile · /contain · /setup · /exit

this turn

/model · /effort · /undo · /plan · /steer · /compact · /image · /copy · /copy diff · /commit

inspect

/help · /status · /context · /expand · /fleet · /skills · /cost · /stats · /store · /export

configure

/config · /theme · /remember · /memory · /mcp · /provider · /plugin · /gates · /import

Shift+TabChange the permission posture, from the next turn
Esc EscRewind the last turn: its files, its memory, the conversation head
Ctrl+FThe tree of children this turn has spawned, and what it costs
Ctrl+TCommit the last step’s full detail into the scrollback
--plainNothing turns, nothing moves; every state change committed as text
io exec "<goal>"One goal to completion, no terminal interaction · --json
io resumeCarries on a run parked on a question, a plan or an interrupted call
io acpThe Agent Client Protocol on stdio, for Zed or a JetBrains IDE
io mcp · plugin · config · skillThe same words from a shell as from the composer
exit 0 1 2 3 4 6ok · failed · refused · ceiling · paused · unverified

What arrives with the crate

The runtime under both of them.

io-cli is one program built on io-harness. This is what the crate itself arrives with — the same boundary, ledger and trace whether a turn came from a terminal, an editor or a CI job.

Permission boundary

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

Containment

Commands run in the host’s own sandbox backend, writing to the workspace and nowhere else, with per-host egress.

Durable runs

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

Budgets

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

Verification

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

Composition

Nested sub-agents over a shared workspace, inherit-and-narrow — and every agent in the tree has an address.

Accounting

Token split, latency and TTFT per call; cost derived on read from a price table you own. An unpriced model makes a total a floor.

Extensibility

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

Reach

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

Native providersOpenRouter · Anthropic · OpenAI, over the crate’s own HTTP+SSE client
13 hosted presetsGroq · xAI · Mistral · DeepSeek · Together · Fireworks · Cerebras · Perplexity · Gemini · Moonshot · Zhipu · Qwen · MiniMax
8 local runtimesOllama · llama.cpp · vLLM · LM Studio · LocalAI · Jan · SGLang · KoboldCpp
Your toolchaincargo · deno · node · go · python · maven · gradle · mix · bundler · composer · swift · cmake · dotnet · make

Get the launch note.

One email when io-harness reaches 1.0 and when the Go plan opens. Nothing else.