Skip to main content

Overview

The Tools module provides core tool implementations for file operations, shell execution, web fetching, web search, and agent-to-agent communication. All tools include automatic metrics collection and security enforcement.

File Operations

tool::file_read

Read file contents with path containment security checks.
path
string
required
File path relative to WORKSPACE_ROOT
maxBytes
number
Optional maximum bytes to read (for limiting large files)
result
object
content
string
The file contents (limited by maxBytes if specified)
path
string
The resolved absolute path
size
number
The total file size in bytes
const result = await trigger('tool::file_read', {
  path: 'src/config.ts',
  maxBytes: 10000
});

console.log(`Read ${result.content.length} of ${result.size} bytes`);
Security: Automatically enforces path containment via assertPathContained() to prevent directory traversal attacks.

tool::file_write

Write content to a file with path containment security.
path
string
required
File path relative to WORKSPACE_ROOT
content
string
required
Content to write to the file
result
object
written
boolean
Confirmation of successful write
path
string
The resolved absolute path
size
number
The number of bytes written
const result = await trigger('tool::file_write', {
  path: 'output/result.json',
  content: JSON.stringify({ status: 'success' }, null, 2)
});

console.log(`Wrote ${result.size} bytes to ${result.path}`);

tool::file_list

List directory contents with file metadata.
path
string
required
Directory path relative to WORKSPACE_ROOT
recursive
boolean
Whether to recursively list subdirectories (not fully implemented)
result
object
path
string
The resolved directory path
entries
array
Array of file/directory entries with:
  • name (string): Entry name
  • type (“file” | “directory”): Entry type
  • size (number): Size in bytes
  • modified (string): ISO timestamp of last modification
const result = await trigger('tool::file_list', {
  path: 'src'
});

result.entries.forEach(entry => {
  console.log(`${entry.type}: ${entry.name} (${entry.size} bytes)`);
});

tool::apply_patch

Apply a unified diff patch to a file.
path
string
required
File path to apply the patch to
patch
string
required
Unified diff format patch content
result
object
patched
boolean
Confirmation of successful patch application
path
string
The resolved file path
const patch = `@@ -1,3 +1,3 @@
-const version = "1.0.0";
+const version = "1.1.0";
`;

const result = await trigger('tool::apply_patch', {
  path: 'src/version.ts',
  patch
});

Shell Execution

tool::shell_exec

Execute commands with sandboxing and allowlist enforcement. No shell interpretation - direct binary execution only.
argv
string[]
required
Command array [binary, …args] - first element must be in SHELL_COMMAND_ALLOWLIST
cwd
string
Working directory relative to WORKSPACE_ROOT
timeout
number
Execution timeout in milliseconds (default: 120000)
result
object
stdout
string
Standard output (limited to 100KB)
stderr
string
Standard error output (limited to 50KB)
exitCode
number
Process exit code (0 = success)

Allowed Commands

const SHELL_COMMAND_ALLOWLIST = [
  'git', 'node', 'npm', 'npx', 'bun', 'deno',
  'python3', 'python', 'pip',
  'ls', 'cat', 'grep', 'find', 'echo', 'mkdir', 'touch', 'cp', 'mv',
  'head', 'tail', 'wc', 'sort', 'uniq', 'diff',
  'curl', 'wget', 'tar', 'zip', 'unzip', 'jq', 'sed', 'awk',
  'which', 'env', 'date',
  'cargo', 'rustc', 'go', 'make', 'cmake'
];
const result = await trigger('tool::shell_exec', {
  argv: ['git', 'status', '--short'],
  cwd: 'my-project'
});

if (result.exitCode === 0) {
  console.log('Git status:', result.stdout);
} else {
  console.error('Error:', result.stderr);
}
Security:
  • Only allowlisted binaries can be executed
  • No shell interpretation (prevents injection)
  • Environment variables filtered through TAINT_ENV_ALLOWLIST
  • Path containment enforced on working directory
  • Output size limits prevent memory exhaustion
  • Execution logged to security audit

Web Access

tool::web_fetch

SSRF-protected HTTP fetch with automatic HTML-to-text conversion.
url
string
required
URL to fetch (validated against SSRF attacks)
maxSize
number
Maximum response size in bytes (default: 500000)
result
object
url
string
The fetched URL
status
number
HTTP status code
contentType
string
Response content type header
content
string
Response content (HTML converted to text, limited to 100KB)
truncated
boolean
Whether content was truncated due to size limits
const result = await trigger('tool::web_fetch', {
  url: 'https://example.com/docs',
  maxSize: 100000
});

if (result.status === 200) {
  console.log('Content:', result.content.slice(0, 500));
}
Security: Automatically calls assertNoSsrf() to prevent requests to internal IP ranges.
Multi-provider web search supporting Tavily, Brave, and DuckDuckGo.
query
string
required
Search query string
provider
string
Search provider: “tavily”, “brave”, or fallback to “duckduckgo”
maxResults
number
Maximum number of results (default: 5)
result
object
results
array
Array of search results with title, url, and content fields
provider
string
The provider that served the results
const result = await trigger('tool::web_search', {
  query: 'TypeScript async patterns',
  provider: 'brave',
  maxResults: 10
});

result.results.forEach(item => {
  console.log(`${item.title}: ${item.url}`);
});
Provider Configuration:
  • Tavily: Requires TAVILY_API_KEY environment variable
  • Brave: Requires BRAVE_API_KEY environment variable
  • DuckDuckGo: No API key required (default fallback)

Agent Communication

tool::agent_spawn

Spawn a sub-agent with depth limits and resource quotas.
template
string
required
Template identifier for the sub-agent type
parentId
string
Parent agent ID for tracking hierarchy
message
string
required
Initial message to send to the spawned agent
result
object
agentId
string
The newly created agent’s ID
response
string
The agent’s response content
depth
number
Depth level in the agent hierarchy
Limits:
  • MAX_AGENT_DEPTH: 5 - Maximum nesting depth
  • DEFAULT_MAX_SUB_AGENTS: 20 - Default quota per parent
const result = await trigger('tool::agent_spawn', {
  template: 'code-analyzer',
  parentId: 'agent-123',
  message: 'Analyze the TypeScript files in src/'
});

console.log(`Spawned agent ${result.agentId} at depth ${result.depth}`);
console.log('Response:', result.response);

tool::agent_send

Send a message to another agent with spam prevention.
agentId
string
required
Sending agent’s ID
targetAgentId
string
required
Receiving agent’s ID
message
string
required
Message content (max 100KB)
result
object
sent
boolean
Confirmation of message queuing
targetAgentId
string
The recipient agent ID
Rate Limits:
  • MESSAGE_MAX_BYTES: 100KB - Maximum message size
  • MESSAGE_QUEUE_MAX: 1000 - Maximum queue depth per agent
  • AGENT_PAIR_RATE_LIMIT: 10 messages per minute between any agent pair
const result = await trigger('tool::agent_send', {
  agentId: 'agent-123',
  targetAgentId: 'agent-456',
  message: 'Task completed, ready for next step'
});

if (result.sent) {
  console.log('Message queued successfully');
}

Metrics Wrapper

All tools automatically use the withToolMetrics() wrapper which records:
  • tool_execution_total - Execution count by status (success/failure)
  • function_call_duration_ms - Execution duration histogram
Location: tools.ts:27

Build docs developers (and LLMs) love