Answer natural language questions about any codebase. WarpGrep finds the relevant code, Claude explains it.
Copy
Ask AI
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: 'You are a codebase expert. Use the search tool to find relevant code before answering. Always cite file paths and line numbers.', messages }); if (response.stop_reason === 'end_turn') { return response.content.find(c => c.type === 'text')?.text; } 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 }); }}// Usageawait askCodebase('How does authentication work in this project?');await askCodebase('What database queries are not using transactions?');await askCodebase('Where are environment variables validated?');
What it does: Agent receives a question, searches the codebase for relevant code, then synthesizes an answer with file references. Multiple search rounds if the first pass doesn’t find enough context.
Review pull requests by searching the surrounding codebase for context the diff alone doesn’t show.
Copy
Ask AI
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 reviewPR(diff: string, changedFiles: string[]) { const messages: Anthropic.MessageParam[] = [{ role: 'user', content: `Review this pull request. Search the codebase to understand how the changed code is used elsewhere before reviewing.Changed files: ${changedFiles.join(', ')}\`\`\`diff${diff}\`\`\`For each changed file:1. Search for callers and consumers of the modified functions2. Check for similar patterns elsewhere that should be updated3. Flag breaking changes, missing error handling, or inconsistenciesOutput a structured review with severity levels (critical, warning, suggestion).` }]; let maxTurns = 8; while (maxTurns-- > 0) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-5-20250929', max_tokens: 8192, tools: [grepTool], messages }); if (response.stop_reason === 'end_turn') { return response.content.find(c => c.type === 'text')?.text; } 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 }); }}// GitHub Actions integrationconst diff = process.env.PR_DIFF!;const files = process.env.PR_FILES?.split(',') || [];const review = await reviewPR(diff, files);// Post as PR commentconst { Octokit } = require('@octokit/rest');const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });await octokit.issues.createComment({ owner: process.env.GITHUB_REPOSITORY_OWNER!, repo: process.env.GITHUB_REPOSITORY?.split('/')[1], issue_number: parseInt(process.env.PR_NUMBER!), body: review});
Why this is better than reviewing the diff alone: The agent searches for callers of modified functions, checks for similar patterns that might need the same change, and finds tests that should be updated. A diff-only review misses these.
Scan a codebase for common security vulnerabilities. WarpGrep finds the code, Claude evaluates the risk.
Copy
Ask AI
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: '.' });const AUDIT_CHECKS = [ 'Find all SQL queries and check for SQL injection vulnerabilities', 'Find user input handling and check for missing sanitization or validation', 'Find authentication and session management code, check for token expiry and secure storage', 'Find file upload handling and check for path traversal or unrestricted file types', 'Find API endpoints that lack authorization checks', 'Find secrets, API keys, or credentials hardcoded in source files', 'Find uses of eval, exec, or dynamic code execution',];async function securityAudit() { const findings = []; for (const check of AUDIT_CHECKS) { const messages: Anthropic.MessageParam[] = [{ role: 'user', content: `${check}Search the codebase thoroughly. For each finding, report:- File and line number- Severity (critical / high / medium / low)- Description of the vulnerability- Suggested fixIf nothing is found, say "No issues found for this check."` }]; let maxTurns = 5; while (maxTurns-- > 0) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-5-20250929', max_tokens: 4096, tools: [grepTool], messages }); if (response.stop_reason === 'end_turn') { findings.push({ check, result: response.content.find(c => c.type === 'text')?.text }); break; } 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 }); } } return findings;}
How it works: Runs each security check as an independent search-and-analyze pass. Each check gets a fresh context window, so WarpGrep can focus its search budget on that specific vulnerability class.
Search inside node_modules to understand how a library works or debug an issue at the source.
Copy
Ask AI
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();async function debugDependency(packageName: string, question: string) { // Search only inside the specific package, with no default excludes const grepTool = morph.anthropic.createWarpGrepTool({ repoRoot: `./node_modules/${packageName}`, excludes: [], }); const messages: Anthropic.MessageParam[] = [{ role: 'user', content: `I'm debugging the "${packageName}" package. ${question}Search the source code and explain what you find. Include file paths and relevant code snippets.` }]; let maxTurns = 5; while (maxTurns-- > 0) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-5-20250929', max_tokens: 4096, tools: [grepTool], messages }); if (response.stop_reason === 'end_turn') { return response.content.find(c => c.type === 'text')?.text; } 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 }); }}// Debug why a library behaves unexpectedlyawait debugDependency('next', 'How does the App Router handle route matching?');await debugDependency('prisma', 'Where does connection pooling happen?');await debugDependency('zod', 'How does .transform() chain with .refine()?');
Why excludes: []: WarpGrep excludes node_modules by default. Passing an empty excludes list disables all default excludes so you can search library source code.
Before a large migration, search for every pattern that needs to change.
Copy
Ask AI
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 migrationPlan(from: string, to: string) { const messages: Anthropic.MessageParam[] = [{ role: 'user', content: `I'm migrating from ${from} to ${to}. Search the codebase and produce a migration checklist.For each pattern you find:1. Search for all usages of ${from}-specific APIs, imports, and patterns2. List every file that needs changes3. Show the current code and what it should become4. Flag any patterns that don't have a direct equivalent in ${to}Group findings by category (imports, API calls, configuration, types, tests).Output a numbered checklist I can work through file by file.` }]; let maxTurns = 10; while (maxTurns-- > 0) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-5-20250929', max_tokens: 12000, tools: [grepTool], messages }); if (response.stop_reason === 'end_turn') { return response.content.find(c => c.type === 'text')?.text; } 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 }); }}// Generate migration plansawait migrationPlan('Express', 'Hono');await migrationPlan('Mongoose', 'Drizzle');await migrationPlan('Jest', 'Vitest');await migrationPlan('Pages Router', 'App Router');
What it does: Exhaustively searches for every usage of the old framework’s patterns, then produces a file-by-file migration checklist with before/after code snippets.