tool_manual: a manual the agent cannot reach is not a manual
tool_manual asked the filesystem for the exact string the model sent, then
fell back to registry.get(). The executor already tolerated the ways models
mangle MCP names; the tool that documents them did not, so the agent calling
mcp__navi-3d__compile_scad got a schema dump while manuals/compile_scad.md sat
there unread. Resolving a name now happens in one place — resolve_tool moved
out of the executor into navi/core/tool_utils.py — so a name that works when
the tool is *called* also works when it is *asked about*. A miss suggests the
closest names instead of "not found", and a tool that exists but is not enabled
for this profile says exactly that: documenting it is still the useful answer,
but the agent must not go on to call it. params["tool_name"] was also a crash
waiting to happen — KeyError with the key omitted, AttributeError on null or a
number — and now anything that is not a usable string means "no name given",
which returns the index of manuals grouped by source.

The generated manual now renders the whole schema. An array of objects showed
as "(array, optional)" with its item shape invisible, so a model that could not
see the fields guessed them; objects, array items, oneOf/anyOf branches, enums
and defaults are all spelled out now, depth-capped. The header names the source
(native / mcp__<server>__) and says the text is a parameter contract, not a
curated manual — otherwise a thin schema reads as "this tool is simple".

Then the manuals themselves. A manual is filed under the tool's own name, and
five of the sixteen were not: write_tool.md and write_mcp_server.md documented
tools that do not exist anywhere (the tools are reload_tools and
create_mcp_server), model_3d.md documented compile_scad, render_3d.md documented
render_stl, and write_context_provider.md documented no tool at all — it is a
guide, and now lives in manuals/guides/. The prompts pointed at the same wrong
names (tool_developer's system prompt, persona_navi_code, docs/context_providers),
so fixing the files without the callers would have moved the breakage rather
than removed it. On HEAD the probe was blunt: tool_manual("mcp__navi-3d__compile_scad")
returned None and the agent got the schema; now it returns the manual.

Nothing was enforcing any of this, which is how it drifted. tests/unit/tools/
test_manual_drift.py reads the real repository tree: every manuals/*.md must be
named after a tool that exists (built-ins and tools/*.py by their name
assignments, MCP tools by @mcp.tool(name=…) in the server sources and by the
mcp_servers.d groups, whose file name is the server name), every manual must be
reachable by both its bare name and its full MCP spelling, a guide must never
shadow a tool's name, and every manuals/<x>.md or tool_manual("x") cited in a
doc or a prompt must resolve. The next rename fails the suite instead of
quietly wasting a manual.

Finally, manuals for the built-ins the agent uses most — ssh_exec, todo, memory,
plan, filesystem, notify, code_exec — written from the current schemas and the
code paths that produce the errors, so the gotchas are the real ones (todo's
`done` validation is enforced; memory's `list` returns categories, not facts;
filesystem's `delete` removes a tree with no prompt). reload_tools.md absorbs
the file format from the deleted write_tool.md, which is where a self-extension
recipe belongs now.

1556 passed, 1 skipped. ruff delta zero.
1 parent 0619a88 commit 1d1103884f6e69fff116267f82b04d0664379a25
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 4 hours ago
Showing 29 changed files
View
docs/context_providers.md
View
manuals/code_exec.md 0 → 100644
View
manuals/compile_scad.md 0 → 100644
View
manuals/create_mcp_server.md 0 → 100644
View
manuals/filesystem.md 0 → 100644
View
manuals/guides/write_context_provider.md 0 → 100644
View
manuals/lint_scad.md
View
manuals/memory.md 0 → 100644
View
manuals/model_3d.md 100644 → 0
View
manuals/notify.md 0 → 100644
View
manuals/plan.md 0 → 100644
View
manuals/reload_tools.md 0 → 100644
View
manuals/render_3d.md 100644 → 0
View
manuals/render_stl.md 0 → 100644
View
manuals/ssh_exec.md 0 → 100644
View
manuals/todo.md 0 → 100644
View
manuals/write_context_provider.md 100644 → 0
View
manuals/write_mcp_server.md 100644 → 0
View
manuals/write_tool.md 100644 → 0
View
navi/core/registry.py
View
navi/core/tool_executor.py
View
navi/core/tool_utils.py
View
navi/profiles/tool_developer/system_prompt.txt
View
navi/tools/list_tools.py
View
navi/tools/tool_manual.py
View
persona_navi_code.txt
View
tests/unit/tools/test_list_tools.py
View
tests/unit/tools/test_manual_drift.py 0 → 100644
View
tests/unit/tools/test_tool_manual.py 0 → 100644