Claude Code skills and subagents for architecture
A skill that scaffolds modules inside your rules and a read-only subagent that reviews the drift lint misses. File formats, examples, when to use which.
Use a skill to scaffold new modules inside your rules and a read-only subagent to review the drift that lint can't see. Lint and hooks catch the architecture mistakes you can express as a rule: "domain/ never imports infrastructure/". Two problems remain:
Code for this guide: https://github.com/KonixDev/claude-code-guardrails — the open-source (MIT) claude-code-guardrails kit.
- Starting right. A new module created from scratch by an agent tends to copy whatever the nearest file looks like, which may not be the pattern you want.
- Drift a linter can't see. Business logic in a controller, a port
declared in the wrong layer, a
// eslint-disableadded to get green — all of it passes lint.
Claude Code has a tool for each: skills for repeatable procedures and subagents for focused, isolated work like review.
Skills vs subagents in one table
| Skill | Subagent | |
|---|---|---|
| What it is | Instructions (and optional files) Claude loads when relevant or when you type /name | A separate Claude instance with its own prompt, tools and context window |
| Lives in | .claude/skills/<name>/SKILL.md | .claude/agents/<name>.md |
| Runs in | Your current conversation (or a subagent, with context: fork) | Its own context; returns a summary |
| Good for | Procedures: "scaffold a module", "cut a release" | Focused tasks that would flood your context: review, research |
A skill that scaffolds a module inside the rules
.claude/skills/new-module/SKILL.md:
---
name: new-module
description: Scaffold a new bounded context under src/modules/<name> with domain, application, infrastructure and interfaces layers that the architecture lint already guards. Use when a feature needs its own module.
argument-hint: "[module-name]"
---
Create a new bounded context named `$ARGUMENTS` (kebab-case; ask if missing).
1. Read AGENTS.md for the layer rules.
2. Create under src/modules/$ARGUMENTS/:
- domain/<entity>.ts — the entity with invariants in the constructor,
plus its repository interface. No imports from outside domain/.
- application/<use-case>.ts — one use case that receives the repository
interface as a parameter, never a concrete class.
- infrastructure/<entity>-repository.ts — the adapter (in-memory is fine
until the real store exists).
- interfaces/http.ts — wires the adapter into the use case.
3. If the module needs another module, declare a port in its own
application/ and `import type` the other module's shapes.
4. Run `npm run -s guardrails` and fix anything it reports.
5. Summarize what you created as a short tree.Details from the Claude Code docs that matter here:
descriptionis what Claude uses to decide when to load the skill on its own, so write it as a trigger ("Use when a feature needs its own module").$ARGUMENTSexpands to whatever you typed after/new-module.- Add
disable-model-invocation: trueif you only ever want to run it by hand. - Step 4 tells Claude to run the same checks the hooks and CI run before it reports the module as created.
A subagent that reviews what lint can't see
.claude/agents/architecture-reviewer.md:
---
name: architecture-reviewer
description: Reviews a diff against the layered architecture in AGENTS.md (inward dependencies, framework-free core, type-only cross-module imports). Use before reporting a non-trivial change as done.
tools: Read, Grep, Glob, Bash
---
You review code changes for architecture drift. You do not write features.
1. Read AGENTS.md for the rules.
2. Get the change set: `git diff --name-only main...HEAD` (this branch),
`git diff --name-only` (uncommitted) and untracked files.
3. Run `npm run -s guardrails`. Report any failure verbatim.
4. Then look for what lint cannot see:
- business rules in interfaces/ or infrastructure/ instead of
domain/ or application/;
- a port declared in infrastructure/ instead of application/;
- one module reaching into another's data store directly;
- eslint-disable, @ts-ignore or `any` added to get past a guardrail.
5. Report: file:line — rule — why it matters — the fix. Do not edit files.Why a subagent and not a paragraph in CLAUDE.md:
- Fresh eyes. It starts from the diff and the rules, not from the reasoning that produced the change, so it doesn't inherit the main session's blind spots.
- Context isolation. Reading a large diff and the rules happens in its own context window; your session only gets the findings.
- Narrow tools.
tools: Read, Grep, Glob, Bashand "Do not edit files" keep a reviewer a reviewer. (Bash is there to run the guardrails; drop it if you prefer a strictly read-only reviewer.)
Ask for it explicitly ("have the architecture-reviewer check this"), or tell
Claude in CLAUDE.md to use it before reporting a non-trivial change.
Where they fit
The skill and the subagent sit on top of lint and two hooks: lint rejects the wrong import, the hooks put that error in front of the agent while it works (Claude Code hooks to enforce your architecture), the skill starts new code in the right shape, and the subagent catches what none of them can express as a rule. The rules file itself is covered in a CLAUDE.md example for a SaaS codebase.
Get the files
The skill, the subagent, both hooks, the ESLint config and AGENTS.md are in
claude-code-guardrails
(MIT). Copy templates/.claude/ into your repo and adjust the paths.
FAQ
Can a subagent call another subagent?
Yes: by default up to three layers below the main conversation
(CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH changes it). A reviewer rarely needs
to — one subagent, one job, with the main session orchestrating, is easier to
reason about.
Will Claude use the skill automatically?
It can, based on the skill's description. If you want it only on demand, set
disable-model-invocation: true and run it as /new-module billing.
Project or user scope?
Project (.claude/skills/, .claude/agents/), committed to the repo. These
encode your codebase's rules, so the whole team — and every agent session —
should get the same ones.
useDeploy ships AGENTS.md, the hooks and the ESLint boundaries on a full SaaS
base: auth, organizations, billing and eleven modules built to these rules. See the modules.