Home / Product / Agent-native surface

A coding agent learns the whole CLI in one call, not by scraping help pages.

hotato describe --format json walks the parser itself and emits a capability manifest: every one of the 72 top-level commands, their subcommands, each argument’s name, type, whether it is required, its default and its help, plus the documented exit codes. Generated from the parser, so the manifest and the flags move together.

bash
$ hotato describe --format json
Pure and deterministic: the same input produces the same manifest every time. Exit 0 means the manifest was printed.
  • 72 top-level commands
  • 174 including subcommands
  • schema_version 1

The manifest carries the loop, not just the flags.

Alongside the command tree it emits the tool version, a stability statement, the two named loops through the product, and the URLs of the JSON schemas its output validates against.

  • core_loop.

    Five steps from one recording to a CI gate, each with its command and its purpose. It is the same start-here block hotato --help prints.

  • deep_loop.

    The investigate-and-label path, for an agent working a call rather than a folder.

  • schemas.

    Five published schema URLs: the result envelope, the error shape, and the three counterexample schemas.

  • stability.

    The public commands are durable; hotato lab moves faster. Every command name that worked before 1.17 still runs unchanged.

describe --format json
"tool": "hotato",
"schema_version": "1",
"version": "1.20.0",
"stability": "...",
"core_loop": [ { "step", "command", "purpose" }, ... ],
"deep_loop": [ ... ],
"schemas": { "envelope", "error", ... },
"subcommands": [ { "name", "purpose", "args" }, ... ]
The keys of the manifest, in the order it emits them.

MCP

Fifteen tools over stdio, and one envelope shape to parse.

Everything, audio included, stays on your machine.

The three groups of tools hotato-mcp exposes
GroupToolsWhat they do
Scoring 1 voice_eval_run returns the identical JSON envelope the CLI emits, schema_version “1”.
Counterexample 3 Reduce a failing scenario to a smaller case that still fails, then re-check that case offline.
Fleet 11 Eight read and propose over a local workspace; three recompute inside a throwaway clone and hand the deploy decision back to you.

Every response, pure reads included, carries the same four-key control envelope, so an autonomous caller parses one shape: evidence_status, refusal_reason, artifact_digests, and pending_irreversible_action — the last naming the exact human-gated action still outstanding, such as a deployment approval.

bash
# zero-install
$ uvx --from "hotato[mcp]" hotato-mcp

# already installed?
$ python -m hotato.mcp_server

# register with every agent config surface the repo already carries
$ hotato init --agents
The console script lives inside the hotato distribution’s mcp extra, so the --from is load-bearing: uvx hotato-mcp without it looks for a PyPI package by that name and fails.

One command writes hotato into the config surfaces your repo already has.

init --agents adds a one-line registration to an AGENTS.md section, a Claude Code skill or CLAUDE.md section, a Cursor rule, and the .mcp.json server entry when that file exists.

It is idempotent and additive: delimited blocks are refreshed in place, every byte outside them is preserved, and a second run changes nothing. Only the outer key differs between clients — Claude Desktop, Cursor and the rest all take the same command and args.

Assert on the measurement inside a test you already have.

Installing hotato installs a pytest plugin through the pytest11 entry point. It adds one fixture and three flags and nothing else, so a plain pytest run behaves identically.

The hotato_score fixture scores a recording and hands back the same envelope the CLI emits, so your assertion is on the measured seconds rather than on a status string.

pytest --hotato-suite runs the bundled battery after your tests and fails the session on a regression, printing the failing events and their fix classes. Point --hotato-suite-scenarios and --hotato-suite-audio at your own labelled set to gate on that instead.

It depends on nothing beyond pytest; the scoring core stays stdlib-only.

test_calls.py
def test_call_yields(hotato_score):
    env = hotato_score(stereo="call.wav", expect="yield")
    assert env["summary"]["regression"] is False
    assert env["events"][0]["verdict"]["seconds_to_yield"] < 1.0
The fixture’s own docstring example, from hotato/pytest_plugin.py.