# How to Write Custom Tools or Extensions for the OMP Coding Agent: A Complete Guide

> Learn how to write custom tools or extensions for the OMP coding agent. This guide explains how to create TypeScript modules and load them into the agent for enhanced functionality.

- Repository: [Can Bölük/oh-my-pi](https://github.com/can1357/oh-my-pi)
- Tags: how-to-guide
- Published: 2026-05-21

---

**To write custom tools for the OMP coding agent, create a TypeScript module that exports a `CustomTool` object conforming to the interface defined in [`types.ts`](https://github.com/can1357/oh-my-pi/blob/main/types.ts), drop it into the `~/.omp/custom-tools` directory (or a path specified by `OMP_CUSTOM_TOOLS_PATH`), and the agent will automatically discover and register it via `discoverAndLoadCustomTools()` at startup.**

The OMP (Oh-My-Pi) coding agent from the `can1357/oh-my-pi` repository provides a flexible **plugin system** that allows developers to extend its capabilities without modifying core agent code. By writing custom tools or extensions for the OMP coding agent, you can integrate external APIs, custom scripts, or domain-specific logic that the LLM can invoke dynamically during conversations. This guide walks through the architecture, implementation patterns, and registration process based on the actual source code structure.

## Understanding the Custom Tool Architecture

The OMP coding agent treats tools as first-class plugins that follow a strict runtime contract. Understanding these four key stages—definition, discovery, registration, and execution—ensures your extensions integrate seamlessly with the agent's tooling pipeline.

### Tool Definition and Contract

Every custom tool must export a `CustomTool` object (or factory function) that describes its metadata, input schema, and execution logic. The type definitions reside in [`packages/coding-agent/src/extensibility/custom-tools/types.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/extensibility/custom-tools/types.ts), which specifies:

- **`name`**: The unique identifier the model uses to invoke the tool.
- **`parameters`**: A JSON Schema object defining valid arguments.
- **`run`**: An async function receiving validated arguments and a `CustomToolContext` (containing `logger`, `signal`, and helpers).
- **`renderResult`** (optional): A function for custom TUI formatting.

### Discovery and Loading

At launch, the agent calls `discoverAndLoadCustomTools()` from [`packages/coding-agent/src/sdk.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/sdk.ts). This routine scans the default `omp-tools` directory or any folder added via the `OMP_CUSTOM_TOOLS_PATH` environment variable for `.ts` and `.js` files. It dynamically imports each module using `import()`, validates the exported shape against the `CustomTool` interface, and prepares them for registration.

### Registration and Execution

Each discovered tool is wrapped by `CustomToolAdapter` in [`packages/coding-agent/src/extensibility/custom-tools/wrapper.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/extensibility/custom-tools/wrapper.ts). This adapter normalizes the tool for the internal pipeline, handling async execution, abort signals, and result rendering. When the model decides to call a tool, the agent looks up the tool by name in the registry, invokes its `run` method, and streams the result back to the conversation.

### MCP Integration

Tools are exposed to the Multi-Channel Protocol (MCP) layer via [`packages/coding-agent/src/mcp/tool-bridge.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/mcp/tool-bridge.ts). This bridge makes custom tools available to both the CLI interface and remote clients, ensuring consistent behavior across all interfaces.

## Creating Your First Custom Tool

A valid custom tool is a TypeScript module that exports a single `CustomTool` object. Below is a complete example that fetches weather data from a public API.

```typescript
// File: ~/.omp/custom-tools/weather.ts
import type { CustomTool, CustomToolContext, RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";

export const weather: CustomTool = {
  // 1️⃣ Tool identifier used by the model
  name: "weather",

  // 2️⃣ JSON Schema for input validation
  description: "Get the current weather for a city.",
  parameters: {
    type: "object",
    properties: {
      city: { type: "string", description: "Name of the city, e.g. 'Berlin'" },
    },
    required: ["city"],
  },

  // 3️⃣ Execution function with automatic abort signal support
  async run(args: { city: string }, ctx: CustomToolContext): Promise<string> {
    const { logger, signal } = ctx;
    const url = `https://wttr.in/${encodeURIComponent(args.city)}?format=%C+%t`;
    
    const resp = await fetch(url, { signal });
    if (!resp.ok) {
      logger.error("Weather API error", { status: resp.status });
      throw new Error(`Unable to fetch weather for ${args.city}`);
    }
    const text = await resp.text();
    return `Current weather in ${args.city}: ${text}`;
  },

  // 4️⃣ Optional TUI rendering for colored output
  renderResult: (result: string, opts: RenderResultOptions) => {
    return opts.theme.fg("toolResult", result);
  },
};

```

Key implementation details from this example:

- **Type Safety**: Import types from `@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types` to ensure compile-time validation.
- **Abort Handling**: The `signal` property in `CustomToolContext` allows the tool to respect cancellation requests from the agent.
- **Logging**: Use `ctx.logger` for structured logging that appears in the agent's debug output.
- **Rendering**: The optional `renderResult` function receives theme helpers for consistent terminal styling.

## Installing and Registering Custom Tools

The OMP coding agent uses a **zero-configuration** discovery system. Simply place your tool file in the correct location and restart the agent.

### Default Installation Path

Create the standard directory and place your TypeScript file inside:

```bash
mkdir -p ~/.omp/custom-tools
cp weather.ts ~/.omp/custom-tools/

```

### Custom Tool Paths

Alternatively, specify additional directories via the environment variable:

```bash
export OMP_CUSTOM_TOOLS_PATH="/path/to/company-tools:/path/to/personal-tools"
omp start

```

The agent recursively scans these paths for `.ts` and `.js` files at startup. No manual registration steps are required—`discoverAndLoadCustomTools()` handles all loading and validation automatically.

## Using Custom Tools in Conversations

Once registered, the model automatically recognizes when to invoke your tool based on its description and the conversation context.

```bash
$ omp ask "What's the weather in Tokyo?"
🛠️  Calling tool: weather
Current weather in Tokyo: Clear +26°C

```

The agent handles the entire execution lifecycle: validation of arguments against your JSON Schema, invocation of the `run` method with proper context, and streaming of results back to the model. If your tool exports a `renderResult` function, the TUI applies the formatting before displaying the output to the user.

## Summary

Writing custom tools or extensions for the OMP coding agent involves these core concepts:

- **Contract Compliance**: Export a `CustomTool` object with `name`, `parameters` (JSON Schema), and an async `run` function conforming to the interface in [`packages/coding-agent/src/extensibility/custom-tools/types.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/extensibility/custom-tools/types.ts).
- **Automatic Discovery**: Place files in `~/.omp/custom-tools` or paths listed in `OMP_CUSTOM_TOOLS_PATH`; the agent discovers them via `discoverAndLoadCustomTools()` in [`packages/coding-agent/src/sdk.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/sdk.ts).
- **Runtime Wrapping**: The `CustomToolAdapter` in [`packages/coding-agent/src/extensibility/custom-tools/wrapper.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/extensibility/custom-tools/wrapper.ts) handles abort signals, logging, and result normalization automatically.
- **MCP Availability**: Tools registered via this system are automatically exposed through [`packages/coding-agent/src/mcp/tool-bridge.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/mcp/tool-bridge.ts) for remote access.
- **Type Safety**: Full TypeScript support with context-provided utilities for logging, fetch aborting, and terminal rendering.

## Frequently Asked Questions

### What is the minimum required structure for a custom tool?

A valid custom tool must export an object with at least three properties: `name` (string), `parameters` (JSON Schema object), and `run` (async function). The `run` function receives validated arguments and a `CustomToolContext` object containing `logger` and `signal`. While `renderResult` is optional for custom UI formatting, the tool will function with just these three core fields as defined in [`packages/coding-agent/src/extensibility/custom-tools/types.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/extensibility/custom-tools/types.ts).

### Can I use JavaScript instead of TypeScript for custom tools?

Yes. The discovery mechanism in [`packages/coding-agent/src/sdk.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/sdk.ts) accepts both `.ts` and `.js` files. While the examples use TypeScript for type safety, plain JavaScript modules that export a `CustomTool`-shaped object will load and execute correctly, though you lose compile-time validation against the interface definitions.

### How does the agent handle errors in custom tools?

Errors thrown within the `run` method are caught by the `CustomToolAdapter` in [`packages/coding-agent/src/extensibility/custom-tools/wrapper.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/extensibility/custom-tools/wrapper.ts) and converted into structured error responses for the model. Use `ctx.logger.error()` for debuggable stack traces, and throw descriptive Error objects to help the LLM understand what went wrong and potentially retry with corrected parameters.

### Where should I place custom tools for team-wide or CI/CD usage?

For shared environments, set the `OMP_CUSTOM_TOOLS_PATH` environment variable to point to a version-controlled directory (e.g., `export OMP_CUSTOM_TOOLS_PATH="./tools"`). The agent scans all paths listed in this variable at startup, allowing you to commit custom tools to your repository and share them across team members or CI pipelines without modifying the default `~/.omp/custom-tools` user directory.