Skip to content

Adding Tools

Tools are the primary way agents interact with external systems. Each tool provides a set of actions with defined parameter schemas, permission levels, and execution logic.

All tools extend the BaseTool abstract class, which provides:

  • Action registration: Define actions with names, descriptions, parameter schemas, and permission levels
  • Permission enforcement: Automatic permission checks before action execution
  • Error handling: Standardized error reporting
  • Lifecycle management: Initialization and cleanup hooks
  1. Create the tool directory and file

    Create src/tools/mytool/index.ts:

    import { BaseTool } from '../base-tool';
    export class MyTool extends BaseTool {
    id = 'mytool';
    name = 'My Tool';
    description = 'Description of what this tool does';
    tools = [
    {
    name: 'my_action',
    description: 'What this action does',
    parameters: {
    type: 'object',
    properties: {
    input: {
    type: 'string',
    description: 'The input parameter'
    }
    },
    required: ['input']
    },
    permissions: {
    action: 'execute',
    level: 'ASK' // ALLOW, ASK, or DENY
    }
    }
    ];
    async execute(toolName: string, args: Record<string, unknown>) {
    switch (toolName) {
    case 'my_action':
    return this.myActionHandler(args);
    default:
    throw new Error(`Unknown action: ${toolName}`);
    }
    }
    private async myActionHandler(args: Record<string, unknown>) {
    const input = args.input as string;
    // Your implementation here
    return { result: `Processed: ${input}` };
    }
    }
  2. Define action parameter schemas

    Action parameters use JSON Schema format. The schema is provided to the LLM so it knows how to call your tool:

    parameters: {
    type: 'object',
    properties: {
    path: {
    type: 'string',
    description: 'The file path to operate on'
    },
    recursive: {
    type: 'boolean',
    description: 'Whether to operate recursively',
    default: false
    }
    },
    required: ['path']
    }
  3. Register the tool

    Add your tool to the tool registry in src/tools/registry.ts:

    import { MyTool } from './mytool';
    // In the registry initialization:
    registry.register(new MyTool());
  4. Enable the tool

    Add your tool ID to the ENABLED_TOOLS environment variable:

    ENABLED_TOOLS=filesystem,shell,git,browser,websearch,docker,mytool

Each action should specify an appropriate permission level:

LevelWhen to Use
ALLOWRead-only operations, safe queries
ASKWrite operations, network requests, anything with side effects
DENYDangerous operations that should never run automatically
  • Keep actions focused: Each action should do one thing well
  • Descriptive parameters: LLMs rely on parameter descriptions to use actions correctly
  • Appropriate permissions: Default to ASK for anything with side effects
  • Error handling: Return meaningful error messages that help the LLM recover
  • Idempotency: Where possible, make actions idempotent so retries are safe
  • Validation: Validate all inputs before executing operations

Study the built-in tools for patterns and conventions:

ToolPathGood Example Of
filesystemsrc/tools/filesystem/Multiple actions, read/write permissions
shellsrc/tools/shell/Background execution, elevated permissions
gitsrc/tools/git/Complex multi-action tool
browsersrc/tools/browser/External dependency (Playwright)
websearchsrc/tools/websearch/Multi-tier fallback strategy
dockersrc/tools/docker/System-level operations
githubsrc/tools/github/REST API integration
google-workspacesrc/tools/google-workspace/Multi-service OAuth tool