Building a Custom Agent
Hands-on: creating a specialized code reviewer agent from scratch
Overview
You have learned why custom agents exist, how to structure their definition files with YAML frontmatter, and how to control their permissions with the tools field. Now it is time to build one. In this lesson, you will create a code reviewer agent from scratch -- a specialized agent that analyzes pull requests, flags issues by severity, and produces structured feedback. You will follow the process step by step: defining the goal, writing the frontmatter, composing the system prompt, and testing the agent against real code.
Step 1: Define the Goal
Before writing a single line of the agent definition, answer three questions:
- What does this agent do? It reviews code changes and produces a structured report of issues found.
- What tools does it need? Read, Glob, and Grep to view and search files. No Edit, Write, or Bash -- it should never modify the codebase.
- What makes it different from a general-purpose agent? It has a reviewer's mindset: it looks for problems, not solutions. It reports issues but does not fix them.
These three answers become the foundation for everything that follows. If you cannot answer them clearly, the agent is not ready to be built.
Step 2: Create the Agent Directory
If your repository does not already have an agents directory, create it:
This gives you the standard location for all custom agent definitions. The .claude/ directory may already exist if you have a settings.json or other Claude configuration files.
Step 3: Write the Frontmatter
Create the agent file at .claude/agents/code-reviewer.md. Start with the required YAML frontmatter:
The frontmatter establishes the agent's identity and constraints before a single line of the system prompt is written:
name: code-reviewer-- the identifier used to invoke this agentdescription-- tells Claude when to delegate to this agent; the phrase "Use after modifying code" encourages proactive delegationtools: Read, Glob, Grep-- enforces read-only access; the agent cannot edit files, write files, or run commands regardless of what anyone asksmodel: sonnet-- uses a capable model that balances quality and speed for analysis
Step 4: Write the System Prompt
Now add the system prompt body after the frontmatter. Build it section by section.
Start with the role definition:
Notice the explicit "You do NOT" statements right up front. The agent's identity and boundaries are established in the first paragraph.
Add context-gathering instructions:
Add the review methodology:
The ordered list gives the agent a consistent process to follow. Starting with correctness and security ensures the most important issues are caught first.
Define the output format:
A rigid output format makes reviews consistent and scannable. Every developer on the team knows exactly where to look for critical issues.
Set explicit constraints:
Step 5: The Complete Agent File
Here is the full agent definition, assembled from the sections above:
Notice how the frontmatter and system prompt complement each other. The tools: Read, Glob, Grep in frontmatter enforces read-only access at the platform level. The "NEVER modify" constraints in the system prompt reinforce this behaviorally. Together, they create an agent that is both well-behaved and technically constrained.
Step 6: Understanding the Agent Lifecycle
When you invoke this agent, here is what happens:
Agent lifecycle sequence: the developer invokes the code-reviewer agent via the CLI. The CLI loads frontmatter (tools, model), system prompt, and CLAUDE.md, then initializes the agent. The developer asks for a review. The agent reads the source file, greps for imports, reads tests, and returns a structured review report. The agent cannot call Edit, Write, or Bash.
The key observation is that the agent's lifecycle is entirely read-only. The tools frontmatter ensures it has Read, Glob, and Grep -- nothing else. Even if the agent's reasoning tells it to edit a file, the platform blocks the attempt.
Step 7: Test the Agent
Testing your agent is straightforward. Invoke it and verify three things:
Test the happy path -- Give it a file to review and check that the output matches your expected format:
Verify that the output contains the Summary, Issues Found, and Verdict sections in the correct format.
Test the boundaries -- Ask the agent to do something outside its role:
The agent should refuse to make changes. Because tools: Read, Glob, Grep does not include Edit or Write, the platform prevents any file modifications even if the agent tries.
Test the context gathering -- Review the agent's output for evidence that it read CLAUDE.md and related files. The review should reference project conventions and understand the broader context, not just the isolated file.
Step 8: Iterate and Refine
Your first agent definition will not be perfect. After a few uses, you will notice:
- Missing guidance -- The agent makes a type of comment you did not anticipate. Add instructions to handle it.
- Too verbose -- The agent writes paragraph-length explanations for nits. Add a constraint: "Keep nit explanations to one sentence."
- Missing context -- The agent does not check related files. Add an explicit step to read imports and tests.
- Inconsistent format -- The agent drifts from the output format. Make the format more explicit with examples.
Treat the agent definition like code: iterate on it based on real-world usage, commit improvements, and review changes with your team.
The best agent definitions are written over weeks, not in a single session. Start with a minimal version and refine based on actual reviews.
Building Other Agent Types
The same process applies to any agent type. Here is a quick template for a different archetype -- a migration helper that updates deprecated API calls:
Notice how this agent has broader tools (including Edit, Bash) because its role requires modifying files and running tests to verify results. The tools match the task.
Checklist: Before You Ship an Agent
Before committing a new agent definition to your repository, verify:
- The
namefield clearly communicates the agent's role - The
descriptionfield explains when to use the agent - The
toolsfield is as restrictive as the task allows - The system prompt establishes identity, methodology, and constraints
- The output format is explicitly defined (if the agent produces structured output)
- You have tested the happy path, boundary cases, and context gathering
- The file is committed to
.claude/agents/in version control
Summary
Building a custom agent follows a deliberate process: define the goal, write the YAML frontmatter with name, description, and tools, compose the system prompt section by section, test the agent against real code, and iterate based on results. The code reviewer agent you built in this lesson demonstrates the pattern: focused frontmatter that enforces read-only access, a structured methodology, a rigid output format, and explicit constraints. This same process applies to any agent archetype -- test writers, migrators, security auditors, and beyond. In the next lesson, you will learn how to coordinate multiple agents working together on complex tasks.