Course · Claude Code · Subagents
Define a reusable custom subagent so a recurring audit always runs the same way
A brief that keeps leaving your mouth is a candidate for saving. Here is one from the small Express plus TypeScript payments service this course uses as its example. The Ledger class in src/payments/ledger.ts records money by account id, but the route in src/index.ts calls ledger.append(result.id, ...) and files each entry under the payment’s UUID instead, so every balance reads zero while the six tests stay green. Once you know a codebase can drift like that between its write path and its read path, you want the same check before every change that touches payments: map the writes, check the reads against them, list what no test covers, keep the tools read-only, come back with conclusions only.
A custom agent is a subagent (a worker with its own context window that returns a summary) whose configuration is saved in a markdown file, so that from then on a name summons the same tools, the same instructions, and the same shape. This lesson writes the payments auditor down as one.
The file is the subagent
Section titled “The file is the subagent”A custom agent is a markdown file with YAML frontmatter on top and its instructions in the body. The frontmatter configures the worker; the body is its system prompt. Here is the auditor, shaped for the real repo. It is a proposal to create, not a file the course’s example payments repo contains:
---name: ledger-auditordescription: Audits the payments service for write/read disagreements - ledger keys, money units, and the tests that cover them. Use proactively before any change that touches payments or the ledger.tools: Read, Grep, Globmodel: inherit---
You are a read-only auditor for the payments service.
When invoked:1. Sweep src/ and tests/ for ledger writes and reads: append, balance, history, and every caller of each.2. For each path, report the key or unit it writes and the key or unit it reads. Flag every disagreement - as when a route filed entries under a payment UUID instead of an account id.3. List writes that no test exercises.
Report conclusions with file and function names. Do not dump filecontents into the reply.Two decisions are baked in. The description says use proactively, which pushes Claude to delegate on its own when a task matches. And the last body line is the terseness you would otherwise enforce by hand in every brief; written once, it holds for every future run.
The fields that carry the contract
Section titled “The fields that carry the contract”Only name and description are required. The ones this file uses, from the supported frontmatter fields table:
name- the identifier you invoke it by, lowercase with hyphens.description- when Claude should delegate to it. Claude reads it to decide whether a task matches, so write it as a trigger, not a label.tools- an allowlist of what the worker may use.model- which model the worker runs on.
The tools default deserves precision: omitting the field does not hand over your session’s exact toolset. The subagent inherits every tool available to subagents, which is the main conversation’s pool narrowed by subagent filters. Some built-ins are removed for every subagent, and background subagents keep a further reduced built-in set. Scoping the auditor to Read, Grep, Glob is stronger than a suggestion: it cannot edit a file even if it tries. disallowedTools is the inverse, inheriting everything except what you name.
For model, inherit runs the same model as the main conversation. Omit the field entirely and Claude Code resolves the model in a documented order: frontmatter, then the CLAUDE_CODE_SUBAGENT_MODEL environment variable, then the main conversation. So omitting is not the same as inheriting. See choose a model. Pinning a mechanical sweep to a lighter tier here makes a per-task model choice permanent; the models chapter covers how to pick that tier. The same table carries an effort override and sharper controls like permissionMode, skills, background, and isolation: worktree.
Two ways to create one
Section titled “Two ways to create one”As of v2.1.198, the /agents command no longer opens a creation wizard. Running it prints a reminder to ask Claude or edit the agents directory directly, as the sub-agents quickstart documents. So there are two current paths.
The first is to ask: “create a ledger-auditor subagent with read-only tools that sweeps src/ and tests/ for write/read disagreements and reports conclusions only.” Claude writes the markdown file into one of the homes below; that is a file edit, so approve it. Then read what it wrote before trusting it. The description is the delegation trigger and deserves your own words more than anyone’s.
The second is to write the file yourself, in one of two homes, documented under write subagent files:
.claude/agents/in the project - the right home forledger-auditor, since it audits this codebase. Check it in and everyone who pulls the repo runs the identical audit, the same way.~/.claude/agents/in your home directory - for personal specialists you want available in every project.
Once it exists, naming it in a prompt lets Claude decide whether to delegate. Mentioning it - @agent- plus the frontmatter name, so @agent-ledger-auditor from the typeahead - guarantees that subagent runs for the task. The mention controls who runs, not what, since Claude still writes the task prompt. Both forms are documented under invoke subagents explicitly. An illustrative run of the saved auditor, not a capture:
> @agent-ledger-auditor sweep for any write/read disagreements before I fix the route
⏵ Agent (ledger-auditor) sweeping write/read paths ⎿ Done (14 tool uses)
No disagreements beyond the known one: the route still files entries under the payment UUID. Coverage gap unchanged - no test exercises the route.The counts and wording there are invented; the finding reflects what that example repo’s source contains. Same isolated context, same terse return, but now reproducible.
One boundary worth knowing: subagents can spawn subagents of their own, up to three layers below the main conversation by default, with the depth configurable; at the limit, Claude Code withholds the Agent tool. To forbid spawning outright, leave Agent out of the tools list. The docs cover this under letting subagents spawn their own.
The seam into skills
Section titled “The seam into skills”What you just built stops one kind of repetition: re-describing the audit’s configuration. But the worker still only runs when called. Each use is a task you initiate, by name or mention, every time.
That is the seam where the next primitive picks up. A subagent runs a task you hand it; a skill packages a procedure once and the agent invokes it itself when the situation matches, with no call from you. The auditor waits to be summoned; a skill recognizes its own moment. The Skills chapter is about teaching the agent procedures it reaches for on its own.