Week 1 · Day 2 of 40 · Use AI

Claude Code: skills and sub-agents

You ship: 3 custom skills and a 3-agent PR review. Builds on: Day 1.

By the end of the day you can

  • Understand Claude Code's full capability set (slash commands, hooks, skills, sub-agents)
  • Build custom skills that automate repetitive development tasks
  • Build sub-agents that parallelize code review

Topics

Anthropic Courses (complete all 3)

Slash Commands, Hooks, and Custom Skills

  • Built-in slash commands: /init, /compact, /review, /commit, /help
  • Hooks: shell commands that run in response to Claude Code events (pre-commit, post-edit, etc.)
  • Custom skills: creating your own slash commands with markdown-based prompt files
  • Skill anatomy: the .claude/skills/ directory, skill file format, parameterization

Sub-agents

  • What sub-agents are: spawning parallel Claude Code instances for independent tasks
  • When to use sub-agents: tasks that can be decomposed and run independently
  • Sub-agent communication: how results flow back to the parent agent
  • Cost and performance considerations

Build

Build exercise 1: Custom Skills

Features shipped today

  • WorkBot: 3 skills in the repository; the review trio on its open PRs

Build 3 skills for the TypeScript project:

/component <name>

  • Scaffolds a React component file at the conventional path
  • Creates a co-located test file with a basic render test
  • Adds the export to the nearest barrel file (index.ts)
  • Follows the project's existing component patterns (reads CLAUDE.md for conventions)

/api-route <name>

  • Scaffolds a Next.js API route handler
  • Includes input validation with Zod
  • Adds error handling with proper HTTP status codes
  • Creates a type file for request/response types

/pre-deploy

  • Runs TypeScript type-check (tsc --noEmit)
  • Runs test suite
  • Searches for console.log statements in source code
  • Verifies required environment variables are set
  • Reports a pass/fail summary

Build exercise 2: Sub-agents

Build a PR review trio - 3 parallel sub-agents that each review a PR from a different angle:

  1. Bug hunter: looks for logic errors, edge cases, null pointer risks, race conditions
  2. Performance reviewer: identifies N+1 queries, unnecessary re-renders, missing memoization, bundle size impact
  3. Security reviewer: checks for injection risks, auth gaps, exposed secrets, unsafe data handling

Each sub-agent produces a focused review. Results are aggregated into a single review summary.

Walkthrough

Add 3 skills, 3 review sub-agents behind a /review skill, and a formatting hook. Everything lives in .claude/ and is committed.

Part 1

Tests first

The component skill scaffolds a test with each component, so install and configure Vitest first.

Study first

  • The 3 Anthropic courses in the day's topics: Claude Code in Action, Introduction to Agent Skills, Introduction to Subagents. The rest of the day assumes them.
  • Vitest: test, expect, vitest run once and vitest to watch.
  • renderToStaticMarkup from react-dom/server renders a component to an HTML string with no browser. It is enough for a component with no state or events.

Build

  1. pnpm add -D vitest, a vitest.config.mts that maps @/ to src/, and a test script running vitest run.
  2. src/components/site-header.test.tsx: render SiteHeader and assert the markup contains WorkBot, href="/" and href="/settings".
  3. Add pnpm test to pnpm check between the type check and the build, so CI runs it.

Done when

  • pnpm test passes, and pnpm check runs the tests before the build.
Technical notes
  • The alias is the whole configuration:
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: { alias: { "@/": new URL("./src/", import.meta.url).pathname } },
});
  • The file is .mts because Vitest 5 warns when it loads an ESM vitest.config.ts from a package without "type": "module", and suggests .mjs or the package setting. .mts needs no change to package.json.
  • When a client component needs events or state in a test, add jsdom and a DOM testing library then.
  • A test sits beside its component: name.test.tsx next to name.tsx.

Part 2

3 skills

A skill is a SKILL.md file: front matter, then instructions Claude follows when you type its name. Today's 3 scaffold a component, scaffold an API route, and run the pre-deploy checks.

Study first

  • The skills documentation: where skills live, the front matter fields, $ARGUMENTS and $0, and inline shell commands.
  • The built-in commands next to them: /init writes a first CLAUDE.md, /compact summarizes the session to free context, /help lists every command.
  • Your AGENTS.md. In each skill, name an existing file as the style example instead of describing the style.

Build

  1. /component <Name>: src/components/<kebab-name>.tsx, composed from the shadcn primitives, and src/components/<kebab-name>.test.tsx beside it. Point the skill at site-header.tsx and its test as the pattern. The exercise's version also adds an export to a barrel file, an index.ts that re-exports a folder; this project imports by path, so the skill skips that step.
  2. /api-route <name> [methods]: src/app/api/<name>/types.ts with Zod schemas for the request and the response and their inferred types; route.ts with one exported function per method, answering 400 with the validation issues on bad input; route.test.ts with one test per method plus one invalid input.
  3. /pre-deploy: 4 inline commands: pnpm typecheck (which runs tsc --noEmit), pnpm test, a grep for console.log under src/, and a Node one-liner that reads the variable names from .env.example and reports which are missing from process.env after loading .env.local. The instruction asks for a pass or fail table and a verdict, nothing else.
  4. Run each one: /component Notice, /api-route echo POST, /pre-deploy. Check the files and run the tests, then delete what the first 2 created.

Done when

  • Each skill produces the files it promises, the tests it scaffolds pass, and /pre-deploy prints its table.
The pre-deploy skill's report
/pre-deploy, run with claude -p: the 4 checks ran inline and the model wrote only the table and the verdict.
Technical notes
  • The skill's instructions also name 404 for a missing resource and 409 for a conflict, for routes that have a resource; an echo route has neither.
  • disable-model-invocation: true keeps a skill out of Claude's own tool choices, so /pre-deploy runs when you ask and not when Claude decides to.
  • An inline command, an exclamation mark followed by the command in backticks, runs before the model reads the prompt, and its output replaces the placeholder. That is why /pre-deploy needs no tool calls.
  • $ARGUMENTS is the whole argument string and $0 its first word: for /api-route echo POST, $0 is echo.
  • A skill runs without a session too. The screenshot above is the output of claude -p "/pre-deploy", which printed the result and exited.

Part 3

The review trio

3 sub-agents, each reading a diff from one angle, run in parallel by a /review skill that merges what they found. Each agent gets one list to check and its own context window.

Study first

  • The sub-agents documentation: the front matter (name, description, tools, model), that a sub-agent starts with a fresh context and returns one message to the session that started it, and that parallel agents multiply the tokens spent.
  • What each angle looks for. Bugs: wrong conditions, unhandled null, unawaited promises, races. Performance: queries in loops, sequential awaits, work repeated per render, missing memoization, a "use client" component with no state, no event handlers and no browser APIs, bundle size. Security: injection, missing authorization, secrets in code or logs, data shown to the wrong caller, prompt injection (external content treated as instructions).

Build

  1. .claude/agents/bug-hunter.md, performance-reviewer.md and security-reviewer.md. Each states its angle, says the other angles belong to other reviewers, lists what to look for, and asks for findings only, most severe first, with file, line and a one-line fix. Front matter: tools: Read, Grep, Glob, Bash and model: sonnet.
  2. .claude/skills/review/SKILL.md. The diff is gh pr diff <n> for a pull request number, otherwise git diff main...HEAD. The skill names that command to the 3 agents, which run it themselves, then writes one review: findings grouped by severity, duplicates merged, a verdict.
  3. Run /review 1 on your Day 1 pull request, or /review on a branch.

Done when

  • /review returns one review with severities and a verdict, and each finding names its reviewer.
The review trio on pull request 1
The merged review of the Day 1 pull request. The bug hunter found that the health route was prerendered at build time and served the build-time commit; Day 3 starts by fixing that.
Technical notes
  • model: sonnet on each agent: 3 agents run per review.
  • tools without Edit or Write makes the reviewers read-only by construction, whatever the prompt says.
  • "Report findings only" and "if nothing is wrong, say so in one sentence" keep the merged review short. The skill tells the aggregator not to add findings of its own, so every item traces to a reviewer.
  • An agent's description is how the session decides when to delegate unprompted. The 3 descriptions say "use when reviewing a pull request or branch" for that reason.
  • Cost: each agent reads the whole diff, so a review costs about 3 times a single pass. Keep the diff to one pull request.

Part 4

A hook that formats

A hook runs on a Claude Code event, whatever Claude intended: AGENTS.md is advice, a hook is enforcement. The one hook today runs Prettier on every file Claude edits.

Study first

  • The hooks documentation: the events, PreToolUse and PostToolUse with a matcher, the JSON a command hook reads on stdin, and what the exit codes mean.

Build

  1. .claude/settings.json with a PostToolUse hook matching Edit|Write. The command reads the edited file's path from stdin and runs Prettier on it; the exact entry is in the technical notes.
  2. A line in AGENTS.md naming the skills, the reviewers and the hook, so the next session knows they exist.

Done when

  • Ask Claude Code to edit a file with odd spacing; the saved file is formatted with no prompt and no follow-up step.
The contents of .claude and the test run
What Day 2 adds to the repository: 3 agents, the hook in settings.json, 4 skills, and a test suite of 1.
Technical notes
  • The hook entry:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs pnpm exec prettier --write --ignore-unknown --log-level warn"
          }
        ]
      }
    ]
  }
}
  • PostToolUse runs after the edit, so it can fix or report, not block. A hook that must stop an action goes on PreToolUse.
  • Exit code 2 from a hook sends its stderr to Claude as feedback; any other non-zero exit shows it to you only. The formatter exits 0, so Claude sees nothing.
  • --ignore-unknown makes Prettier skip files it has no parser for, instead of failing the hook on a .png.
  • .claude/settings.json is committed and applies to everyone; .claude/settings.local.json is personal and ignored by git.

Resources