
Claude Code의 6대 커스터마이징 기능 정리 - CLAUDE.md / rules / commands / subagents /
요약
Claude Code의 효율적인 활용을 위한 6가지 커스터마이징 기능(CLAUDE.md, rules, commands, subagents, skills, hooks)을 정리합니다. 각 기능의 로드 타이밍과 동작 주체를 기준으로 구분하여 컨텍스트 관리 최적화 방법을 제시합니다.
핵심 포인트
- CLAUDE.md는 세션 시작 시 항상 로드되는 프로젝트 공통 규칙 파일입니다.
- 서브 에이전트는 독립된 인스턴스로 동작하여 메인 컨텍스트 오염을 방지합니다.
- 기능별 로드 타이밍과 실행 주체를 파악하여 컨텍스트를 효율적으로 관리할 수 있습니다.
- 개인용(CLAUDE.local.md)과 프로젝트용 규칙을 분리하여 관리할 수 있습니다.
Claude Code를 깊게 사용하다 보면, 다음과 같은 답답함을 느낀 적이 없으신가요?
- CLAUDE.md에 규칙을 계속 추가하다 보니, 어느샌가 컨텍스트 (Context)가 가득 차버려서...
- 서브 에이전트 (Subagents), Skills, Hooks... 이름은 들어봤지만, 결국 무엇을 사용해야 할지 모르겠다
- 공식 문서를 읽어도 실전적인 구분 사용법에 대한 이미지가 잘 떠오르지 않는다
저 자신도 같은 지점에서 막혔었기에, 나름대로 정리해 보았습니다.
Claude Code에는 프로젝트에 맞춰 동작을 커스터마이징하기 위한 기능이 크게 6가지가 있습니다.
CLAUDE.md
.claude/rules/
- 커스텀 슬래시 커맨드 (Custom Slash Commands)
- 서브 에이전트 (Subagents)
- Skills
- Hooks
솔직히 처음에는 모두 비슷해 보여서 혼란스러웠습니다. 하지만 "언제 로드되는가"와 "누가 실행하는가"라는 두 가지 축으로 살펴보니, 의외로 깔끔하게 정리할 수 있다는 것을 깨달았습니다. 그래서 이번에는 그 관점에서 정리해 보겠습니다.
결론부터 말씀드리겠습니다.
| 기능 | 로드되는 타이밍 | 동작 주체 | 컨텍스트 (Context)에 미치는 영향 |
|---|---|---|---|
| CLAUDE.md | 세션 시작 시 항상 로드 | Claude (메인) | 항상 소비함 |
| 커스텀 커맨드 | /command 실행 시에만 | Claude (메인) | 실행 시에만 소비 |
| 서브 에이전트 (Subagents) | Task 툴로 호출되었을 때 | 독립된 Claude 인스턴스 | 메인 컨텍스트를 더럽히지 않음 |
| Skills | 태스크 내용에 따라 Claude가 판단 | Claude (메인/서브) | 필요한 계층만 단계적으로 소비 |
| Hooks | 특정 이벤트 발생 시 (확정적) | 쉘 스크립트 등 (Claude를 거치지 않음) | 컨텍스트를 거의 소비하지 않음 |
표의 위에서 아래로 내려갈수록 "상시 로드되는 것"에서 "필요할 때만 호출되는 것"으로 변하며, 마지막에는 "Claude의 판단조차 거치지 않는 기계적인 자동화"에 도달하는 흐름으로 되어 있습니다. 이 흐름만 머릿속에 넣어두면, "지금 쓰려는 이 규칙, 정말 CLAUDE.md에 상주시켜야 할까?"라고 자연스럽게 멈춰서 생각할 수 있게 됩니다.
판단의 기준으로 다음과 같은 플로우로 생각하면 이미지를 잡기 쉬울 것입니다.
그 규칙은 모든 태스크에서 항상 필요한가?
├─ Yes → CLAUDE.md
└─ No
...
그럼 하나씩 천천히 살펴보겠습니다.
CLAUDE.md는 프로젝트 루트에 두는, 말하자면 "Claude Code를 위한 인수인계 메모"와 같은 것입니다. 세션이 시작되면 자동으로 로드되며, 그 이후의 모든 상호작용에 서서히 영향을 미칩니다.
처음부터 쓰는 것이 힘들다면 /init 커맨드를 시도해 보는 것이 좋습니다. 기존 코드베이스를 분석하여 CLAUDE.md의 초안을 어느 정도 자동으로 생성해 줍니다.
/init
의외로 잘 알려지지 않았지만, CLAUDE.md는 한 곳이 아니라 우선순위를 가진 몇 가지 계층으로 나누어 둘 수 있습니다.
| 우선순위 | 배치 장소 | 용도 |
|---|---|---|
| 높음 | ./CLAUDE.local.md | 개인용 메모 (Git 관리 외) |
| 높음 | ./CLAUDE.md | 프로젝트 공통 규칙 |
| 중간 | 상위 디렉토리의 CLAUDE.md | 모노레포(Monorepo) 전체의 공통 규칙 |
| 낮음 | ~/.claude/CLAUDE.md | 자신의 머신 전체의 글로벌 설정 |
개인적인 메모와 팀 공유 규칙을 분리할 수 있다는 점은 은근히 유용한 포인트입니다.
CLAUDE.md에서 흔히 저지르기 쉬운 실수는 "정신론적인" 방식으로 작성하는 것입니다.
❌ 이런 방식은 전달력이 떨어짐
- 코드를 깔끔하게 작성해 주세요
- 테스트를 제대로 작성해 주세요
...
"지켜졌는지 여부를 Claude 스스로 판단할 수 있는" 정도의 입도(Granularity)로 작성해 주면 의도가 더 잘 전달되는 인상을 줍니다. 하지만 이를 계속 파고들다 보면 이번에는 "이것도 저것도" 규칙이 늘어나게 되어, 서두에서 언급한 컨텍스트 비대화 문제에 부딪힙니다. 그때 도움이 되는 것이 다음에 소개할 .claude/rules/입니다.
CLAUDE.md가 비대해지는 전형적인 패턴은, "프론트엔드 전용 규칙"이나 "특정 배치 처리 전용 규칙"까지 무엇이든 가리지 않고 CLAUDE.md에 다 적어버리는 것이라고 생각합니다. 이를 효과적으로 해결해 주는 것이 바로 .claude/rules/ 디렉토리입니다.
.claude/
└── rules/
├── frontend.md
...
각 규칙 파일에는 프론트매터 (Frontmatter)를 통해 paths (Glob 패턴)를 지정할 수 있으며, 해당 파일을 다루고 있을 때만 조용히 읽어 들여지는 구조로 되어 있습니다.
---
description: "프론트엔드 컴포넌트 규칙"
paths: ...
---
---
description: "백엔드 API 규칙"
paths: ...
---
이렇게 설정해 두면, 프론트엔드를 작업하는 동안에는 백엔드 규칙이 컨텍스트 (Context)에 포함되지 않으며, 그 반대의 경우도 마찬가지입니다. 대략적인 방침으로는, "항상 알고 있어야 하는 것"은 CLAUDE.md에, "해당 영역을 다룰 때만 알면 되는 것"은 .claude/rules/에 나누어 배치한다는 느낌으로 접근하면 수월하게 관리할 수 있습니다.
.claude/commands/ 하위에 Markdown 파일을 두면, /파일명을 통해 슬래시 커맨드 (Slash Command)로 호출할 수 있게 됩니다. 반복적으로 비슷한 지시를 내리는 작업이 있다면 템플릿화하여 매우 편리하게 사용할 수 있습니다.
.claude/
└── commands/
└── review-pr.md
---
description: "지정한 PR 번호의 차이점(diff)을 리뷰한다"
allowed-tools: ["Bash(gh pr diff:*)", "Read"]
...
---
프론트매터의 allowed-tools를 사용하면, 이 커맨드 실행 시 사용할 수 있는 도구를 제한할 수 있습니다. 은근히 안심을 주는 설정 항목입니다.
인자 (Argument)를 받는 방법은 두 가지가 있습니다. 취향이나 용도에 따라 선택할 수 있습니다.
$ARGUMENTS: 호출 시의 인자를 통째로 하나의 문자열로 받습니다.$1,$2,$3: 위치 인자 (Positional Argument)로 개별적으로 받습니다. (위의 예시인/review-pr 123 "타입 안정성"과 같은 호출에 대응)
커맨드 본문 안에서는 두 가지 특수 접두사 (Prefix)도 사용할 수 있습니다.
@접두사:@src/config.ts와 같이 파일을 직접 지정하여 그 내용을 포함시킵니다.!접두사:!gh pr diff $1와 같이 Bash 커맨드를 실행하여 그 결과를 포함시킵니다.
이 두 가지를 조합하면, "PR 번호만 전달하면 차이점 추출부터 리뷰까지 한 번에 진행되는" 식의 유용한 커맨드를 만들 수 있습니다.
서브 에이전트 (Subagent)는 메인 대화와는 **별도의 컨텍스트 윈도우 (Context Window)**를 가진, 말하자면 전문 특화형 Claude입니다. .claude/agents/ 하위에 Markdown 파일을 두어 정의할 수 있으며, /agents 커맨드를 통해 대화형으로 만들 수도 있습니다.
.claude/
└── agents/
└── test-runner.md
---
name: test-runner
description: "테스트 실행 및 실패 원인 조사에 사용한다. 테스트가 실패했을 때 적극적으로 사용할 것."
...
---
기쁜 점은, 방대한 조사 로그나 테스트 출력이 메인 대화의 컨텍스트를 압박하지 않는다는 것입니다. 예를 들어 "방대한 로그를 읽고 원인을 한 줄로 요약하여 보고하라"와 같은 작업을 서브 에이전트에게 맡기면, 로그 내용 자체는 서브 에이전트 측의 컨텍스트 내에서 완결되며, 메인 대화에는 요약본만 깔끔하게 전달됩니다.
다만 반대로 생각하면, 서브 에이전트는 호출될 때마다 새로운 컨텍스트에서 시작하므로 이전까지의 대화 흐름은 공유되지 않습니다. "독립적인 조사 작업을 여러 개 병렬로 실행하고 싶을 때"에는 적합하지만, "지금까지의 세세한 주고받음을 바탕으로 미세 조정을 해주길 원할 때"에는 그리 능숙하지 않다는 인상을 줍니다.
Skills는 '레시피 북'에 비유하면 이해하기 쉬운 기능이라고 느꼈습니다. 레시피 북은 평소에는 책장에 꽂혀 있다가, 필요할 때만 꺼내서 해당 페이지를 펼치곤 하죠. Skills도 이와 비슷하여, 평소에는 description (개요)만 인식되다가 Claude가 작업 내용과 일치한다고 판단했을 때 비로소 본체 내용이 로드됩니다.
이 메커니즘은 Progressive Disclosure (단계적 개시)라고 불리며, 크게 세 가지 계층으로 나뉩니다.
메타데이터 계층: description만 항상 가볍게 로드됨
본체 계층: 실제로 Skill이 호출되는 시점에 SKILL.md 본체가 로드됨
상세 자료 계층: SKILL.md에서 참조하는 reference.md나 scripts/는 더 필요해진 시점에만 로드됨
.claude/
└── skills/
└── pdf-report/
...
---
name: pdf-report
description: "PDF 형식의 리포트를 생성할 때 사용한다. 사용자가 PDF 출력이나 장표 작성을 요청했을 때 트리거된다."
...
여기서 꽤 중요하다고 느낀 점은 description을 작성하는 방식입니다. "언제, 어떤 상황에서 사용해야 하는가"를 Claude 스스로도 알 수 있을 정도로 구체적으로 작성하지 않으면, 공들여 준비한 Skill이 좀처럼 호출되지 않는 상황이 발생하기 쉽습니다. 커스텀 커맨드가 "사람이 명시적으로 호출하는" 것이라면, Skills는 "Claude가 스스로 선택하는" 것이라는 이미지를 가지고 있으면 구분하기 쉬울 것입니다.
지금까지 소개한 5가지 기능은 모두 최종적으로 Claude의 추론을 거쳐 실행되므로, 말하자면 **확률론적 (Probabilistic)**입니다. CLAUDE.md에 "커밋 전에 반드시 lint를 실행해줘"라고 써두어도, Claude가 깜빡 잊어버릴 가능성은 제로가 아닙니다 (사람도 마찬가지니까요).
반면 Hooks는 특정 이벤트가 발생한 시점에 Claude를 거치지 않고 정해진 쉘 커맨드 (Shell Command)를 기계적으로 실행하는 **결정론적 (Deterministic)**인 메커니즘입니다. "절대로 지켜야 하는 규칙"이 있다면, Hooks에 맡기는 것이 가장 확실합니다.
주요 후크 이벤트는 다음 10여 가지 정도가 있습니다.
| 이벤트 | 타이밍 |
|---|---|
PreToolUse | 툴 실행 전 |
PostToolUse | 툴 실행 후 |
UserPromptSubmit | 사용자가 프롬프트를 전송했을 때 |
Stop | 메인 에이전트가 응답을 완료했을 때 |
SubagentStop | 서브 에이전트가 응답을 완료했을 때 |
Notification | 알림이 발생했을 때 |
PreCompact | 컨텍스트 압축 직전 |
SessionStart | 세션 시작 시 |
SessionEnd | 세션 종료 시 |
| 기타 (버전에 따라 추가될 수 있음) | - |
설정은 .claude/settings.json (또는 사용자 설정)에 작성합니다. 예를 들어 "TypeScript 파일을 편집하면 반드시 ESLint를 자동 실행한다"는 경우는 다음과 같습니다.
{
"hooks": {
"PostToolUse": [
...
matcher에는 툴 이름의 정규 표현식 (이 예시에서는 Edit 또는 Write)을 지정하여 대상을 좁힙니다. CLAUDE.md에 "편집하면 lint 해줘"라고 부탁하는 것보다 이 방법이 훨씬 확실하며, 컨텍스트도 거의 사용하지 않습니다.
내용이 길어졌지만, 다시 한번 6가지 기능을 "로드되는 타이밍"과 "동작 주체"라는 축으로 되돌아보면 다음과 같이 정리할 수 있습니다.
- 항상 프로젝트 전체에서 필요한 최소한의 규칙 →
CLAUDE.md - 특정 경로 나 영역을 다룰 때만 필요한 규칙 →
.claude/rules/ - 매번 내가 명시적으로 호출하고 싶은 정형 작업 → 커스텀 커맨드
- 독립된 문맥에서 한꺼번에 조사·구현시키고 싶은 작업 → 서브 에이전트
- 복잡한 절차서나 스크립트를 필요할 때만 살짝 건네주고 싶은 지식 → Skills
- 확률에 의존하지 않고 반드시 지키게 하고 싶은 자동화 → Hooks
「일단 전부 CLAUDE.md에 적어둔다」는 방식에서 한 걸음 더 나아가, 이 6가지를 상황에 맞춰 잘 조합할 수 있게 된다면, 컨텍스트 (Context)를 낭비하지 않으면서도 재현성 (Reproducibility)이 높은 자신만의 「전용 어시스턴트 (Assistant)」로 키워나갈 수 있을 것입니다. 꼭 여러분의 프로젝트에서 현재의 CLAUDE.md를 재검토하는 것부터 가볍게 시도해 보시기 바랍니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기