Newer
Older
navi-1 / docs / tools.md

Tool System

Tools are the agent's actions. All tools implement the Tool ABC from navi/tools/base.py.

Two tiers

Built-in tools (navi/tools/)

Registered in build_default_registries() as builtins. Never removed on hot-reload.

Tool Name Description
WebSearchTool web_search DuckDuckGo search
WebViewTool web_view Fetch and render a URL
FilesystemTool filesystem Read/write/list local files (path restrictions via config)
HttpRequestTool http_request Generic HTTP client (GET/POST/etc.)
CodeExecTool code_exec Execute Python in a subprocess sandbox
TerminalTool terminal Run shell commands (command allowlist via config)
SshExecTool ssh_exec SSH into remote hosts; connection pool keyed by session ID
ImageViewTool image_view Load image from path/URL → returns base64 for multimodal LLM
TodoTool todo Per-session task checklist (set/update/read)
ScratchpadTool scratchpad Per-session named working notes (write/append/read/clear)
ReloadToolsTool reload_tools Hot-reload user tools without server restart
WriteToolTool write_tool Write a new user tool file and reload immediately
ListToolsTool list_tools Return the live tool list from registry
ToolManualTool tool_manual Return manuals/{name}.md or auto-generate from schema
MemoryTool memory Unified memory tool: save, search, and forget facts
SpawnAgentTool spawn_agent Spawn an isolated subagent (blocking). Optional profile_id selects another profile; omitted means parent profile
SwitchProfileTool switch_profile Switch the active profile for a session
ListProfilesTool list_profiles List all available profiles
ShareFileTool share_file Copy an existing local file into session files and return a download link
ContentPublishTool content_publish Register an existing session file for inline viewing in chat
Model3DTool model_3d Compile an OpenSCAD script into a binary STL file
ScadLintTool scad_lint Lightweight OpenSCAD source linting before STL compilation
Render3DTool render_3d Render preview PNG images from an STL file (up to 3 views)
DeleteToolTool delete_tool Delete a user tool file
TestToolTool test_tool Run a user tool and verify its output
McpStatusTool mcp_status Check connectivity and list tools for configured MCP servers
ReflectTool reflect Self-reflection and analysis

User tools (tools/*.py)

Written by the agent via write_tool or manually. Auto-discovered at startup.

  • Files starting with _ are ignored.
  • tools/enabled.json — list of user tool names to include in all profiles automatically.
  • tools/_template.py — canonical format reference (not loaded).

Currently present: get_current_datetime.py, gmail.py, weather.py.


Tool formats

Module-level format (preferred for user tools)

name = "my_tool"
description = "What it does and when to use it — be specific."
parameters = {
    "type": "object",
    "properties": {
        "param": {"type": "string", "description": "..."}
    },
    "required": ["param"]
}

async def execute(params: dict) -> str:
    # Return a plain string on success.
    # Raise an exception to signal failure.
    return "result"

No classes, no module-level print(). The loader wraps execute in a Tool subclass automatically.

Class-based format (built-in tools)

from navi.tools.base import Tool, ToolResult

class MyTool(Tool):
    name = "my_tool"
    description = "..."
    parameters = {"type": "object", "properties": {...}, "required": [...]}

    async def execute(self, params: dict) -> ToolResult:
        return ToolResult(success=True, output="result")

ToolResult fields:

  • success: bool
  • output: str — always a string; LLM sees this
  • error: str | None — included in output on failure via to_message_content()
  • metadata: dict — internal hints (e.g. is_image: True → triggers image injection into context)

Tool loading (navi/tools/loader.py)

load_tools_from_dir(tools_dir) returns LoadResult(loaded, errors).

Load order:

  1. Try module-level format (checks for name, description, parameters, execute).
  2. Fall back to class-based (scans for Tool subclasses).

Errors are isolated per file — one broken file does not prevent others from loading. Errors are logged and returned in LoadResult.errors.


Hot-reload

reload_tools tool calls ToolRegistry.reload_user_tools(tools_dir):

  1. Drops all tools that are NOT in _builtin_names.
  2. Re-runs load_tools_from_dir.
  3. New tools registered without server restart.

New tools become available from the next user message (tool schemas are built at run_stream() entry, not during execution).


Self-extension via write_tool

WriteToolTool validates the code before writing (checks for the 4 required definitions). On success:

  1. Writes the file to tools/{name}.py.
  2. Adds the name to tools/enabled.json.
  3. Calls reload_user_tools() — tool is registered immediately.

The agent should call tool_manual("write_tool") before using write_tool for the first time — the manual at manuals/write_tool.md has the full format reference and a complete example.


Scratchpad and Todo

Both are per-session, stored in-memory keyed by current_session_id.

Scratchpad — named sections for working notes within a task. Operations: write, append, read, clear. Subagents get isolated scratchpads (unique UUID-based session ID in run_ephemeral()).

Todo — checklist for tracking multi-step plans. Operations: set (replace all tasks), update (set status of one task), read. Statuses: pending, in_progress, done, failed, skipped.


Image tool flow

When image_view succeeds, it returns ToolResult with metadata={"is_image": True, "base64": "..."}.

The agent detects this and appends a synthetic user message with the image to session.context (but not session.messages). This makes the image visible to the next LLM call without polluting the display history.

See sessions.md for the dual-buffer design.