Skip to main content

Module tool_text

Module tool_text 

Source
Expand description

The one place each shared tool description is written (#590). The one place each shared tool description is written.

roteiro:ignore-file — this file is prose about the tools, and two of them are about intent debt: debt’s description has to name TODO/FIXME/HACK and todo!()/unimplemented!() stubs, and debt_density’s has to name the prose matches (“for now”, “deferred”, “tbd”) a reader might otherwise be surprised by. Scanned, those descriptions register as three markers the repository does not have. The same opt-out is on markers.rs, check_cli.rs and the tool-choice fixture, for the same reason: a file that documents a scanner is not a file that owes work.

§Why a module of string constants

Four tools are advertised on two surfaces: the served-chat registry in roteiro, and this crate’s MCP server. The prose was written twice, and nothing compared the copies — so they drifted. Measured when this module was introduced: sandbox_status differed by 363 bytes, sandbox_clear by 197, security_list by 55. A served model and an MCP client were told materially different things about the same tool, including sandbox_clear, the one tool on either surface that destroys anything.

A description is not decoration here. It carries the warnings that prevent the likeliest misuses — that no-analyzer-on-record is not a clean repository, that bytes.exclusive and not bytes.total is what clearing an image frees — so one surface quietly holding an older draft is a real divergence.

§What #675 removed, and the rule it used

This prose is the dominant cost of every tooled turn: measured on the 15-tool surface before the trim, rto_serve::advertised_system_prompt rendered 14,586 bytes of which 12,354 — 85% — were these constants, and they reach a local model a second time through its own chat template’s tool slot (#681), so this is the one lever that pays on both paths.

What went was the prose that restates a guarantee something else already upholds, on the surface where it is upheld:

  • The schema states it. sandbox_clear’s dry_run semantics and the consequence of naming neither scope are in its everything/dry_run argument descriptions, which go out beside this text on both surfaces. Two tools also declared the absence of an argument (“No project argument”, “Takes key and nothing else”) beside a rendered signature that already showed what they take — and one of those two had gone stale, because context had since gained project.
  • The code refuses it. sandbox_clear’s three store-integrity refusals (a registered box, an unrecognised store entry, an index row pointing outside the root) are rto_exec::sandbox_store’s, each with its own test, and each reaches the caller as an error rather than as prose read beforehand.
  • The result body says it. no-analyzer-on-record carries rto_exec’s NO_RESULT_REASON, and check’s not-run carries not_run_reason with no report at all — read every time, where a description is read once.
  • The system turn says it. search’s “read the snippet, then explain is rto_serve::advertised_system_prompt’s grounding rule, stated once for every tool.

What stayed is what nothing but the words upholds: look before you delete, quote freed_bytes, escalate a complete: false retention, config_secrets is not a secret scanner, a truncated findings page hides only the least severe. Those were left even where they are long, because no measurement in this repository can yet say what a model loses without them — see #675.

§Why the cut is 14% and not the 59% #675 hoped for

Because most of what the rule above marks cuttable is already pinned by a test that was written on purpose, and each pin encodes a decision this issue has no standing to reverse:

phrasepinned bythe decision behind it
limit is 1-n … no unlimited settingevery_limit_tool_advertises_the_bound_it_enforces, both surfaces#393: “a model reads the description even when it does not validate against the schema”
It needs no limit / COUNTS, NEVER FINDINGSsecurity_status_advertises_no_bound_on_either_surface, security_status_states_why_it_needs_no_bound#402: a schema that disagrees with the clamp
DIFFERENT REQUESTSthe_mutating_tool_states_its_obligations_where_a_model_reads_them, and its served twinADR-0014 v1.6: the obligations that “do not survive living in a doc comment”
THREE statesare ALWAYS presentsecurity_status_description_says_what_ready_has_checked, both surfaces#464: a host missing both assets and binary must not be two round trips
carries NO reportrather than report zero findingssecurity_list_description_refuses_the_clean_readingthe never-run reading, refused where a model reads it

Every one of those is duplication with a schema, a refusal in code, or a result field — and every one was put there knowing that, on the stated ground that a model reads this string and may act before it reads anything else. So the honest reading of #675 is not “the prose is bloated” but “the prose is the same fact stated in three places, and the repository has already decided it wants it stated in all three.” Recovering those bytes is a different piece of work from shortening: it means moving the shared statements to the one-per-server places that already exist — crate::mcp’s instructions and rto_serve’s system turn, where #599’s working-tree caveat already lives — and re-pointing five tests at the new home. That is a design change, and it needs the interpretation measurement #675 describes, because it trades “every tool says it” for “the server says it once”.

§Why the MCP side still repeats the text

It should not have to, and this is the closest the framework allows. rmcp’s #[tool(description = …)] is parsed by darling into a String, so it takes a string literal and rejects a path: description = SANDBOX_STATUS fails to compile with “Unexpected type path. Nor can the served side simply read the MCP surface, because serve does not imply mcp — a serve-only build has no MCP module to ask.

So the constant here is the source, roteiro uses it directly, and the literal mcp.rs is forced to carry is compared against it by both_tool_surfaces_describe_a_tool_the_same_way. One authority, one mechanically-checked copy — rather than two copies and a hope.

Ungated on purpose: a serve build without mcp needs these too.

Constants§

CHECK
check.
CONFIG_SECRETS
config_secrets.
CONTEXT
context.
COUPLING
coupling.
DEBT
debt.
DEBT_DENSITY
debt_density.
EXPLAIN
explain.
LIST_PROJECTS
list_projects.
LIST_TOOL_CLASSES
list_tool_classes — the index that keeps a withheld class discoverable.
PATH
path.
SANDBOX_CLEAR
sandbox_clear — delete cached images; the one tool that changes anything.
SANDBOX_STATUS
sandbox_status — what the machine-global sandbox image store holds.
SEARCH
search.
SECURITY_LIST
security_list — stored findings, with the run evidence behind them.
SECURITY_STATUS
security_status — readiness, in two separately scoped halves.

Functions§

for_tool
The description for name, or None for a tool this module does not own.