Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The tools

What your agent gets from Otōto over MCP, and what each is for. Every one also runs from a shell, as ototo <tool>, in the current directory.

ToolNeeds the small modelIn a line
askyesA whole question about the code, answered with checked citations
locateyesWhere something is defined, by name or by description
callersyesThe call sites of a symbol, counted and checked not to be a namesake
edityesA small, mechanical change, returned as a diff
readnoCode by address: lines, a declaration, a key, an entry of a JAR
outlinenoThe shape of a file, a directory or an archive, before reading it
searchnoExact text or a regex across the repository
changesnoWhat a checkout, a commit or a range changed, by declaration
historynoThe commits behind some lines
replace_allnoFind-and-replace across the repository, as a diff first
forgenoA merge request, a pipeline, a failed job’s log; with a forge plugin granted

The four that need the small model are offered only when one is set up; the rest work without (Quick start). How it works says what happens inside a delegated call.

ask

Hand over a whole question about what the code does: “how is auth wired into the router?”, “where is the retry count decided, and under what conditions?”. The small model explores and answers briefly, and every path:line it cites is checked against the files, with the code of the main ones attached. Seconds to minutes.

  • Several at once. Up to five independent questions go in one call (questions), and are answered side by side.
  • One thing per question. A long question in several parts is cut off more often than its parts asked apart.
  • It finds and explains; it does not decide. Ask where a value is set and what reads it, not what the fix should be: that is the agent’s to work out from the answer.
  • Read the footer. An answer that lists claims “Not backed by the cited code”, or says it was cut off, is the one to check before relying on it. The rest need not be read again.
ototo ask "which class validates a new pet?" --also "what page size lists owners?"

locate and callers

locate finds where something is defined or implemented, by its name or by a description (“the retry logic in the HTTP client”), and must cite a declaration. callers finds the usages of a function, method, type or field, each checked to be that symbol and not another of the same name, and returns the count with the citations; hint names the defining class or file when the name alone is ambiguous.

edit

Delegates a small, mechanical change: add a parameter and update the callers, fix the imports. It returns a unified diff and writes nothing unless the call says apply. With a check_cmd in the settings (a build or a type check), the small model tries its change against it before answering, and the verdict is in the reply. For a plain rename, replace_all is the tool: exact, instant, and no model.

read

Code by address, many addresses in one call:

AddressReturns
path:120-160those lines
path:137the whole function round that line
path#Name, path#Class.methodone declaration
Name, Class.methodthe declaration, found in the repository
patha small file whole, a large one as its outline
docs/plan.md#Goal, package.json#scripts.builda section of a document, a key of a config file
lib/core.jar!org.demo.Shelfa class in an archive, as its declarations; !META-INF/MANIFEST.MF any other entry

Up to 2,000 lines a call; a longer range is cut with a note saying where to continue. With a plugin for the file’s kind, path#name returns the thing as its tool evaluates it: a CI job with its extends merged, a dependency with its effective version (the plugins).

ototo read write_exceeded_line crates/printer/src/standard.rs:47

outline

The shape of code before reading it. A file gives every declaration with its line range; a directory or a glob (src/**/*Controller.java) each file’s length and top-level declarations; an archive its entries. It is how an agent chooses what to read, in place of ls and opening files.

It reads Java, Kotlin, TypeScript and JavaScript, Rust, Python, Go, C#, shell and SQL as their declarations, and Terraform, YAML, JSON, TOML, XML, properties, CSV, Dockerfiles, Makefiles and Markdown by their own names: a resource, a key, a column, a stage, a target, a heading.

ototo outline src/ui/control

Exact text or a regex across the repository: path:line:text for each matching line, 100 unless limit says otherwise, then the total, and where the rest are. fixed takes the text as it is, word whole words, ignore_case, and glob narrows it (src/**/*.ts, several comma-separated, !dir/** to leave one out). Ignored, binary and secrets files are skipped. An empty search says why: no file matches the glob, or none holds the text.

It is for a known string, identifier or message. For code you can only describe, ask or locate.

changes and history

changes is what the checkout changed since its base (the merge-base with the default branch), committed or not: each file with its added and removed lines and the declarations touched (changed Orders.place (12-48), added Orders.cancel). Or one commit, or a range. history is the commits behind path:10-40, path:25, path#Name or path, newest first, one line each. Between them they stand in for git diff, show, log and blame, and say it in declarations.

replace_all

Find-and-replace across the repository in one step: literal text, or a regex with ${1} groups; word, ignore_case and glob as for search. It returns the count in each file and a unified diff, and writes only with apply.

ototo replace max_columns_preview max_cols_preview --word

forge

The repository’s forge, through a plugin: with no arguments, the checked-out branch’s open merge request and its latest pipeline; change for one by number; pipeline for its jobs by stage; job for a failed job’s log, cut to what failed. It is offered only once a forge plugin is installed and granted (ototo plugins grant gitlab), since it reaches outside the machine.

Where a call works

Every tool takes root, to work in another git worktree of the repository or in a directory added to the session. Absolute paths inside one of those do the same without it.

Beside the tools

  • ototo digest -- <command> runs a build or a test command and prints the failures and the summary, not every line of progress; the exit code is the command’s.
  • ototo find "a few words" is the small model’s own first tool, on the command line: the repository’s declarations ranked against the words, for when the name is not known.
  • Routines (experimental, off unless routines = true): a job described once in a Markdown file, which the small model does with its read-only tools; the agent then gets a routine tool.

A shorter menu

Every tool’s definition is carried in the agent’s context on every turn. tools = "ask,read,search" in ~/.config/ototo/config.toml (or OTOTO_TOOLS) offers only those, and Otōto’s instructions then name only them.