koa-cli · 1.0 release candidate

A coding agent for the terminal, built with AI.

koa-cli reads your repo, edits files, runs your tests and shows every change as a diff you approve before it is written. One engine behind a full-screen TUI, a headless JSON mode, and an editor protocol. Written by one person working with AI agents, and used every day on the workspace it came from.

$ koa
~25klines of Python in src/
2,664tests passing across 111 files
213commits to koa-cli since 22 May 2026
7provider adapters + fallback chain
18CLI subcommands, 21 slash commands

Counted from the repository on 7 Oct 2026, bot-generated commits excluded. Full suite on a clean checkout: 2,664 passed, 14 skipped, 2 failing (both koa-proxy header tests, tracked).


Two failing tests. One approved diff. Green.

These are unedited captures of the real TUI from 7 Oct 2026, run against a small demo repo (a token-bucket rate limiter with two planted bugs). The model was GLM-4.6 through the routing gateway. Nothing was mocked or retouched.

koa-cli splash screen: empty chat with starter suggestions, the half-block koala mascot, and a sidebar showing model, task, provider, cwd, branch, token counts, and permission mode

Start. Sidebar shows the routed model, task type, git branch, tokens and permission mode. The koala reacts to agent state.

01 · ASKS BEFORE RUNNING
Confirmation modal for the bash tool showing the command python -m pytest -q

Shell commands need a keypress: enter once, t always for this tool, a yes to all, esc deny.

02 · SHOWS THE DIFF
Confirmation modal for edit_file showing a unified diff that caps the token refill at capacity and changes > to >=

The agent found both root causes. The edit arrives as a diff, and nothing touches disk until you approve it.

Finished session: collapsible tool cards for bash, read_file and edit_file with timings, an explanation of both root causes, and the sidebar tool list

Finished. Tool cards collapse and carry timings; the summary names both causes. I ran pytest myself afterwards: 2 passed.


More than a chat box in a terminal

Everything below exists in the code and is covered by tests. Nothing here is a roadmap item.

Safe by default

The agent proposes; you decide. Each layer can be tightened independently.

Three permission modes

default asks, accept-edits auto-approves writes inside the working directory plus safe shell, plan removes every mutating tool from the schema and ends with an approve/continue gate. Cycle with ctrl+o.

Anchored edits

read_file emits content anchors; edit_file validates against them, so a stale view of a file cannot be silently overwritten. Falls back to normalized and fuzzy matching before giving up.

Lifecycle hooks that can veto

Six events: PreToolUse, PostToolUse, Stop, SessionStart, SessionEnd, UserPromptSubmit. A hook that exits 2 blocks the call and its stderr becomes the reason shown to the model. Reads Claude Code–style settings.json.

Containment flags

--restricted drops the shell, disables MCP and confines writes. --bare and --safe-mode strip hooks, plugins, memory and config for troubleshooting. Secrets are redacted from hook payloads and session exports.

Loop guard + budget gate

Caps on turns and repeated calls. A client-side budget gate degrades the model one step at warn, aborts with exit 3 at blocked, and --max-budget-usd caps a single session.

Customer-safe profiles

koa client <profile> loads one TOML: fixed model, spend cap, read-only HTTPS tools only, no shell, no memory. The loader fails closed: a profile that violates an invariant refuses to start.

Context that scales

Long sessions and big repos without the usual token bleed.

Subagents

The task tool spawns a child engine with its own history; only the final report returns. Several read-only explore agents run in parallel.

Auto-compaction

Past 70% of the served model's window, older turns are summarized and the last ten are kept verbatim. The saved session is untouched.

Project rules

Merges .koa-cli/rules.md, AGENTS.md, CLAUDE.md, .cursor/rules and parent directories in a fixed precedence under a size budget. koa rules prints exactly what was loaded and what was dropped.

Parallel reads, capped output

Consecutive read_file/grep/glob/web_* calls run concurrently. Oversized tool output is trimmed head and tail before it reaches the model.

@-mentions and images

@path autocompletes with Tab and is inlined at send. ctrl+v attaches a clipboard image through a vision route.

Long-term memory

A local Markdown memory with search and write tools, injected as a budgeted index. Fully opt-out with one env var.

Extensible

Plugs into the ecosystem instead of replacing it.

MCP client + OAuth 2.1

stdio and Streamable HTTP servers in three scopes (user, project, local). Remote servers authenticate via discovery, dynamic client registration and PKCE (RFC 9728, 8414, 7591, 8707).

Lazy MCP servers

deny_tools/allow_tools globs and "lazy": true. Measured on my own setup: 108 → 71 tool schemas, about 24K → 17K base tokens per call.

Skills, commands, agents as files

SKILL.md, .koa-cli/commands/*.md and .koa-cli/agents/*.md, and it also reads the .claude/ equivalents. A file agent can only narrow the parent's tool allowlist, never widen it.

Plugin API

Providers, tools and hooks register through one registry; built-ins and plugins are peers. Adding a provider means registering two conversion functions.

7 provider adapters

Anthropic, OpenAI-compatible, Gemini, GLM, MiniMax, Ollama and OpenRouter, plus a fallback chain and a routing gateway that picks a model per task type.

Reasoning kept out of answers

A streaming ThinkStripper handles tags split across chunks and routes thinking to a dimmed, collapsible channel instead of the reply.

Lives where you work

Same engine, different front ends.

Full-screen TUI

Textual-based: token streaming, markdown and syntax highlighting, collapsible tool cards, a live task panel, multi-line prompt, ctrl+k palette, three themes.

ACP server

koa acp speaks the Agent Client Protocol over stdio for Emacs agent-shell and Zed: permission dialogs with inline diff, session resume, and reads of unsaved editor buffers.

Native in Emacs

Runs in an eat terminal with truecolor and mouse, with commands to send a region or buffer to the prompt.

Sessions as data

Append-only JSONL. --resume, sessions export (redacted, portable JSON), sessions fork --at-turn N, and background sessions you can attach to later.


The same agent as a pipe

koa run streams newline-delimited JSON events and ends with a typed result, and exits with a code a CI runner can branch on. Below, a real run: the agent reads the file, answers, and emits a success result. In JSON mode the shell tool is denied unless --yolo is passed.

Terminal running koa run --format json: NDJSON events for init, turn_start, usage, tool_start read_file, assistant_message, and a final result with subtype success
ExitMeaningresult.subtype
0oksuccess
2tool, loop or schema errorerror_schema_validation · error_loop_guard · error_stall
3budget blockederror_budget
4provider exhausted after retrieserror_provider
130Ctrl-Cnone

--json-schema forces the final answer to conform to a schema and retries with the validation error as feedback. --input-format stream-json accepts one message per line on stdin for multi-turn automation.

The /help screen listing slash commands: model, models, task, agent, provider, memory, tools, skills, recipe, theme, yolo, mode, cwd, sessions, clear, pr, palette, history, tasks, quit

21 slash commands. The interface is currently in Spanish because it was built for my own workspace; localization is on the list.


Getting sturdier every month

Commits touching koa-cli per month, straight from git log (auto-generated fan-out and checkpoint commits excluded). The September spike is the productization push; October is a partial month, seven days in.

How it gets built. I work with AI agents, but the process is mine: each change starts as a plan item, gets an isolated git worktree, lands through a pull request, and passes a pre-push review before merge. The log shows it: several tasks went through two or three rounds of P0/P1 review fixes before they landed.

koa-cli is also the tool that does a share of that work, so every rough edge costs me time first. That is the fastest feedback loop I know for making a developer tool better.


koa-cli is in private beta. It is not on PyPI yet and the source is not public. I am happy to demo it live or walk through the code. Write to [email protected].

The public project from the same studio is koalabs-ai/koa (MIT): a personal workspace for working with AI agents on your own machine. More at koalabs.ai.