<!-- source: https://deepwiki.com/qhkm/zeptoclaw/8.5-custom-tools -->

# Custom Tools

- src/tools/binary_plugin.rs
- src/tools/custom.rs
- src/tools/delegate.rs
- src/tools/mcp/wrapper.rs
- src/tools/plugin.rs
- src/tools/registry.rs
- src/tools/types.rs

This page documents the custom tool system, which allows users to define shell-based tools in the configuration file without writing Rust code. Custom tools execute shell commands with parameter interpolation and are subject to the same security controls as built-in tools.

For binary plugins that communicate via JSON-RPC, see [Binary Plugin System](/qhkm/zeptoclaw/8.6-binary-plugin-system). For tools generated by the LLM at runtime, see [Tool Composition](/qhkm/zeptoclaw/8.8-tool-composition). For MCP server tools, see [MCP Integration](/qhkm/zeptoclaw/8.7-mcp-integration).

## Overview

Custom tools are defined in the `custom_tools` array in `config.json` and are registered at agent startup. Each custom tool consists of a shell command template with `{{parameter}}` placeholders that are interpolated at execution time.

The system is implemented in `src/tools/custom.rs` and exposes custom tools through the standard `Tool` trait interface [src/tools/custom.rs131-132](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L131-L132) Custom tools are registered alongside built-in tools in the `ToolRegistry` [src/tools/registry.rs49-50](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/registry.rs#L49-L50) and are available to the LLM for function calling.

**Key characteristics:**

- Shell-based execution : Runs via sh -c using tokio::process::Command src/tools/custom.rs 217-218
- Template interpolation : Uses {{param}} syntax with automatic shell escaping or sanitization src/tools/custom.rs 87-107
- Raw String Support : Allows raw_string parameter types for CLI wrappers where word-splitting is required (e.g., passing multiple flags) src/tools/custom.rs 81-84
- Safety : Automatic single-quote wrapping for standard parameters src/tools/custom.rs 26-28 and strict character stripping for raw_string parameters src/tools/custom.rs 40-77
- Constraints : Configurable timeout (default 30s), working directory, and environment variables src/tools/custom.rs 211-236
- Output Management : Truncates stdout at 50KB to protect LLM context src/tools/custom.rs 19

Sources: [src/tools/custom.rs1-128](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L1-L128) [src/tools/registry.rs48-87](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/registry.rs#L48-L87) [src/tools/types.rs197-202](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/types.rs#L197-L202)

## Configuration Structure

Custom tools are defined in the `custom_tools` section of the configuration file. The `CustomToolDef` struct maps the JSON configuration to the internal tool representation.

### Configuration Fields

### Data Flow: Config to Tool Entity

The following diagram shows how configuration definitions are transformed into active `CustomTool` instances within the `ToolRegistry`.

**Config to Entity Mapping**

```

```

Sources: [src/tools/custom.rs110-128](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L110-L128) [src/tools/registry.rs83-87](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/registry.rs#L83-L87) [src/tools/types.rs197-202](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/types.rs#L197-L202)

## Parameter Interpolation and Security

Custom tools use a dual-mode interpolation system to balance flexibility for CLI tools with security against command injection.

### Shell Escaping ( string )

The `shell_escape` function [src/tools/custom.rs26-28](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L26-L28) wraps values in single quotes. Any embedded single quotes are escaped as `'\''` to ensure the parameter remains a single literal string to the shell.

### Sanitization ( raw_string )

For parameters that need to allow shell word-splitting (e.g., passing multiple flags like `--verbose --count 5`), the `raw_string` type is used. The `sanitize_raw_string` function [src/tools/custom.rs40-77](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L40-L77) strips 22 dangerous characters including `;`, `|`, `$()`, and backticks, while preserving spaces and dashes.

### Interpolation Logic

1. Extraction : Arguments are extracted from the LLM's JSON input src/tools/custom.rs 179-191
2. Mode Selection : The interpolate function checks the parameter type defined in CustomToolDef src/tools/custom.rs 95-98
3. Processing : If type is raw_string , it applies sanitize_raw_string ; otherwise, it applies shell_escape src/tools/custom.rs 99-103
4. Replacement : Replaces {{key}} in the template with the processed value src/tools/custom.rs 104

### Security Validation

Before execution, the final interpolated command is passed to `ShellSecurityConfig::validate_command()` [src/tools/custom.rs201-206](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L201-L206) This checks the command against global blocklists to prevent execution of forbidden binaries or patterns.

**Command Preparation Pipeline**

```

```

Sources: [src/tools/custom.rs26-107](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L26-L107) [src/tools/custom.rs201-206](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L201-L206)

## Execution Model

Custom tools implement the `execute` method of the `Tool` trait [src/tools/custom.rs177-264](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L177-L264)

### Environment and Context

- Timeout : Determined by timeout_secs (default 30), clamped to a minimum of 1 second ( MIN_TIMEOUT_SECS ) src/tools/custom.rs 211-212
- Working Directory : Resolved in order: CustomToolDef.working_dir -> ToolContext.workspace src/tools/custom.rs 223-227
- Environment : Custom variables defined in env are injected into the child process src/tools/custom.rs 230-234

### Output Handling

The tool captures `stdout` and `stderr` using `child.wait_with_output()` [src/tools/custom.rs239](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L239-L239)

- Success : If the exit code is 0, stdout is returned as ToolOutput::llm_only() . If stdout exceeds 50,000 bytes, it is truncated src/tools/custom.rs 245-253
- Failure : If the exit code is non-zero, the tool returns a ZeptoError::Tool containing the stderr content src/tools/custom.rs 255-262

**Execution Logic Flow**

```

```

Sources: [src/tools/custom.rs18-22](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L18-L22) [src/tools/custom.rs211-264](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/custom.rs#L211-L264)

## Tool Registration and Filtering

Custom tools are registered during system initialization. The `ToolRegistry` governs which tools are actually available to an agent.

If a tool is requested by an LLM but was not registered (or was filtered out by an agent template), the `ToolRegistry` returns a helpful error message via `opt_in_tool_hint` [src/tools/registry.rs18-25](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/registry.rs#L18-L25)

### Comparison with Plugin Tools

ZeptoClaw also supports `PluginTool` [src/tools/plugin.rs68](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/plugin.rs#L68-L68) and `BinaryPluginTool` [src/tools/binary_plugin.rs68](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/binary_plugin.rs#L68-L68) While `CustomTool` is defined directly in the main `config.json`, `PluginTool` is defined in external plugin manifests but follows similar shell-interpolation logic [src/tools/plugin.rs105-119](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/plugin.rs#L105-L119) `BinaryPluginTool` differs by using JSON-RPC 2.0 over stdin/stdout instead of shell command strings [src/tools/binary_plugin.rs3-6](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/binary_plugin.rs#L3-L6)

**Tool Implementation Hierarchy**

```

```

Sources: [src/tools/registry.rs172-181](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/registry.rs#L172-L181) [src/tools/plugin.rs1-120](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/plugin.rs#L1-L120) [src/tools/binary_plugin.rs1-73](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/binary_plugin.rs#L1-L73) [src/tools/mcp/wrapper.rs9-21](https://github.com/qhkm/zeptoclaw/blob/2c743d31/src/tools/mcp/wrapper.rs#L9-L21)
