Skip to main content
Search local code repositories on disk. WarpGrep takes a natural language query, runs multiple grep and file-read operations in a separate context window, and returns the relevant code.

Why?

Use codebase search when your primary agent needs to do broad exploration across a local repository — finding implementations, understanding how modules connect, or locating code by description rather than exact pattern.
See complete agent examples for each framework — copy-paste ready.

Quick Start

import Anthropic from '@anthropic-ai/sdk';
import { MorphClient } from '@morphllm/morphsdk';

const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
const anthropic = new Anthropic();

const grepTool = morph.anthropic.createWarpGrepTool({ repoRoot: '.' });

async function askCodebase(question: string) {
  const messages: Anthropic.MessageParam[] = [
    { role: 'user', content: question }
  ];
  let maxTurns = 5;

  while (maxTurns-- > 0) {
    const response = await anthropic.messages.create({
      model: 'claude-sonnet-4-5-20250929',
      max_tokens: 8192,
      tools: [grepTool],
      system: 'Use the search tool to find relevant code before answering. Cite file paths.',
      messages
    });

    // Model is done — return the final text
    if (response.stop_reason === 'end_turn') {
      return response.content.find(c => c.type === 'text')?.text;
    }

    // Otherwise, execute tool calls and feed results back
    messages.push({ role: 'assistant', content: response.content });

    const toolResults = [];
    for (const block of response.content) {
      if (block.type === 'tool_use') {
        const result = await grepTool.execute(block.input);
        toolResults.push({
          type: 'tool_result' as const,
          tool_use_id: block.id,
          content: grepTool.formatResult(result)
        });
      }
    }

    messages.push({ role: 'user', content: toolResults });
  }
}

await askCodebase('How does authentication work in this project?');
import OpenAI from 'openai';
import { MorphClient } from '@morphllm/morphsdk';

const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
const openai = new OpenAI();

const grepTool = morph.openai.createWarpGrepTool({ repoRoot: '.' });

async function askCodebase(question: string) {
  const messages: OpenAI.ChatCompletionMessageParam[] = [
    { role: 'user', content: question }
  ];
  let maxTurns = 5;

  while (maxTurns-- > 0) {
    const response = await openai.chat.completions.create({
      model: 'gpt-4o',
      tools: [grepTool],
      messages
    });

    const choice = response.choices[0];
    if (choice.finish_reason === 'stop') {
      return choice.message.content;
    }

    messages.push(choice.message);

    for (const toolCall of choice.message.tool_calls || []) {
      const result = await grepTool.execute(toolCall.function.arguments);
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: grepTool.formatResult(result)
      });
    }
  }
}

Configuration

const grepTool = morph.openai.createWarpGrepTool({
  repoRoot: '.',
  excludes: ['dist', '*.test.ts'],
  includes: ['src/**/*.ts'],
});
OptionDefaultDescription
repoRoot(required)Root directory of the repository to search
excludes(see below)Glob patterns to exclude
includes(all files)Glob patterns to include (e.g., ['src/**/*.ts', 'lib/**/*.js'])
namecodebase_searchTool name exposed to the LLM
description(see SDK)Tool description for the LLM
remoteCommands(local)Functions for remote sandbox execution (see Sandbox Execution)
morphApiUrlhttps://api.morphllm.comOverride API base URL
timeout30000Timeout in ms (also via MORPH_WARP_GREP_TIMEOUT env var)

Default Excludes

WarpGrep excludes common non-source directories by default:
  • Dependencies: node_modules, bower_components, .pnpm, .yarn, vendor, Pods, .bundle
  • Build output: dist, build, .next, .nuxt, out, target, .output
  • Python: __pycache__, .pytest_cache, .mypy_cache, .ruff_cache, .venv, venv, site-packages
  • Version control: .git, .svn, .hg
  • Lock files, minified files, source maps, and common binary formats
Pass excludes to override these defaults. Your list replaces the defaults entirely — it does not merge with them.
To search inside node_modules (e.g., debugging a library), pass excludes: []. See the node_modules example.

Error Handling

const result = await grepTool.execute(toolUse.input);

if (!result.success) {
  console.error(result.error);
  // Common errors:
  // - "Search did not complete" — the model did not call finish within 4 turns
  // - "API error" — authentication or network issue
  // - "timeout" — search took longer than the configured timeout
}