Sitemap

How to create a subagent in Claude Code

Organising context for better results using Elastic Agent Builder

--

If you use Claude Code for anything beyond small edits, you quickly run into a context problem.

You ask the agent to plan a feature, inspect a few files, check some logs, maybe review an implementation idea, and before long the main conversation is carrying too much baggage. The result is slower reasoning, more noise, and less focus.

Subagents come to the rescue to solve that!

In this tutorial, I’ll show you how to think about subagents, how to create one in Claude Code, and how to extend it with external business context using Elastic Agent Builder.

What is a subagent?

A subagent is a focused assistant inside Claude Code with its own instructions, its own context window, and optionally its own tool access. You hand it a specific job, it does the work, and it returns the result to the main agent without dragging every intermediate step into the main chat.

It has its own job description, can be limited to only the tools it needs, and runs separately from the main chat. That matters because the main agent can stay focused on the bigger workflow while the subagent handles a narrower task such as:

  • exploring a codebase
  • planning a feature
  • reviewing code quality
  • debugging a failure
  • pulling information from an external source

Claude Code already leans into this model with built-in agent patterns like Explore and Plan. The point is not to create more complexity. The point is to keep each part of the job in the right place.

When should I use a subagent?

Create a subagent when all three of these are true:

  1. The task is specialised.
  2. The task needs its own context.
  3. You want to reuse that capability later.

For example, a planning subagent makes sense because planning usually involves reading multiple files, comparing alternatives, and returning a clean implementation outline. You want the conclusion, not every search query and discarded idea, to remain in the main conversation.

A retrieval subagent also makes sense when you need to query systems outside the local repo, such as Elasticsearch, APIs, or internal documentation. Let’s dig into a practical guide that you can follow to create a subagent in Claude code.

Step 1: Scope the job before you create the subagent

This is the part most people get wrong.

If the job is vague, the subagent will behave vaguely. If the job is narrow, the output gets much better.

Too broad:

Review the code.

Much better:

Review src/auth/index.ts and focus on JWT validation and token refresh behavior.

That one change affects everything. It changes how much the agent searches, how many tokens it spends, and how likely it is to return something you can actually use.

As a rule, write the subagent request the same way you would brief a strong engineer who has no background context and no patience for ambiguity.

Step 2: Give the subagent only the tools it needs

Subagents work better when they are constrained and focused.

If a subagent only needs to inspect files, do not give it write access. If it only needs to search, do not give it terminal tools it can misuse. The narrower the toolset, the more predictable and secure the behavior.

A read-only analysis subagent might use:

tools: Read, Grep, Glob

A coding subagent might use:

tools: Read, Edit, Write, Grep, Glob

Choosing specific tools adds safety and improves focus. Fewer tools means fewer pointless decisions. You can learn all Claude Code tools here.

Step 3: Understand the shape of a Claude Code subagent

Claude Code subagents use a simple structure: metadata at the top, followed by the actual instructions.

A minimal example looks like this:

---
name: planning-agent
description: Use this subagent when deep analysis is needed before implementation
tools: Read, Grep, Glob
model: sonnet
permissionMode: default
---

You are a planning specialist. Analyze the relevant files, identify dependencies,
surface risks, and produce a concrete implementation plan with clear sequencing.
Do not propose code changes until the problem boundaries are clear.

There are two parts that matter most:

  • the description, which tells Claude when to use the subagent
  • the instruction body, which tells the subagent how to think and what to return

If those two are weak, the subagent will not be reliable.

Step 4: Create the subagent in Claude Code

Claude Code makes this easier than it sounds.

The simplest path is to let Claude generate the starting definition for you.

  1. Run /agents
  2. Choose Create new agent
  3. Select Project scope
  4. Choose how you want to generate the agent (with Claude or manually)
  5. Describe what the agent should do
  6. Select the tools it should have
  7. Pick the model
  8. Confirm the new agent

If you are creating a planning-oriented helper, a description like this is a good starting point:

Agent that analyzes a codebase before implementation. Use this agent when you need a detailed plan, dependency analysis, risk assessment, or task breakdown.

Claude will turn that into a subagent you can refine.

Step 5: Call the subagent with a focused prompt

Once the subagent exists, the quality of the invocation still matters.

Weak invocation:

Use the planning agent.

Better invocation:

Use the planning agent to analyze the authentication flow.
Focus on token refresh, session expiration, and error handling.
Read only the auth-related files and return a step-by-step implementation plan.

The subagent should not have to guess what success looks like.

This is especially important because subagents do not automatically inherit the detailed intent from the surrounding conversation. You need to give them enough to work with.

Step 6: Reuse it instead of recreating it

One of the practical advantages of subagents is that they are reusable.

If you create a strong planning subagent, you can use it across sessions and across tasks. That gives you a stable workflow instead of a new prompt experiment every time.

Subagents are also stateful. If you resume a previous one with its agent ID, you can continue a longer investigation instead of starting over. That is useful for deep code analysis, staged reviews, or work that spans multiple conversations.

How subagents fit into larger workflows

In practice, you usually use subagents in one of three patterns.

Sequential

One subagent hands off to the next.

For example:

First use the planning agent to design the feature,
then use the coding agent to implement it,
finally use the reviewer agent to inspect the result.

This is a good fit when each stage depends on the last.

Press enter or click to view image in full size

Parallel

Multiple subagents work independently at the same time.

That is useful when you want several perspectives, such as architecture review, security review, and test-gap analysis, without waiting for each one to finish in sequence.

Hub-and-spoke (aka delegation)

The main agent coordinates multiple specialized helpers and combines the output.

This is the most interesting pattern when some context is local and some comes from external systems.

Adding business context with Elastic Agent Builder

Using subagents to face business challenges is the part that makes the workflow more useful in real teams.

Claude Code can read your local project files, but it does not automatically know what is happening in your production systems, support queue, or internal knowledge base. If you want planning decisions to reflect business reality, you need a way to bring that context in.

I like to use Elastic Agent Builder for this because it’s designed for this exact purpose. It allows users to ship agents grounded in your data in minutes.

The idea is straightforward:

  • create an agent in Elastic that can search documents and run ES|QL queries
  • expose that agent over MCP
  • let a Claude Code subagent call those tools when planning or prioritising work

You do not need to make Elastic the centre of the workflow. Think of it as an optional data source that upgrades your subagent from “good local analyst” to “analyst with business context.”

A lightweight hands-on example

Here is a practical end-to-end workflow you can follow to build a retrieval subagent with Elastic and use it from Claude Code.

For this example, I use the following tools:

The flow has five steps: load the demo data into Elasticsearch, create an Agent Builder agent, connect that agent to Claude Code through MCP, create a Claude Code subagent that uses those tools, and test it with a planning prompt.

The scenario is technical debt prioritisation. So, for this example we will provide to Claude Code a local file called TECH_DEBT.md. Elasticsearch adds the missing operational context: production errors, support volume, customer tier impact, and internal knowledge.

In the following code block, you can find the content of the TECH_DEBT.md file that I provided to Claude Code.

# Tech Debt Items

## AUTH-001: Token refresh race condition
- **Module**: src/auth/refresh.ts
- **Symptom**: Users randomly logged out
- **Estimate**: 3 days

## EXPORT-002: CSV export timeout on large datasets
- **Module**: src/export/csv.ts
- **Symptom**: Timeout after 30s for >10k rows
- **Estimate**: 2 days

## SEARCH-003: Indexing lag after bulk updates
- **Module**: src/search/indexer.ts
- **Symptom**: New products not searchable for ~5min
- **Estimate**: 5 days

## API-004: Rate limiter inconsistency
- **Module**: src/api/rate-limiter.ts
- **Symptom**: Some endpoints not rate limited
- **Estimate**: 1 day

## NOTIFY-005: Silent email failures
- **Module**: src/notifications/email.ts
- **Symptom**: Emails fail without alerting
- **Estimate**: 2 days

## CACHE-006: Redis connection pooling
- **Module**: src/cache/redis.ts
- **Symptom**: Occasional connection exhaustion
- **Estimate**: 3 days

## LOG-007: Inconsistent log levels
- **Module**: Multiple
- **Symptom**: Debug logs in production
- **Estimate**: 1 day

## DB-008: Missing database indexes
- **Module**: src/db/queries.ts
- **Symptom**: Slow queries on user table
- **Estimate**: 0.5 days

## TEST-009: Flaky integration tests
- **Module**: tests/integration/*
- **Symptom**: Random CI failures
- **Estimate**: 4 days

## UI-010: Memory leak in dashboard
- **Module**: src/components/Dashboard.tsx
- **Symptom**: Browser slowdown after 2hrs
- **Estimate**: 2 days

## SEC-011: Outdated dependencies
- **Module**: package.json
- **Symptom**: 3 moderate vulnerabilities
- **Estimate**: 1 day

## PERF-012: N+1 queries in reports
- **Module**: src/reports/generator.ts
- **Symptom**: Report generation slow
- **Estimate**: 2 days

Step 1: Load the demo data with Kibana Dev Tools

Open Kibana Dev Tools and run the following Elasticsearch request index setup scripts:

Knowledge index:

PUT knowledge
{
"mappings": {
"properties": {
"title": { "type": "text" },
"content": { "type": "text" },
"category": { "type": "keyword" },
"tags": { "type": "keyword" },
"source": { "type": "keyword" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" }
}
}
}

POST knowledge/_bulk
{"index":{}}
{"title":"Engineering Standards: Enterprise Reliability","content":"Enterprise reliability is non-negotiable. Any issue affecting paying customers on Enterprise tier must be prioritized over issues affecting free tier users. Response time SLA for enterprise customers is 4 hours. All enterprise-impacting bugs are P1 by default.","category":"standards","tags":["engineering","enterprise","reliability","priority"],"source":"engineering-team","created_at":"2024-01-15","updated_at":"2024-11-01"}
{"index":{}}
{"title":"Q1 2025 Roadmap Priorities","content":"Q1 priorities focus on enterprise expansion and reliability. Key initiatives: 1) Reduce enterprise churn by fixing top 3 pain points, 2) Improve export functionality for large datasets, 3) Enhance authentication security. Performance optimizations are secondary unless they impact enterprise customers.","category":"roadmap","tags":["roadmap","q1","enterprise","priorities"],"source":"product-team","created_at":"2024-12-01","updated_at":"2024-12-15"}
{"index":{}}
{"title":"Technical Debt Policy","content":"Technical debt should be prioritized based on: 1) Customer impact (enterprise > pro > free), 2) Error frequency in production, 3) Support ticket volume, 4) Strategic alignment with quarterly roadmap. Quick wins (< 2 days effort) that address enterprise issues should be prioritized.","category":"standards","tags":["tech-debt","policy","prioritization"],"source":"engineering-team","created_at":"2024-06-01","updated_at":"2024-10-15"}

Error logs index:

PUT error_logs
{
"mappings": {
"properties": {
"module": { "type": "keyword" },
"error_type": { "type": "keyword" },
"message": { "type": "text" },
"severity": { "type": "keyword" },
"count": { "type": "integer" },
"user_ids_affected": { "type": "keyword" },
"timestamp": { "type": "date" }
}
}
}

POST error_logs/_bulk
{"index":{}}
{"module":"src/auth/refresh.ts","error_type":"TokenRefreshRaceCondition","message":"User session terminated unexpectedly during token refresh","severity":"error","count":342,"user_ids_affected":["user_001","user_002","user_003","user_045","user_089"],"timestamp":"2024-12-20T10:00:00Z"}
{"index":{}}
{"module":"src/export/csv.ts","error_type":"ExportTimeout","message":"CSV export timed out after 30s for datasets exceeding 10k rows","severity":"error","count":89,"user_ids_affected":["enterprise_user_01","enterprise_user_02","enterprise_user_05"],"timestamp":"2024-12-20T10:00:00Z"}
{"index":{}}
{"module":"src/search/indexer.ts","error_type":"IndexingLag","message":"Search index not updated within expected 30s window after bulk update","severity":"warning","count":12,"user_ids_affected":["user_112","user_445"],"timestamp":"2024-12-20T10:00:00Z"}
{"index":{}}
{"module":"src/api/rate-limiter.ts","error_type":"RateLimitMisconfiguration","message":"Rate limit applied inconsistently across API endpoints","severity":"warning","count":23,"user_ids_affected":["user_067","user_089"],"timestamp":"2024-12-20T10:00:00Z"}
{"index":{}}
{"module":"src/notifications/email.ts","error_type":"EmailDeliveryFailure","message":"Email notifications failing silently for some users","severity":"error","count":156,"user_ids_affected":["user_034","user_078","user_123"],"timestamp":"2024-12-20T10:00:00Z"}

Support tickets index:

PUT support_tickets
{
"mappings": {
"properties": {
"ticket_id": { "type": "keyword" },
"title": { "type": "text" },
"description": { "type": "text" },
"related_module": { "type": "keyword" },
"priority": { "type": "keyword" },
"status": { "type": "keyword" },
"customer_tier": { "type": "keyword" },
"created_at": { "type": "date" },
"marked_urgent": { "type": "boolean" }
}
}
}

POST support_tickets/_bulk
{"index":{}}
{"ticket_id":"TKT-1001","title":"CSV export keeps timing out","description":"Every time I try to export our quarterly report (about 15k rows), the export fails. This is blocking our monthly reporting.","related_module":"src/export/csv.ts","priority":"high","status":"open","customer_tier":"enterprise","created_at":"2024-12-18T09:00:00Z","marked_urgent":true}
{"index":{}}
{"ticket_id":"TKT-1002","title":"Export not working for large datasets","description":"Cannot export customer list. Times out every time.","related_module":"src/export/csv.ts","priority":"high","status":"open","customer_tier":"enterprise","created_at":"2024-12-17T14:00:00Z","marked_urgent":true}
{"index":{}}
{"ticket_id":"TKT-1003","title":"Random logouts are frustrating","description":"I keep getting logged out randomly throughout the day. Have to log back in 3-4 times.","related_module":"src/auth/refresh.ts","priority":"medium","status":"open","customer_tier":"pro","created_at":"2024-12-19T11:00:00Z","marked_urgent":false}
{"index":{}}
{"ticket_id":"TKT-1004","title":"Session timeout issue","description":"Getting logged out unexpectedly. Not a huge deal but annoying.","related_module":"src/auth/refresh.ts","priority":"low","status":"open","customer_tier":"free","created_at":"2024-12-15T16:00:00Z","marked_urgent":false}
{"index":{}}
{"ticket_id":"TKT-1005","title":"URGENT: Cannot generate monthly compliance report","description":"Our compliance team needs the export working by end of week or we face regulatory issues.","related_module":"src/export/csv.ts","priority":"critical","status":"open","customer_tier":"enterprise","created_at":"2024-12-19T08:00:00Z","marked_urgent":true}
{"index":{}}
{"ticket_id":"TKT-1006","title":"Export failing consistently","description":"Large dataset exports not working. Need this fixed ASAP.","related_module":"src/export/csv.ts","priority":"high","status":"open","customer_tier":"enterprise","created_at":"2024-12-16T10:00:00Z","marked_urgent":true}
{"index":{}}
{"ticket_id":"TKT-1007","title":"Bulk export timeout","description":"Trying to export 20k records and it times out.","related_module":"src/export/csv.ts","priority":"high","status":"open","customer_tier":"enterprise","created_at":"2024-12-18T13:00:00Z","marked_urgent":true}
{"index":{}}
{"ticket_id":"TKT-1008","title":"Search results outdated","description":"After adding new products, they don't show up in search for several minutes.","related_module":"src/search/indexer.ts","priority":"low","status":"open","customer_tier":"pro","created_at":"2024-12-14T09:00:00Z","marked_urgent":false}

Customer data index:

PUT customer_data
{
"mappings": {
"properties": {
"user_id": { "type": "keyword" },
"customer_tier": { "type": "keyword" },
"company_name": { "type": "text" },
"mrr": { "type": "float" },
"joined_at": { "type": "date" }
}
}
}

POST customer_data/_bulk
{"index":{}}
{"user_id":"enterprise_user_01","customer_tier":"enterprise","company_name":"Acme Corp","mrr":2500.00,"joined_at":"2023-01-15"}
{"index":{}}
{"user_id":"enterprise_user_02","customer_tier":"enterprise","company_name":"GlobalTech Inc","mrr":4200.00,"joined_at":"2022-08-20"}
{"index":{}}
{"user_id":"enterprise_user_05","customer_tier":"enterprise","company_name":"DataFlow Systems","mrr":3100.00,"joined_at":"2023-06-01"}
{"index":{}}
{"user_id":"user_001","customer_tier":"free","company_name":"","mrr":0,"joined_at":"2024-03-15"}
{"index":{}}
{"user_id":"user_002","customer_tier":"free","company_name":"","mrr":0,"joined_at":"2024-05-20"}
{"index":{}}
{"user_id":"user_045","customer_tier":"pro","company_name":"SmallBiz LLC","mrr":49.00,"joined_at":"2024-01-10"}
{"index":{}}
{"user_id":"user_089","customer_tier":"pro","company_name":"StartupXYZ","mrr":49.00,"joined_at":"2024-02-28"}

Once the indexes are loaded, your retrieval agent has enough data to answer something more useful than a generic prioritisation guess.

Step 2: Create the Agent Builder agent from the provided request

Next, create the Elastic agent itself by running the following command from the Console in the Developer Tools:

POST kbn://api/agent_builder/agents
{
"id": "tech-debt-advisor",
"name": "Tech Debt Prioritization Agent",
"description": "I help prioritize technical debt by analyzing error logs, support tickets, customer impact, and aligning with engineering standards and roadmap priorities.",
"avatar_color": "#BFDBFF",
"avatar_symbol": "TD",
"configuration": {
"instructions": "This agent helps prioritize technical debt items. Use the following indices:\n\n* knowledge: Engineering standards, policies, and roadmap priorities\n* error_logs: Production error frequency by module\n* support_tickets: Customer complaints and their urgency\n* customer_data: Customer tier information (enterprise, pro, free)\n\nWhen analyzing tech debt:\n1. Check error frequency in error_logs\n2. Cross-reference affected users with customer_data to understand tier impact\n3. Count support tickets and note urgency markers\n4. Check knowledge base for relevant policies and Q1 priorities\n5. Synthesize findings into prioritized recommendations",
"tools": [
{
"tool_ids": [
"platform.core.search",
"platform.core.list_indices",
"platform.core.get_index_mapping",
"platform.core.get_document_by_id",
"platform.core.execute_esql",
"platform.core.generate_esql"
]
}
]
}
}

If the request succeeds, you will see a 200 response status in the lower right corner of the output section in the console as you can see in the image below.

Press enter or click to view image in full size

Now, you can start using the agent in Kibana through the AI Agent chat. To do so, you need to select the Tech Debt Prioritization Agent that we created before as the following image shows.

Press enter or click to view image in full size

Once you select your custom agent, you can create a simple visualisation with the following prompt:

Create a chart with our clients sorted by MRR.

The following image shows an example of the expected result.

Step 3: Add the Agent Builder MCP server to Claude Code

Now we can connect Claude Code to the agent created in the previous step through the MCP server that it exposes.

You can get the MCP server URL in the Agents tab of Elastic Cloud Console as it’s shown in the animation below:

Press enter or click to view image in full size

Besides your MCP server URL, you will also need to create an API key in your Elastic Cloud Console. You can find detailed instructions for creating an API key in this article from Elastic docs .

After getting your MCP server URL and API key, open Claude Code and run the following command. Note that this command considers that you set your MCP server URL and API key as environment variables.

claude mcp add --transport http agentbuilder ${MCP_URL} --header "Authorization: ApiKey ${API_KEY}"

After successfully running this command, you will see a confirmation as follows:

Press enter or click to view image in full size

Then you can confirm the connection from Claude Code to the Elastic agent with the following command.

claude mcp get agentbuilder

After that, Claude Code can see the Agent Builder tools you enabled.

Press enter or click to view image in full size

Step 4: Create the Claude Code subagent

Open Claude Code and follow the next instructions to create the subagent using its agent creator tool as follows.

Open Claude Code and run the /agents command.

Choose Create new agent and select Project as the location.

In the selection method, select Manual configuration.

Next, enter tech-debt-analyst as the agent unique identifier.

As you want this subagent act as a technical lead, you can use something like this as the system prompt:

You are a Technical Lead agent. Your job is to help engineering and product teams prioritize technical debt based on real business impact, not just engineering intuition.

Use a description close to this:

Agent that analyzes technical debt by querying Elasticsearch for error logs, support tickets, customer data, and engineering knowledge base. Use this agent when you need to prioritize tech debt items based on business impact.

In Select tools, choose Advance options and be sure that you only select the tools defined on the Elastic agent creation.

☒ platform_core_search (agentbuilder)
☒ platform_core_get_document_by_id (agentbuilder)
☒ platform_core_execute_esql (agentbuilder)
☒ platform_core_generate_esql (agentbuilder)
☒ platform_core_get_index_mapping (agentbuilder)
☒ platform_core_list_indices (agentbuilder)

You should see a tools selection as follows:

Press enter or click to view image in full size

Select Continue and choose a model. For this demonstration, you can use Opus as this model excels in reasoning capacity.

As a final step, select the agent background colour you prefer and the recommendation is to enable the agent memory in the very last step.

As you can see in the following image, you will see a summary with the Claude agent configuration as a final confirmation. Press Enter to save the agent and you’re done.

Press enter or click to view image in full size

Step 5: Test your agents it with a real planning prompt

Now, you can give Claude Code a task that genuinely needs multiple sources of evidence. You can use the following prompt and the sample TECH_DEBT.md file provided to give a try.

Based on TECH_DEBT.md, which items should we prioritize for our 2-week sprint?
Use the tech-debt-analyst agent to check error frequency, customer impact,support ticket volume, and alignment with engineering standards.

This is where the setup pays off. Claude can read your local debt file, while the retrieval subagent checks the Elastic indices you loaded earlier and brings back the business context.

In practice, that means the agent can combine data from error_logs, support_tickets, customer_data, and knowledge and run several queries instead of relying on a single signal such as raw error count.

The image below shows how the agent orchestrates multiple queries:

Press enter or click to view image in full size

Once the agent completes its analysis, it gives you a sprint planning proposal and key findings based on your data available in Elasticsearch.

Press enter or click to view image in full size

If you want to inspect the prompt and tool overhead after setup, run /context in Claude Code.

Press enter or click to view image in full size

What actually makes a subagent successful

After working through the setup, the main lessons are simple.

A good subagent is not defined by how clever its prompt sounds. It is defined by how well you control:

  • scope
  • tool access
  • inputs
  • output expectations

If the task is precise, the tools are limited, and the request includes the right files or data sources, subagents become one of the most practical ways to keep Claude Code effective on larger tasks.

Final thoughts

If you only take one thing from this article, make it this: a subagent is a way to protect focus.

Use the main agent to drive the workflow. Use subagents to do the specialised work. Keep each helper narrow, explicit, and reusable.

And if you need your planning decisions to reflect business reality, not just local source code, connecting a retrieval subagent through Elastic Agent Builder is a strong next step.

Additional Resources

--

--

Sean Handley
Sean Handley

Written by Sean Handley

Sean Handley is a keen open-source fan & technology leader @ Elastic