Claude Code Subagents: Examples Worth Copying
Four subagent files you can drop into .claude/agents/ today: a reviewer that cannot edit, a test runner that only reports, a docs checker, and a board recorder that can read and comment and nothing else. Each with the reasoning behind its tool list.
6 min read
The Claude Code subagents worth copying are small and narrow: one job, a description that tells Claude when to use it, and a tools list that makes the wrong actions impossible rather than merely discouraged. Below are four complete files for .claude/agents/: a code reviewer, a test runner, a docs checker and a board recorder. Each comes with why its tool list and model are what they are, so you can adapt them instead of pasting them blind. If you are collecting subagents from repositories on GitHub, the same reasoning is the checklist for reading someone else’s.
This post assumes you know what a subagent is and how Claude hands work to one; Claude Code Task tool vs subagents covers that. A larger worked example, a project manager subagent with a hook that stops it moving cards, is in building a project manager subagent.
The fields that matter
A subagent is a Markdown file with YAML frontmatter; the body is its system prompt. The subagents documentation (opens in a new tab) lists many fields, but four do most of the work:
nameanddescriptionare the only required ones. Claude reads the description to decide when to delegate, so write it as an instruction: when to use it, and when not to.toolsis an allowlist. Leave it out and the subagent inherits every tool the main conversation has, MCP tools included. List tools and it gets only those.modeltakes an alias such assonnet,opusorhaiku, a full model ID, orinherit. Match it to the job: reading and summarising rarely needs the largest model.maxTurnsstops a subagent after that many agentic turns and hands back its output marked as partial. A cheap guard against one that wanders.
Others are useful in particular cases: disallowedTools to remove a tool from an inherited set, permissionMode, memory for notes that persist across sessions, isolation: worktree for a private checkout, and hooks for rules a tool list cannot express.
1. A code reviewer that cannot edit
--- name: code-reviewer description: Reviews a change for bugs, missing tests and unsafe patterns. Use after a feature or fix is written and before it is committed. Does not fix anything. tools: Read, Grep, Glob model: sonnet memory: project --- You review code changes. You were given the changed files or the diff. For each problem, report: file:line, what is wrong, why it matters, and the smallest fix. Order by severity. Say plainly when you found nothing serious. Check: error handling, input validation, tests that cover the change, and anything that contradicts the conventions in your memory. When you learn a convention of this codebase, add it to your memory.
Why it is built this way. Read, Grep, Glob and nothing else: no Edit, no Write, no Bash. A reviewer that can also fix things tends to fix things, and then nobody reviewed the fix. With this list it cannot change a file however it is prompted. Because it has no shell it cannot run git diff itself, so ask the main conversation to pass the diff or the changed files in the delegation. memory: project gives it a notes folder under .claude/agent-memory/ that it reads at the start of each run, so the conventions it learns in March are still known in May.
2. A test runner that only reports
--- name: test-runner description: Runs the test suite and reports failures. Use whenever tests need running. Never use it to change code. tools: Read, Grep, Glob, Bash model: haiku maxTurns: 15 --- Run the tests with the project's test command. Do not edit any file. Report, in at most fifteen lines: - the command you ran and the pass/fail counts - for each failure: test name, the assertion or error line, and the file that most likely holds the cause Leave out passing tests, stack frames from libraries, and progress output.
This is the single most useful subagent to have. A full test run can print thousands of lines; in the main conversation they crowd out everything else, and in a subagent they stay in its context while fifteen lines come back. It needs Bash to run the tests, which is the one real grant here, so the prompt keeps it to the test command and maxTurns keeps it from turning a failure into a debugging session. A small, fast model suits a job that is mostly reading output and summarising it. Fixing is a separate job, with a separate subagent or the main conversation.
The limit of this design is worth stating: with Bash granted, “run only the tests” is an instruction, not a control. If you need it enforced, add a PreToolUse hook to the frontmatter that exits with code 2 for any command that is not your test command; the hooks reference (opens in a new tab) explains the exit codes, and the project manager example above shows the pattern.
3. A docs checker
--- name: docs-checker description: Checks that README, docs/ and code comments still match the code after a change. Use after changing a public function, a CLI flag, a config key or an endpoint. tools: Read, Grep, Glob model: sonnet --- You check documentation against code. You do not edit. For the change you were given, find every mention of the changed names in README.md, docs/ and comments (use Grep). For each one that is now wrong, report: file:line, what it says, what is true now. Also report public names in the change that are documented nowhere.
Documentation drifts one change at a time, and the moment to catch it is right after the change, while Claude still knows which names moved. The checker is read-only for the same reason as the reviewer: it reports, and the main conversation, which has the context, writes the fix. Its description names the triggers, a function, a flag, a config key, an endpoint, so Claude reaches for it at the right moments without being asked.
4. A board recorder that can only read and comment
The last one does no engineering at all. It writes the outcome of work onto the task the work belonged to, so the record outlives the session. It assumes a fenbs board connected in Claude Code as an MCP server named fenbs; the MCP documentation (opens in a new tab) gives the naming rule that turns the board’s fenbs_comment tool into mcp__fenbs__fenbs_comment.
--- name: board-recorder description: Records the outcome of finished work on its fenbs task. Use when a task is done or stopped and you have a ref such as BUG-042. Never use it to change a task. tools: mcp__fenbs__fenbs_whoami, mcp__fenbs__fenbs_get_item, mcp__fenbs__fenbs_search, mcp__fenbs__fenbs_list_items, mcp__fenbs__fenbs_comment model: haiku maxTurns: 8 --- You record work on the fenbs board. You were given a task ref and a summary. 1. fenbs_get_item on the ref. If it does not exist, fenbs_search for the title and use the match; if none, report that and stop. 2. Comment once, starting with "recorder:". Say what changed, the commit hash, and how it was checked (or that it was not). 3. Report the ref and the first line of your comment.
The tool list is the design. It can read tasks, search and comment; it cannot create, move, edit or delete one, because fenbs_create_item, fenbs_update_item and fenbs_delete_item are not on the list. Moving the task to Completed stays with the main conversation or with you. The “recorder:” prefix matters because every subagent in a session shares the session’s connection, so the board records them all as Claude acting for you; the prefix tells this one’s comments apart.
The board has a second gate of its own. The session’s connection holds the scopes you ticked when you approved it (read, write, comment), and fenbs checks them on every call. If you want the board itself to refuse anything but comments, connect the session with a token that has only read and comment ticked; the recorder’s tool list and the token then agree.
The same subagent without a file
For a one-off or a CI job you may not want a file in the repository. The `--agents` flag (opens in a new tab) takes the same definition as JSON for the current session only, with prompt in place of the file body:
claude --agents '{
"test-runner": {
"description": "Runs the test suite and reports failures. Never changes code.",
"prompt": "Run the tests. Report the command, counts, and each failure with its likely file.",
"tools": ["Read", "Grep", "Glob", "Bash"],
"model": "haiku"
}
}'Reading a subagent you found on GitHub
Collections of subagent files are easy to find, and a file from one is a prompt plus a set of permissions. Read it the way you would read a script before running it:
- No
toolsline means it inherits everything, MCP tools included. Add one. - A
hooksblock runs shell commands with your user’s permissions while the subagent is active. Read every command it names. - An
mcpServersblock can start or connect servers you have not added yourself. - A description such as “use proactively for all tasks” means Claude will reach for it constantly. Narrow it to the job.
- Check
model. A file written for the largest model may not need it, and every delegation costs tokens.
Commit the ones you keep to .claude/agents/ so the team reviews changes to them like code, and put personal ones in ~/.claude/agents/. To adapt one, ask Claude to rewrite it for your project, or edit the file directly; on recent versions /agents no longer opens a creation wizard.
Related
Connect the board the recorder writes to: Claude Code integration. What each scope allows: assistant tokens and scopes. When several workers need to talk to each other rather than report back: subagents vs agent teams.