tools.toolSearch.
For the generic OpenClaw runtime that exposes a QuickJS-WASI exec/wait
surface instead of Tool Search controls, see Code Mode.
OpenClaw embedded and Copilot runs use structured Tool Search automatically when
tools.toolSearch is unset. This defers tool schemas while keeping the
policy-approved capabilities available. It does not enable lean mode or remove
optional tools. Set tools.toolSearch: false to restore direct schemas. Engaged
Code Mode takes precedence, and Codex keeps its native surface.
Explicit settings are preserved; no configuration file is rewritten.
When enabled for OpenClaw runs, the model automatically receives a bounded
directory of the available trusted tool names and descriptions. Explicitly
setting tools.toolSearch: true selects one tool_search_code tool, plus any direct-only tools whose
structured results cannot cross the compact bridge. The code tool runs a short
JavaScript body in an isolated Node subprocess with an openclaw.tools bridge:
How a turn runs
At planning time the OpenClaw embedded runner builds the effective catalog for the run:- Resolve the active tool policy for the agent, profile, sandbox, and session.
- List eligible OpenClaw and plugin tools.
- List eligible MCP tools through the session MCP runtime.
- Add eligible client tools supplied for the current run.
- Keep core coding primitives and direct-only tools model-visible and index compact descriptors for the remaining catalog-eligible tools.
- Add a deterministic, bounded, policy-filtered capability directory to the cache-stable system-prompt prefix.
- Expose the OpenClaw code bridge, the structured fallback tools, or the compact directory surface alongside those stable, directly callable tools.
openclaw.tools.call(...) crosses the bridge back into the Gateway, where the
normal policy, approval, hook, logging, and result handling still apply.
Modes
tools.toolSearch has three model-facing modes:
code: exposestool_search_code, the explicitly selected JavaScript bridge, alongside the capability directory and direct-only tools.tools: the default whentools.toolSearchis unset. Exposestool_search,tool_describe, andtool_callas plain structured tools, alongside the capability directory and direct-only tools.directory: exposestool_search,tool_describe, andtool_callplus a bounded, cache-stable prompt directory. Core coding primitives, direct-only tools, and tools required by the run’s delivery policy remain visible; other schemas stay deferred.
catalogMode: "direct-only" stay outside that catalog and
remain model-visible. If the current runtime cannot launch the isolated Node code-mode child
process, explicitly selected code mode falls back to tools before catalog
compaction. In directory mode, client-provided tools stay directly visible
for the current run while OpenClaw tools, plugin tools, and MCP tools can be
compacted behind the directory catalog. A direct call to an exact hidden
directory name is hydrated from that same authorized catalog before execution
in the embedded harness. The Copilot harness instead maps
directory to structured tools semantics: hidden OpenClaw catalog names must
be invoked through tool_call, because they are not registered SDK handlers.
The structured tools surface is on by default for OpenClaw runs. It does not
add the Node code bridge’s wall-clock deadline to tools that wait for approval or
take more than a few seconds. Explicit toolSearch: true and object settings
retain their existing semantics: true still selects code, and an object
without a mode still uses code. See Runtime boundary.
Codex harness runs use their native surfaces.
Compaction is not always cheaper: small catalogs can gain schema overhead, and
additional discovery turns can offset initial payload savings. Set
tools.toolSearch: false when direct schemas suit your workload better.
There is no separate source-selection config. When Tool Search is enabled, the
catalog includes catalog-eligible OpenClaw, MCP, and client tools after normal
policy filtering; direct-only tools are retained separately.
Why this exists
Large catalogs are useful but expensive. Sending every tool schema to the model makes the request larger, slows planning, and increases accidental tool selection. Tool Search changes the shape:- direct tools: the model sees every selected schema before the first token
- Tool Search code mode: the model sees one compact code tool, a bounded capability directory, a short API contract, and any direct-only tools
- Tool Search tools mode: the model sees three compact structured fallback tools, the same capability directory, and any direct-only tools
- Tool Search directory mode: the model sees a bounded directory plus search/describe/call controls, policy-required direct tools, and any direct-only tools
- during the turn: the model can load remaining schemas as needed
toolsAllow restrictions apply before the final prompt is
submitted: the embedded and Copilot prompts advertise only the remaining
catalog, without rerunning the hook or rewriting earlier conversation turns.
API
openclaw.tools.search(query, options?)
Searches the effective catalog for the current run.
Queries must be written in English. Ranking is lexical (Okapi BM25 over tool
names, descriptions, and first-party parameter names and descriptions), with
light English stemming so scheduling reaches a tool described as Schedule a recurring task, and a small intent expansion so look up the price reaches one
described as Search the web. Tool names and descriptions are written in English,
so a query in another language will usually match nothing. It is not rejected —
a catalog may legitimately describe a tool in another script — but a query with
no usable terms returns no ranked results rather than an arbitrary slice of the
catalog. An exact tool name is still honored even when it tokenizes to nothing.
Both tool_search and the code-mode bridge state this
requirement in their model-facing descriptions.
Untrusted parameter schemas are never indexed. MCP and client tools are matched
on name and description only, which is the same boundary that defers their input
signatures as input: "unknown".
Results are compact and safe
to put back into prompt context. Each hit includes a bounded TypeScript-style
input signature, such as { id: string; mode?: "drip" | "flood" }, so the
model can skip describe when that signature is sufficient. A trusted
OpenClaw core or plugin tool may also include a compact output hint, such as
Array<{ id: string; paid: boolean }>. MCP and client output-schema claims are
not promoted into this trusted hint. Their untrusted input schemas are also
deferred as input: "unknown"; use describe before calling them. Open,
oversized, or otherwise partial output schemas omit the hint and remain
available through describe instead.
openclaw.tools.describe(id)
Loads full metadata for one search result, including the exact input schema and
the trusted full outputSchema when the tool declares one.
openclaw.tools.call(id, args)
Calls a selected tool through OpenClaw and returns the raw { tool, result }
envelope. JSON-returning tools normally place their value in
result.details. OpenClaw validates a trusted core or plugin tool’s declared
input schema before execution. Missing required arguments, incorrect types,
and forbidden properties return actionable tool errors instead of executing
the tool; misspelled properties include a suggested parameter when available.
If a trusted tool also declares outputSchema, OpenClaw compiles that schema
before execution and validates final details after normal tool hooks before
returning the catalog call. MCP and client-owned schemas remain deferred to
their owning execution boundary.
In structured mode, tool_call also repairs flattened target arguments from
local models. It preserves target fields such as id and name, and rejects
ambiguous tool selectors instead of calling the wrong tool. Nest target
arguments under args when a target field matches another cataloged tool.
The structured control’s model-facing text includes only the tool’s id,
name, and source alongside the unchanged target result; it does not repeat
the description and input signature. Its structured details retain the full
call envelope for runtime consumers. Use tool_describe for full tool metadata.
outputSchema property.
It describes AgentToolResult.details, not rendered content blocks. Include
all non-throwing variants or omit it for unstable results. See
Code Mode output contracts and
Tool plugins.
The structured fallback mode exposes the same operations as tools:
tool_searchtool_describetool_call
tool_call.id and all target parameters in
tool_call.args, including when other instructions refer to the deferred tool
by name. A compact search signature may be enough to call it; use
tool_describe when the full schema is needed.
tool_search accepts either the existing single-query shape or a batch of
independent queries:
query runs first, with the
top-level limit scoped to it. Batch entries follow in request order, including
repeated query text; each occurrence keeps its own limit and counts toward the
batch budgets.
Beside a non-empty batch, an omitted, null, empty, or whitespace-only query
is ignored. In that case, omit the top-level limit or set it to null; a
non-null top-level limit is rejected rather than applied to the batch.
An omitted or null queries retains scalar behavior, and queries: [] also
falls back to the scalar shape when query is non-empty. A blank scalar query
without a batch still returns an empty candidate array. A missing or null
scalar with no batch, or an empty batch with no non-empty scalar, is rejected.
A scalar limit: null uses the default limit, just like an omitted limit.
Invalid query shapes, invalid limits, and over-budget batches still fail.
Batch calls return { results: [{ query, candidates }] } in request order. Each
query uses the same effective catalog, ranking, filtering, and per-query limit
as an ordinary search; a candidate may appear in more than one result group.
Descriptions are compacted before output. If the complete batch would exceed
the 4,000-character response budget, lower-ranked candidates are removed and
the response includes truncated: true. A result group that lost candidates
also includes truncated: true, so an empty truncated group cannot be mistaken
for a query that had no matches.
Omitted per-query limits use searchDefaultLimit. The effective limits in one
batch may request at most 50 candidates in total. A batch accepts at most 16
queries, with at most 512 characters per query and 512 UTF-8 bytes across the
serialized query list. Invalid batches fail as one request, while a valid query
with no matches returns an empty candidates array.
Directory mode exposes:
tool_searchtool_describetool_call
tool_search to find them and
tool_describe to retrieve their full schemas. If the model requests an exact
hidden directory tool name directly, the embedded harness resolves it from the
authorized catalog before normal execution. Copilot uses tool_call instead,
as described under Modes.
Directory-mode client tool names must not collide with OpenClaw, plugin, or MCP
tool names because exact deferred dispatch uses those names.
Runtime boundary
The code bridge runs in a short-lived Node subprocess. The subprocess starts with Node permission mode enabled, an empty environment, no filesystem or network grants, and no child-process or worker grants. OpenClaw enforces a parent-process wall-clock timeout and kills the subprocess on timeout, including after async continuations. The defaultcodeTimeoutMs is 10 seconds for the entire tool_search_code
invocation, including bridged tool execution and approval waits. The deadline
does not pause while openclaw.tools.call(...) waits on the host. This bridge
does not return a resumable waiting result: expiry kills the child and cancels
outstanding calls. Before retrying a timed-out mutation, inspect its outcome;
cancellation cannot undo side effects that already occurred.
This is different from the QuickJS-WASI Code Mode
exec/wait surface, which pauses its budget for approvals and can checkpoint
unfinished tool waits for a later wait. Use structured tools mode when the
Node bridge deadline is unsuitable; target tools still enforce their own
timeouts, approvals, and cancellation. The hard deadline also stops runaway
JavaScript after async continuations, so disabling it around host waits is not
a safe substitute for resumable execution.
Outstanding bridged tool calls are canceled when the child settles, including
fatal exits and final results. Failed exits wait for stderr to drain before
rendering a bounded diagnostic. The error separately reports bytes discarded
from the 64 KiB retained tail and bytes omitted from its final text preview.
The runtime exposes only:
console.log,console.warn, andconsole.erroropenclaw.tools.searchopenclaw.tools.describeopenclaw.tools.call
- tool allow and deny policies
- per-agent and per-sandbox tool restrictions
- channel/runtime tool policy
- approval hooks
- plugin
before_tool_callhooks - tool
executionMode: sequential calls run exclusively with other calls in the same catalog, including calls from other Tool Search or Code Mode cells - session identity, logs, and telemetry
Config
Withtools.toolSearch unset, OpenClaw runs use structured tools mode with
a default search limit of 8 and a maximum of 20. Local Ollama models, LM Studio,
and managed local services retain their smaller limits of 5 and 10. Known hosted
Ollama routes use the general limits. An untagged alias served by an Ollama daemon
inherits the daemon’s limits even if that alias forwards to a hosted model.
Other providers are not classified as local from model names or a loopback URL alone.
An explicit tools.toolSearch value takes precedence, including false.
Setting agents.defaults.experimental.localModelLean: false restores optional
tools but does not turn off automatic Tool Search.
Opt into the legacy Node code bridge explicitly (not the structured default):
codeTimeoutMs to 1000-60000, maxSearchLimit to 1-50, and
searchDefaultLimit to 1..maxSearchLimit.
Disable it:
Prompt and telemetry
Code mode attaches atelemetry object to every tool_search_code result:
catalogSize: number of catalog entries the runtime resolvedsources: catalog entry counts split intoopenclaw,mcp, andclientcounterScope: opaque identifier for the counter lifetime; it stays stable when tools are appended or prompt policy narrows the catalog, and changes when the catalog is replaced or restoredsearchCount,describeCount,callCount: running totals for the catalog session, carried across calls rather than reset per call
tools and directory mode emit no telemetry object; their tool_search,
tool_describe, and tool_call results carry only the catalog data for that
operation. OpenClaw does not record serialized tool or prompt byte counts. The
E2E scenario measures provider payload bytes separately from
the mock provider lane, not from the runtime.
Regardless of mode, completed target calls persist as bounded, redacted display
activity in session history without adding synthetic model turns to replay.
Search, describe, and call results carry each tool’s id and source.
Session logs therefore still answer:
- how many tool schemas the model saw up front
- how many search and describe operations it performed
- which final tool was called
- whether the result came from OpenClaw, MCP, or a client tool
E2E validation
The QA Lab gateway scenario proves all three paths with the OpenClaw runtime:- Direct mode can call the fake plugin tool.
- Tool Search can call the same fake plugin tool.
- Direct mode exposes the fake plugin tool schemas directly to the provider.
- Tool Search exposes only the compact bridge plus any direct-only tools.
- The Tool Search request payload is smaller for the large fake catalog.
- Session logs show the expected tool-call counts and bridged call telemetry.
- Structured mode resolves two queries with one
tool_searchcall before the selected plugin tool runs throughtool_call.
Real-model comparison
Failure behavior
Tool Search should fail closed:- if a tool is not in the effective policy, search should not return it
- if a selected tool becomes unavailable,
tool_callshould fail - if policy or approval blocks execution, the call result should report that block instead of bypassing it
- if the code bridge cannot create an isolated runtime, use
mode: "tools"or disable Tool Search for that deployment