๐ฎ๐น zaino /หdzaiฬฏ.no/ ยท noun. backpack
An agent harness
you can carry.
Five providers, eight tools, subagents and MCP in one Go binary, and not an SDK in it. It asks before it writes or runs anything, and keeps every road a conversation ever took.
$ curl -fsSL https://raw.githubusercontent.com/zenodea/Zaino/main/install.sh | sh Go 1.26.5+ ยท lands in ~/.local/bin ยท --uninstall takes it back out
- The lid five hand-rolled clients
- Main compartment the turn loop
- Front pocket eight tools
- Haul loop one binary, no runtime
- The buckle asks before it acts
- Side pocket MCP, over stdio
- Reinforced base tested throughout
What's in the pack
The clients, the loop, the composer and the transcript are written in this repo, not wrapped from an SDK.
Packing list
- Streaming, and the turn loop that drives it
- Eight tools:
read write edit bash grep find ls fetch task, which hands work to a second agent- MCP servers, spoken over stdio
- Compaction when the context window fills
- Anthropic, Gemini, OpenAI, Grok & OpenRouter, hand-rolled
- Two frontends: full-screen TUI and a plain REPL
- A vim-style composer, and a walkable transcript
- Permissions, sessions, prompt recall
/rewindand/journey: the session as a tree, every branch kept- Images, attached with
@pathor read from disk - Prompt caching on Anthropic, marked by hand
- Config files under
~/.config/zaino, with profiles - Markdown rendering, wire logging
The plain REPL
A pipe is
a terminal too.
When stdin isn't a TTY, zaino skips the interface and reads lines: each one a prompt, slash commands included. Only the answer lands on stdout; the tool chatter, thinking and permission questions all go to stderr, so whatever you redirect stays clean.
# answers on stdout, everything else on stderr $ echo "say hi" | zaino $ echo "sum up this repo" | zaino > NOTES.md $ zaino -v < prompts.txt # one turn per line $
Tools
Eight tools, and one
that hands the work away.
Withhold one with -exclude-tools bash, hand out a subset with -tools read,grep, or turn the lot off with -no-tools. /tools lists what the model has.
- read
- write
- edit
- bash
- grep
- find
- ls
- fetch
- task
task: a second agent
It runs with its own conversation and hands back only what it concluded. A search that reads twenty files costs this conversation one paragraph instead of twenty file contents.
The child inherits the parent's gate, so it is not a way around a refusal: same policy, same approver. It cannot ask you anything itself, so the prompt has to carry everything it needs. Nesting stops two deep.
MCP servers plug in over stdio, declared in mcp.json. Their tools arrive named server__tool and ask for approval like anything else
that leaves the process.
fetch returns a page with the markup stripped. It leaves the
process too, so manual and accept-edits both stop to ask first.
Four pockets
Permission is a mode.
โงโฅ cycles it mid-conversation; -permission sets it
at the door.
manual
Ask before writing, running or fetching.
defaultaccept-edits
Edits go through. Still asks before running or fetching.
plan
Read only. Nothing written or run, but pages can still be read.
bypass
Everything goes through unasked.
on youOne rule the modes can't lift. Paths outside the working directory
are refused, not asked about. Symlinks are resolved first, so a
link pointing out of the tree is still out of the tree. -allow-outside is the only thing that moves it.
The journey
Nothing you tried
is lost.
/rewind takes the conversation up again from an earlier
turn: your prompt comes back to the composer to be changed and asked
again, and everything after it leaves the context. Nothing is deleted:
the turns you walk away from stay in the file, on a branch of their
own. The file has always been a tree.
/journey draws that file whole: every turn on every road,
the abandoned ones dimmed. Pick any stop, lit or not, and the context
is rebuilt as it stood there. A rewind walks back along the road you
are on; a journey can cross to one you left.
TRAIL MAP
THE OLDEST ATTEMPT KEEPS ITS LANE
Commands
Driving it
A line starting with / acts on the session instead of going to
the model. A prompt that merely starts with a slash
(/etc/hosts is wrong) is still a prompt, and the panel knows
it.
A command that takes a value and is given none asks instead of explaining:
it opens a list with what is currently in effect marked. Passing the value
outright (/effort low) skips it.
- /clear
- forget the conversation
- /model
- show or change the model
- /provider
- switch provider
- /effort
- show or set output effort
- /thinking
- show or hide the model's reasoning
- /system
- show, set, or drop the system prompt
- /profile
- switch to a named bundle of settings
- /config
- what the config files came to
- /compact
- fold the conversation into a summary
- /limit
- stop when the context passes a ceiling
- /rewind
- take it up again from an earlier turn
- /journey
- the tree of turns, every branch included
- /permission
- when tools stop to ask
- /tools
- list the tools the model has
- /usage
- token usage for this session
- /sessions
- pick up an earlier conversation
- /vim
- modal editing in the composer
- /bro
- say the last answer again, simply
- /help
- list the commands
- /quit
- leave zaino
Modal editing, on by default
The composer starts in insert, so nothing is different until you
press esc. Then motions, operators with counts, and a visual
mode the composer draws itself, since the text box underneath can't
show a selected range. -vim=false turns it off.
Walk the transcript
โj and โk move a bar through the transcript one entry at a time. With a tool call under the bar, โ opens the arguments it was called with and everything it returned. Typing hands the keyboard back.
The mouse is left to the terminal
Select and copy the way you do anywhere else; scrolling is on the
keyboard instead. -mouse gives the wheel to zaino, at the
cost of needing โง-drag to select.
/clear deletes nothing
A session is one append-only file of things that happened. What gets sent is worked out from that record, so clearing just marks where the context starts; the transcript before it stays readable.
Come back to it
-continue is the newest run from this directory; -resume takes any prefix of an id. The model, prompt,
effort and thinking come back as you left them.
Stopping, and leaving
esc stops a running turn, but only once vim has nothing else for it to do. โc stops it too; with nothing running it arms the quit and says so in the footer, and any other key stands it down.
๐
Pick it up.
$ curl -fsSL https://raw.githubusercontent.com/zenodea/Zaino/main/install.sh | sh