capo-agent 0.10.0

Coding-agent library built on motosan-agent-loop. Composable, embeddable.
Documentation

Capo

A Rust-native coding agent CLI. Single binary, library-first, focused on shipping correct code through a small set of well-understood tools.

$ capo

Install

cargo install capo-cli

The crate is published as capo-cli (the name capo was already taken on crates.io); the installed binary is still capo.

Or grab a pre-built binary from the latest GitHub Release.

Quickstart

export ANTHROPIC_API_KEY=sk-ant-...
capo                  # interactive TUI
capo -p "fix the failing test in src/auth/mod.rs"   # print mode
capo -c               # continue the most recent session in this directory
capo --resume         # pick a recent session

Capo reads AGENTS.md / CLAUDE.md from the current directory upward, so per-project context is automatic.

Supported providers

Capo dispatches to one of six providers, selected by --provider <name> or model.provider in ~/.capo/agent/settings.toml (legacy settings.json is still read when no TOML file exists).

provider Backend Auth
anthropic Direct Anthropic API ANTHROPIC_API_KEY env, or auth.json::anthropic.key
claude-code Shells out to the claude CLI (Claude Code subscription) The claude CLI handles its own auth
codex-cli Shells out to OpenAI's codex exec --json The codex CLI handles its own auth
openai Direct OpenAI API OPENAI_API_KEY env, or auth.json::openai.key
gemini Direct Google Generative AI REST API GEMINI_API_KEY env, or auth.json::gemini.key
gemini-cli Shells out to Google's gemini CLI The gemini CLI handles its own auth

Set the model name with --model <name> or model.name in settings; capo passes the name through to the provider's API verbatim.

Tools

Tool What it does
read Read a file. Always allowed.
grep Regex search over file contents. Always allowed.
find List files/directories by glob. Always allowed.
ls List a directory's entries. Always allowed.
write Create or overwrite a file. Prompts unless allowlisted.
edit Patch an existing file via unique-string replacement. Prompts unless allowlisted.
bash Run a shell command via PTY. Prompts every time unless allowlisted.

Configure allowlists in ~/.capo/agent/permissions.toml. See docs/superpowers/specs/2026-04-23-capo-design.md §4 for the full permission model.

Commands & editor

Inside the TUI:

  • Type / for the command palette — /help, /quit, /new, /model, /compact, /resume.
  • Type @ to fuzzy-search and insert a project file path.
  • A line starting with ! runs a shell command and sends its output to the agent; !! runs it and shows the output without sending.
  • --resume (or /resume) opens an interactive picker of recent sessions for the current directory.
  • Attach an image: type /image <path> (one or more paths, optional trailing text). Most modern terminals also let you drag an image file into the prompt — they paste the file's path as text, which Capo auto-detects when it appears at the start or end of your message. Supported: PNG, JPEG, GIF, WEBP. Max 5 MiB per image. Works against any vision-capable provider (Anthropic, OpenAI, Gemini).
  • Cumulative session tokens render in the footer (Σ N↑ M↓) when ui.footer_show_cost = true in ~/.capo/agent/settings.toml. Token-only — no price estimation. Providers that don't surface token counts (CLI-shell providers) show tokens: unavailable.
  • Type /settings to open an inline editor for settings.toml. Edit any of 13 fields across 5 sections; navigate with /, edit with Enter, toggle bools with Space, save with F2, cancel with Esc. Save tries the rebuild first — if the new settings fail to apply (e.g. invalid provider), settings.toml stays unchanged on disk.
  • Reduce transcript noise with [ui] collapse settings (edit via /settings): hide_thinking_blocks, collapse_tool_output_by_default, collapse_tool_args_max_lines, collapse_history_after. All apply to rendering only — the agent still sees full content.
  • Press Ctrl+E to globally expand all collapsed blocks in this session (toggle).
  • Press F3 to enter history-nav mode: ↑↓ or j/k move selection, Space toggles the selected block's collapsed state (also works on default-collapsed blocks), gg jumps to top, G to bottom, Esc exits. Selection marker is in the left gutter; nav-hint row appears above the footer while active.
  • Thinking / reasoning blocks (Claude extended thinking) render as dim italic in the transcript. hide_thinking_blocks = true (the default) keeps them invisible; flip to false in /settings to reveal.
  • Permission modes. Set how capo prompts for tool calls. Three modes: bypass (auto-allow everything except hard-blocked paths), accept-edits (auto-allow write/edit, prompt bash), prompt (current default — prompt write/edit/bash unless allowlisted). Hard-blocked paths (.git/**, .env*, **/.ssh/**) enforce in every mode. Switch sources, highest priority first:
    • CLI: capo --mode bypass (or --mode accept-edits / --mode prompt)
    • ~/.capo/agent/settings.toml: [permissions] default_mode = "bypass"
    • TUI runtime: Shift+Tab cycles modes (session-only, doesn't write to disk)
    • RPC: Command::SetPermissionMode { mode }
  • Footer indicator shows current mode: [bypass] (red), [accept-edits] (yellow), [prompt] (dim).
  • The legacy --dangerously-allow-all flag now also works in TUI mode (silently aliases --mode bypass). v0.9 ignored it outside --json.

JSON / RPC mode

Capo can speak structured JSON instead of running its TUI, for use from scripts and IDE plugins:

  • One-shot: capo -p "<prompt>" --json runs a single turn and streams the result as line-delimited JSON. See docs/json.md.
  • Persistent: capo --rpc runs a long-lived server speaking bidirectional JSONL over stdin/stdout. See docs/rpc.md.
  • Attachments: in print and JSON mode, repeat --image <PATH> on the command line (e.g. capo -p "describe these" --image a.png --image b.jpg --json). In --rpc mode, send attachments inside Command::SendUserMessage's attachments array — see docs/rpc.md for the wire form.

Skills

Markdown files in ~/.capo/agent/skills/<name>/SKILL.md (or flat <name>.md) become discoverable skills. They follow the Agent Skills standard:

---
name: rust-error-triage
description: Use when debugging Rust compile errors or runtime panics
---

Body content (loaded by the model via the `read` tool when the description matches).

Per-project skills live at <repo>/.capo/skills/.

Extensions

Capo loads third-party extensions from ~/.capo/agent/extensions.toml. An extension is any executable that reads a JSON event on stdin and writes a JSON action on stdout — capo spawns it fresh per event.

Three hook events:

  • session_before_switch — before /new, /resume, /model, /clone, /fork. Extension can cancel to block the action.
  • before_user_message — before every Enter press, gets the user's text and attachments. Extension can cancel to block the turn or transform_text to rewrite it.
  • command — when the user types a slash command an extension has registered. Extension can reply with a Notice or send a synthesized user message.

Manifest example:

[[extensions]]
name = "dirty-repo-guard"
command = "~/.capo/agent/extensions/dirty-repo-guard.sh"
hooks = ["session_before_switch"]

Run capo and type /extensions to see what's loaded.

See examples/extensions/ for working scripts and docs/superpowers/specs/2026-05-21-capo-v0.7-design.md for the full design.

MCP

Capo speaks the Model Context Protocol. Servers configured in ~/.capo/agent/mcp.toml are connected at startup; their tools become available as <server>__<tool> (rendered as <server>:<tool> in the UI):

[servers.github]
transport = "stdio"
command = "github-mcp-server"
args = ["--scope", "read-only"]
env = { GITHUB_TOKEN = "${GITHUB_TOKEN}" }

Using capo-agent as a library

use capo_agent::{AppBuilder, Auth, Settings};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let agent_dir = capo_agent::agent_dir();
    let app = AppBuilder::new()
        .with_settings(Settings::load(&Default::default())?)
        .with_auth(Auth::load(&agent_dir)?)
        .with_builtin_tools()
        .build()
        .await?;

    let stream = app.send_user_message("list every .rs file in src/".into());
    use futures::StreamExt;
    futures::pin_mut!(stream);
    while let Some(_event) = stream.next().await { /* render UI events */ }
    Ok(())
}

See crates/capo-agent/examples/list_rust_files.rs for a runnable version.

Architecture

Three crates, all under crates/:

  • capo-tui — Elm-style MVU TUI runtime/rendering; consumes capo-agent UI event types.
  • capo-agent — coding-agent SDK; built on motosan-agent-loop.
  • capo — the binary you install.

Detailed design lives in docs/superpowers/specs/2026-04-23-capo-design.md.

License

MIT — see LICENSE.