Build
Clients
The terminal UI, print and JSON modes, the RPC protocol, and ACP for editors.
Terminal UI#
oino with a terminal attached starts the interactive UI. Messages and files can be passed up front; @file arguments attach paths and images.
oino # new session
oino "Explain src/main.rs" # first message queued
oino @screenshot.png "What is wrong?" # attachments
oino -c # continue the last session hereThe screen is a transcript (markdown, syntax highlighting, collapsible thinking and tool output), extension widgets and panels, and a multi-line editor with history, kill ring, undo, @ path completion and / command completion. The footer shows tokens, cache and cost figures, context use, model, thinking level and extension status.
Input rules worth knowing: enter sends, and while the agent works it steers (delivered after the current tool call); alt+enter queues a follow-up; escape interrupts; escape escape opens the session tree; !cmd runs a shell command and adds its output to the context (!!cmd skips adding it). ctrl+l is the model picker, ctrl+p cycles scoped models, shift+tab changes the thinking level, ctrl+d quits.
Built-in slash commands: /new, /resume, /name, /session, /tree, /fork, /clone, /compact, /import, /copy, /export, /reload, /model, /thinking, /scoped-models, /settings, /hotkeys, /changelog, /login, /logout, /quit. Commands from extensions, prompt templates (/review style) and skills (/skill:<name>) appear in the same menu.
Print and JSON#
oino -p answers one prompt and exits; it is what scripts and CI call. When stdio is not a TTY the CLI switches to print mode on its own.
oino -p -- "- Summarize these points" # prompts starting with a dash need --
oino --mode json "List the crates" # same events as RPC, no command inputJSON mode emits the session event stream, one JSON object per line: agent_start, message_update, message_end, tool_execution_start, tool_execution_end, agent_settled, and so on. The shapes are the wire shapes of oino-ai.
RPC#
oino --mode rpc speaks JSONL on stdin/stdout: one JSON object per line. Commands carry an optional id and every command gets a response ({"id","type":"response","command","success","data"|"error"}); session events stream as they happen.
printf '%s\n' '{"id":"1","type":"prompt","message":"hello"}' | oino --mode rpcCommands: prompt, steer, follow_up, abort, new_session, get_state, set_model, cycle_model, get_available_models, set_thinking_level, cycle_thinking_level, get_available_thinking_levels, set_steering_mode, set_follow_up_mode, compact, set_auto_compaction, set_auto_retry, abort_retry, bash, abort_bash, get_session_stats, export_html, switch_session, fork, clone, get_fork_messages, get_entries, get_tree, get_last_assistant_text, set_session_name, get_messages, get_commands, clear_queue.
Oino extensions to the protocol, all prefixed _oino/:
| Command | Purpose |
|---|---|
_oino/hello |
capability handshake (advertise frontend capabilities such as images, panels) |
_oino/ui_snapshot |
current extension UI state (status, widgets, frame, panels, pending dialogs) |
_oino/navigate_tree |
move to another entry of the session tree |
_oino/set_label |
label an entry |
_oino/get_context_usage |
context window usage |
_oino/import_jsonl, _oino/export_jsonl |
session import and export |
Extensions talk to the user through extension_ui_request events: dialogs (select, confirm, input, editor, form, multiselect, approval, custom) expect an extension_ui_response with the same id; notify, setStatus, setWidget, setFrame, setTitle, panels and setPlan are fire and forget. Unknown methods may be ignored, so a minimal client can answer nothing and still work.
From Rust, oino-rpc's RpcClient and RpcBackend handle the framing and the handshake; from anywhere else, the format above is the whole protocol. oino serve (RPC over TCP with pairing) is specified but not implemented yet.
ACP#
oino --mode acp runs Oino as an Agent Client Protocol v1 agent on stdio (logs on stderr). Sessions, prompts with text and images, streamed message and thought chunks, tool calls with kinds, titles, locations and diffs, plans, usage and compaction notices all map to ACP; session/set_config_option sets the model and thinking level. Slash commands are published as ACP commands, approval dialogs become session/request_permission, and when the client advertises fs and terminal capabilities, file tools and bash run through the client.
Zed configuration:
{
"agent_servers": {
"Oino": { "type": "custom", "command": "oino", "args": ["--mode", "acp"], "env": {} }
}
}Any other ACP client works the same way. MCP servers passed in session/new are not forwarded to the MCP extension yet, and the refusal stop reason is never returned; the per-method gap list lives in the repository's developer docs.