The dashboard, and watching it work
Otōto logs every call on your machine, and three things read that log: a dashboard, a live tail, and a report to send when something goes wrong. None of it leaves the machine unless you send it.
The dashboard
ototo ui
serves a page at http://127.0.0.1:7777 (--port for another), and prints the link to open. It reads the log
file, not a running server, so it covers every session and every repository that logged to that file, and needs
nothing running but itself.
For a time range, a repository, a tool or a model, it shows:
- Totals: delegated and direct calls, the small model’s tokens in and out, what went back to your agent, and the model’s time (median and 90th percentile).
- Reliability: answers that finished and were not cut off, with what cut the others off (out of turns, out of tokens, repeating its calls, answered without finishing; more budget helps only the first two), citations dropped as unverifiable, build checks passed, and errors. No grade is given under twenty answers.
- Activity over time, delegated against direct, and latency of each delegated call over time, which shows when the model server was busy.
- By tool, by repository and by model: calls, errors, times, turns, tokens and reply size. Point Otōto at another model and it gets a row of its own to compare.
- What the small model did: its steps across all turns: its own tools, tools it made up (it has seen other
agents’
Grep,ReadandBashin training), turns it answered in prose, and calls it garbled, with the share of turns that went on those. A row opens to recent examples. - Recent calls, each opening to the question, the small model’s steps turn by turn, and the exact reply your agent got. Running now shows the calls in progress.
- Model servers: a probe of each (latency, the models it serves), in the order they are tried.
- Settings: the settings file’s path and what it says now, read again each time the page opens.
- Plugins: each one’s version, the files it reads, who signed it, and whether it loads. One can be switched off
or on, removed, or added from its
.wasmand signature, and only if a key you already trust signed it; trusting another key is never done from the page.
Light or dark, or following the system.
Who can open it
The log holds questions, code and replies, so the dashboard keeps to this machine:
- It listens on 127.0.0.1 only, and answers only requests addressed to 127.0.0.1 or localhost, so a web page whose name is pointed at 127.0.0.1 cannot read it through your browser.
- Its data needs a key, kept in
~/.ototo/ui.keywhere only you can read it, so another user of a shared machine gets nothing from the port. The linkototo uiprints carries the key after a#, which browsers never send to a server;ototo ui --linkprints it again, for a dashboard a service started. - Changes to plugins are accepted only from the page itself.
From another machine, tunnel to it, and open the printed link:
ssh -L 7777:127.0.0.1:7777 <host>
A live tail
ototo tail
follows every delegated call as it runs, from every session on the machine: its question, each turn of the small model (the tool it called, tokens so far, time), the claim check, and how it ended.
12:39:17 21572.1 ask start Which class validates a new pet, and what does it check?
12:39:22 21572.1 ask turn 1 find({"query":"validate new pet"}) · 1.6k tok · 4.7s
12:39:24 21572.1 ask turn 2 read({"addresses":["src/main/java/…/PetValidator.java"]}) · 3.8k tok · 7.1s
12:39:40 21572.1 ask turn 3 finish({"answer":"The class is PetValidator …"}) · 7.3k tok · 22.9s
12:39:40 21572.1 ask end 23.0s · 3 turns · 7.3k tok · ok
Your agent is told the same while a delegated call runs, when it asks for progress (Claude Code does): a notice
when it starts, then every few seconds the turns so far and the latest step (turn 5 · read src/lib.rs). When no
turn ends for 30 seconds, as when the model server is busy, it says so (waiting for the model's reply to turn 6, 4 min). That also keeps Claude Code from ending a long call that is still working.
From a shell, ototo ask, locate, callers and edit show the call on the terminal’s last line while it runs,
and clear it before the answer is printed:
(•) ask · gpu · 4 s · turn 2 · read src/cache/Store.kt#evict
The run log
~/.ototo/runs.jsonl: one line a call, from your agent’s sessions and from the command line alike. A line has the
kind of call, the repository, the session, the input, the small model’s steps, the reply (its first 6,000
characters), turns, tool calls, tokens, timings, citations kept and dropped, a check’s verdict, and whether an edit
was applied. It also names the Otōto that made the call and, for a delegated one, a short hash of the prompts and
tool descriptions the small model was given, so that two calls with the same hash had the same instructions.
The log is rotated at 20 MB, three old files kept, and the dashboard reads those too. run_log = "off" turns it
off, run_log moves it, and trace = "off" stops the live trace beside it: Settings.
A report to send
ototo report
writes one file for when something goes wrong: the version and the machine, what ototo doctor finds, the settings
with their credentials taken out (keys, headers, passwords in URLs), the log’s counts per tool for the last week
(--days), and its latest errors’ messages (--errors, 20 unless set). Not the questions, the code read or the
answers: --with-inputs adds each error’s input. The file is readable by you only, and nothing is sent: it is yours
to read and to send.
Across a team
The dashboard is one machine’s. For usage across many, Otōto sends counts, never questions, code or answers, to an OpenTelemetry collector of yours: Metrics and For organisations.