Claude Code 완전 정복 가이드 Part 3: Skills 시스템 - 온디맨드 전문가 활용하기
이 글은 Claude Opus 4.5 을 이용해 초안이 작성되었으며, 이후 퇴고를 거쳤습니다.
예상 소요 시간: 1시간 난이도: ⭐⭐⭐ 사전 요구사항: Part 1, 2 완료 Claude Code 버전: 2.1.x (Hot Reload 지원)
1. Skills란 무엇인가?#
1.1 CLAUDE.md vs Skills의 핵심 차이#
CLAUDE.md는 항상 로드되는 “기본 매뉴얼"입니다. 반면 Skills는 필요할 때만 로드되는 “전문 레시피북"입니다.
💡 Claude Code 2.1+ 새 기능: Hot Reload - Skills를 수정하면 Claude Code를 재시작하지 않아도 즉시 반영됩니다. ~/.claude/skills/ 또는 .claude/skills/ 디렉토리의 변경사항이 실시간으로 적용됩니다.
┌─────────────────────────────────────────────────────────────────┐
│ CLAUDE.md │
├─────────────────────────────────────────────────────────────────┤
│ • 항상 전체 내용이 로드됨 │
│ • 프로젝트 기본 정보 (빌드, 테스트, 구조) │
│ • 모든 대화에 적용되는 규칙 │
│ • 간결하게 유지해야 함 (Part 2 참조) │
└─────────────────────────────────────────────────────────────────┘
│
│ 보완
▼
┌─────────────────────────────────────────────────────────────────┐
│ Skills │
├─────────────────────────────────────────────────────────────────┤
│ • 필요할 때만 로드됨 (Progressive Disclosure) │
│ • 특정 작업에 대한 상세 지식 │
│ • Claude가 description 보고 자동 판단 │
│ • 토큰 효율적 │
└─────────────────────────────────────────────────────────────────┘
1.2 Progressive Disclosure: 필요할 때만 로드되는 지식#
Skills는 2단계 로딩 시스템을 사용합니다:
┌─────────────────────────────────────────────────────────────────┐
│ Skills 로딩 메커니즘 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1단계: 메타데이터 스캔 (항상) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ name: go-error-handling │ │
│ │ description: Go 에러 처리 패턴. 에러 핸들링, │ ~100 │
│ │ 에러 래핑, 커스텀 에러 작업 시 사용 │ 토큰 │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ description이 현재 작업과 매칭되면 │
│ ▼ │
│ 2단계: 전체 내용 로드 (필요시에만) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ # Go Error Handling Patterns │ │
│ │ │ │
│ │ ## 기본 원칙 │ <5k │
│ │ - 에러는 즉시 처리 │ 토큰 │
│ │ - fmt.Errorf로 컨텍스트 추가 │ │
│ │ ... │ │
│ │ (상세 내용) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
1.3 토큰 절약 효과#
| 구분 | 토큰 사용 | 언제 |
|---|---|---|
| 메타데이터 | ~100 토큰/Skill | 항상 (모든 대화) |
| 전체 내용 | <5,000 토큰 | 활성화 시에만 |
10개의 Skill이 있어도 메타데이터만 ~1,000 토큰. 실제로 사용되는 Skill만 전체 로드됩니다.
2. Skills vs Subagents: 언제 무엇을 쓸까?#
2.1 개념 비교#
┌─────────────────────────────────────────────────────────────────┐
│ Skills vs Subagents │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Skills (레시피) Subagents (전문가) │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ │ │ │ │
│ │ 📖 │ │ 👨💼 │ │
│ │ 지식/패턴 │ │ 독립 에이전트 │ │
│ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ • 메인 컨텍스트에 주입 • 격리된 컨텍스트 윈도우 │
│ • 자동 호출 (description) • 명시적 위임 또는 자동 │
│ • 가벼운 참조 지식 • 복잡한 워크플로우 처리 │
│ • 도구 제한 가능 • 도구 권한 별도 설정 │
│ │
│ 예: 코딩 컨벤션, API 패턴 예: 코드 리뷰어, 디버거 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 선택 기준#
┌─────────────────────────────────────────────────────────────────┐
│ 무엇을 선택할까? │
├─────────────────────────────────────────────────────────────────┤
│ │
│ "이 작업은..." │
│ │
│ □ 참조용 지식이 필요하다 (패턴, 컨벤션, 가이드) │
│ └─▶ Skill 사용 │
│ │
│ □ 독립적인 분석/처리가 필요하다 │
│ └─▶ Subagent 사용 │
│ │
│ □ 여러 단계의 복잡한 워크플로우다 │
│ └─▶ Subagent 사용 │
│ │
│ □ 메인 대화의 컨텍스트를 오염시키고 싶지 않다 │
│ └─▶ Subagent 사용 │
│ │
│ □ 다른 에이전트/대화에서도 재사용하고 싶다 │
│ └─▶ Skill 사용 (포터블) │
│ │
└─────────────────────────────────────────────────────────────────┘
2.3 함께 사용하기#
Skills와 Subagents는 상호 보완적입니다:
┌─────────────────────────────────────────────────────────────────┐
│ 조합 사용 예시 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 사용자: "이 PR을 리뷰해줘" │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────┐ │
│ │ code-reviewer (Subagent) │ │
│ │ │ │
│ │ 격리된 컨텍스트에서 PR 분석 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────┐ │ │
│ │ │ go-conventions (Skill) 호출 │ │ │
│ │ │ Go 코딩 컨벤션 참조 │ │ │
│ │ └───────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 리뷰 결과 생성 │ │
│ └─────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 메인 대화에 결과만 반환 (컨텍스트 오염 없음) │
│ │
└─────────────────────────────────────────────────────────────────┘
3. 첫 번째 Skill 만들기#
3.1 디렉토리 구조#
~/.claude/skills/ # 전역 Skills (모든 프로젝트)
└── my-skill/
└── SKILL.md
.claude/skills/ # 프로젝트 Skills
└── project-skill/
├── SKILL.md # 필수
├── scripts/ # 선택: 실행 스크립트
│ └── helper.py
└── resources/ # 선택: 참조 파일
└── template.json
3.2 SKILL.md 작성법#
SKILL.md는 두 부분으로 구성됩니다:
---
name: skill-name
description: 이 스킬이 무엇을 하는지, 언제 사용하는지 설명
---
# Skill 제목
여기에 Claude가 따라야 할 상세 지침을 작성합니다.
## 섹션 1
...
## 섹션 2
...
3.3 YAML Frontmatter 필드#
| 필드 | 필수 | 설명 |
|---|---|---|
name |
✅ | Skill 이름 (슬래시 커맨드가 됨: /skill-name) |
description |
✅ | Claude가 자동 호출 판단에 사용 |
disable-model-invocation |
true면 자동 호출 비활성화 |
|
allowed-tools |
사용 가능한 도구 제한 | |
user-invocable |
메뉴에 표시 여부 |
💡 Claude Code 2.1+ 새 기능: Skills 내에서 ${CLAUDE_SESSION_ID} 변수를 사용하여 현재 세션 ID에 접근할 수 있습니다. 세션별 로깅이나 상태 관리에 유용합니다.
3.4 기본 예제: 코드 설명 Skill#
---
name: explain-code
description: 코드를 시각적 다이어그램과 비유로 설명합니다.
코드 동작 방식을 설명하거나, 코드베이스를 가르치거나,
"이게 어떻게 동작해?" 질문에 사용합니다.
---
# 코드 설명 Skill
코드를 설명할 때 항상 다음 구조를 따르세요:
## 1. 비유로 시작
코드를 일상생활의 무언가에 비유하여 시작합니다.
## 2. 다이어그램 그리기
ASCII 아트로 흐름, 구조, 관계를 시각화합니다.
## 3. 단계별 설명
코드가 어떻게 동작하는지 단계별로 설명합니다.
## 4. 주의점 하이라이트
흔한 실수나 오해를 짚어줍니다.
## 예시
사용자: "이 함수 어떻게 동작해?"
응답:
"이 함수는 식당의 주문 시스템과 비슷합니다.
주문 접수 → 주방 전달 → 조리 → 서빙 │ │ │ │ validate enqueue process return
단계별로 보면..."
4. 실전 Skills 예제#
4.1 Java 프로젝트용 테스트 작성 Skill#
---
name: java-test-writer
description: Java 테스트 코드를 작성합니다.
JUnit 5, MockK, Given-When-Then 패턴을 사용합니다.
"테스트 작성해줘", "테스트 코드", "단위 테스트" 요청 시 사용.
---
# Java Test Writing Skill
## 테스트 클래스 구조
```java
@ExtendWith(MockKExtension.class)
class {TargetClass}Test {
@MockK
private lateinit var dependency: DependencyType
@InjectMockKs
private lateinit var sut: TargetClass // System Under Test
@BeforeEach
fun setUp() {
// 공통 설정
}
@Test
fun `should 결과 when 조건`() {
// Given
val input = ...
// When
val result = sut.methodUnderTest(input)
// Then
assertThat(result).isEqualTo(expected)
}
}
네이밍 규칙#
- 클래스:
{대상클래스}Test - 메서드:
should_{기대결과}_when_{조건}(백틱 사용) - 변수:
sut(System Under Test)
Given-When-Then 패턴#
@Test
fun `should return user when valid id provided`() {
// Given - 테스트 데이터 및 Mock 설정
val userId = 1L
val expectedUser = User(id = userId, name = "John")
every { userRepository.findById(userId) } returns expectedUser
// When - 테스트 대상 메서드 실행
val result = userService.getUser(userId)
// Then - 결과 검증
assertThat(result).isEqualTo(expectedUser)
verify(exactly = 1) { userRepository.findById(userId) }
}
Mock 사용 규칙#
- MockK 사용 (Mockito 금지)
every { }/verify { }구문answers { }for complex stubbing
금지 사항#
@Autowiredin tests (use@InjectMockKs)- Real database connections
- Thread.sleep() for async tests
### 4.2 Go 프로젝트용 에러 핸들링 Skill
```markdown
---
name: go-error-handling
description: Go 에러 처리 패턴을 적용합니다.
에러 래핑, 커스텀 에러, 센티넬 에러 작업 시 사용.
"에러 처리", "error handling", "에러 래핑" 요청 시 활성화.
---
# Go Error Handling Patterns
## 기본 원칙
1. 에러는 즉시 처리하거나 래핑하여 반환
2. 에러 메시지에 컨텍스트 추가
3. 절대로 에러를 무시하지 않음
## 에러 래핑 패턴
```go
// ✅ 좋은 예: 컨텍스트 추가
if err != nil {
return fmt.Errorf("failed to create user %s: %w", username, err)
}
// ❌ 나쁜 예: 컨텍스트 없음
if err != nil {
return err
}
// ❌ 최악: 에러 무시
result, _ := someFunction()
커스텀 에러 타입#
// 도메인 에러 정의
type UserNotFoundError struct {
UserID int64
}
func (e *UserNotFoundError) Error() string {
return fmt.Sprintf("user not found: %d", e.UserID)
}
// 사용
func GetUser(id int64) (*User, error) {
user, err := repo.Find(id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, &UserNotFoundError{UserID: id}
}
return nil, fmt.Errorf("failed to get user: %w", err)
}
return user, nil
}
센티넬 에러#
// 패키지 레벨에 정의
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidInput = errors.New("invalid input")
)
// 사용
if errors.Is(err, ErrNotFound) {
// 404 처리
}
에러 체크 패턴#
// errors.Is - 에러 체인에서 특정 에러 찾기
if errors.Is(err, sql.ErrNoRows) { ... }
// errors.As - 특정 타입으로 캐스팅
var notFoundErr *UserNotFoundError
if errors.As(err, ¬FoundErr) {
log.Printf("User %d not found", notFoundErr.UserID)
}
금지 패턴#
// ❌ panic 남용
panic("something went wrong") // 복구 불가능한 경우만 사용
// ❌ 에러 문자열 비교
if err.Error() == "not found" { ... } // errors.Is 사용
// ❌ 에러 로그 후 반환
log.Println(err)
return err // 중복 로깅 발생, 한 곳에서만 로그
### 4.3 Redis 캐시 패턴 Skill
```markdown
---
name: redis-cache-patterns
description: Redis 캐시 구현 패턴을 제공합니다.
캐시 키 설계, TTL 전략, Cache-Aside 패턴 작업 시 사용.
"Redis", "캐시", "caching" 관련 요청 시 활성화.
---
# Redis Cache Patterns
## 캐시 키 네이밍 규칙
{service}:{entity}:{identifier}:{optional-suffix}
예시:
- user-service:user:12345
- payment:transaction:uuid-here:status
- inventory:product:SKU123:stock
## 키 프리픽스 상수화
```java
public class CacheKeys {
public static final String USER_PREFIX = "user-service:user:";
public static final String SESSION_PREFIX = "user-service:session:";
public static String userKey(Long userId) {
return USER_PREFIX + userId;
}
}
Cache-Aside 패턴#
public User getUser(Long userId) {
String key = CacheKeys.userKey(userId);
// 1. 캐시 조회
User cached = redisTemplate.opsForValue().get(key);
if (cached != null) {
return cached;
}
// 2. DB 조회
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException(userId));
// 3. 캐시 저장
redisTemplate.opsForValue().set(key, user, Duration.ofHours(1));
return user;
}
TTL 전략#
| 데이터 유형 | TTL | 이유 |
|---|---|---|
| 세션 | 30분 | 보안 |
| 사용자 프로필 | 1시간 | 자주 변경되지 않음 |
| 상품 정보 | 5분 | 재고 등 변경 가능 |
| 설정값 | 24시간 | 거의 변경 없음 |
캐시 무효화#
// 단일 키 삭제
public void evictUser(Long userId) {
redisTemplate.delete(CacheKeys.userKey(userId));
}
// 패턴으로 삭제 (주의: 프로덕션에서 KEYS 명령 지양)
public void evictUserCache() {
Set<String> keys = redisTemplate.keys("user-service:user:*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
// 권장: SCAN 사용
public void evictByPattern(String pattern) {
ScanOptions options = ScanOptions.scanOptions()
.match(pattern)
.count(100)
.build();
try (Cursor<String> cursor = redisTemplate.scan(options)) {
while (cursor.hasNext()) {
redisTemplate.delete(cursor.next());
}
}
}
주의사항#
- 프로덕션에서
KEYS *명령 금지 (블로킹) - 대량 삭제 시
SCAN+ 배치 삭제 사용 - 캐시 워밍업 전략 고려
### 4.4 API 설계 컨벤션 Skill
```markdown
---
name: api-conventions
description: REST API 설계 컨벤션을 제공합니다.
API 엔드포인트 설계, 응답 형식, 에러 처리 시 사용.
"API 만들어줘", "엔드포인트", "REST" 요청 시 활성화.
---
# REST API Design Conventions
## URL 설계 원칙
GET /api/v1/users # 목록 조회 GET /api/v1/users/{id} # 단일 조회 POST /api/v1/users # 생성 PUT /api/v1/users/{id} # 전체 수정 PATCH /api/v1/users/{id} # 부분 수정 DELETE /api/v1/users/{id} # 삭제
하위 리소스#
GET /api/v1/users/{id}/orders POST /api/v1/users/{id}/orders
액션 (동사가 필요한 경우)#
POST /api/v1/users/{id}/activate POST /api/v1/orders/{id}/cancel
## 응답 형식
### 성공 응답
```json
{
"success": true,
"data": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
"meta": {
"requestId": "req-uuid",
"timestamp": "2025-01-23T10:00:00Z"
}
}
목록 응답 (페이징)#
{
"success": true,
"data": [...],
"pagination": {
"page": 1,
"size": 20,
"totalElements": 100,
"totalPages": 5
}
}
에러 응답 (RFC 7807 Problem Details)#
{
"success": false,
"error": {
"type": "https://api.example.com/errors/validation",
"title": "Validation Error",
"status": 400,
"detail": "The request body contains invalid fields",
"instance": "/api/v1/users",
"errors": [
{
"field": "email",
"message": "must be a valid email address"
}
]
}
}
HTTP 상태 코드#
| 코드 | 의미 | 사용 시점 |
|---|---|---|
| 200 | OK | GET 성공, PUT/PATCH 성공 |
| 201 | Created | POST 생성 성공 |
| 204 | No Content | DELETE 성공 |
| 400 | Bad Request | 요청 형식 오류, 유효성 검증 실패 |
| 401 | Unauthorized | 인증 필요 |
| 403 | Forbidden | 권한 없음 |
| 404 | Not Found | 리소스 없음 |
| 409 | Conflict | 중복, 상태 충돌 |
| 422 | Unprocessable Entity | 비즈니스 규칙 위반 |
| 500 | Internal Server Error | 서버 오류 |
쿼리 파라미터#
# 페이징
GET /api/v1/users?page=1&size=20
# 정렬
GET /api/v1/users?sort=createdAt,desc
# 필터링
GET /api/v1/users?status=active&role=admin
# 검색
GET /api/v1/users?q=john
버전 관리#
- URL 경로:
/api/v1/,/api/v2/ - 주요 변경 시에만 버전 증가
- 이전 버전 최소 6개월 지원
---
## 5. Skills에 스크립트와 리소스 추가하기
### 5.1 scripts/ 디렉토리 활용
Skills는 실행 가능한 스크립트를 포함할 수 있습니다:
~/.claude/skills/codebase-visualizer/ ├── SKILL.md └── scripts/ └── generate-tree.py
**SKILL.md**:
```markdown
---
name: codebase-visualizer
description: 코드베이스의 인터랙티브 트리 시각화를 생성합니다.
"코드 구조 보여줘", "프로젝트 구조 시각화" 요청 시 사용.
---
# Codebase Visualizer
코드베이스 구조를 시각화하려면 번들된 스크립트를 실행하세요:
```bash
python ~/.claude/skills/codebase-visualizer/scripts/generate-tree.py
생성된 HTML 파일을 브라우저에서 열어 인터랙티브하게 탐색할 수 있습니다.
### 5.2 resources/ 디렉토리로 템플릿 제공
~/.claude/skills/api-scaffold/ ├── SKILL.md └── resources/ ├── controller-template.java ├── service-template.java └── dto-template.java
**SKILL.md**:
```markdown
---
name: api-scaffold
description: 새 API 엔드포인트를 위한 Controller, Service, DTO를 생성합니다.
"새 API 만들어줘", "CRUD 생성" 요청 시 사용.
---
# API Scaffolding
템플릿 파일들을 참조하여 일관된 구조로 생성하세요:
- Controller: `resources/controller-template.java`
- Service: `resources/service-template.java`
- DTO: `resources/dto-template.java`
## 생성 순서
1. DTO 먼저 생성 (Request, Response)
2. Service 인터페이스 및 구현체
3. Controller
4. 테스트 코드
5.3 실행 가능한 유틸리티 스크립트 번들링#
더 복잡한 스킬은 여러 스크립트를 포함할 수 있습니다:
~/.claude/skills/db-migration-helper/
├── SKILL.md
└── scripts/
├── check-migration.sh # 마이그레이션 상태 확인
├── generate-migration.py # 새 마이그레이션 생성
└── rollback.sh # 롤백 실행
6. Skills 호출 제어#
6.1 invocation: auto vs manual#
기본적으로 Claude는 description을 보고 자동으로 Skill을 호출합니다. 이를 제어할 수 있습니다:
---
name: dangerous-operation
description: 위험한 작업을 수행합니다.
disable-model-invocation: true # 자동 호출 비활성화
---
# 이 Skill은 /dangerous-operation으로만 호출 가능
6.2 allowed-tools로 도구 제한#
읽기 전용 Skill을 만들 수 있습니다:
---
name: safe-analyzer
description: 코드를 분석합니다 (수정 없음).
allowed-tools: Read, Grep, Glob
---
# Code Analyzer
이 Skill은 코드를 읽고 분석만 합니다. 수정 권한이 없습니다.
사용 가능한 도구들:
Read: 파일 읽기Write: 파일 쓰기Edit: 파일 수정Bash: 명령 실행Glob: 파일 패턴 검색Grep: 텍스트 검색
6.3 Permission 설정#
/permissions 명령으로 특정 Skill의 사용을 제어할 수 있습니다:
# 특정 Skill만 허용
Skill(commit)
Skill(review-pr:*)
# 특정 Skill 차단
Skill(deploy:*)
7. 실습: 기존 CLAUDE.md에서 Skills 분리하기#
7.1 Before: 모든 것이 CLAUDE.md에#
# CLAUDE.md (200줄)
## 프로젝트 정보
...
## 빌드/테스트
...
## Go 에러 처리 규칙 (50줄)
- 에러는 즉시 처리
- fmt.Errorf로 래핑
- ... (상세 규칙들)
## API 설계 규칙 (60줄)
- REST 원칙
- 응답 형식
- ... (상세 규칙들)
## 테스트 작성 규칙 (40줄)
- Given-When-Then
- ... (상세 규칙들)
7.2 After: Skills로 분리#
CLAUDE.md (50줄):
# User Service
Go 1.22 기반 사용자 관리 서비스
## 빌드 및 테스트
- 빌드: `go build ./cmd/server`
- 테스트: `go test ./...`
- 린트: `golangci-lint run`
## 프로젝트 구조
cmd/server/ # 진입점 internal/ # 내부 패키지 pkg/ # 공개 패키지 api/ # OpenAPI specs
## 핵심 규칙
IMPORTANT: 에러 처리, API 설계, 테스트 작성 시
해당 Skills가 자동으로 활성화됩니다.
.claude/skills/go-error-handling/SKILL.md:
---
name: go-error-handling
description: Go 에러 처리 패턴. 에러 래핑, 커스텀 에러 작업 시 사용.
---
(Part 4.2의 내용)
.claude/skills/api-conventions/SKILL.md:
---
name: api-conventions
description: REST API 설계 규칙. 엔드포인트, 응답 형식 설계 시 사용.
---
(Part 4.4의 내용)
.claude/skills/go-test-writer/SKILL.md:
---
name: go-test-writer
description: Go 테스트 작성. 테이블 기반 테스트, Mock 사용 시.
---
(테스트 관련 상세 규칙)
7.3 결과 비교#
| 항목 | Before | After |
|---|---|---|
| CLAUDE.md 크기 | 200줄 | 50줄 |
| 항상 로드되는 토큰 | ~4,000 | ~1,000 + (Skill 메타데이터 ~300) |
| 에러 처리 코드 작성 시 | 전체 200줄 로드 | 필요한 Skill만 로드 |
| 유지보수 | 한 파일에서 관리 | 주제별 분리로 명확 |
8. 정리#
이번 파트에서 배운 것#
- Skills는 Progressive Disclosure: 메타데이터만 스캔, 필요시 전체 로드
- Skills vs Subagents: Skills는 참조 지식, Subagents는 독립 에이전트
- SKILL.md 구조: YAML Frontmatter + Markdown 지침
- 스크립트/리소스 번들링: 실행 파일과 템플릿 포함 가능
- 호출 제어:
disable-model-invocation,allowed-tools
핵심 원칙#
CLAUDE.md에는 “항상 필요한 것"만, Skills에는 “때때로 필요한 것"을
다음 파트 예고#
Skills를 만들었다면, 이제 커뮤니티가 만든 플러그인을 활용하고 나만의 규칙과 조합하는 방법을 배웁니다. Part 4에서는 Plugins & Marketplace를 다룹니다.
참고 자료#
- Claude Code Skills 공식 문서
- Anthropic Skills GitHub
- Skills Explained - Claude Blog
- Skills vs Subagents 비교