A coding agent you can rebuild

oino is a Rust agent core with extensions as WASM components. Write tools and providers in any language that compiles to wasm32-wasip2, embed the runtime in your own app, or just use the CLI.

curl -fsSL https://oino.dev/install.sh | sh
src/lib.rs
// an oino extension: one file, any language that builds a WASM component
use oino_extension::prelude::*;

#[derive(Default)]
struct Hello;

#[derive(Deserialize, JsonSchema)]
struct HelloArgs { name: String }

impl Extension for Hello {
    async fn init(&'static self, cx: &mut Init<Self>) -> Result<()> {
        cx.tool(
            Tool::new("hello")
                .description("Greets a person by name")
                .args::<HelloArgs>()
                .run(|_ext, args: HelloArgs, _cx| async move {
                    Ok(ToolResult::text(format!("Hello, {}!", args.name)))
                }),
        );
        Ok(())
    }
}

oino_extension::export_extension!(Hello);

Build for wasm32-wasip2, run oino -e ./acme.hello, and the hello tool is live in every client.

One loop in the middle, everything else attaches

A prompt goes into a small core, loops through the model and the tools, and leaves as action. Providers, commands, panels and whole feature sets snap on around it as sandboxed components, written in whatever language you like.

How a request moves through oinoClients (terminal UI, ACP for editors, JSONL RPC, or embedded in your app) send a prompt into oino-core. The request loops around the core, through the model providers (Anthropic, OpenAI, OpenAI-compatible gateways, Google or your own) and the extensions snapped on around it (WASM components written in any language), and leaves as action: edits, commands and the answer.ClientsTUIoino in a terminalACPZed and other editorsRPCJSONL over stdioEmbeddedoino-core in your apppromptProvidersAnthropicOpenAIOpenAI-compatibleGoogleyour providermodel streampermission gateRustslash commandsTypeScriptpanelsGosubagentsRustyour toolany languageextensions: WASM components on the ringoino-coreActionedits, commands, the answerHow a request moves through oinoClients (terminal UI, ACP for editors, JSONL RPC, or embedded in your app) send a prompt into oino-core. The request loops around the core, through the model providers (Anthropic, OpenAI, OpenAI-compatible gateways, Google or your own) and the extensions snapped on around it (WASM components written in any language), and leaves as action: edits, commands and the answer.ClientsTUIACPRPCEmbeddedProvidersAnthropicOpenAIOpenAI-compatibleGoogleyour providerpermission gateRustslash commandsTypeScriptpanelsGosubagentsRustyour toolany languageoino-coreActionedits, commands,the answer

What you get

Small core, components everywhere

The agent loop, sessions, the built-in tools and compaction live in oino-core. Providers, commands, panels, permission gates: all of it is WASM components the host loads at startup. A crashing extension cannot take your session down, and every capability it touches is granted in its manifest, nothing more.

Concepts
what lives where
# in oino-core
agent loop, sessions, compaction
read write edit bash grep find ls

# loaded as components
providers, commands, panels, gates

Extensions in any language

The contract is the WIT package oino:extension@2.0.0. Use the Rust guest SDK (cargo add oino-extension), or build the same world from Go, TypeScript, Python or anything that compiles a component. One command builds, one flag loads: oino -e ./your-package.

Extensions
bash
cargo add oino-extension
cargo build --target wasm32-wasip2
oino -e ./your-package

Embed it

Nineteen crates on crates.io. Services::create, AgentSessionRuntime::create, and you have the agent loop, tools, sessions and streaming events inside your own program. Prefer process isolation? Drive oino --mode rpc with the typed client. Same contract, either way.

Embedding the SDK
main.rs (excerpt)
let services = Services::create(ServicesOptions {
    cwd,
    agent_dir,
    /* … see the embedding guide */
}).await?;

let runtime = Arc::new(
    AgentSessionRuntime::create(services, SessionOptions::default()).await?,
);

Every client shape

Interactive terminal UI. Print mode for scripts, JSON events for pipelines, JSONL RPC for apps, and Agent Client Protocol for editors: oino --mode acp works in Zed today.

Clients
bash
oino                                 # terminal UI
oino -p "Summarize this repository"  # print: one answer, then exit
oino --mode json "List the crates"   # JSON event stream
oino --mode rpc                      # JSONL protocol on stdio
oino --mode acp                      # Agent Client Protocol

Bring your own models

Anthropic, OpenAI, OpenAI-compatible gateways and Google Gemini ship as components. Point models.json at any gateway, or write a provider component and register it alongside the rest.

Providers and models
~/.oino/models.json (excerpt)
{
  "providers": {
    "my-gateway": {
      "baseUrl": "https://llm.example.com/v1",
      "api": "openai-completions",
      "apiKey": "MY_GATEWAY_KEY"
    }
  }
}

Built with oino

UniPi

A full desktop and phone coding app built with oino end to end. One runtime, one set of extensions, both form factors. Read its code as a reference.

Runtime
embedded oino-core wiring and the RPC client
Sessions
the session tree, settings screens, panels and dialogs
Form factors
desktop, and the phone app driving the same runtime