▞ jazzdocsblogpersonas
github

Tools

This page explains what a tool is, what the risk tiers mean for you, and how to add your own.

For the exact list of tool names, see Tools reference. For the machinery, see Internals → Tools & approval.


What a tool is

A tool is a typed function the model can call. Each one declares a name, a Zod schema for its arguments, a risk level, and an implementation. The model never runs code — it emits a request to call a named tool with arguments, and Jazz validates, gates, and executes it.

flowchart LR
    M["Model"] -->|"tool call:<br/>name + JSON args"| V["Schema validation"]
    V --> G["Risk gate"]
    G --> E["Execution"]
    E -->|"formatted result"| M

    classDef gate fill:#f9a03f,stroke:#b3541e,color:#1a1a1a
    class G gate

Tools come from four places:

SourceScopeExample
Built-inalways availableread_file, execute_command, web_search
Skillswhen the agent has skillsfind_skills, load_skill
MCPper agent, from configured serversmcp_notion_search
Customper agent, defined by youwhatever you declare

An agent’s config lists which tools it may use. Omitting a tool is the strongest control there is — an agent without execute_command cannot run shell commands no matter what policy is set.

MCP tools, along with a few other situational categories (background jobs, reminders, wake triggers, workspace, peers), are also deferred: the model sees their names and a one-line summary every turn, but not their full schema until it calls search_tools. Built-in tools like read_file and execute_command are always sent in full. See Design decisions.

Built-in and custom tools are validated against their own schema before the handler runs. MCP tools are the exception: their schemas are translated from the server’s JSON Schema, and that translation is lossy enough that enforcing it locally would reject calls the server accepts. Their arguments are forwarded as-is and the server validates them. The risk gate is unaffected either way — it runs on every tool.


Risk tiers

Every tool declares a risk level. One dial (--approval-policy, or autoApprove: in a workflow) decides what runs without asking.

TierToolsCount
read-onlyReads, searches, web requests20
low-riskmanage_todos, update_work_state, spawn_subagent, plus opt-in memory/reminders/web_app7
high-riskAnything that mutates: writes, deletes, moves6
unknownexecute_command — classified per command, then judged by the tier1

⚠️ low-risk is narrower than most people expect. It is not “moderately dangerous things”. Email, calendar, and Obsidian are skills that shell out via execute_command, so they are gated at unknown and a low-risk run declines anything the classifier does not call inspect-only or minor. See Tools reference.

When a tier is too coarse

Rather than raising the whole tier, narrow the exception:

ControlWhereScope
Per-tool allowlist“Always approve this tool” in an approval promptthis session
Per-command allowlistautoApprovedCommands in ~/.jazz/config.jsonpersisted, execute_command only
Toolset trimmingthe agent’s configpermanent, strongest
// ~/.jazz/config.json — let one binary through, keep the tier low
{ "autoApprovedCommands": ["himalaya", "khal"] }

Command matching uses a parsed key (binary + first subcommand), never a raw string prefix, so approving git status does not also approve git status && rm -rf /.


Gated tools act in two phases

A high-risk tool does not act when called. It returns a description of what it would do — for edits, an actual preview diff — and only after approval does Jazz invoke the hidden execute_* half of the pair.

This is why you see the exact diff before a file is written, and why an unattended run behaves identically to an interactive one apart from who answers.


Adding your own

Custom tools (declarative)

Define a tool in an agent’s config with customTools — a name, description, parameter schema, and a record or command handler. No code, no rebuild. Full schema and validation rules: Configuration → customTools.

MCP servers (reuse an ecosystem)

If the capability already exists as an MCP server, that is almost always the better route — you get its tools without writing anything. See Integrations → MCP.

Built-in tools (contributing)

Adding a tool to Jazz itself means implementing the Tool interface and registering it in a category. Gated tools use defineApprovalTool to produce the propose/execute pair. See Code map, and update Tools reference — a test fails if the docs and the registry drift.


machine-readable: /docs/concepts/tools.md · /llms.txt · /llms-full.txt