가이드 ·
Claude Code 스킬 만들기 — SKILL.md 하나로 '일하는 법'을 적어 두는 법
Claude Code 스킬은 폴더 하나와 SKILL.md 파일 하나다. 어디에 두는지, name·description·disable-model-invocation 같은 머리말 항목이 무엇을 정하는지, Claude가 언제 알아서 꺼내 쓰는지, /이름으로 직접 부르는 법, 서브에이전트와 무엇이 다른지, 하이아이오가 쓰는 test-analysis 스킬을 예로 정리했다.
Claude Code 스킬은 .claude/skills/<스킬이름>/SKILL.md 파일이다. 내 모든 프로젝트용은 ~/.claude/skills/, 이 프로젝트용은 .claude/skills/, 플러그인은 <플러그인>/skills/ 에 둔다. 머리말 항목은 모두 선택이고 description만 권장된다. 평소에는 스킬의 description만 Claude 컨텍스트에 올라가 있고, 요청과 맞으면 그때 본문 전체를 불러온다. 사용자는 /스킬이름 으로 직접 부를 수 있고, disable-model-invocation: true 로 Claude가 알아서 부르지 못하게 막을 수 있다. 예전의 .claude/commands/ 명령은 스킬로 합쳐졌고 그대로 동작한다. 스킬은 본 대화 안에서 지침으로 쓰이고, context: fork 를 주면 서브에이전트에서 따로 돌린다.
Claude Code 한국어 실전 가이드 · 5/10편
결론부터. 스킬은 "이런 일이 오면 이렇게 해"를 파일 하나에 적어 두는 것이다. 폴더를 만들고 그 안에 SKILL.md를 쓰면, Claude Code가 맞는 요청이 올 때 꺼내 읽고 그대로 일한다. 직접 /스킬이름으로 부를 수도 있다. 이 글은 AI(Claude)가 썼고, 내용은 Claude Code 공식 문서 — Skills와 대조했다. 하이아이오는 웹사이트 테스트 녹화를 분석하는 일을 스킬 하나로 만들어 쓰고 있다.
스킬이 뭐가 좋은가
같은 설명을 매번 다시 하지 않아도 된다. 공식 문서는 이렇게 쓰라고 권한다. 같은 지시문을 채팅에 자꾸 붙여 넣거나, CLAUDE.md의 한 부분이 '사실'이 아니라 '절차'로 커졌을 때.
가장 큰 장점은 필요할 때만 읽힌다는 점이다.
- 평소에는 스킬의 description만 컨텍스트에 올라가 있다
- 요청이 맞으면 그때 본문 전체를 불러온다
- 그래서 스킬을 여러 개 만들어도 평소 대화가 무거워지지 않는다
CLAUDE.md는 매번 통째로 읽힌다는 점과 다르다.
파일은 어디에 두나
스킬 하나는 폴더 하나다. 폴더 안에 SKILL.md가 꼭 있어야 한다.
| 위치 | 경로 | 범위 |
|---|---|---|
| 기업(Enterprise) | 관리자 설정 폴더 안 .claude/skills/<이름>/SKILL.md |
조직이 배포한 모든 사용자 |
| 개인 | ~/.claude/skills/<이름>/SKILL.md |
내 모든 프로젝트 |
| 프로젝트 | .claude/skills/<이름>/SKILL.md |
이 저장소(커밋하면 팀과 공유) |
| 하위 폴더 | <하위폴더>/.claude/skills/<이름>/SKILL.md |
그 폴더 안에서 일할 때 |
| 플러그인 | <플러그인>/skills/<이름>/SKILL.md |
플러그인을 켠 곳. /플러그인이름:스킬이름으로 부름 |
같은 이름이 겹치면 기업 > 개인 > 프로젝트 순으로 이긴다. 공식 문서의 예: deploy가 ~/.claude/skills/와 프로젝트 .claude/skills/에 둘 다 있으면 /deploy는 개인 것이 돈다. 서브에이전트(프로젝트가 개인보다 먼저)와 순서가 반대이니 헷갈리지 말자. 플러그인 스킬은 이름 앞에 플러그인 이름이 붙어서 겹쳐도 둘 다 쓰인다.
스킬 파일을 고치거나 새로 넣으면 다시 시작하지 않아도 그 세션에 바로 반영된다. 세션을 열 때 없던 스킬 폴더를 새로 만들었다면 /reload-skills를 친다.
파일 모양
공식 문서의 첫 예제를 우리말로 옮겼다. 위치는 ~/.claude/skills/summarize-changes/SKILL.md다.
---
description: 커밋 안 한 변경을 요약하고 위험한 곳을 짚는다. 무엇이 바뀌었는지 묻거나, 커밋 메시지를 원하거나, diff 검토를 부탁할 때 쓴다.
---
## 지금 변경
!`git diff HEAD`
## 할 일
위 변경을 두세 줄로 요약하고, 빠진 오류 처리·박아 넣은 값·고쳐야 할 테스트 같은 위험을 적는다. diff가 비어 있으면 커밋 안 한 변경이 없다고 말한다.
--- 사이가 머리말이고, 그 아래 본문이 Claude가 따를 지침이다. 여는 ---는 파일 첫 줄에 있어야 한다.
name이 없으니 폴더 이름summarize-changes가 명령 이름이 된다.!`git diff HEAD`줄은 Claude가 읽기 전에 명령을 실행해 그 결과로 바꿔 넣는다. 그래서 Claude는 명령이 아니라 실제 변경 내용을 받는다.
꼭 알아야 할 항목
공식 문서: 모든 항목은 선택이다. description만 권장한다.
| 항목 | 정하는 것 | 빼면 |
|---|---|---|
name |
/ 메뉴에 보이는 이름 |
폴더 이름 |
description |
무슨 일을 하고 언제 쓰는지. Claude가 이걸 보고 꺼낼지 정한다 | 본문의 첫 번째 글 줄 |
when_to_use |
언제 쓸지 덧붙이는 설명(description 뒤에 붙음) | — |
disable-model-invocation |
true면 Claude가 알아서 못 부름. 나만 /이름으로 부름 |
false |
user-invocable |
false면 / 메뉴에서 숨김. Claude만 부름 |
true |
allowed-tools |
이 스킬을 부른 턴 동안 묻지 않고 쓸 도구 | — |
argument-hint |
/이름 뒤에 무엇을 넣을지 보여 주는 힌트. 예: [issue-number] |
— |
context |
fork면 서브에이전트에서 따로 돌림 |
본 대화 안에서 |
agent |
context: fork일 때 쓸 서브에이전트 종류 |
— |
paths |
이 파일 패턴을 다룰 때만 자동으로 켜짐 | — |
이 밖에 arguments·disallowed-tools·model·effort·background·hooks·shell도 있다. metadata·license·compatibility는 받아 두기만 하고 Claude Code가 따로 쓰지는 않는다.
공식 문서가 경고하는 함정 둘.
- 항목 이름을 틀리게 쓰면 오류 없이 무시된다. 스킬 항목은
disable-model-invocation처럼 하이픈(-)으로 잇는다. 서브에이전트의disallowedTools(camelCase)와 모양이 다르다. - YAML이 깨지면 항목이 하나도 없는 채로 읽힌다.
/이름으로는 불리지만, description이 없으니 Claude가 알아서 꺼내지 못한다.claude --debug로 실행하면 오류를 볼 수 있다.
Claude는 언제 꺼내 쓰나
공식 문서: Claude는 description(그리고 when_to_use)을 내 요청과 맞춰 보고 스킬을 고른다. 그래서 description에는 사용자가 실제로 할 법한 말을 넣으라고 한다.
길이 제한도 있다. description과 when_to_use를 합친 글이 목록에서 1,536자에서 잘린다. 가장 중요한 쓰임새를 맨 앞에 쓴다. 스킬이 아주 많으면 전체 목록이 정해진 양(모델 컨텍스트 창의 1%)을 넘을 수 있다. 그러면 덜 쓴 스킬부터 description이 빠진다.
누가 부를 수 있는지는 두 항목으로 정한다.
| 머리말 | 내가 부름 | Claude가 부름 | 컨텍스트에 올라가는 것 |
|---|---|---|---|
| (기본) | 된다 | 된다 | description은 늘, 본문은 부를 때 |
disable-model-invocation: true |
된다 | 알아서는 못 함 | description도 안 올라감. 본문은 부를 때 |
user-invocable: false |
안 됨 | 된다 | description은 늘, 본문은 부를 때 |
공식 문서는 /deploy·/commit처럼 결과가 남는 일은 disable-model-invocation: true로 두라고 한다. "코드가 준비돼 보인다"고 Claude가 알아서 배포하면 곤란하기 때문이다.
직접 부르기와 인자 넘기기
메시지 맨 앞에 /스킬이름을 친다. 뒤에 붙인 글은 본문 안 자리표시자로 들어간다.
---
name: migrate-component
description: 컴포넌트를 다른 언어로 옮긴다
---
$0 컴포넌트를 $1에서 $2로 옮긴다. 기존 동작과 테스트는 그대로 지킨다.
/migrate-component SearchBar JavaScript TypeScript라고 치면 $0·$1·$2에 차례로 들어간다. 받은 글 전체는 $ARGUMENTS다. 자리표시자가 없는데 인자를 주면, 본문 끝에 ARGUMENTS: <입력>이 붙는다. 여러 단어 값은 따옴표로 묶는다.
스크립트·참고 파일 같이 두기
스킬 폴더에는 SKILL.md 말고 다른 파일도 둘 수 있다. 공식 문서의 예다.
my-skill/
├── SKILL.md (필수. 개요와 안내)
├── reference.md (자세한 자료. 필요할 때 읽음)
├── examples.md (예시. 필요할 때 읽음)
└── scripts/
└── helper.py (실행만 하고 읽어 들이지 않음)
- SKILL.md는 500줄 아래로. 자세한 자료는 다른 파일로 빼고, SKILL.md에서 링크로 "이 파일엔 무엇이 있고 언제 읽어라"를 적는다.
- 스크립트 경로는
${CLAUDE_SKILL_DIR}로 쓴다. 개인·프로젝트·플러그인 어디에 깔려도 경로가 맞는다.
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/render.sh *)
이렇게 본문과 allowed-tools에 같은 경로를 쓰면, 그 스크립트는 권한 질문 없이 돈다.
슬래시 명령·서브에이전트와 무엇이 다른가
슬래시 명령: 공식 문서는 "사용자 정의 명령은 스킬로 합쳐졌다"고 쓴다. .claude/commands/deploy.md와 .claude/skills/deploy/SKILL.md는 둘 다 /deploy를 만들고 똑같이 동작한다. 예전 commands 파일도 그대로 돈다. 스킬은 여기에 세 가지를 더한다. 참고 파일을 둘 폴더, 누가 부를지 정하는 머리말, 그리고 Claude가 알아서 꺼내 쓰는 기능이다. 이름이 겹치면 스킬이 이긴다.
서브에이전트: 4편에서 본 서브에이전트는 자기 컨텍스트 창에서 따로 일하고 요약만 돌려준다. 스킬은 기본으로 본 대화 안에 지침으로 들어온다. 한 번 불리면 그 내용이 대화에 남아 다음 턴에도 이어진다.
둘을 섞는 길도 있다.
- 스킬에
context: fork를 주면 서브에이전트를 새로 띄워 스킬 본문을 지시문으로 준다. 그 서브에이전트는 본 대화 기록을 못 본다. 그래서 공식 문서는 할 일이 분명히 적힌 스킬에만 쓰라고 한다. - 반대로 서브에이전트 머리말의
skills에 스킬 이름을 적으면, 그 서브에이전트가 시작할 때 스킬 본문 전체를 미리 넣어 준다.
우리 파일 예: test-analysis
하이아이오는 웹사이트 테스트 레코더로 테스터 화면과 목소리를 녹화한다. 그 ZIP을 받아 '고칠 부분' 문서로 정리하는 일을 개인 스킬로 만들었다. 위치는 ~/.claude/skills/test-analysis/SKILL.md이고, 머리말은 이렇다.
---
name: test-analysis
description: 웹사이트 테스트 레코더가 만든 ZIP(website-test-*.zip, 옛 이름 moneysofa-test-*.zip)을 받아 분석하고 '고칠 부분' 문서를 만든다. 사용자가 테스트 녹화 ZIP을 주며 "분석해 줘", "테스트 결과 정리", "고칠 거 뽑아 줘"라고 할 때, 또는 summary.md·hesitations.json·memos.json 이 든 폴더를 줄 때 쓴다. 여러 ZIP을 한꺼번에 받으면 같은 문제를 합친다.
---
본문은 이런 순서로 짜여 있다.
# 테스트 녹화 분석
## 0. 원칙 (녹화는 밖으로 안 보냄, 가려진 값은 복원 안 함)
## 1. 풀기 (ZIP마다 새 빈 폴더, 안의 스크립트는 실행 안 함)
## 2. 목소리를 글로 옮기기
## 3. 시간순으로 묶기
## 4. '고칠 부분' 문서 만들기 (항목 틀과 중요도 P0~P3)
## 5. 여러 ZIP 합치기
## 6. 보고
써 보며 정한 것 세 가지.
- description에 사용자가 할 말과 파일 이름을 그대로 넣었다. "분석해 줘", "고칠 거 뽑아 줘" 같은 말과
summary.md·hesitations.json같은 파일 이름이다. 공식 문서도 스킬이 안 불리면 먼저 "사람이 실제로 쓰는 말이 description에 있는지" 보라고 한다. - 꼭 지킬 규칙을 맨 위 '0. 원칙'에 뒀다. 공식 문서에 따르면 대화가 압축되면 불린 스킬의 앞부분만 다시 붙는다. 그래서 중요한 지침은 위에 두는 게 맞다.
name은 폴더 이름과 같게 했다. 빼도 폴더 이름이 쓰이지만, 적어 두면 파일만 열어 봐도/test-analysis로 불린다는 걸 바로 안다.
이 스킬은 아직 SKILL.md 한 장이다.
자주 하는 실수
- description을 비우거나 너무 넓게 쓴다. 너무 좁으면 안 불리고, 너무 넓으면 아무 때나 불린다. 너무 자주 불리면 description을 더 좁히거나
disable-model-invocation: true를 준다. - 항목 이름 오타. 오류 없이 무시된다.
disable_model_invocation(밑줄)은 안 먹는다. - "한 번은 지키다 나중에 안 지킨다." 스킬은 불릴 때 한 번 대화에 들어오고, 그 뒤 턴에 파일을 다시 읽지 않는다. 매번 반드시 지켜야 하는 규칙이라면 hooks로 옮기라는 게 공식 문서의 답이다. 대화가 압축된 뒤라면 스킬을 다시 부른다.
allowed-tools로 도구를 막으려 한다. 이 항목은 "묻지 않고 쓰게 해 주는 것"이다. 다른 도구를 막지는 않는다. 막으려면disallowed-tools나 권한 설정을 쓴다.- 동기화된 스킬을 고친다. claude.ai에서 동기화돼 내려온 스킬(
synced폴더)은 다음 동기화 때 덮어씌워질 수 있다. 고칠 스킬은 직접 만든 폴더에 둔다.
자주 묻는 질문
스킬과 .claude/commands/ 명령은 뭐가 다른가요?
둘 다 /이름을 만들고 똑같이 동작한다. 공식 문서는 명령이 스킬로 합쳐졌다고 말한다. 스킬은 참고 파일을 둘 폴더, 누가 부를지 정하는 머리말, Claude가 알아서 꺼내 쓰는 기능을 더 가진다. 예전 commands 파일은 그대로 두어도 된다.
스킬을 Claude가 알아서 부르지 못하게 하려면요?
머리말에 disable-model-invocation: true를 넣는다. 그러면 description도 컨텍스트에 올라가지 않고, 내가 /이름으로 부를 때만 돈다. 배포·커밋·메시지 보내기처럼 결과가 남는 일에 맞다.
스킬이 안 불려요. 어디부터 보나요?
공식 문서의 순서는 이렇다. ① description에 사람이 실제로 쓰는 말이 있는지 ② "What skills are available?"라고 물어 목록에 있는지 ③ 요청을 description에 가깝게 바꿔 보기 ④ /이름으로 직접 불러 보기. YAML이 깨졌는지는 claude --debug로 본다.
스킬을 너무 많이 만들면 느려지나요?
평소에는 이름과 description만 올라가고 본문은 부를 때만 읽힌다. 다만 목록 전체가 정해진 양을 넘으면 덜 쓴 스킬의 description부터 빠진다. /doctor로 목록이 차지하는 양을 볼 수 있고, /skill-doctor로 안 쓰는 스킬을 찾을 수 있다.
다른 AI 도구에서도 쓸 수 있나요?
Claude Code 스킬은 Agent Skills 공개 규격을 따른다. 다만 Claude Code 밖(claude.ai 업로드 등)에서도 먹는 머리말은 name·description·license·compatibility·metadata·allowed-tools뿐이다. context: fork 같은 항목은 Claude Code 전용이다.