scaffolder
Generates boilerplate code following loaded rules. Creates new components, modules, APIs, and features that automatically comply with your coding standards. Extracts patterns from rules and applies them consistently.
Best use case
scaffolder is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Generates boilerplate code following loaded rules. Creates new components, modules, APIs, and features that automatically comply with your coding standards. Extracts patterns from rules and applies them consistently.
Teams using scaffolder should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/scaffolder/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How scaffolder Compares
| Feature / Agent | scaffolder | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Generates boilerplate code following loaded rules. Creates new components, modules, APIs, and features that automatically comply with your coding standards. Extracts patterns from rules and applies them consistently.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
<identity>
Rule-Aware Scaffolder - Creates new code that automatically adheres to your project's coding standards.
</identity>
<capabilities>
- Creating new React/Vue/Angular components
- Adding new API endpoints or routes
- Setting up new modules or packages
- Generating test files for existing code
- Creating data models or database schemas
- Bootstrapping feature directories
</capabilities>
<instructions>
<execution_process>
### Step 1: Load Rule Index
Load the rule index to discover relevant rules dynamically:
- @.claude/context/rule-index.json
### Step 2: Identify Target Framework and Query Index
Determine which technologies apply based on what you're scaffolding:
**Component scaffolding**:
- Detect: React, Next.js, TypeScript
- Query: `index.technology_map['react']`, `index.technology_map['nextjs']`, `index.technology_map['typescript']`
**API Route scaffolding**:
- Detect: Next.js App Router or FastAPI
- Query: `index.technology_map['nextjs']` or `index.technology_map['fastapi']`
**Test File scaffolding**:
- Detect: Jest, Cypress, Playwright, Vitest, pytest
- Query: `index.technology_map['jest']`, `index.technology_map['cypress']`, etc.
**Database Model scaffolding**:
- Detect: Prisma, SQL, database patterns
- Query: `index.technology_map['prisma']` or database-related rules
### Step 3: Load Relevant Rules
Load only the relevant rule files from the index (progressive disclosure):
- Master rules first (from `.claude/rules-master/`)
- Archive rules supplement (from `.claude/archive/`)
- Load 3-5 most relevant rules, not all 1,081
### Step 4: Extract Patterns from Rules
Parse the loaded rule files to extract scaffolding patterns:
**From Next.js rules** (TECH_STACK_NEXTJS.md or nextjs.mdc):
- Server Components by default
- 'use client' only when needed
- Place in `app/` for routes, `components/` for shared
- Use lowercase-with-dashes for directories
**From TypeScript rules**:
- Interfaces for object shapes
- Proper return type annotations
- Avoid `any`, use `unknown`
- PascalCase for types/interfaces
**From React rules**:
- Functional components only
- Custom hooks for reusable logic
- Props interface for each component
- Error boundaries for critical sections
### Step 5: Generate Compliant Code
Apply extracted patterns to generate code that passes rule-auditor.
</execution_process>
<best_practices>
1. **Always Audit After**: Run `/audit` after scaffolding to catch any edge cases
2. **Customize Templates**: Add project-specific patterns to rules for consistent generation
3. **Use for Consistency**: Scaffold even simple files to maintain team conventions
4. **Review Generated Code**: Scaffolded code is a starting point, not final implementation
5. **Keep Rules Updated**: As patterns evolve, update rules so scaffolder stays current
</best_practices>
<integration>
### Component Generation Flow
```
1. User: /scaffold component UserDashboard
2. Scaffolder reads: nextjs.mdc, typescript.mdc, react.mdc
3. Extracts patterns: Server Component, Suspense, interfaces
4. Generates compliant code structure
5. Writes files to correct locations
6. Runs rule-auditor to verify compliance
7. Reports any manual adjustments needed
```
### Feature Module Generation
For larger features, scaffold generates a complete module:
```
/scaffold feature user-management
Generates:
app/
└── (dashboard)/
└── users/
├── page.tsx # List page
├── [id]/
│ └── page.tsx # Detail page
├── new/
│ └── page.tsx # Create page
└── components/
├── user-list.tsx
├── user-card.tsx
└── user-form.tsx
components/
└── users/
└── ... (shared components)
lib/
└── users/
├── api.ts # API functions
├── types.ts # Type definitions
└── validations.ts # Zod schemas
```
</integration>
</instructions>
<examples>
<code_example>
**Next.js Server Component**
**Command**: `/scaffold component UserProfile`
**Generated**: `components/user-profile/index.tsx`
```tsx
// Server Component (default per nextjs.mdc)
// Location: components/user-profile/ (lowercase-with-dashes per nextjs.mdc)
import { Suspense } from 'react'
import { UserProfileSkeleton } from './skeleton'
import { UserProfileContent } from './content'
// Interface defined (per typescript.mdc)
interface UserProfileProps {
userId: string
showDetails?: boolean
}
// Async Server Component for data fetching (per nextjs.mdc > Data Fetching)
export async function UserProfile({ userId, showDetails = false }: UserProfileProps) {
return (
// Suspense boundary (per nextjs.mdc > Components)
<Suspense fallback={<UserProfileSkeleton />}>
<UserProfileContent userId={userId} showDetails={showDetails} />
</Suspense>
)
}
// Default export for dynamic imports (per nextjs.mdc)
export default UserProfile
```
**Also generates**:
- `components/user-profile/content.tsx` - Async content component
- `components/user-profile/skeleton.tsx` - Loading skeleton
- `components/user-profile/types.ts` - Shared types
- `components/user-profile/index.ts` - Barrel export
</code_example>
<code_example>
**Next.js Client Component**
**Command**: `/scaffold client-component SearchBar`
**Generated**: `components/search-bar/index.tsx`
```tsx
'use client' // Required for useState (per nextjs.mdc > Components)
import { useState, useCallback } from 'react'
import { useDebounce } from '@/hooks/use-debounce'
// Props interface (per typescript.mdc)
interface SearchBarProps {
onSearch: (query: string) => void
placeholder?: string
debounceMs?: number
}
// Functional component (per react.mdc)
export function SearchBar({
onSearch,
placeholder = 'Search...',
debounceMs = 300,
}: SearchBarProps) {
// Minimal client state (per nextjs.mdc > State Management)
const [query, setQuery] = useState('')
// Debounced callback (per nextjs.mdc > Performance)
const debouncedSearch = useDebounce(onSearch, debounceMs)
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setQuery(value)
debouncedSearch(value)
}, [debouncedSearch])
return (
<input
type="search"
value={query}
onChange={handleChange}
placeholder={placeholder}
className="w-full px-4 py-2 border rounded-lg" // Tailwind (per tailwind.mdc)
aria-label={placeholder} // Accessibility
/>
)
}
export default SearchBar
```
</code_example>
<code_example>
**Next.js API Route (App Router)**
**Command**: `/scaffold api users`
**Generated**: `app/api/users/route.ts`
```tsx
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod' // Zod for validation (per nextjs.mdc > Forms and Validation)
// Request schema (per typescript.mdc > Type System)
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
})
// Response type (per typescript.mdc)
interface UserResponse {
id: string
email: string
name: string
createdAt: string
}
// GET handler (per nextjs.mdc > Routing)
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') ?? '1')
const limit = parseInt(searchParams.get('limit') ?? '10')
// TODO: Replace with actual database query
const users: UserResponse[] = []
return NextResponse.json({
data: users,
pagination: { page, limit, total: 0 },
})
} catch (error) {
// Proper error handling (per nextjs.mdc > Data Fetching)
console.error('Failed to fetch users:', error)
return NextResponse.json(
{ error: 'Failed to fetch users' },
{ status: 500 }
)
}
}
// POST handler with validation
export async function POST(request: NextRequest) {
try {
const body = await request.json()
// Server-side validation (per nextjs.mdc > Forms and Validation)
const validated = CreateUserSchema.parse(body)
// TODO: Replace with actual database insert
const user: UserResponse = {
id: crypto.randomUUID(),
...validated,
createdAt: new Date().toISOString(),
}
return NextResponse.json({ data: user }, { status: 201 })
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation failed', details: error.errors },
{ status: 400 }
)
}
console.error('Failed to create user:', error)
return NextResponse.json(
{ error: 'Failed to create user' },
{ status: 500 }
)
}
}
```
</code_example>
<code_example>
**FastAPI Endpoint**
**Command**: `/scaffold fastapi-route users`
**Generated**: `app/routers/users.py`
```python
"""User management endpoints."""
# Type hints required (per python.mdc)
from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel, EmailStr, Field
# Router with tags (per fastapi.mdc > API Design)
router = APIRouter(prefix="/users", tags=["users"])
# Pydantic models (per fastapi.mdc > Components and Validation)
class UserCreate(BaseModel):
"""Schema for creating a user."""
email: EmailStr
name: str = Field(..., min_length=2, max_length=100)
class UserResponse(BaseModel):
"""Schema for user response."""
id: UUID
email: EmailStr
name: str
created_at: str
class Config:
from_attributes = True
class PaginatedResponse(BaseModel):
"""Paginated response wrapper."""
data: list[UserResponse]
total: int
page: int
limit: int
# Dependency injection (per fastapi.mdc > Dependency Injection)
async def get_db():
"""Database session dependency."""
# TODO: Replace with actual database session
yield None
# GET endpoint with pagination (per fastapi.mdc > Performance)
@router.get("", response_model=PaginatedResponse)
async def list_users(
db: Annotated[None, Depends(get_db)],
page: Annotated[int, Query(ge=1)] = 1,
limit: Annotated[int, Query(ge=1, le=100)] = 10,
) -> PaginatedResponse:
"""
List all users with pagination.
- **page**: Page number (starting from 1)
- **limit**: Items per page (max 100)
"""
# TODO: Replace with actual database query
users: list[UserResponse] = []
total = 0
return PaginatedResponse(data=users, total=total, page=page, limit=limit)
# POST endpoint with validation
@router.post("", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(
user_data: UserCreate,
db: Annotated[None, Depends(get_db)],
) -> UserResponse:
"""
Create a new user.
- **email**: Valid email address
- **name**: User's display name (2-100 chars)
"""
# TODO: Replace with actual database insert
# Check for existing user, create, return
raise HTTPException(
status_code=status.HTTP_501_NOT_IMPLEMENTED,
detail="Database integration pending",
)
# GET by ID endpoint
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(
user_id: UUID,
db: Annotated[None, Depends(get_db)],
) -> UserResponse:
"""Get a specific user by ID."""
# TODO: Replace with actual database query
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User {user_id} not found",
)
```
</code_example>
<code_example>
**Test File (Vitest/Jest)**
**Command**: `/scaffold test components/user-profile`
**Generated**: `components/user-profile/__tests__/index.test.tsx`
```tsx
// Test file (per jest-*.mdc / vitest-*.mdc patterns)
import { render, screen, waitFor } from '@testing-library/react'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { UserProfile } from '../index'
// Mock external dependencies (per testing best practices)
vi.mock('@/lib/api', () => ({
fetchUser: vi.fn(),
}))
describe('UserProfile', () => {
// Clear mocks before each test (per clean-code.mdc)
beforeEach(() => {
vi.clearAllMocks()
})
// Descriptive test names (per testing guidelines)
it('renders loading skeleton initially', () => {
render(<UserProfile userId="123" />)
expect(screen.getByTestId('user-profile-skeleton')).toBeInTheDocument()
})
it('displays user information after loading', async () => {
const mockUser = {
id: '123',
name: 'John Doe',
email: 'john@example.com',
}
const { fetchUser } = await import('@/lib/api')
vi.mocked(fetchUser).mockResolvedValue(mockUser)
render(<UserProfile userId="123" />)
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument()
expect(screen.getByText('john@example.com')).toBeInTheDocument()
})
})
it('handles error state gracefully', async () => {
const { fetchUser } = await import('@/lib/api')
vi.mocked(fetchUser).mockRejectedValue(new Error('Network error'))
render(<UserProfile userId="123" />)
await waitFor(() => {
expect(screen.getByText(/failed to load/i)).toBeInTheDocument()
})
})
// Edge cases (per qa best practices)
it('shows details when showDetails prop is true', async () => {
render(<UserProfile userId="123" showDetails />)
await waitFor(() => {
expect(screen.getByTestId('user-details-section')).toBeInTheDocument()
})
})
})
```
</code_example>
<code_example>
**Cypress E2E Test**
**Command**: `/scaffold e2e-test user-flow`
**Generated**: `cypress/e2e/user-flow.cy.ts`
```typescript
// E2E test (per cypress-e2e-testing-*.mdc)
describe('User Flow', () => {
// Setup before tests (per cypress best practices)
beforeEach(() => {
// Reset state and seed data
cy.task('db:seed')
cy.visit('/')
})
// Critical user flow (per cypress-e2e-testing guidelines)
it('allows user to sign up, login, and view profile', () => {
// Use data-testid selectors (per cypress best practices)
cy.get('[data-testid="signup-link"]').click()
// Fill signup form
cy.get('[data-testid="email-input"]').type('test@example.com')
cy.get('[data-testid="password-input"]').type('SecurePass123!')
cy.get('[data-testid="name-input"]').type('Test User')
cy.get('[data-testid="signup-submit"]').click()
// Verify redirect to dashboard
cy.url().should('include', '/dashboard')
// Navigate to profile
cy.get('[data-testid="profile-link"]').click()
// Verify profile data
cy.get('[data-testid="profile-name"]').should('contain', 'Test User')
cy.get('[data-testid="profile-email"]').should('contain', 'test@example.com')
})
// API mocking example (per cypress-api-testing guidelines)
it('handles API errors gracefully', () => {
// Mock API failure
cy.intercept('GET', '/api/users/*', {
statusCode: 500,
body: { error: 'Internal server error' },
}).as('getUserError')
cy.visit('/profile')
// Wait for mocked request
cy.wait('@getUserError')
// Verify error handling
cy.get('[data-testid="error-message"]')
.should('be.visible')
.and('contain', 'Failed to load profile')
// Verify retry option
cy.get('[data-testid="retry-button"]').should('be.visible')
})
})
```
</code_example>
<usage_example>
**Quick Commands**:
```
# Generate a Server Component
/scaffold component MyComponent
# Generate a Client Component
/scaffold client-component MyInteractiveWidget
# Generate an API route
/scaffold api resource-name
# Generate a FastAPI router
/scaffold fastapi-route resource-name
# Generate test for existing file
/scaffold test path/to/component
# Generate E2E test
/scaffold e2e-test flow-name
# Generate with specific rules
/scaffold component MyComponent --rules nextjs,typescript
# Generate in specific location
/scaffold component MyComponent --path src/features/auth
# List available scaffold templates
/scaffold --list
```
**Available Templates**:
| Template | Framework | Files Generated |
|----------|-----------|-----------------|
| `component` | Next.js/React | index.tsx, types.ts, skeleton.tsx |
| `client-component` | Next.js | index.tsx with 'use client' |
| `page` | Next.js App Router | page.tsx, loading.tsx, error.tsx |
| `api` | Next.js App Router | route.ts with handlers |
| `fastapi-route` | FastAPI | router file with endpoints |
| `hook` | React | Custom hook with types |
| `context` | React | Context provider + hook |
| `test` | Jest/Vitest | Test file for component |
| `e2e-test` | Cypress/Playwright | E2E test spec |
| `model` | Prisma | Schema model |
| `migration` | Database | Migration file |
</usage_example>
</examples>Related Skills
solution-scaffolder
Create new .NET solutions with complete project structure, configurations, and conventions based on the ArticlesSite architecture. Guides users through interactive prompts to scaffold solutions following SOLID principles, clean architecture, and established coding standards.
project-scaffolder
Guide for setting up Claude Code infrastructure in new or existing projects
api-integration-test-scaffolder
Generates integration tests for frontend → backend → Genkit flow connections. Use when creating E2E API tests.
m365-agent-scaffolder
Quickly scaffolds new Microsoft 365 Copilot declarative agent (M365 agent, copilot agent, agent, declarative copilot, copilot) projects using ATK CLI. Collects project information and creates the initial project structure. Use only when creating a new empty M365 Copilot agent project from scratch.
bgo
Automates the complete Blender build-go workflow, from building and packaging your extension/add-on to removing old versions, installing, enabling, and launching Blender for quick testing and iteration.
testing-builder
Automatically generates comprehensive test suites (unit, integration, E2E) based on code and past testing patterns. Use when user says "write tests", "test this", "add coverage", or after fixing bugs to create regression tests. Eliminates testing friction for ADHD users.
Testing Anti-Patterns
This skill should be used when encountering "flaky tests", "test maintenance issues", "slow test suites", "brittle tests", "test code smells", "test debugging problems", or when tests are hard to understand, maintain, or debug.
testcontainers-integration-tests
Use when integration tests require real infrastructure (database, message queue, cache) or when mocking infrastructure is insufficient. Defines container lifecycle, test isolation, and performance optimization for Testcontainers-based testing.
test-generation
Master skill for intelligent test case generation. Identifies technology stack and delegates to specialized testing sub-skills for creating high-quality integration and API tests.
test-driven-development
Use when implementing any feature or bugfix, before writing implementation code
Test and Refine Your Kubernetes Skill
No description provided.
test-and-fix-workflow
Automated workflow for running tests and fixing failures systematically. Use when implementing the mandatory test workflow or fixing code quality issues. Keywords - testing, debugging, workflow, failures, systematic fixes.