Skip to content

Toolbox

Toolbox tools are simple executables that describe themselves and accept structured input. They are easier than running an MCP server and safer than letting the model improvise a shell command every time.

Tell Anode where to find toolbox executables.

Environment variable:

export ANODE_TOOLBOX="/home/user/tools:/home/user/project/.tools"

The value is an OS-native path list (colon-separated on Unix).

Config file:

{
"tools": {
"toolboxDirs": [
"/home/user/tools",
".tools"
]
}
}

Anode scans these directories at startup. Earlier directories win on name conflicts.

Toolbox tools communicate through environment variables and stdio. Anode calls each tool twice during its lifecycle: once to describe, once to execute.

Anode sets TOOLBOX_ACTION=describe and runs the executable. The tool prints JSON metadata to stdout:

{
"name": "run-tests",
"description": "Run the project test suite with optional filter",
"args": {
"filter": "Test name pattern to match",
"verbose": "Show detailed output (true/false)"
},
"permission": "confirm_execute",
"timeout_seconds": 60
}
FieldTypeRequiredDescription
namestringYesTool name. Registers as tb__<sanitized_name>
descriptionstringYesShort description shown to the model
argsmapNoArgument keys and descriptions, or a JSON schema-like object
permissionstringNoPermission level (default: confirm_execute)
timeout_secondsintNoExecution timeout in seconds. If omitted, tools.externalTimeout applies.

For tools that need complex parameters (objects, arrays), the describe output can return a full JSON schema instead of the simple key-value args map.

Invalid describe output is skipped with a diagnostic. Anode continues loading other tools.

Anode sets TOOLBOX_ACTION=execute and TOOLBOX_WORKSPACE (the workspace root path). It passes a JSON object of arguments on stdin. The tool reads stdin, does its work, and prints results to stdout.

Toolbox tools register as tb__<sanitized_name>. The name from the describe output is lowercased and restricted to alphanumeric characters, dashes, and underscores.

View all registered tools (built-in, toolbox, and MCP) with:

anode tools list

Toolbox tools go through the same permission rules as built-in and MCP tools. The permission field in the describe output sets the default level. Your permission policy can override it.

A single Bash script that describes itself and runs tests.

#!/usr/bin/env bash
set -euo pipefail
if [ "$TOOLBOX_ACTION" = "describe" ]; then
cat <<'EOF'
{
"name": "run-tests",
"description": "Run Go tests with optional package filter",
"args": {
"package": "Package path to test (default: ./...)",
"verbose": "Show verbose output (true/false)"
},
"permission": "confirm_execute",
"timeout_seconds": 120
}
EOF
exit 0
fi
# Execute
cd "$TOOLBOX_WORKSPACE"
INPUT=$(cat)
PACKAGE=$(echo "$INPUT" | jq -r '.package // "./..."')
VERBOSE=$(echo "$INPUT" | jq -r '.verbose // "false"')
ARGS=("-count=1" "$PACKAGE")
if [ "$VERBOSE" = "true" ]; then
ARGS=("-v" "${ARGS[@]}")
fi
go test "${ARGS[@]}" 2>&1

Save this as run-tests in a toolbox directory, make it executable, and restart Anode. The model can now call tb__run-tests.

A Node.js script for running read-only database queries.

#!/usr/bin/env node
const { execSync } = require("child_process");
if (process.env.TOOLBOX_ACTION === "describe") {
console.log(JSON.stringify({
name: "db-query",
description: "Run a read-only SQL query against the development database",
args: {
query: "SQL SELECT statement to execute",
limit: "Max rows to return (default: 50)"
},
permission: "confirm_execute",
timeout_seconds: 30
}));
process.exit(0);
}
// Execute
let input = "";
process.stdin.on("data", (chunk) => { input += chunk; });
process.stdin.on("end", () => {
const { query, limit = "50" } = JSON.parse(input);
if (!/^\s*SELECT\b/i.test(query)) {
console.error("Error: only SELECT queries are allowed");
process.exit(1);
}
const fullQuery = `${query.replace(/;\s*$/, "")} LIMIT ${limit};`;
const result = execSync(
`psql "$DATABASE_URL" -c ${JSON.stringify(fullQuery)} --csv`,
{ cwd: process.env.TOOLBOX_WORKSPACE, encoding: "utf-8" }
);
console.log(result);
});

Save as db-query in a toolbox directory and make it executable.

Use toolbox tools for project-local, deterministic behavior:

  • Test runners - wrap go test, pytest, jest with project-specific flags.
  • Database queries - safe, read-only access to development data.
  • Build actions - compile, lint, or bundle with locked configurations.
  • CLI wrappers - expose project-specific CLI tools to the agent with constrained interfaces.

Toolbox tools live alongside your code. They are versioned, reviewable, and predictable.

  • MCP Integration - connect to full MCP servers for richer tool capabilities
  • Permissions - control what toolbox tools are allowed to do
  • Tools - reference for all built-in tools
  • Configuration - tools.toolboxDirs and other settings