MINARA

Adding a Tool

How to add a new tool to the registry

Tools are typed TypeScript functions with JSON-Schema parameters. They live at apps/agent/src/tools/<name>.ts and export a factory that returns a ToolEntry[].

Minimal example

Create apps/agent/src/tools/my-provider.ts:

import { PermissionTier, type ToolEntry } from "../core/tool-registry.js";
import { ok, err, errFromThrow } from "./_shared/result.js";

export function createMyProviderTools(): ToolEntry[] {
  const apiKey = process.env.MY_PROVIDER_API_KEY;
  if (!apiKey) return []; // feature-gate: registry hides missing tools

  return [
    {
      name: "my_provider_search",
      toolSet: "research",
      permissionTier: PermissionTier.READ_ONLY,
      isAsync: true,
      description: "Search My Provider for a query",
      schema: {
        name: "my_provider_search",
        description: "Search My Provider for a query",
        parameters: {
          type: "object",
          properties: {
            query: { type: "string", description: "The search query" },
            limit: { type: "number", description: "Max results", default: 10 },
          },
          required: ["query"],
        },
      },
      handler: async ({ query, limit }) => {
        try {
          const res = await fetch(
            `https://api.myprovider.com/search?q=${encodeURIComponent(query)}&limit=${limit ?? 10}`,
            { headers: { Authorization: `Bearer ${apiKey}` } },
          );
          if (!res.ok) return err(`HTTP ${res.status}`);
          return ok(await res.json());
        } catch (e) {
          return errFromThrow(e);
        }
      },
    },
  ];
}

Register it in apps/agent/src/app.ts (around line ~365, where all tool factories are plugged in):

import { createMyProviderTools } from "./tools/my-provider.js";
// ...
toolRegistry.register(...createMyProviderTools());

Add a tool-set entry in apps/agent/src/core/tool-registry.ts inside BUILTIN_TOOL_SETS:

research: {
  description: "Market and social research tools",
  tools: [
    // ... existing
    "my_provider_search",
  ],
},

Permission tiers

Permission tiers are defined in apps/agent/src/core/tool-registry.ts:

TierNameWhen to use
1READ_ONLYprice / balance / search / read_file
2CONFIRM_ONCEanalysis, research, small swaps
3ALWAYS_CONFIRMwrite_file, patch, fund-moving, document generation
4MANUAL_ONLYwithdraws, external-address sends, emergency stop

When in doubt, match the closest existing tool's tier.

Result envelope

Every handler returns a string via ok({...}) / err("...") from apps/agent/src/tools/_shared/result.ts. Never throw from handlers. Use errFromThrow(e) to convert caught errors. The agent loop parses the envelope and presents structured errors to the LLM.

Sandbox-rooted file tools

If your tool touches the filesystem, resolve every path through resolveInSandbox() from apps/agent/src/tools/_shared/sandbox.ts. This is non-negotiable. See Sandbox & Permissions.

On this page