Documentation Index
Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
Use this file to discover all available pages before exploring further.
Subagents are autonomous agents that run in their own context window. The Explore subagent searches your codebase using WarpGrep, decides what to search next based on results, and returns a structured summary. Your main agent’s context stays clean.
Why?
Codebase exploration is context-heavy. A single WarpGrep call returns relevant code, but understanding how a system works often takes 3-8 searches. The Explore subagent handles this loop autonomously on a cheap/fast model (Haiku), then returns only the summary to your primary agent.
The subagent also supports pause-and-ask messaging: if it hits a fork in the road (“Found JWT and OAuth auth. Which should I focus on?”), it can ask your app and wait for a reply before continuing.
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();
// Create the subagent
const explore = morph.anthropic.createExploreSubagent({
client: anthropic,
model: 'claude-haiku-4-5-20251001',
repoRoot: '.',
});
// Run an exploration
const session = explore.run('How does the authentication system work?');
session.on('step', (step) => {
console.log(`Step ${step.step}: searching "${step.searchRequest}"`);
});
const result = await session.result;
console.log(result.summary); // Concise summary for your agent
console.log(result.contexts); // Full code contexts for your app
import { generateText, stepCountIs } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
// Create the subagent
const explore = morph.vercel.createExploreSubagent({
model: anthropic('claude-haiku-4-5-20251001'),
repoRoot: '.',
});
// Use as a tool in your parent agent
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { explore: explore.tool },
stopWhen: stepCountIs(5),
prompt: 'How does the auth flow work in this codebase?',
});
Three Ways to Use
The subagent exposes a .tool property you can pass to any agent. The parent model calls it like any other tool, and the subagent runs its full search loop internally.
const explore = morph.anthropic.createExploreSubagent({
client: anthropic,
model: 'claude-haiku-4-5-20251001',
repoRoot: '.',
});
// Use alongside other tools
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8000,
tools: [explore.tool, editTool],
messages: [{ role: 'user', content: 'Find and fix the auth bug' }]
});
// Execute when the model calls it
const toolUse = response.content.find(c => c.type === 'tool_use' && c.name === 'explore');
if (toolUse) {
const result = await explore.tool.execute(toolUse.input);
console.log(result.summary);
}
const explore = morph.vercel.createExploreSubagent({
model: anthropic('claude-haiku-4-5-20251001'),
repoRoot: '.',
});
// Vercel AI SDK handles the tool loop
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { explore: explore.tool, edit: editTool },
stopWhen: stepCountIs(5),
prompt: 'Find and fix the auth bug',
});
2. Direct Run with Messaging
Call .run() to start an exploration and listen for events. The subagent can pause and ask questions via send_message, and your app replies.
const session = explore.run('Explore the payment processing system');
// Listen for progress
session.on('step', (step) => {
console.log(`Step ${step.step}: searching "${step.searchRequest}" -> ${step.contextsFound} files`);
});
// Handle pause-and-ask messages
session.on('message', (msg, reply) => {
console.log(`Subagent asks: ${msg.content}`);
// e.g. "Found Stripe and PayPal integrations. Which should I focus on?"
reply('Focus on Stripe');
});
const result = await session.result;
// result.success, result.summary, result.contexts, result.searchCount, result.durationMs
3. Streaming
Use .stream() to get events as an async generator.
for await (const event of explore.stream('Find all API routes')) {
if (event.type === 'step') {
console.log(`Searching: ${event.searchRequest} -> ${event.contextsFound} files`);
}
if (event.type === 'message') {
console.log(`Subagent: ${event.content}`);
}
}
Messaging Protocol
The subagent has two internal tools: codebase_search (WarpGrep) and send_message. The system prompt instructs it to use send_message when it:
- Hits a fork: “Found auth in both
src/middleware/ and legacy/auth/. Should I focus on one or cover both?”
- Needs clarification: “There are 3 auth strategies (JWT, session, OAuth). Which one?”
- Has a key finding to share before continuing: “The main handler is in
src/auth/index.ts. Continuing to trace the JWT flow.”
When send_message is called, the tool blocks until your app replies (or a timeout fires). The reply is injected back as the tool result, and the subagent continues with that context.
Your App Explore Subagent
| |
|---- run("How does auth work?") ----->|
| |-- codebase_search("auth")
|<-- step: searching "auth" ----------|-- WarpGrep returns results
| |-- model has a question
| |-- send_message("Found JWT and OAuth...")
|<-- message: "Found JWT and..." -----|-- BLOCKS, waiting for reply
| |
|---- reply("Focus on JWT") --------->|-- tool returns "Response: Focus on JWT"
| |-- codebase_search("JWT validation")
|<-- step: searching "JWT..." --------|-- WarpGrep returns results
| |-- model has enough info
|<-- result: ExploreResult ------------|
Configuration
const explore = morph.vercel.createExploreSubagent({
model: anthropic('claude-haiku-4-5-20251001'),
repoRoot: '.',
thoroughness: 'medium',
replyTimeout: 30000,
excludes: ['dist', '*.test.ts'],
});
| Option | Default | Description |
|---|
model | (required) | Vercel AI SDK model instance, or model string for Anthropic |
client | (Anthropic only) | Anthropic SDK client instance |
repoRoot | (required) | Root directory of the repository to search |
thoroughness | 'medium' | 'quick' (1-2 searches), 'medium' (2-4), 'thorough' (4-8) |
maxTurns | (auto) | Override the max model turns (defaults based on thoroughness) |
timeout | (none) | Timeout in ms for the entire exploration |
replyTimeout | 30000 | Timeout in ms for waiting for host reply to send_message |
excludes | (WarpGrep defaults) | Glob patterns to exclude from search |
includes | (all files) | Glob patterns to include in search |
Result Shape
interface ExploreResult {
success: boolean; // Whether the exploration completed
summary: string; // Concise summary (for model consumption)
contexts: WarpGrepContext[]; // Full code contexts (for your app)
searchCount: number; // Number of WarpGrep searches performed
durationMs: number; // Total wall-clock time
error?: string; // Error message if failed
}
Each context in contexts contains:
interface WarpGrepContext {
file: string; // File path relative to repoRoot
content: string; // Relevant code with line numbers
lines?: '*' | Array<[number, number]>; // Line ranges
}
Direct Import
You can also import the subagent creators directly without MorphClient:
import { createExploreSubagent } from '@morphllm/morphsdk/subagents/anthropic';
const explore = createExploreSubagent({
client: new Anthropic(),
model: 'claude-haiku-4-5-20251001',
morphApiKey: process.env.MORPH_API_KEY,
repoRoot: '.',
});
import { createExploreSubagent } from '@morphllm/morphsdk/subagents/vercel';
const explore = createExploreSubagent({
model: anthropic('claude-haiku-4-5-20251001'),
morphApiKey: process.env.MORPH_API_KEY,
repoRoot: '.',
});