Tools are the agent's actions. All tools implement the Tool ABC from navi/tools/base.py.
navi/tools/)Registered in build_default_registries() as builtins. Never removed on hot-reload.
| Tool | Name | Description |
|---|---|---|
WebSearchTool |
mcp:navi-web:web_search |
DuckDuckGo search |
WebViewTool |
mcp:navi-web:web_view |
Fetch and render a URL |
FilesystemTool |
filesystem |
Read/write/list/copy/grep/diff local files (path restrictions via config) |
HttpRequestTool |
mcp:navi-web: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 exec and SCP file transfer; connection pool keyed by session ID |
ImageViewTool |
image_view |
Load image from path/URL → resize to 1024px, convert to JPEG, return 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 |
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 |
McpTool (navi-3d) |
mcp:navi-3d:compile_scad |
Compile an OpenSCAD script into a binary STL file |
McpTool (navi-3d) |
mcp:navi-3d:lint_scad |
Lightweight OpenSCAD source linting before STL compilation |
McpTool (navi-3d) |
mcp:navi-3d:render_stl |
Render preview PNG images from an STL file (up to 3 views) |
McpTool (navi-web) |
mcp:navi-web:web_search |
Web search (SearXNG primary, DDG fallback, Brave tertiary) |
McpTool (navi-web) |
mcp:navi-web:web_view |
Open a URL in a headless browser and return clean readable text |
McpTool (navi-web) |
mcp:navi-web:http_request |
Raw HTTP request (GET/POST/PUT/PATCH/DELETE) |
McpStatusTool |
mcp_status |
Check connectivity and list tools for configured MCP servers |
ReflectTool |
reflect |
Self-reflection and analysis |
ScheduleRecallTool |
schedule_recall |
Schedule a headless callback for the current session (once/recurring/immediate) |
ManageRecallTool |
manage_recall |
Cancel, skip, or list scheduled recalls for the current session |
tools/*.py)Written manually or via create_mcp_server. Auto-discovered at startup.
_ 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.
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.
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: booloutput: str — always a string; LLM sees thiserror: 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)navi/tools/loader.py)load_tools_from_dir(tools_dir) returns LoadResult(loaded, errors).
Load order:
name, description, parameters, execute).Tool subclasses).Errors are isolated per file — one broken file does not prevent others from loading. Errors are logged and returned in LoadResult.errors.
reload_tools tool calls ToolRegistry.reload_user_tools(tools_dir):
_builtin_names.load_tools_from_dir.New tools become available from the next user message (tool schemas are built at run_stream() entry, not during execution).
New capabilities are added as MCP servers using create_mcp_server. The server scaffolding includes:
mcp-servers/{name}/.server.py entrypoint with stdio transport.mcp_servers.d/{name}.json.reload_tools or server restart.The agent should call tool_manual("create_mcp_server") before using it for the first time.
Both are per-session, backed by the PostgreSQL KV-store (session_store table) and survive server restarts.
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.
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.