Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tools: Overview

Tools are the agent’s hands. A tool is a capability the model can invoke mid-conversation, run a shell command, fetch an HTTP URL, open a browser, write a file, read a sensor. Every tool call is subject to security policy. Successful executions can include a tool receipt when receipts are enabled.

Tools are not to be confused with zeroclaw CLI subcommands. CLI commands are for operators; tools are for the agent.

An agent gets its tools through the skill, knowledge, and MCP bundles it references; see Agents for how bundles attach to an agent. For the turn-level path from provider tool call to approval, dispatch, receipt, observer event, and history entry, see Tool execution lifecycle.

Before adding a built-in tool or replacing one with an external integration, use the Built-In Tool Inventory to choose the smallest durable home. Working built-in integrations stay available until a replacement is real, documented, and independently reviewed; that replacement-first rule is the accepted RFC #6165 policy, recorded in the inventory’s Replacement-First Policy section.

Minimal and full tools

Configurations use full unless they select minimal: every built-in carried by this binary and allowed by its existing configuration, prerequisites and permission rules. Setup and config generation write optional = ["*"]. A file without [tools], or a [tools] section without optional, also loads full, so upgrading to v0.8.6 keeps existing tool availability. Existing explicit selections are preserved.

[tools]
optional = ["*"] # full; the default

Minimal is opt-in: eleven built-ins in Chat, or eight in Code/ACP, which retains its exclusion of persistent-memory tools. Chat’s eleven are shell, file_read, file_write, file_edit, glob_search, content_search, memory_recall, memory_store, memory_forget, web_fetch, and git_operations. Existing policy can narrow either catalog.

[tools]
optional = [] # minimal

For minimal plus selected extras, use their callable names:

[tools]
optional = ["calculator", "cron_list", "sessions_history"]

The wildcard is a union with named entries: ["*", "calculator"] has the same selection as ["*"], with no duplicate tool. Full is not a fixed tool count; configured integrations, runtime capabilities and policy determine the effective catalog. It does not enable every integration. Selecting a tool does not install a browser or vendor CLI, supply credentials, enable a disabled integration or grant permission. Full also preserves Code/ACP’s existing memory exclusion.

Selection happens before constructors run. An unselected tool contributes no schema or tool-catalog prompt text. Risk profiles, caller narrowing, approval, path/network policy and receipts still apply. Explicit MCP servers, skills, plugins and peripherals retain their existing activation and authority paths. Progressive schema disclosure is a separate feature, not part of these settings.

To select minimal, set optional = [] in [tools], or run:

zeroclaw config set tools.optional '[]' --no-interactive

Reload the daemon after changing selection. Config schema stays version 3. zeroclaw config migrate records optional = ["*"] for an existing file without [tools]; ordinary saves also retain selector intent.

Builds and upgrade path

ChannelCompiled capabilityRuntime selection
Release archiveStandard dist includes the native tools-compat adaptersFull by default; minimal and named extras work without another download
Desktop sidecarThe same target-resolved dist CLI, plus requested desktop featuresThe same minimal/full settings and prerequisites
Homebrew source buildDepends on the formula’s feature selection; a Cargo-default build omits native adaptersFull includes only the adapters the formula carries; use the standard source build below when it omits them
Docker dist imageStandard dist, including native adaptersBaked configs omit [tools] and load full, the default; set optional = [] for minimal

One release matrix has ten target legs, with unchanged archive names. Android is experimental and allowed to fail; publication requires the other nine targets. There is no second compatibility archive matrix or dedicated compat-tools image. The historical all-features Docker image remains broader than dist, including additional channels and hardware features.

dist includes tools-compat (tools-saas, tools-coding-cli, tools-external). dist-compat is a compatibility alias for the same build. Plain Cargo defaults remain smaller: custom source builds can omit adapters. A compiled-out external adapter named in optional gets a clear diagnostic; full selects only the adapters this binary carries and reports nothing for the rest. Enabled vendor/CLI sections retain their existing missing-feature diagnostic. Runtime configuration cannot add compiled-out code. Build the standard selection to recover it:

# From a source checkout; use the target you intend to run.
TARGET=x86_64-unknown-linux-gnu
FEATURES="$(cargo run --quiet --locked -p xtask --bin generate -- features --selection dist --target "$TARGET")"
cargo build --release --locked --bin zeroclaw --target "$TARGET" --no-default-features --features "$FEATURES"
# For a local Linux image, resolve features for its build target.
docker build -t zeroclaw-dist-local .

For a Homebrew installation whose formula omits adapters, run the standard source-built binary alongside the package-managed binary and use its own config, data and service paths. A config setting cannot change a bottle’s compiled features. Source users can also select individual existing tool-* features or tools-compat; they still need the runtime selection.

Standard dist includes the plugin host and plugins-wasm-cranelift on the seven supported native 64-bit targets: GNU and musl Linux on x86_64 and aarch64, both macOS architectures, and x86_64 Windows MSVC. ARMv6/ARMv7 omit Cranelift and Prometheus; experimental Android omits Cranelift and WhatsApp Web. Cargo defaults do not include a plugin host. Compiling the host leaves plugins.enabled and plugins.auto_discover false; consent, trust, grants and configured activation still apply. Runtime-only precompiled .cwasm support and Pulley do not replace portable registry .wasm compilation. Target policy comes from package.metadata.zeroclaw in Cargo.toml.

Minimal is a runtime catalog selection. Standard dist still carries the compiled native adapters, so minimal alone is not binary-size evidence for the tool extraction work. Container, Kubernetes and Nix defaults omit [tools] and load full like any other configuration; set optional = [] in them for minimal.

Built-in tools

The following built-in capabilities are available when compiled and selected, which full does for all of them; the eleven-tool minimal set is listed above. This list is not the core set; see Tiers and the retained core set for the core set and the tier of each tool the runtime registry builds.

ToolWhat it does
shellExecute a shell command in the workspace directory. Subject to command allow/deny lists
file_readRead a file with line numbers; supports partial reads and base64 encoding for binary files (path must be inside the workspace unless autonomy permits otherwise)
file_writeWrite a file (same path constraint)
file_editReplace an exact string match in a file with new content
glob_searchList files matching a glob pattern within the workspace
content_searchSearch file contents by regex within the workspace (ripgrep with grep fallback)
http_requestHTTP GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS to allowlisted domains
web_search_toolWeb search. Provider is configurable: DuckDuckGo (default, no key), Brave, Tavily, SearXNG, Jina, Bocha, AnySearch, Serply, or Keenable (no key required; optional key lifts rate limits)
web_fetchFetch a page and return clean plain text
browserHeadless-browser automation. Opt-in: requires [browser] automation_enabled = true. See Browser automation
memory_recallSearch long-term memory for relevant facts, preferences, or context
memory_storeStore a fact, preference, or note in long-term memory
ask_userSend a question to the active channel and wait for a reply. Supports optional choices for structured responses (inline keyboard on Telegram, numbered list on CLI). On ACP, choices are required: free-form ask awaits the ACP elicitation RFD. Parameters: question (required), choices (optional list), timeout_secs (default 600).
escalate_to_humanSend a structured escalation message with urgency routing. high / critical urgency additionally notifies any channels listed in [escalation] alert_channels. Parameters: summary (required), context (optional), urgency (low/medium/high/critical, default medium), wait_for_response (bool, default false), timeout_secs (default 600). On ACP, wait_for_response: true fails immediately if the channel cannot receive free-form replies (awaits ACP elicitation RFD).

AnySearch provider

AnySearch is an explicit, opt-in backend for web_search_tool:

[web_search]
search_provider = "anysearch"
# Optional; omit to use AnySearch's lower, rate-limited anonymous quota.
anysearch_api_key = "..."

Search queries and the configured result limit are sent to https://api.anysearch.com/v1/search. When anysearch_api_key is configured, ZeroClaw sends it only as a Bearer authorization header; without a key, no Authorization header is sent. Selecting this provider therefore sends search queries to a third-party service even in anonymous mode. It does not change the default provider and is not used as an automatic fallback.

Additional first-party built-ins, included in full but not in minimal:

ToolNotes
cron_*Manage scheduled jobs: cron_add, cron_list, cron_remove, cron_update, cron_run, cron_runs
scheduleShell-only one-shot/recurring scheduling
memory_export, memory_purgeLong-term memory management
spawn_subagent, delegateRun a subtask in a child agent

Selected tools also retain these prerequisites:

ToolEnabled by
knowledge[knowledge].enabled = true. Stores structured relationship memory; see Relationship memory
Hardware probes--features hardware: GPIO reads/writes, device discovery, firmware flashing
sop_* toolsRegistered when the SOP runtime is enabled (sop.sops_dir set to a non-empty value; unset by default, which disables it; the documented value is shared/sops): run and inspect SOPs
discord_searchRegistered when a Discord alias has archive enabled

Built-in schema discovery

Enable deferred_builtin_tools on the agent’s runtime profile through the ZeroCode Config editor to reduce the built-in tool catalog sent to the model. It defaults to false, which preserves eager schema loading. The setting is independent of MCP’s deferred_loading option.

When enabled, permitted shell, file_read, file_write, file_edit, memory_recall, and memory_store schemas remain visible. Other enabled built-ins appear in a compact discovery list. The model uses tool_search with keywords or select:<tool_name> to retrieve full definitions. Selected schemas appear in subsequent native-tool requests; text providers receive the definition in the search result.

Discovery never grants permission or changes tool approval. Agent policy, principal restrictions, and caller allowlists still apply, including after a session narrows its tools. Built-in executables stay in the existing scoped registry, so memory routing does not retain a separate stale tool instance. If policy does not admit tool_search, remaining built-in schemas stay eager. Tool-listing endpoints still list the complete admitted registry.

Extension protocols

Beyond built-in tools, ZeroClaw supports the MCP (Model Context Protocol) extension surface. Connect any MCP server (Claude Code’s filesystem, Playwright, your own) and the agent picks up its tools at startup.

For IDE-side integration where an editor drives ZeroClaw as a subprocess, see ACP: Agent Client Protocol lives under channels since it’s an inbound session-management surface, not a tool the agent invokes.

Authoring a tool

Implement the Tool trait in zeroclaw-api:

#![allow(unused)]
fn main() {
#[async_trait]
pub trait Tool: Send + Sync + Attributable {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn parameters_schema(&self) -> serde_json::Value;   // JSON Schema for args
    async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult>;
}
}

Every Tool is also Attributable, so a tool call’s log emissions and audit traces carry the same <kind>.<alias> attribution the rest of the runtime uses.

Register via the runtime’s tool factory. See Developing → Plugin protocol for the full pattern.

Describing tools to the model

Tool descriptions are Mozilla Fluent strings: one per tool, localised per locale. This keeps tool descriptions terse in the model’s context window while allowing UI localisation.

Source of truth: crates/zeroclaw-runtime/locales/en/tools.ftl. Translations are generated and maintained via cargo fluent fill --locale <code> (see Maintainers → Docs & Translations).

Risk and approval

Every tool invocation is classified by risk:

  • Low (read-only, no side effects): file_read, memory_recall, http_request GET to allowed domains
  • Medium (mutates local state): file_write, shell with known safe commands
  • High (destructive or remote side effects): shell with unknown commands, http_request POST to unconstrained URLs

The autonomy level determines what each risk tier can do without operator approval. Default (Supervised): low runs, medium asks, high blocks.

When receipts are enabled, successful executions receive a tool receipt. Denied, blocked, replaced, failed, or interrupted calls do not receive receipts.

Disabling tools on non-CLI channels

The schema has no per-channel tools_allow / tools_deny field. Tool gating lives on the agent’s risk profile ([risk_profiles.<alias>]):

  • excluded_tools removes the listed tools from every non-CLI channel (Discord, Telegram, Bluesky, Matrix, Slack, etc.) while leaving the local CLI untouched. The granularity is binary (CLI vs non-CLI), not per-channel. It also subtracts from the agentic-delegate allow-list resolved at runtime, which is the only way to block individual <server>__<tool> MCP names that would otherwise be auto-admitted by the rule below.
  • allowed_tools is an allowlist. Omitted and an explicit empty list (allowed_tools = []) mean the same legacy state: no authorization constraint. A nonempty list is a closed set for built-ins (and, via the MCP exception below, auto-admits namespaced MCP tools). An empty list does not mean deny-all; for that, set the sibling deny_all_tools = true, which denies built-ins, MCP tools, and skill-defined tools alike. Setting both deny_all_tools = true and a nonempty allowed_tools is a configuration error rejected at load.
  • MCP exception: when allowed_tools is non-empty, runtime-discovered MCP tools (any name containing __, the <server>__<tool> convention) are auto-admitted into the effective allow-list without having to be listed there individually. This keeps the post-#7464 eager-MCP default usable for agents that already pin an explicit allow-list. To block individual MCP tools, list them in excluded_tools.
  • The MCP exception is scoped to the risk profile’s allowed_tools only. Caller-supplied per-run allow-lists (cron job allowed_tools, narrowed delegate invocations, etc.) are still treated as strict explicit-list intersections. A job that narrows itself to allowed_tools = ["cron_add"] will not surface runtime-discovered MCP wrappers it did not name, even when the agent’s risk profile would auto-admit them.

If you need finer-grained gating under Full autonomy, put sensitive tools in the per-profile always_ask list: they still prompt (or fail closed) even when level = "full". Dropping the profile to read_only or supervised is only required when you want the whole risk-tier matrix, not when you need a handful of exceptions.

See Autonomy levels for the full set of per-profile fields.

See also