| name | claude-code-agent-design |
| description | Deep dive guide for building AI agents with Claude Code - architecture, tools, context engineering, and runtime patterns |
| triggers | ["how to build an AI agent with Claude Code","explain Claude Code agent architecture","show me Claude Code tool system design","how does context engineering work in Claude Code","implement MCP protocol integration","design multi-agent system with Claude Code","Claude Code permission model and security","build custom tools for Claude Code"] |
Claude Code Agent Design Guide
Skill by ara.so — Claude Code Skills collection.
Expert guidance for understanding and implementing AI agent systems based on Claude Code's architecture. This comprehensive guide covers agent runtime design, tool systems, context engineering, multi-agent coordination, and extension mechanisms.
What This Guide Covers
Claude Code is Anthropic's official AI programming assistant CLI tool - not just a chatbot, but a complete Agent Runtime System including:
- Tool calling and execution framework
- Context engineering patterns
- Multi-agent collaboration
- Permission management
- Extension system (MCP protocol, Skills, Plugins)
- State management and message loops
Core Architecture Concepts
Query Engine - The Heart of Conversations
The query engine manages the agent's interaction loop:
class QueryEngine {
async processQuery(userInput, context) {
const systemPrompt = this.buildSystemPrompt(context);
const messages = this.prepareMessages(userInput, context.history);
const response = await this.llm.complete({
system: systemPrompt,
messages: messages,
tools: this.availableTools,
stream: true
});
while (response.hasToolCalls()) {
const toolResults = await this.executeTool(response.toolCalls);
response = await this.llm.continue(toolResults);
}
return response.finalMessage;
}
}
Tool System Design Philosophy
Tools are the agent's hands - allowing it to interact with the world:
const toolDefinition = {
name: "execute_command",
description: "Execute a shell command in the project directory",
input_schema: {
type: "object",
properties: {
command: {
type: "string",
description: "The command to execute"
},
workingDirectory: {
type: "string",
description: "Optional working directory"
}
},
required: ["command"]
},
permission: "auto",
async execute({ command, workingDirectory }, context) {
const result = await context.shell.exec(command, {
cwd: workingDirectory || context.projectRoot
});
return {
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.code
};
}
};
Built-in Tools Categories
Claude Code includes 43 built-in tools organized by function:
const fileTools = [
'read_file',
'write_file',
'edit_file',
'list_directory',
'create_directory',
'move_file',
'delete_file'
];
const analysisTools = [
'search_files',
'analyze_code',
'find_references',
'get_diagnostics'
];
const execTools = [
'execute_command',
'run_tests',
'start_dev_server',
'install_packages'
];
const memoryTools = [
'update_memory',
'read_memory',
'add_to_claudemd'
];
Context Engineering
System Prompt Construction
Building effective system prompts is critical:
function buildSystemPrompt(context) {
const sections = [
`You are Claude Code, an AI programming assistant.
You have access to ${context.tools.length} tools for file operations,
code analysis, command execution, and more.`,
context.claudeMd ? `
## Project Context (from CLAUDE.md)
${context.claudeMd}
` : '',
context.activeTask ? `
## Current Task
${context.activeTask.description}
Progress: ${context.activeTask.progress}
` : '',
context.memory.length > 0 ? `
## Relevant Memory
${context.memory.map(m => `- ${m.content}`).join('\n')}
` : '',
`
## Tool Usage Guidelines
- Use file operations tools to read and modify code
- Execute commands to run tests and checks
- Update memory for important discoveries
- Ask for permission before destructive operations
`,
`
## Response Format
- Explain your reasoning before taking actions
- Show command output and analysis
- Suggest next steps when tasks complete
`
];
return sections.filter(Boolean).join('\n\n');
}
CLAUDE.md - Project Memory
The CLAUDE.md file serves as persistent project context:
<!-- Example CLAUDE.md structure -->
# Project Overview
This is a React + TypeScript web application for task management.
## Tech Stack
- React 18 with TypeScript
- Vite for bundling
- TanStack Query for data fetching
- Tailwind CSS for styling
## Key Architecture Decisions
- All API calls go through `src/api/client.ts`
- State management uses React Context + TanStack Query
- Component structure: `src/components/{feature}/{Component}.tsx`
## Important Patterns
- Use custom hooks for business logic (src/hooks/)
- API types are generated from OpenAPI spec (npm run generate-types)
- All forms use react-hook-form with zod validation
## Environment Variables
- `VITE_API_URL` - Backend API endpoint
- `VITE_AUTH_DOMAIN` - Auth0 domain
- `VITE_SENTRY_DSN` - Error tracking
## Common Tasks
- `npm run dev` - Start dev server
- `npm run test` - Run unit tests
- `npm run type-check` - TypeScript validation
- `npm run generate-types` - Update API types from OpenAPI
Context Compression (Auto-Compact)
Managing token limits through intelligent compression:
class ContextCompactor {
async compactHistory(messages, maxTokens) {
const tokenCount = this.countTokens(messages);
if (tokenCount <= maxTokens) {
return messages;
}
const cutoffIndex = this.findCutoffPoint(messages, maxTokens);
const oldMessages = messages.slice(0, cutoffIndex);
const recentMessages = messages.slice(cutoffIndex);
const summary = await this.summarizeMessages(oldMessages);
return [
{
role: 'system',
content: `## Previous Conversation Summary\n${summary}`
},
...recentMessages
];
}
async summarizeMessages(messages) {
const prompt = `Summarize this conversation concisely, preserving:
- Key decisions made
- Files modified
- Important discoveries
- Current task status
Conversation:
${messages.map(m => `${m.role}: ${m.content}`).join('\n\n')}`;
const summary = await this.llm.complete({
: [{ : , : prompt }],
:
});
summary.;
}
}
Task System and Multi-Agent Patterns
Task Definition and Execution
class Task {
constructor(config) {
this.id = config.id;
this.description = config.description;
this.status = 'pending';
this.subtasks = [];
this.dependencies = [];
this.assignedAgent = null;
}
async execute(context) {
this.status = 'in_progress';
try {
if (this.shouldDecompose()) {
this.subtasks = await this.decompose();
for (const subtask of this.subtasks) {
await subtask.execute(context);
}
} else {
await this.(context);
}
. = ;
} (error) {
. = ;
. = error;
error;
}
}
() {
. > ||
..() ||
.();
}
}
Multi-Agent Coordination
class AgentCoordinator {
constructor() {
this.agents = {
coder: new CodingAgent(),
tester: new TestingAgent(),
reviewer: new ReviewAgent(),
debugger: new DebuggingAgent()
};
}
async handleComplexTask(task, context) {
const plan = await this.createExecutionPlan(task);
for (const step of plan.steps) {
const agent = this.selectAgent(step.type);
const result = await agent.execute(step, context);
plan.results.push(result);
context.memory.add({
step: step.description,
agent: agent.,
: result.
});
}
.(plan.);
}
() {
mapping = {
: ..,
: ..,
: ..,
: ..
};
mapping[taskType] || ..;
}
}
MCP Protocol - Extension System
The Model Context Protocol enables tool interoperability:
class MCPServer {
constructor() {
this.tools = new Map();
this.resources = new Map();
}
registerTool(toolDef) {
this.tools.set(toolDef.name, {
definition: {
name: toolDef.name,
description: toolDef.description,
inputSchema: toolDef.inputSchema
},
handler: toolDef.handler
});
}
async handleToolsList() {
return {
tools: Array.from(this.tools.values()).map(t => t.definition)
};
}
async handleToolCall(name, args) {
const tool = this.tools.get(name);
(!tool) {
();
}
tool.(args);
}
() {
{
: .(..())
};
}
}
{
() {
response = (, {
: ,
: { : },
: .({
: ,
: [, ]
})
});
{ tools, resources } = response.();
tools.( .(tool));
}
}
Permission Model
Three-tier permission system for tools:
const permissionLevels = {
AUTO: 'auto',
ASK: 'ask',
DENY: 'deny'
};
class PermissionManager {
constructor() {
this.rules = new Map();
this.userPreferences = {};
}
async checkPermission(tool, args, context) {
if (this.isDenied(tool, args)) {
throw new Error(`Permission denied for tool: ${tool.name}`);
}
if (this.isAutoApproved(tool, args, context)) {
return { allowed: true, needsConfirmation: false };
}
const allowed = await this.requestUserApproval(tool, args);
if (allowed.) {
.(tool, args, allowed.);
}
{ : allowed., : };
}
() {
([, , ].(tool.)) {
;
}
(tool. === &&
.(args., context.)) {
;
}
.[tool.] === ;
}
}
Skills System
Creating reusable agent behaviors:
const debuggingSkill = {
name: 'advanced-debugging',
description: 'Systematic debugging using multiple tools',
async execute(context) {
const reproSteps = await this.reproduceIssue(context);
const diagnostics = await context.tools.get_diagnostics();
const logs = await context.tools.execute_command({
command: 'tail -n 100 error.log'
});
const analysis = await this.analyzeStackTrace(logs.stdout);
for (const hypothesis of analysis.hypotheses) {
const result = await this.testHypothesis(hypothesis, context);
if (result.confirmed) {
return this.proposeFixtrue(hypothesis, context);
}
}
{
: ,
: analysis.
};
}
};
Common Patterns and Best Practices
Pattern: Incremental Code Changes
async function incrementalUpdate(file, changes) {
const content = await readFile(file);
for (const change of changes) {
await editFile({
path: file,
start_line: change.startLine,
end_line: change.endLine,
new_content: change.newContent
});
}
const updated = await readFile(file);
const diff = createDiff(content, updated);
return { diff, success: true };
}
Pattern: Verification Loop
async function implementWithVerification(task, context) {
await task.execute(context);
const testResult = await context.tools.run_tests({
pattern: task.testPattern
});
const typeCheck = await context.tools.execute_command({
command: 'npm run type-check'
});
if (!testResult.success || !typeCheck.success) {
const fixes = await analyzeFailures(testResult, typeCheck);
await applyFixes(fixes, context);
return implementWithVerification(task, context);
}
return { success: true };
}
Pattern: Context-Aware Suggestions
async function suggestNextSteps(currentState, context) {
const suggestions = [];
if (context.project.type === 'web-app') {
if (!currentState.hasTests) {
suggestions.push('Add unit tests for the new component');
}
if (!currentState.hasStorybook) {
suggestions.push('Create Storybook story for component');
}
}
const recentFiles = currentState.modifiedFiles;
if (recentFiles.some(f => f.endsWith('.tsx'))) {
suggestions.push('Run type checking: npm run type-check');
}
const previousIssues = context.memory.query('errors');
if (previousIssues.length > 0) {
suggestions.push('Verify previous error is fixed');
}
return suggestions;
}
Troubleshooting
Managing Context Window
function monitorTokens(context) {
const usage = context.getTokenUsage();
if (usage.total > usage.limit * 0.8) {
console.warn('Approaching token limit, compacting context...');
context.compact();
}
if (usage.total > usage.limit * 0.9) {
context.clearOldMessages({ keepRecent: 20 });
}
}
Tool Execution Failures
async function safeToolExecution(tool, args, context) {
try {
return await tool.execute(args, context);
} catch (error) {
context.logger.error(`Tool ${tool.name} failed:`, error);
if (tool.fallback) {
return await tool.fallback(args, context);
}
return {
success: false,
error: error.message,
suggestion: `Consider trying ${tool.alternatives.join(' or ')}`
};
}
}
Memory Management
class ManagedMemory {
constructor(maxSize = 1000) {
this.items = [];
this.maxSize = maxSize;
}
add(item) {
this.items.push({
...item,
timestamp: Date.now(),
importance: this.calculateImportance(item)
});
if (this.items.length > this.maxSize) {
this.prune();
}
}
prune() {
this.items.sort((a, b) => {
const scoreA = a.importance + (Date.now() - a.timestamp) / 1000000;
const scoreB = b.importance + (Date.now() - b.timestamp) / ;
scoreB - scoreA;
});
. = ..(, .);
}
}
Key Takeaways
- Tool-First Design: Build agents around concrete tools, not abstract capabilities
- Context is King: Effective system prompts and memory management determine agent quality
- Verification Loops: Always verify actions with tests, checks, or user confirmation
- Incremental Actions: Prefer small, verifiable changes over large rewrites
- Layered Permissions: Balance autonomy with safety through tiered permission model
- Extensibility: Use MCP protocol for tool interoperability and ecosystem growth
This architecture demonstrates how to build production-grade AI agent systems that are reliable, safe, and extensible.