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.
| Tool | Needs the small model | In a line |
|---|---|---|
ask | yes | A whole question about the code, answered with checked citations |
locate | yes | Where something is defined, by name or by description |
callers | yes | The call sites of a symbol, counted and checked not to be a namesake |
edit | yes | A small, mechanical change, returned as a diff |
read | no | Code by address: lines, a declaration, a key, an entry of a JAR |
outline | no | The shape of a file, a directory or an archive, before reading it |
search | no | Exact text or a regex across the repository |
changes | no | What a checkout, a commit or a range changed, by declaration |
history | no | The commits behind some lines |
replace_all | no | Find-and-replace across the repository, as a diff first |
forge | no | A 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:
| Address | Returns |
|---|---|
path:120-160 | those lines |
path:137 | the whole function round that line |
path#Name, path#Class.method | one declaration |
Name, Class.method | the declaration, found in the repository |
path | a small file whole, a large one as its outline |
docs/plan.md#Goal, package.json#scripts.build | a section of a document, a key of a config file |
lib/core.jar!org.demo.Shelf | a 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
search
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 aroutinetool.
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.