2. 스킬로 Claude 확장하기
SKILL.md 생성·프론트매터·동적 컨텍스트·배포 등 스킬 확장 가이드
스킬로 Claude 확장하기
Claude Code에서 스킬을 생성, 관리, 공유하여 Claude의 기능을 확장하세요. 커스텀 명령어와 번들 스킬을 포함합니다.
스킬은 Claude가 할 수 있는 것을 확장합니다. 지시사항이 담긴 SKILL.md 파일을 만들면 Claude가 이를 도구 키트에 추가합니다. Claude는 관련 상황에서 스킬을 사용하거나, /skill-name으로 직접 호출할 수 있습니다.
참고:
/help,/compact같은 내장 명령어는 인터랙티브 모드를 참고하세요.커스텀 명령어가 스킬에 통합되었습니다.
.claude/commands/review.md에 있는 파일과.claude/skills/review/SKILL.md에 있는 스킬은 모두/review를 만들며 동일하게 작동합니다. 기존.claude/commands/파일은 계속 작동합니다. 스킬은 추가 기능을 제공합니다: 보조 파일을 위한 디렉토리, 호출 주체를 제어하는 프론트매터, Claude가 관련 상황에서 자동으로 로드하는 기능 등입니다.
Claude Code 스킬은 여러 AI 도구에서 작동하는 Agent Skills 오픈 표준을 따릅니다. Claude Code는 이 표준에 호출 제어, 서브에이전트 실행, 동적 컨텍스트 주입 같은 추가 기능을 확장합니다.
번들 스킬
번들 스킬은 Claude Code와 함께 제공되며 모든 세션에서 사용할 수 있습니다. 고정된 로직을 직접 실행하는 내장 명령어와 달리, 번들 스킬은 프롬프트 기반입니다: Claude에게 상세한 플레이북을 제공하고 도구를 사용해 작업을 조율하게 합니다. 따라서 번들 스킬은 병렬 에이전트를 생성하고, 파일을 읽고, 코드베이스에 맞게 적응할 수 있습니다.
번들 스킬은 다른 스킬과 동일하게 호출합니다: / 뒤에 스킬 이름을 입력하면 됩니다.
-
/simplify: 최근 변경한 파일의 코드 재사용, 품질, 효율성 문제를 검토한 뒤 수정합니다. 기능이나 버그 수정을 구현한 후 작업을 정리하는 데 사용하세요. 세 개의 리뷰 에이전트를 병렬로 생성하고(코드 재사용, 코드 품질, 효율성), 결과를 종합한 뒤 수정을 적용합니다. 선택적으로 텍스트를 전달하여 특정 관심사에 집중할 수 있습니다:/simplify focus on memory efficiency. -
/batch <instruction>: 코드베이스 전체에 걸친 대규모 변경을 병렬로 조율합니다. 변경 내용을 설명하면/batch가 코드베이스를 조사하고, 작업을 5~30개의 독립적인 단위로 분해한 뒤, 승인을 위한 계획을 제시합니다. 승인되면 단위당 하나의 백그라운드 에이전트를 생성하며, 각각 격리된 git worktree에서 실행됩니다. 각 에이전트는 자신의 단위를 구현하고, 테스트를 실행하고, 풀 리퀘스트를 엽니다. git 저장소가 필요합니다. 예시:/batch migrate src/ from Solid to React. -
/debug [description]: 세션 디버그 로그를 읽어 현재 Claude Code 세션의 문제를 해결합니다. 선택적으로 문제를 설명하여 분석 초점을 맞출 수 있습니다. -
/loop [interval] <prompt>: 세션이 열려 있는 동안 프롬프트를 주기적으로 반복 실행합니다. Claude가 간격을 파싱하고, 반복 cron 작업을 스케줄링하고, 주기를 확인합니다. 배포 폴링, PR 모니터링, 다른 스킬의 주기적 재실행에 유용합니다. 예시:/loop 5m check if the deploy finished. 프롬프트 스케줄 실행을 참고하세요. -
/claude-api: 프로젝트 언어(Python, TypeScript, Java, Go, Ruby, C#, PHP 또는 cURL)에 맞는 Claude API 참조 자료와 Python/TypeScript용 Agent SDK 참조를 로드합니다. 도구 사용, 스트리밍, 배치, 구조화된 출력, 일반적인 함정을 다룹니다. 코드에서anthropic,@anthropic-ai/sdk, 또는claude_agent_sdk를 import할 때 자동으로 활성화됩니다.
시작하기
첫 번째 스킬 만들기
이 예제는 Claude에게 시각적 다이어그램과 비유를 사용하여 코드를 설명하도록 가르치는 스킬을 만듭니다. 기본 프론트매터를 사용하므로, 무언가의 작동 방식을 물어볼 때 Claude가 자동으로 로드하거나, /explain-code로 직접 호출할 수 있습니다.
Step 1: 스킬 디렉토리 생성
개인 스킬 폴더에 스킬용 디렉토리를 만듭니다. 개인 스킬은 모든 프로젝트에서 사용할 수 있습니다.
mkdir -p ~/.claude/skills/explain-code
Step 2: SKILL.md 작성
모든 스킬에는 두 부분으로 구성된 SKILL.md 파일이 필요합니다: Claude에게 스킬 사용 시점을 알려주는 YAML 프론트매터(--- 마커 사이)와, 스킬이 호출될 때 Claude가 따르는 지시사항이 담긴 마크다운 콘텐츠입니다. name 필드가 /슬래시-명령어가 되고, description은 Claude가 자동 로드 여부를 결정하는 데 사용됩니다.
~/.claude/skills/explain-code/SKILL.md를 생성하세요:
---
name: explain-code
description: Explains code with visual diagrams and analogies. Use when explaining how code works, teaching about a codebase, or when the user asks "how does this work?"
---
When explaining code, always include:
1. **Start with an analogy**: Compare the code to something from everyday life
2. **Draw a diagram**: Use ASCII art to show the flow, structure, or relationships
3. **Walk through the code**: Explain step-by-step what happens
4. **Highlight a gotcha**: What's a common mistake or misconception?
Keep explanations conversational. For complex concepts, use multiple analogies.
Step 3: 스킬 테스트
두 가지 방법으로 테스트할 수 있습니다:
Claude가 자동으로 호출하게 하기 — description에 맞는 질문을 하세요:
How does this code work?
또는 스킬 이름으로 직접 호출하기:
/explain-code src/auth/login.ts
어느 쪽이든 Claude는 설명에 비유와 ASCII 다이어그램을 포함해야 합니다.
스킬 저장 위치
스킬을 어디에 저장하느냐에 따라 누가 사용할 수 있는지가 결정됩니다:
| 위치 | 경로 | 적용 범위 |
|---|---|---|
| 엔터프라이즈 | 관리 설정 참고 | 조직 내 모든 사용자 |
| 개인 | ~/.claude/skills/<skill-name>/SKILL.md | 모든 프로젝트 |
| 프로젝트 | .claude/skills/<skill-name>/SKILL.md | 해당 프로젝트만 |
| 플러그인 | <plugin>/skills/<skill-name>/SKILL.md | 플러그인이 활성화된 곳 |
동일한 이름의 스킬이 여러 레벨에 있을 경우, 우선순위가 높은 위치가 적용됩니다: 엔터프라이즈 > 개인 > 프로젝트. 플러그인 스킬은 plugin-name:skill-name 네임스페이스를 사용하므로 다른 레벨과 충돌하지 않습니다. .claude/commands/에 파일이 있는 경우에도 동일하게 작동하지만, 스킬과 명령어가 같은 이름을 공유하면 스킬이 우선합니다.
중첩 디렉토리에서 자동 발견
하위 디렉토리의 파일로 작업할 때, Claude Code는 중첩된 .claude/skills/ 디렉토리에서 스킬을 자동으로 발견합니다. 예를 들어 packages/frontend/의 파일을 편집 중이면, Claude Code는 packages/frontend/.claude/skills/에서도 스킬을 찾습니다. 이는 패키지마다 고유한 스킬이 있는 모노레포 구성을 지원합니다.
각 스킬은 SKILL.md를 진입점으로 하는 디렉토리입니다:
my-skill/
├── SKILL.md # 메인 지시사항 (필수)
├── template.md # Claude가 채울 템플릿
├── examples/
│ └── sample.md # 예상 형식을 보여주는 예시 출력
└── scripts/
└── validate.sh # Claude가 실행할 수 있는 스크립트
SKILL.md는 메인 지시사항을 포함하며 필수입니다. 다른 파일은 선택사항이며 더 강력한 스킬을 만들 수 있게 합니다: Claude가 채울 템플릿, 예상 형식을 보여주는 예시 출력, Claude가 실행할 수 있는 스크립트, 또는 상세한 참조 문서 등입니다. SKILL.md에서 이 파일들을 참조하여 Claude가 각 파일의 내용과 로드 시점을 알 수 있게 하세요. 자세한 내용은 보조 파일 추가를 참고하세요.
참고:
.claude/commands/의 파일도 여전히 작동하며 동일한 프론트매터를 지원합니다. 보조 파일 등 추가 기능을 지원하므로 스킬을 권장합니다.
추가 디렉토리의 스킬
--add-dir로 추가한 디렉토리의 .claude/skills/에 정의된 스킬은 자동으로 로드되며 실시간 변경 감지가 적용되므로, 세션 중에 편집해도 재시작할 필요가 없습니다.
참고:
--add-dir디렉토리의 CLAUDE.md 파일은 기본적으로 로드되지 않습니다. 로드하려면CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1을 설정하세요. 추가 디렉토리에서 로드를 참고하세요.
스킬 구성
스킬은 SKILL.md 상단의 YAML 프론트매터와 그 뒤에 오는 마크다운 콘텐츠로 구성됩니다.
스킬 콘텐츠 유형
스킬 파일에는 어떤 지시사항이든 포함할 수 있지만, 호출 방식을 생각하면 무엇을 포함할지 결정하는 데 도움이 됩니다:
참조 콘텐츠는 Claude가 현재 작업에 적용하는 지식을 추가합니다. 규칙, 패턴, 스타일 가이드, 도메인 지식 등입니다. 이 콘텐츠는 인라인으로 실행되므로 Claude가 대화 컨텍스트와 함께 사용할 수 있습니다.
---
name: api-conventions
description: API design patterns for this codebase
---
When writing API endpoints:
- Use RESTful naming conventions
- Return consistent error formats
- Include request validation
작업 콘텐츠는 배포, 커밋, 코드 생성 같은 특정 작업에 대한 단계별 지시사항을 Claude에게 제공합니다. Claude가 자동으로 실행하는 것보다 /skill-name으로 직접 호출하고 싶은 작업인 경우가 많습니다. Claude의 자동 트리거를 방지하려면 disable-model-invocation: true를 추가하세요.
---
name: deploy
description: Deploy the application to production
context: fork
disable-model-invocation: true
---
Deploy the application:
1. Run the test suite
2. Build the application
3. Push to the deployment target
SKILL.md에는 어떤 내용이든 포함할 수 있지만, 스킬의 호출 방식(본인, Claude, 또는 둘 다)과 실행 위치(인라인 또는 서브에이전트)를 생각해보면 무엇을 포함할지 결정하는 데 도움이 됩니다. 복잡한 스킬의 경우 보조 파일을 추가하여 메인 스킬에 집중할 수도 있습니다.
프론트매터 참조
마크다운 콘텐츠 외에도, SKILL.md 파일 상단의 --- 마커 사이에 YAML 프론트매터 필드를 사용하여 스킬 동작을 구성할 수 있습니다:
---
name: my-skill
description: What this skill does
disable-model-invocation: true
allowed-tools: Read, Grep
---
Your skill instructions here...
모든 필드는 선택사항입니다. Claude가 스킬 사용 시점을 알 수 있도록 description만 권장됩니다.
| 필드 | 필수 여부 | 설명 |
|---|---|---|
name | 아니오 | 스킬의 표시 이름. 생략하면 디렉토리 이름을 사용합니다. 소문자, 숫자, 하이픈만 허용 (최대 64자). |
description | 권장 | 스킬의 기능과 사용 시점. Claude가 스킬 적용 시점을 결정하는 데 사용합니다. 생략하면 마크다운 콘텐츠의 첫 번째 문단을 사용합니다. |
argument-hint | 아니오 | 자동완성 시 예상 인자를 나타내는 힌트. 예: [issue-number] 또는 [filename] [format]. |
disable-model-invocation | 아니오 | true로 설정하면 Claude의 자동 로드를 방지합니다. /name으로 수동 트리거하고 싶은 워크플로에 사용합니다. 기본값: false. |
user-invocable | 아니오 | false로 설정하면 / 메뉴에서 숨깁니다. 사용자가 직접 호출하지 않을 배경 지식에 사용합니다. 기본값: true. |
allowed-tools | 아니오 | 이 스킬이 활성화될 때 Claude가 권한 요청 없이 사용할 수 있는 도구. |
model | 아니오 | 이 스킬이 활성화될 때 사용할 모델. |
context | 아니오 | fork로 설정하면 포크된 서브에이전트 컨텍스트에서 실행합니다. |
agent | 아니오 | context: fork 설정 시 사용할 서브에이전트 유형. |
hooks | 아니오 | 이 스킬의 생명주기에 범위가 지정된 훅. 구성 형식은 스킬과 에이전트의 훅을 참고하세요. |
사용 가능한 문자열 치환
스킬은 스킬 콘텐츠의 동적 값에 대한 문자열 치환을 지원합니다:
| 변수 | 설명 |
|---|---|
$ARGUMENTS | 스킬 호출 시 전달된 모든 인자. 콘텐츠에 $ARGUMENTS가 없으면, 인자가 ARGUMENTS: <value> 형태로 끝에 추가됩니다. |
$ARGUMENTS[N] | 0부터 시작하는 인덱스로 특정 인자에 접근합니다. 예: $ARGUMENTS[0]은 첫 번째 인자입니다. |
$N | $ARGUMENTS[N]의 축약형입니다. 예: $0은 첫 번째 인자, $1은 두 번째 인자입니다. |
${CLAUDE_SESSION_ID} | 현재 세션 ID. 로깅, 세션별 파일 생성, 스킬 출력과 세션 연관에 유용합니다. |
${CLAUDE_SKILL_DIR} | 스킬의 SKILL.md 파일이 있는 디렉토리. 플러그인 스킬의 경우, 플러그인 루트가 아니라 플러그인 내 스킬의 하위 디렉토리입니다. 현재 작업 디렉토리에 관계없이 스킬과 번들된 스크립트나 파일을 참조하는 bash 주입 명령어에 사용하세요. |
치환 사용 예시:
---
name: session-logger
description: Log activity for this session
---
Log the following to logs/${CLAUDE_SESSION_ID}.log:
$ARGUMENTS
보조 파일 추가
스킬은 디렉토리에 여러 파일을 포함할 수 있습니다. 이를 통해 SKILL.md는 핵심 내용에 집중하면서 Claude가 필요할 때만 상세 참조 자료에 접근할 수 있게 합니다. 대용량 참조 문서, API 명세, 예시 모음은 스킬이 실행될 때마다 컨텍스트에 로드할 필요가 없습니다.
my-skill/
├── SKILL.md (필수 - 개요 및 네비게이션)
├── reference.md (상세 API 문서 - 필요 시 로드)
├── examples.md (사용 예시 - 필요 시 로드)
└── scripts/
└── helper.py (유틸리티 스크립트 - 로드가 아닌 실행)
SKILL.md에서 보조 파일을 참조하여 Claude가 각 파일의 내용과 로드 시점을 알 수 있게 하세요:
## 추가 리소스
- 전체 API 상세 내용은 [reference.md](reference.md)를 참고하세요
- 사용 예시는 [examples.md](examples.md)를 참고하세요
팁:
SKILL.md는 500줄 이하로 유지하세요. 상세 참조 자료는 별도 파일로 옮기세요.
호출 주체 제어
기본적으로 사용자와 Claude 모두 모든 스킬을 호출할 수 있습니다. /skill-name을 입력하여 직접 호출할 수 있고, Claude도 대화에 관련될 때 자동으로 로드할 수 있습니다. 두 가지 프론트매터 필드로 이를 제한할 수 있습니다:
-
disable-model-invocation: true: 사용자만 스킬을 호출할 수 있습니다. 부수 효과가 있거나 타이밍을 제어하고 싶은 워크플로에 사용합니다./commit,/deploy,/send-slack-message같은 경우입니다. 코드가 준비되어 보인다고 Claude가 배포를 결정하는 것을 원하지 않을 것입니다. -
user-invocable: false: Claude만 스킬을 호출할 수 있습니다. 명령어로서 의미가 없는 배경 지식에 사용합니다.legacy-system-context스킬은 레거시 시스템의 작동 방식을 설명합니다. Claude는 관련 상황에서 이를 알아야 하지만,/legacy-system-context는 사용자에게 의미 있는 동작이 아닙니다.
이 예제는 사용자만 트리거할 수 있는 배포 스킬을 만듭니다. disable-model-invocation: true 필드는 Claude의 자동 실행을 방지합니다:
---
name: deploy
description: Deploy the application to production
disable-model-invocation: true
---
Deploy $ARGUMENTS to production:
1. Run the test suite
2. Build the application
3. Push to the deployment target
4. Verify the deployment succeeded
두 필드가 호출과 컨텍스트 로드에 미치는 영향:
| 프론트매터 | 사용자 호출 가능 | Claude 호출 가능 | 컨텍스트 로드 시점 |
|---|---|---|---|
| (기본값) | 예 | 예 | description은 항상 컨텍스트에, 전체 스킬은 호출 시 로드 |
disable-model-invocation: true | 예 | 아니오 | description이 컨텍스트에 없음, 전체 스킬은 사용자 호출 시 로드 |
user-invocable: false | 아니오 | 예 | description은 항상 컨텍스트에, 전체 스킬은 호출 시 로드 |
참고: 일반 세션에서 스킬 description은 Claude가 사용 가능한 것을 알 수 있도록 컨텍스트에 로드되지만, 전체 스킬 콘텐츠는 호출 시에만 로드됩니다. 스킬이 사전 로드된 서브에이전트는 다르게 작동합니다: 전체 스킬 콘텐츠가 시작 시 주입됩니다.
도구 접근 제한
allowed-tools 필드를 사용하여 스킬이 활성화될 때 Claude가 사용할 수 있는 도구를 제한합니다. 이 스킬은 Claude가 파일을 탐색할 수 있지만 수정할 수 없는 읽기 전용 모드를 만듭니다:
---
name: safe-reader
description: Read files without making changes
allowed-tools: Read, Grep, Glob
---
스킬에 인자 전달
사용자와 Claude 모두 스킬 호출 시 인자를 전달할 수 있습니다. 인자는 $ARGUMENTS 플레이스홀더를 통해 사용할 수 있습니다.
이 스킬은 번호로 GitHub 이슈를 수정합니다. $ARGUMENTS 플레이스홀더는 스킬 이름 뒤에 오는 내용으로 대체됩니다:
---
name: fix-issue
description: Fix a GitHub issue
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS following our coding standards.
1. Read the issue description
2. Understand the requirements
3. Implement the fix
4. Write tests
5. Create a commit
/fix-issue 123을 실행하면 Claude는 "Fix GitHub issue 123 following our coding standards..."를 받습니다.
인자를 포함하여 스킬을 호출했지만 스킬에 $ARGUMENTS가 없는 경우, Claude Code는 ARGUMENTS: <your input>을 스킬 콘텐츠 끝에 추가하여 Claude가 입력을 볼 수 있게 합니다.
위치별로 개별 인자에 접근하려면 $ARGUMENTS[N] 또는 축약형 $N을 사용하세요:
---
name: migrate-component
description: Migrate a component from one framework to another
---
Migrate the $ARGUMENTS[0] component from $ARGUMENTS[1] to $ARGUMENTS[2].
Preserve all existing behavior and tests.
/migrate-component SearchBar React Vue를 실행하면 $ARGUMENTS[0]은 SearchBar, $ARGUMENTS[1]은 React, $ARGUMENTS[2]은 Vue로 대체됩니다. $N 축약형을 사용한 동일한 스킬:
---
name: migrate-component
description: Migrate a component from one framework to another
---
Migrate the $0 component from $1 to $2.
Preserve all existing behavior and tests.
고급 패턴
동적 컨텍스트 주입
!command`` 구문은 스킬 콘텐츠가 Claude에게 전송되기 전에 셸 명령을 실행합니다. 명령 출력이 플레이스홀더를 대체하므로 Claude는 명령이 아닌 실제 데이터를 받습니다.
이 스킬은 GitHub CLI로 실시간 PR 데이터를 가져와 풀 리퀘스트를 요약합니다. !gh pr diff`` 및 기타 명령이 먼저 실행되고, 출력이 프롬프트에 삽입됩니다:
---
name: pr-summary
description: Summarize changes in a pull request
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---
## Pull request context
- PR diff: !`gh pr diff`
- PR comments: !`gh pr view --comments`
- Changed files: !`gh pr diff --name-only`
## Your task
Summarize this pull request...
이 스킬이 실행될 때:
- 각
!command``가 즉시 실행됩니다(Claude가 보기 전) - 출력이 스킬 콘텐츠의 플레이스홀더를 대체합니다
- Claude는 실제 PR 데이터가 포함된 완전히 렌더링된 프롬프트를 받습니다
이것은 전처리이며 Claude가 실행하는 것이 아닙니다. Claude는 최종 결과만 봅니다.
팁: 스킬에서 확장 사고를 활성화하려면 스킬 콘텐츠 어딘가에 "ultrathink"라는 단어를 포함하세요.
서브에이전트에서 스킬 실행
스킬을 격리된 환경에서 실행하려면 프론트매터에 context: fork를 추가하세요. 스킬 콘텐츠가 서브에이전트를 구동하는 프롬프트가 됩니다. 대화 기록에 접근할 수 없습니다.
주의:
context: fork는 명확한 지시사항이 있는 스킬에서만 의미가 있습니다. 스킬에 작업 없이 "이 API 규칙을 사용하세요" 같은 가이드라인만 포함되어 있으면, 서브에이전트는 가이드라인을 받지만 실행 가능한 프롬프트가 없어 의미 있는 출력 없이 반환됩니다.
스킬과 서브에이전트는 두 방향으로 함께 작동합니다:
| 접근 방식 | 시스템 프롬프트 | 작업 | 추가 로드 |
|---|---|---|---|
context: fork를 사용한 스킬 | 에이전트 유형에서 제공 (Explore, Plan 등) | SKILL.md 콘텐츠 | CLAUDE.md |
skills 필드를 사용한 서브에이전트 | 서브에이전트의 마크다운 본문 | Claude의 위임 메시지 | 사전 로드된 스킬 + CLAUDE.md |
context: fork에서는 스킬에 작업을 작성하고 이를 실행할 에이전트 유형을 선택합니다. 반대의 경우(스킬을 참조 자료로 사용하는 커스텀 서브에이전트 정의)는 서브에이전트를 참고하세요.
예시: Explore 에이전트를 사용한 리서치 스킬
이 스킬은 포크된 Explore 에이전트에서 리서치를 실행합니다. 스킬 콘텐츠가 작업이 되고, 에이전트는 코드베이스 탐색에 최적화된 읽기 전용 도구를 제공합니다:
---
name: deep-research
description: Research a topic thoroughly
context: fork
agent: Explore
---
Research $ARGUMENTS thoroughly:
1. Find relevant files using Glob and Grep
2. Read and analyze the code
3. Summarize findings with specific file references
이 스킬이 실행될 때:
- 새로운 격리된 컨텍스트가 생성됩니다
- 서브에이전트가 스킬 콘텐츠를 프롬프트로 받습니다("Research $ARGUMENTS thoroughly...")
agent필드가 실행 환경(모델, 도구, 권한)을 결정합니다- 결과가 요약되어 메인 대화에 반환됩니다
agent 필드는 사용할 서브에이전트 구성을 지정합니다. 내장 에이전트(Explore, Plan, general-purpose) 또는 .claude/agents/의 커스텀 서브에이전트를 사용할 수 있습니다. 생략하면 general-purpose를 사용합니다.
Claude의 스킬 접근 제한
기본적으로 Claude는 disable-model-invocation: true가 설정되지 않은 모든 스킬을 호출할 수 있습니다. allowed-tools를 정의한 스킬은 스킬이 활성화된 동안 해당 도구에 대한 사용별 승인 없이 Claude에게 접근 권한을 부여합니다. 권한 설정은 다른 모든 도구에 대한 기본 승인 동작을 계속 관장합니다. /compact, /init 같은 내장 명령어는 Skill 도구를 통해 사용할 수 없습니다.
Claude가 호출할 수 있는 스킬을 제어하는 세 가지 방법:
모든 스킬 비활성화 — /permissions에서 Skill 도구를 거부합니다:
# 거부 규칙에 추가:
Skill
특정 스킬 허용 또는 거부 — 권한 규칙을 사용합니다:
# 특정 스킬만 허용
Skill(commit)
Skill(review-pr *)
# 특정 스킬 거부
Skill(deploy *)
권한 구문: Skill(name)은 정확한 매칭, Skill(name *)은 접두사 매칭(모든 인자 포함)입니다.
개별 스킬 숨기기 — 프론트매터에 disable-model-invocation: true를 추가합니다. 이렇게 하면 Claude의 컨텍스트에서 스킬이 완전히 제거됩니다.
참고:
user-invocable필드는 메뉴 가시성만 제어하며 Skill 도구 접근을 제어하지 않습니다. 프로그래밍 방식의 호출을 차단하려면disable-model-invocation: true를 사용하세요.
스킬 공유
스킬은 대상에 따라 다양한 범위로 배포할 수 있습니다:
시각적 출력 생성
스킬은 모든 언어로 스크립트를 번들하고 실행할 수 있어, 단일 프롬프트로는 불가능한 기능을 Claude에게 제공합니다. 강력한 패턴 중 하나는 시각적 출력을 생성하는 것입니다: 데이터 탐색, 디버깅, 또는 보고서 작성을 위해 브라우저에서 여는 인터랙티브 HTML 파일입니다.
이 예제는 코드베이스 탐색기를 만듭니다: 디렉토리를 확장하고 축소할 수 있고, 파일 크기를 한눈에 볼 수 있으며, 색상으로 파일 유형을 식별할 수 있는 인터랙티브 트리 뷰입니다.
스킬 디렉토리를 만드세요:
mkdir -p ~/.claude/skills/codebase-visualizer/scripts
~/.claude/skills/codebase-visualizer/SKILL.md를 만드세요. description은 Claude에게 이 스킬을 활성화할 시점을 알려주고, 지시사항은 번들된 스크립트를 실행하도록 Claude에게 알려줍니다:
---
name: codebase-visualizer
description: Generate an interactive collapsible tree visualization of your codebase. Use when exploring a new repo, understanding project structure, or identifying large files.
allowed-tools: Bash(python *)
---
# Codebase Visualizer
Generate an interactive HTML tree view that shows your project's file structure with collapsible directories.
## Usage
Run the visualization script from your project root:
```bash
python ~/.claude/skills/codebase-visualizer/scripts/visualize.py .
```text
This creates `codebase-map.html` in the current directory and opens it in your default browser.
## What the visualization shows
- **Collapsible directories**: Click folders to expand/collapse
- **File sizes**: Displayed next to each file
- **Colors**: Different colors for different file types
- **Directory totals**: Shows aggregate size of each folder
~/.claude/skills/codebase-visualizer/scripts/visualize.py를 만드세요. 이 스크립트는 디렉토리 트리를 스캔하고 다음을 포함하는 자체 완결형 HTML 파일을 생성합니다:
- 파일 수, 디렉토리 수, 전체 크기, 파일 유형 수를 보여주는 요약 사이드바
- 파일 유형별 코드베이스 분석을 보여주는 막대 차트 (크기 기준 상위 8개)
- 디렉토리를 확장/축소할 수 있고 색상 코딩된 파일 유형 표시가 있는 축소 가능한 트리
이 스크립트는 Python이 필요하지만 내장 라이브러리만 사용하므로 설치할 패키지가 없습니다:
#!/usr/bin/env python3
"""Generate an interactive collapsible tree visualization of a codebase."""
import json
import sys
import webbrowser
from pathlib import Path
from collections import Counter
IGNORE = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build'}
def scan(path: Path, stats: dict) -> dict:
result = {"name": path.name, "children": [], "size": 0}
try:
for item in sorted(path.iterdir()):
if item.name in IGNORE or item.name.startswith('.'):
continue
if item.is_file():
size = item.stat().st_size
ext = item.suffix.lower() or '(no ext)'
result["children"].append({"name": item.name, "size": size, "ext": ext})
result["size"] += size
stats["files"] += 1
stats["extensions"][ext] += 1
stats["ext_sizes"][ext] += size
elif item.is_dir():
stats["dirs"] += 1
child = scan(item, stats)
if child["children"]:
result["children"].append(child)
result["size"] += child["size"]
except PermissionError:
pass
return result
def generate_html(data: dict, stats: dict, output: Path) -> None:
ext_sizes = stats["ext_sizes"]
total_size = sum(ext_sizes.values()) or 1
sorted_exts = sorted(ext_sizes.items(), key=lambda x: -x[1])[:8]
colors = {
'.js': '#f7df1e', '.ts': '#3178c6', '.py': '#3776ab', '.go': '#00add8',
'.rs': '#dea584', '.rb': '#cc342d', '.css': '#264de4', '.html': '#e34c26',
'.json': '#6b7280', '.md': '#083fa1', '.yaml': '#cb171e', '.yml': '#cb171e',
'.mdx': '#083fa1', '.tsx': '#3178c6', '.jsx': '#61dafb', '.sh': '#4eaa25',
}
lang_bars = "".join(
f'<div class="bar-row"><span class="bar-label">{ext}</span>'
f'<div class="bar" style="width:{(size/total_size)*100}%;background:{colors.get(ext,"#6b7280")}"></div>'
f'<span class="bar-pct">{(size/total_size)*100:.1f}%</span></div>'
for ext, size in sorted_exts
)
def fmt(b):
if b < 1024: return f"{b} B"
if b < 1048576: return f"{b/1024:.1f} KB"
return f"{b/1048576:.1f} MB"
html = f'''<!DOCTYPE html>
<html><head>
<meta charset="utf-8"><title>Codebase Explorer</title>
<style>
body {{ font: 14px/1.5 system-ui, sans-serif; margin: 0; background: #1a1a2e; color: #eee; }}
.container {{ display: flex; height: 100vh; }}
.sidebar {{ width: 280px; background: #252542; padding: 20px; border-right: 1px solid #3d3d5c; overflow-y: auto; flex-shrink: 0; }}
.main {{ flex: 1; padding: 20px; overflow-y: auto; }}
h1 {{ margin: 0 0 10px 0; font-size: 18px; }}
h2 {{ margin: 20px 0 10px 0; font-size: 14px; color: #888; text-transform: uppercase; }}
.stat {{ display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #3d3d5c; }}
.stat-value {{ font-weight: bold; }}
.bar-row {{ display: flex; align-items: center; margin: 6px 0; }}
.bar-label {{ width: 55px; font-size: 12px; color: #aaa; }}
.bar {{ height: 18px; border-radius: 3px; }}
.bar-pct {{ margin-left: 8px; font-size: 12px; color: #666; }}
.tree {{ list-style: none; padding-left: 20px; }}
details {{ cursor: pointer; }}
summary {{ padding: 4px 8px; border-radius: 4px; }}
summary:hover {{ background: #2d2d44; }}
.folder {{ color: #ffd700; }}
.file {{ display: flex; align-items: center; padding: 4px 8px; border-radius: 4px; }}
.file:hover {{ background: #2d2d44; }}
.size {{ color: #888; margin-left: auto; font-size: 12px; }}
.dot {{ width: 8px; height: 8px; border-radius: 50%; margin-right: 8px; }}
</style>
</head><body>
<div class="container">
<div class="sidebar">
<h1>📊 Summary</h1>
<div class="stat"><span>Files</span><span class="stat-value">{stats["files"]:,}</span></div>
<div class="stat"><span>Directories</span><span class="stat-value">{stats["dirs"]:,}</span></div>
<div class="stat"><span>Total size</span><span class="stat-value">{fmt(data["size"])}</span></div>
<div class="stat"><span>File types</span><span class="stat-value">{len(stats["extensions"])}</span></div>
<h2>By file type</h2>
{lang_bars}
</div>
<div class="main">
<h1>📁 {data["name"]}</h1>
<ul class="tree" id="root"></ul>
</div>
</div>
<script>
const data = {json.dumps(data)};
const colors = {json.dumps(colors)};
function fmt(b) {{ if (b < 1024) return b + ' B'; if (b < 1048576) return (b/1024).toFixed(1) + ' KB'; return (b/1048576).toFixed(1) + ' MB'; }}
function render(node, parent) {{
if (node.children) {{
const det = document.createElement('details');
det.open = parent === document.getElementById('root');
det.innerHTML = `<summary><span class="folder">📁 ${{node.name}}</span><span class="size">${{fmt(node.size)}}</span></summary>`;
const ul = document.createElement('ul'); ul.className = 'tree';
node.children.sort((a,b) => (b.children?1:0)-(a.children?1:0) || a.name.localeCompare(b.name));
node.children.forEach(c => render(c, ul));
det.appendChild(ul);
const li = document.createElement('li'); li.appendChild(det); parent.appendChild(li);
}} else {{
const li = document.createElement('li'); li.className = 'file';
li.innerHTML = `<span class="dot" style="background:${{colors[node.ext]||'#6b7280'}}"></span>${{node.name}}<span class="size">${{fmt(node.size)}}</span>`;
parent.appendChild(li);
}}
}}
data.children.forEach(c => render(c, document.getElementById('root')));
</script>
</body></html>'''
output.write_text(html)
if __name__ == '__main__':
target = Path(sys.argv[1] if len(sys.argv) > 1 else '.').resolve()
stats = {"files": 0, "dirs": 0, "extensions": Counter(), "ext_sizes": Counter()}
data = scan(target, stats)
out = Path('codebase-map.html')
generate_html(data, stats, out)
print(f'Generated {out.absolute()}')
webbrowser.open(f'file://{out.absolute()}')
테스트하려면 아무 프로젝트에서 Claude Code를 열고 "Visualize this codebase."라고 요청하세요. Claude가 스크립트를 실행하고, codebase-map.html을 생성하고, 브라우저에서 엽니다.
이 패턴은 모든 시각적 출력에 적용됩니다: 의존성 그래프, 테스트 커버리지 보고서, API 문서, 데이터베이스 스키마 시각화 등. 번들된 스크립트가 핵심 작업을 수행하고 Claude가 조율을 담당합니다.
트러블슈팅
스킬이 트리거되지 않음
Claude가 예상대로 스킬을 사용하지 않는 경우:
- description에 사용자가 자연스럽게 말할 키워드가 포함되어 있는지 확인하세요
What skills are available?에서 스킬이 표시되는지 확인하세요- description에 더 가깝게 요청을 다시 표현해 보세요
- 스킬이 user-invocable이면
/skill-name으로 직접 호출하세요
스킬이 너무 자주 트리거됨
Claude가 원하지 않을 때 스킬을 사용하는 경우:
- description을 더 구체적으로 만드세요
- 수동 호출만 원하면
disable-model-invocation: true를 추가하세요
Claude가 모든 스킬을 인식하지 못함
스킬 description은 Claude가 사용 가능한 것을 알 수 있도록 컨텍스트에 로드됩니다. 스킬이 많으면 문자 예산을 초과할 수 있습니다. 예산은 컨텍스트 윈도우의 2%로 동적으로 조절되며, 폴백은 16,000자입니다. /context를 실행하여 제외된 스킬에 대한 경고를 확인하세요.
한도를 재정의하려면 SLASH_COMMAND_TOOL_CHAR_BUDGET 환경 변수를 설정하세요.