Six specialized sub-agents, each with a dedicated model and tool scope. Agents are invoked from within Claude Code to handle specific types of work. They load relevant skills automatically and enforce project conventions.
Use agents when work is scoped and repeatable. A single conversation can delegate to multiple agents -- plan with the planner, build with the builder, review with the reviewer.
| Situation | Agent |
|---|---|
| Breaking a feature into implementation steps | craft-planner |
| Building a new plugin feature (elements, services, controllers) | craft-feature-builder |
| Building site templates, components, or content architecture | craft-site-builder |
| Investigating a bug or unexpected behavior | craft-debugger |
| Reviewing code before merge | craft-code-reviewer |
| Deep review of a high-stakes change (release branch, security-sensitive code, migrations, multi-service flows) | craft-code-reviewer-deep |
For complex work (more than 3 steps), always plan first, then build. The planner's output feeds directly into the builder.
Model: Opus (complex reasoning)
Tools: Read, Grep, Glob (read-only)
Skills loaded: craftcms
Breaks large tasks into scoped implementation steps that can each be completed in a single session.
- Reads the high-level requirement
- Identifies all affected areas (elements, queries, services, controllers, migrations, templates, project config, tests)
- Maps dependencies -- what must be built first
- Breaks work into steps of roughly equal size
- Writes the plan to
docs/plans/{feature-name}.md
Each step includes:
- Files to create or modify (exact paths)
- Dependencies on previous steps
- Which
ddev craft makecommand to scaffold with - A verification gate -- a runnable command with expected outcome (not "looks right")
- Estimated complexity: small (< 15 min), medium (15-30 min), large (30-45 min)
- Each step's verification gate must be a runnable command. "Check that it works" is not a gate --
ddev craft migrate/upsucceeds and shows the new table" is a gate. - Steps are ordered so each layer can be verified before the next depends on it: migrations before records, records before services, services before controllers.
- No step may require a later step to verify itself.
- Architectural decisions are surfaced as explicit decision points, not buried as assumptions.
- Multi-site implications and project config impacts are flagged.
- Auth level is asked upfront: public, any user, admin, or permission-gated.
Plan the implementation of a Job Listings custom element type with
department relations, salary range, and a full CP edit page.
Model: Opus (complex multi-file work)
Tools: Read, Write, Edit, Bash, Grep, Glob, TaskCreate, TaskUpdate, TaskList
Skills loaded: craftcms, craft-php-guidelines, craft-garnish
Builds production-quality plugin code following project architecture. Receives implementation plans and executes them layer by layer.
This is the core discipline. Each layer must pass its gate before the next layer starts. The builder never writes five files and verifies at the end -- that compounds debugging complexity.
Gate order for plugin work:
- Migration --
ddev craft migrate/upsucceeds, schema exists - Record / Model -- class resolves,
ddev craftdoesn't throw on boot - Service -- minimal method callable via Craft CLI or Pest test
- Controller -- actual request (
curlor browser) returns expected response - CP templates -- edit/index pages render without Twig errors
- Tests --
ddev craft pest/testgreen - Simplification pass -- collapse nesting, remove debug artifacts, verify PHPDocs
- Final verification --
ddev composer check-cs+ddev composer phpstanclean
A gate is "I ran the thing and saw it work." If a gate fails, the builder stops and fixes before moving on. It never plasters over a failed gate.
When a plan has more than 3 steps, the builder creates a todo list before writing any code. One todo per plan step. A step is marked completed only after its verification gate passes -- never batch-completed.
The builder enforces these rules that the reviewer will flag if violated:
andWhere()notwhere()on element queries- No hardcoded site IDs
$allowAnonymouslists specific actions, never blankettrue- No
$e->getMessage()returned to anonymous users - Permission handles as class constants
- Cached badge counts in
getCpNavItem() Gc::EVENT_RUNfor cleanup, not synchronous hooks- Conditional asset bundle registration
- No
|rawon admin content in<style>/<script> - All query properties wired in
beforePrepare() - Twig extension functions return, not echo
addSelect()notselect(),site('*')in queue workersDb::parseParam()for user input- Idempotent migrations with
muteEvents
After all gates pass, the builder does one sweep on files it just wrote (while context is fresh):
- Collapse nesting with early returns
- Remove temporary debug variables
- Simplify conditionals (
matchoverswitch) - Delete dead code and unused imports
- Verify section headers and PHPDocs
- Re-run ECS and PHPStan
Build the Job Listings element type following the plan in docs/plans/job-listings.md
Model: Opus (complex multi-file work)
Tools: Read, Write, Edit, Bash, Grep, Glob, TaskCreate, TaskUpdate, TaskList
Skills loaded: craft-site, craft-twig-guidelines, craft-content-modeling
Builds site templates, content architecture, and component systems following atomic design principles.
Adapted for site work, but the same discipline applies -- verify each layer before composing the next.
Gate order for site work:
- Content model -- sections, entry types, fields created. Verified in CP.
- Sample content -- at least one entry per type exists for rendering
- Atoms -- render standalone in a scratch template without errors
- Molecules -- render with real atom compositions, props flow correctly
- Organisms / layouts -- full-page render succeeds, no Twig errors
- Routes / views -- actual page load returns expected HTML
- Eager loading audit -- Elements Panel shows no N+1 on relational fields
- Responsive / a11y check -- after content renders correctly
- Plans content models and presents them as decision tables before implementing
- Builds atoms before molecules before organisms (never top-down)
- Enforces
onlyon every{% include %} - Uses
.eagerly()on every relational field in loops - Applies atomic design naming (by visual treatment, not parent context)
- Uses
collect({})for props and class collections - Handles Matrix block rendering with
ignore missing
- Install plugins without approval
- Write PHP plugin/module code (that's
craft-feature-builder) - Skip eager loading on relational fields
- Use macros for UI components
- Hardcode content that should come from fields
Build the blog listing and detail templates with a card component,
topic filtering, and pagination.
Model: Sonnet (focused, single-concern)
Tools: Read, Write, Edit, Bash, Grep, Glob
Skills loaded: craftcms, craft-php-guidelines
Systematic bug investigation with a hypothesis-driven approach.
- Reproduce -- understand the exact steps, read error logs and queue failures
- Hypothesize -- form 2-3 possible explanations before reading code
- Investigate -- read relevant code, check
storage/logs/, run targeted tests - Isolate -- write a minimal failing test that captures the bug
- Fix -- make the smallest change that fixes the issue
- Verify -- run ECS, PHPStan, and the full test suite
The debugger knows where to look for common Craft issues:
- Element not found? Check site context -- queue workers run in primary site. Try
->site('*')->status(null). - Project config drift? Compare YAML with database via
ddev craft project-config/diff. - Migration failed? Check for stale mutex locks in
cachetable. - Queue job failing silently? Check
ddev craft queue/infoand Craft logs for TTR timeouts. - Element status wrong? Status is computed from dates/conditions, not stored -- check
getStatus().
- Always writes a regression test before fixing
- Explains reasoning at each step
- Never fixes a symptom without finding the root cause
- States what has been ruled out if the cause is not found
The sync queue job is failing silently on the staging server. No errors
in the queue log, but entries aren't being updated. Investigate.
Model: Sonnet (focused, single-concern)
Tools: Read, Grep, Glob (read-only)
Skills loaded: craftcms, craft-php-guidelines, craft-garnish
Code review with a structured findings report. Read-only -- it never modifies files.
- Identify changed files via
git diff - Read each changed file thoroughly
- Check against the checklist
- Generate a findings report grouped by severity
- Critical (must fix before merge) -- security issues, data integrity risks, broken conventions
- Important (should fix) -- missing PHPDocs, incomplete
@throws, architectural violations - Suggestions (nice to have) -- naming improvements, simplification opportunities, test coverage gaps
Security (5 checks):
$allowAnonymoususes specific action names, never blankettrue- Exception messages never returned to anonymous users
|rawin CP templates reviewed for XSS- Permission handles match between registration and checking
Db::parseParam()for user input
Query safety (5 checks):
6. addSelect() not select()
7. andWhere() not where()
8. No hardcoded site IDs
9. All query class properties wired in beforePrepare()
10. site('*') in queue workers
Performance (4 checks):
11. getCpNavItem() badge counts are cheap
12. No synchronous cleanup in init()
13. defineSources() uses aggregate queries
14. Asset bundles registered conditionally
Code quality (5 checks):
15. PHPDoc completeness on every class, method, property
16. Section headers present and correct
17. Early returns, match over switch
18. Twig extensions return (not echo), delegate to services
19. Migration safety: idempotent, muteEvents
- Classes extend
Garnish.Base - Listeners use
addListener(), not jQuery.on() - Non-button elements use
activateevent, notclick - Key codes use Garnish constants
- ESC handling through
uiLayerManager - Webpack uses externals for Garnish
destroy()callsthis.base()- Deprecated APIs flagged
Review the changes in the job-listings branch before I open a PR.
Model: Opus (xhigh effort)
Tools: Read, Grep, Glob, Bash (read-only — git diff/log/show/blame only)
Skills loaded: craftcms, craft-php-guidelines, craft-garnish, craft-twig-guidelines, craft-site
The deep-review counterpart to craft-code-reviewer. The standard reviewer (Sonnet) catches checklist violations per file; this one (Opus, xhigh) catches what surface pattern-matching misses. Use it when the extra scrutiny is worth the token cost — release branches, security-sensitive code, large architectural changes, migrations, multi-service flows. Use the standard reviewer for daily review.
- Cross-file data flow — traces request data controller → service → element → DB to catch multi-file authorization gaps and TOCTOU escalations.
- Untested paths — reads the test suite and identifies new branches, exception paths, and negative cases the diff doesn't cover.
- Architecture — whether the abstraction is right, whether a service should exist, whether a migration can roll back.
- Race conditions & transaction boundaries — read-then-write without locking, resaves inside loops without
muteEvents, single-worker assumptions in queue jobs. - N+1 at production scale — eager-loading gaps in services called from loops elsewhere, with the math run at real data volume.
- Semantic correctness — does the code do what was intended, including empty arrays, soft-deleted parents, disabled multi-site, drafts.
- Migration safety at scale — add-column on million-row tables, unbatched long migrations, index additions that lock.
- Plugin lifecycle correctness — settings that mutate mid-request, events wired after they fire, DB hits during plugin boot.
It does not fabricate runtime bugs from generic framework intuition — claims about state staleness, DI timing, or cache lifecycle must trace through Craft's actual Yii2 source, or they're downgraded to "Verify". Depth means more accurate, not longer: a correct one-line finding beats a three-paragraph speculation.
Same severity grouping as the standard reviewer (Critical / Important / Suggestions), but each finding adds why it matters at depth — the subtle issue surface scanning would miss. Read-only; never modifies files.
Deep-review the release/1.6.0 branch before tagging — it touches migrations,
the asset filesystem, and the permission layer.
The builder and reviewer are designed as complementary pairs. The builder's prevention rules map to the reviewer's checklist items. Everything the builder prevents, the reviewer detects -- and vice versa.
This means code built by the craft-feature-builder agent passes the craft-code-reviewer agent's checklist with zero findings if the builder followed its own rules. The overlap is intentional: if the builder misses something (it sometimes does), the reviewer catches it.
The most common pattern. Plan first to break down complexity, then build layer by layer.
1. Delegate to craft-planner: "Plan the implementation of..."
2. Review the plan, adjust if needed
3. Delegate to craft-feature-builder: "Build following the plan in docs/plans/..."
After building, get a second opinion.
1. Delegate to craft-feature-builder: "Build the webhook controller..."
2. Delegate to craft-code-reviewer: "Review the changes in the webhook branch"
3. Fix any findings from the review
When something breaks, investigate before patching.
1. Delegate to craft-debugger: "The sync job is failing silently..."
2. Debugger identifies root cause and writes regression test
3. If fix is complex, delegate to craft-feature-builder for the implementation
For significant features:
1. craft-planner -- break down the feature
2. craft-feature-builder -- implement layer by layer
3. craft-code-reviewer -- review before merge
4. craft-debugger -- investigate if anything breaks in staging