Skills
Skills are domain-specific capabilities that can be added to agents to extend their functionality with specialized knowledge. Think of skills as "plugins" that give agents superpowers in specific domains.
What Are Skills?
While agents define roles and responsibilities, skills define capabilities and knowledge.
Analogy: Agents vs. Skills
Agent = Role (e.g., "Backend Developer")
→ Knows: Architecture patterns, clean code principles
→ Responsible for: Services, repositories, APIs
Skill = Capability (e.g., "Prisma ORM")
→ Knows: Prisma schema syntax, migration commands
→ Provides: Database modeling patterns, query patterns
Backend Agent + Prisma Skill
→ Can do: Design schemas, write migrations, optimize queriesSkill Definition
Skills are defined in .claude/skills/ as markdown files:
---
name: prisma-orm
applies_to: [backend, architect]
description: Prisma ORM expertise for database modeling and queries
---
# Prisma ORM Skill
You have expertise in Prisma ORM.
## Schema Design
```prisma
model User {
id String @id @default(cuid())
email String @unique
password String
posts Post[]
}Common Patterns
Relations
// One-to-many
model User {
posts Post[]
}
model Post {
author User @relation(fields: [authorId], references: [id])
authorId String
}Migrations
npx prisma migrate dev --name init
npx prisma migrate deployBest Practices
- Always use
@default(cuid())for IDs - Use
@uniquefor email fields - Add indexes for frequently queried fields
## Why Skills Exist
### Problem: Agents Are Generalists
Base agents have **broad knowledge** but **shallow domain-specific expertise**:Backend Agent: ✅ Knows clean architecture ✅ Knows REST API patterns ✅ Knows service/repository pattern ❌ Doesn't know Prisma-specific patterns ❌ Doesn't know Next.js 14 specific API routes ❌ Doesn't know Tailwind utility patterns
### Solution: Skills Add Specialization
Skills inject **deep domain knowledge** into agents:Backend Agent + Prisma Skill: ✅ Knows clean architecture ✅ Knows REST API patterns ✅ Knows Prisma schema syntax ✅ Knows Prisma query patterns ✅ Knows migration workflow ✅ Knows relation modeling
## Skill Types
### 1. Technology Skills
Specific technologies and frameworks:
```markdown
---
name: nextjs-14
applies_to: [frontend, backend, architect]
description: Next.js 14 App Router expertise
---
# Next.js 14 Skill
## App Router Patterns
### Server Components (Default)
```tsx
// src/app/dashboard/page.tsx
async function getData() {
const res = await fetch('https://api.example.com/data', {
cache: 'no-store',
});
return res.json();
}
export default async function DashboardPage() {
const data = await getData();
return <div>{data.title}</div>;
}Client Components (When Needed)
'use client';
export function InteractiveButton() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}Route Handlers
// src/app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(req: NextRequest) {
const users = await db.user.findMany();
return NextResponse.json(users);
}
### 2. Database Skills
ORM and database expertise:
```markdown
---
name: postgresql
applies_to: [backend, architect]
description: PostgreSQL database expertise
---
# PostgreSQL Skill
## Query Patterns
### Indexes
```sql
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_post_author ON posts(author_id);Full-Text Search
SELECT * FROM posts
WHERE to_tsvector(title || ' ' || content) @@ to_tsquery('react');Best Practices
- Use
TEXTinstead ofVARCHAR(no performance penalty) - Use
TIMESTAMPTZfor timestamps (with timezone) - Add foreign keys for data integrity
- Use
EXPLAIN ANALYZEto optimize queries
### 3. Styling Skills
CSS and styling frameworks:
```markdown
---
name: tailwind-css
applies_to: [frontend]
description: Tailwind CSS utility-first styling
---
# Tailwind CSS Skill
## Utility Patterns
### Responsive Design
```tsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{items.map(item => <Card key={item.id} {...item} />)}
</div>Dark Mode
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
<h1>Adaptive to theme</h1>
</div>Component Patterns
Card Component
export function Card({ children, className }) {
return (
<div className={cn(
"bg-white rounded-lg shadow-md p-6",
"dark:bg-gray-800",
className
)}>
{children}
</div>
);
}
### 4. Testing Skills
Testing frameworks and strategies:
```markdown
---
name: vitest
applies_to: [tester]
description: Vitest testing framework expertise
---
# Vitest Skill
## Test Patterns
### Unit Tests
```typescript
import { describe, it, expect, vi } from 'vitest';
describe('UserService', () => {
it('should create user with hashed password', async () => {
const user = await service.register({
email: 'test@example.com',
password: 'password123'
});
expect(user.password).not.toBe('password123');
expect(user.password).toMatch(/^\$2[ayb]\$.{56}$/);
});
});Mocking
const mockRepo = {
findByEmail: vi.fn().mockResolvedValue(null),
create: vi.fn().mockResolvedValue({ id: '1' })
};Coverage Configuration
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
thresholds: {
lines: 80,
functions: 80,
branches: 80,
statements: 80
}
}
}
});
### 5. Domain Skills
Industry-specific knowledge:
```markdown
---
name: ecommerce
applies_to: [backend, frontend, architect]
description: E-commerce domain expertise
---
# E-commerce Domain Skill
## Common Patterns
### Shopping Cart
```typescript
interface CartItem {
productId: string;
quantity: number;
variant?: string;
}
interface Cart {
items: CartItem[];
subtotal: number;
tax: number;
total: number;
}Inventory Management
async function checkInventory(productId: string, quantity: number) {
const product = await db.product.findUnique({ where: { id: productId } });
if (product.stock < quantity) {
throw new InsufficientStockError(product.stock, quantity);
}
return product;
}Best Practices
- Always use transactions for order creation
- Implement optimistic locking for inventory
- Cache product data but invalidate on updates
- Use webhooks for payment status updates
## How Skills Work
### Skill Loading
When an agent is invoked, agentful:
1. **Detects applicable skills**
```bash
# Reads skill frontmatter
applies_to: [backend, architect]
# Checks current agent
current_agent = "backend"
# → Load this skill-
Injects skill knowledge
- Agent definition + skill content = enhanced capabilities
- Agent can now use skill-specific patterns
- Agent knows best practices from skill
-
Applies to implementation
- Backend agent using Prisma skill:
// Knows to use Prisma patterns export class UserRepository { async findById(id: string) { return db.user.findUnique({ where: { id } }); } }
- Backend agent using Prisma skill:
Skill Composition
Multiple skills can be combined:
Backend Agent
+ Prisma Skill (database)
+ JWT Skill (authentication)
+ Zod Skill (validation)
→ Can build complete auth systemCreating Custom Skills
You can add your own skills in .claude/skills/:
---
name: your-skill-name
applies_to: [agent1, agent2]
description: What this skill provides
---
# Skill Name
Brief description of what this skill does.
## Patterns
### Pattern Name
```language
// Code exampleBest Practices
- Best practice 1
- Best practice 2
### Example: Custom API Skill
```markdown
---
name: stripe-api
applies_to: [backend]
description: Stripe payment integration expertise
---
# Stripe API Skill
## Payment Patterns
### Create Payment Intent
```typescript
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
async function createPaymentIntent(amount: number, currency: string) {
const paymentIntent = await stripe.paymentIntents.create({
amount: amount * 100, // Convert to cents
currency,
automatic_payment_methods: { enabled: true },
});
return paymentIntent;
}Webhook Handler
import { headers } from 'next/headers';
export async function POST(req: Request) {
const body = await req.text();
const sig = headers().get('stripe-signature')!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
}
switch (event.type) {
case 'payment_intent.succeeded':
// Handle successful payment
break;
}
return NextResponse.json({ received: true });
}Best Practices
- Always verify webhook signatures
- Store payment intent IDs in your database
- Handle idempotency keys for retries
- Use Stripe CLI for local testing
## Skill Discovery
### Automatic Skill Loading
agentful automatically discovers and loads skills:.claude/ ├── agents/ │ ├── backend.md │ └── frontend.md └── skills/ ├── prisma-orm.md (applies_to: [backend]) ├── nextjs-14.md (applies_to: [frontend, backend]) ├── tailwind-css.md (applies_to: [frontend]) └── vitest.md (applies_to: [tester])
When @backend agent invoked: → Loads: prisma-orm.md → Loads: nextjs-14.md (if applicable) → Combines with backend.md
### Skill Priority
When skills conflict, **most specific wins**:
```javascript
Generic skill: "database" (applies_to: [backend])
Specific skill: "prisma-orm" (applies_to: [backend])
→ Use prisma-orm (more specific)Skills vs. Agent Specialization
When to Use Skills
Use skills when:
- Multiple agents need the same capability
- Example: Both backend and architect need PostgreSQL knowledge
- Capability is optional or tech-specific
- Example: Not all backend agents use Prisma
-
Capability can be composed
- Example: Backend + Prisma + JWT = complete auth system
When to Use Agents
Use agents when:
-
Role is fundamentally different
- Example: Backend vs. Frontend (different domains)
-
Responsibilities don't overlap
- Example: Tester never reviews code
-
Scope needs strict boundaries
- Example: Backend never touches UI
Skill Examples
Example 1: Adding React Query Skill
---
name: react-query
applies_to: [frontend]
description: React Query for server state management
---
# React Query Skill
## Query Patterns
### Fetching Data
```tsx
import { useQuery } from '@tanstack/react-query';
function UserProfile({ userId }) {
const { data: user, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading user</div>;
return <div>{user.name}</div>;
}Mutations
import { useMutation, useQueryClient } from '@tanstack/react-query';
function UpdateProfile() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (data) => fetch('/api/users', {
method: 'PUT',
body: JSON.stringify(data),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['user'] });
},
});
}
### Example 2: Adding Docker Skill
```markdown
---
name: docker
applies_to: [backend, architect]
description: Docker containerization expertise
---
# Docker Skill
## Dockerfile Patterns
### Node.js App
```dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["npm", "start"]Docker Compose
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://db:5432/myapp
depends_on:
- db
db:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
## Best Practices for Skills
### DO ✅
- **Keep skills focused** - One capability per skill
- **Provide examples** - Show common patterns
- **Specify applies_to** - Clear which agents use it
- **Document best practices** - Share domain knowledge
- **Keep updated** - Match current framework versions
### DON'T ❌
- **Don't duplicate agent logic** - Skills add, don't replace
- **Don't make skills too broad** - "web-development" is too broad, "nextjs-14" is good
- **Don't assume tech stack** - Make skills optional
- **Don't hardcode paths** - Use generic patterns
## Summary
Skills are agentful's extensibility mechanism:
- **Domain-specific** - Deep knowledge in specific areas
- **Composable** - Combine multiple skills
- **Optional** - Load only what's needed
- **Extensible** - Add your own skills
- **Specialized** - Give agents superpowers
They transform generalist agents into **specialized experts** while keeping the agent system simple and maintainable.
**Next:** [Learn about state management](./state-management)