Claude Code의 Skills과 Hooks — AI 코딩 에이전트를 내 방식대로 쓰는 법 2가지

AI 코딩 에이전트를 쓰다 보면 반복되는 패턴이 생긴다.

커밋 메시지를 특정 포맷으로 쓰거나, PR 올리기 전에 린트를 돌리거나, 배포 스크립트를 실행하는 식이다.

Claude Code에는 이런 반복 작업을 자동화하는 두 가지 시스템이 있다.

하나는 스킬(Skills), 다른 하나는 훅(Hooks)이다.

스킬은 “무엇을 할지”를 마크다운 파일로 정의하는 것이고

훅은 “어떤 조건에서 자동으로 개입할지”를 설정 파일로 정의하는 것이다.

복잡한 플러그인 개발 없이 파일 몇 개로 에이전트의 행동을 커스터마이징할 수 있다는 점이 핵심이다.

이 글에서는 두 시스템의 구조, 주요 설정, 그리고 실무 활용 패턴을 정리해본다.


1. Skills이란

스킬은 .claude/skills/ 디렉토리에 SKILL.md 파일로 존재한다.

  • YAML 프론트매터 — 이름, 설명, 호출 조건 등 메타데이터
  • 마크다운 본문 — Claude가 따르는 실제 지침

예를 들어 커밋 자동화 스킬은 이렇게 생겼다.

---
name: commit
description: 변경 사항을 분석하고 커밋 메시지를 생성합니다
disable-model-invocation: true
---

git diff를 확인하고, 변경 내용을 요약하여
Conventional Commits 형식으로 커밋 메시지를 작성하세요.

name: commit으로 정의하면 /commit이라는 슬래시 커맨드가 자동 생성된다.

터미널에서 /commit만 입력하면 Claude가 diff를 분석하고 커밋을 수행한다.

참고로 Claude Code에는 /batch, /simplify, /debug, /loop, /claude-api 같은 번들 스킬이 기본 탑재되어 있다.

이것들도 내부적으로는 같은 SKILL.md 구조로 되어 있다.

번들 스킬이 빌트인 명령어(/help, /compact 등)와 다른 점은

프롬프트 기반이라 상황에 따라 유연하게 동작한다는 것이다.


2. 스킬 디렉토리 구조

스킬은 단일 SKILL.md 파일만으로도 동작하지만 디렉토리 안에 참조 파일을 함께 둘 수 있다.

my-skill/
├── SKILL.md           # 메인 지침 (필수)
├── template.md        # Claude가 채울 템플릿
├── examples/
│   └── sample.md      # 예시 출력
└── scripts/
    └── validate.sh    # Claude가 실행할 스크립트

SKILL.md는 500줄 이내로 유지하고 상세한 레퍼런스는 별도 파일로 분리하는 것이 권장된다.

SKILL.md 안에서 참조 파일을 언급해두면 Claude가 필요할 때 읽어들인다.

저장 위치에 따라 적용 범위가 달라진다.

글로벌: ~/.claude/skills/<name>/SKILL.md → 모든 프로젝트
프로젝트: .claude/skills/<name>/SKILL.md → 해당 프로젝트만
플러그인: <plugin>/skills/<name>/SKILL.md → 플러그인 활성화 시
엔터프라이즈: 관리자 설정 → 조직 전체

모노레포 환경이라면 packages/frontend/.claude/skills/ 같은 하위 디렉토리에도 스킬을 둘 수 있다. Claude Code가 해당 디렉토리에서 작업할 때 자동으로 탐색한다.

기존의 .claude/commands/ 디렉토리에 만들어둔 커스텀 명령어가 있다면 그대로 동작한다.

commands와 skills가 통합되었기 때문이다. 같은 이름이 충돌하면 skills가 우선한다.


3. 프론트매터 전체 옵션

스킬의 동작 방식은 프론트매터로 제어한다.

전체 필드를 정리하면 이렇다.

---
name: my-skill
description: 이 스킬의 용도와 언제 쓸지
disable-model-invocation: true
user-invocable: true
allowed-tools: Read, Grep, Glob
argument-hint: [filename] [format]
model: opus
effort: high
context: fork
agent: Explore
---

name — 슬래시 커맨드 이름. 소문자, 숫자, 하이픈만 가능 (최대 64자)
description — 스킬 용도. Claude가 자동 호출 여부를 판단하는 기준
disable-model-invocation — true면 사용자만 /name으로 호출 가능. Claude가 임의 실행 안 함
user-invocable — false면 슬래시 메뉴에서 숨김. Claude만 자동 호출 가능
allowed-tools — 스킬 실행 중 사용 가능한 도구 제한
argument-hint — 자동완성 시 표시되는 인자 힌트
model — 특정 모델로 실행 (opus, sonnet 등)
effort — 추론 강도 (low, medium, high, max)
context — fork으로 설정하면 서브에이전트에서 실행
agent — context: fork 시 사용할 에이전트 타입
hooks — 이 스킬 실행 중에만 적용되는 훅 정의

호출 제어가 중요한 이유

기본적으로 모든 스킬은 사용자와 Claude 양쪽에서 호출 가능하다.

사용자가 /name으로 직접 실행할 수도 있고 Claude가 대화 맥락에서 관련성을 판단해 자동으로 로드할 수도 있다.

문제는 사이드 이펙트가 있는 스킬이다.

배포, 슬랙 메시지 전송, 데이터 삭제 같은 작업을 Claude가 “코드가 준비된 것 같으니 배포하겠습니다”라고 자동 실행하면 곤란하다.

이때 disable-model-invocation: true를 쓴다.

Claude의 컨텍스트에서 완전히 제거되어 자동 트리거가 불가능해진다.

반드시 사용자가 /deploy를 직접 입력해야만 실행된다.

반대로 user-invocable: false는 배경 지식 용도다.

팀의 레거시 시스템 구조나 코딩 컨벤션을 정리해둔 스킬에 쓴다.

사용자가 /legacy-system-context를 실행하는 건 의미가 없지만

Claude가 관련 코드를 수정할 때 자동으로 참조하면 유용하다.

정리하면 이렇다.

기본값: 사용자 호출 O / Claude 호출 O / description 항상 로드
disable-model-invocation: true: 사용자 호출 O / Claude 호출 X / 로드 안 됨
user-invocable: false: 사용자 호출 X / Claude 호출 O / description 항상 로드


4. 인자 전달과 동적 컨텍스트

스킬에 인자를 전달할 수 있다.

$ARGUMENTS 플레이스홀더가 실행 시 실제 값으로 치환된다.

---
name: fix-issue
description: GitHub 이슈를 수정합니다
disable-model-invocation: true
---

GitHub 이슈 $ARGUMENTS를 코딩 스탠다드에 맞춰 수정하세요.
1. 이슈 설명 읽기
2. 요구사항 파악
3. 수정 구현
4. 테스트 작성
5. 커밋 생성

/fix-issue 123을 실행하면 $ARGUMENTS123으로 치환된다.

인자가 여러 개면 $ARGUMENTS[0], $ARGUMENTS[1] 또는 축약형 $0, $1으로 접근할 수 있다.

동적 컨텍스트 주입

더 강력한 기능은 !`<command>` 문법이다.

셸 커맨드를 실행하고 그 출력을 스킬 본문에 삽입한다.

Claude가 실행하는 게 아니라 스킬 로드 시 전처리로 실행되는 것이다.

---
name: pr-summary
description: PR 요약을 생성합니다
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---

## PR 컨텍스트
- PR diff: !`gh pr diff`
- PR 코멘트: !`gh pr view --comments`
- 변경 파일: !`gh pr diff --name-only`

## 작업
위 내용을 기반으로 PR을 요약하세요.

스킬이 실행될 때 gh pr diff 등이 먼저 실행되고 그 결과가 Claude에게 전달된다.

Claude는 실제 PR 데이터가 포함된 완성된 프롬프트를 받게 된다.


5. 서브에이전트와의 조합

프론트매터에 context: fork를 설정하면 스킬이 메인 대화와 분리된 서브에이전트에서 실행된다.

서브에이전트는 독립된 컨텍스트를 가지며 중간 과정의 도구 호출은 내부에서만 처리되고

최종 결과만 메인으로 돌아온다.

---
name: deep-research
description: 코드베이스를 심층 조사합니다
context: fork
agent: Explore
---

$ARGUMENTS를 조사하세요:
1. Glob과 Grep으로 관련 파일 탐색
2. 코드 분석
3. 파일 경로를 포함한 결과 요약

agent 필드에는 빌트인 에이전트 타입(Explore, Plan, general-purpose)이나

.claude/agents/에 정의한 커스텀 에이전트를 지정할 수 있다.

생략하면 general-purpose가 기본값이다.

주의할 점은 context: fork는 명확한 작업 지시가 있는 스킬에만 의미가 있다는 것이다.

“이 API 컨벤션을 따르세요” 같은 가이드라인만 있고 구체적인 태스크가 없으면

서브에이전트가 할 일을 찾지 못해 빈 결과를 반환한다.

코드 리뷰 시 스타일 체커, 보안 스캐너, 테스트 커버리지 체커를 각각

context: fork로 병렬 실행하면 순차 처리보다 훨씬 빠르다.


6. Hooks — 이벤트 기반 자동화

여기서부터는 두 번째 시스템인 훅(Hooks) 이야기다.

훅은 Claude Code의 라이프사이클 특정 시점에 자동으로 실행되는 셸 커맨드(또는 HTTP 요청, LLM 프롬프트)다.

스킬이 “Claude에게 무엇을 시킬지”를 정의한다면

훅은 “특정 이벤트가 발생했을 때 자동으로 무엇을 할지”를 정의한다.

설정 파일(settings.json)에 이벤트와 핸들러를 등록하는 방식이다.

훅 이벤트 종류

주요 이벤트를 정리하면 이렇다.

SessionStart — 세션 시작/재개 시 (차단 불가)
UserPromptSubmit — 사용자 프롬프트 처리 전 (차단 가능)
PreToolUse — 도구 실행 전 (차단 가능)
PostToolUse — 도구 실행 성공 후 (차단 불가)
PostToolUseFailure — 도구 실행 실패 후 (차단 불가)
PermissionRequest — 권한 요청 다이얼로그 표시 시 (차단 가능)
Stop — Claude 응답 완료 시 (차단 가능)
SubagentStart — 서브에이전트 생성 시 (차단 불가)
SubagentStop — 서브에이전트 종료 시 (차단 가능)
TaskCompleted — 태스크 완료 표시 시 (차단 가능)
PreCompact — 컨텍스트 압축 전 (차단 불가)
PostCompact — 컨텍스트 압축 후 (차단 불가)
SessionEnd — 세션 종료 시 (차단 불가)

“차단 가능”이라는 건 훅이 exit code 2를 반환하면 해당 동작을 중단시킬 수 있다는 뜻이다.

예를 들어 PreToolUse 훅에서 exit 2를 반환하면 그 도구 호출 자체가 차단된다.

설정 구조

~/.claude/settings.json 또는 .claude/settings.json에 다음과 같이 설정한다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/block-dangerous.sh",
            "timeout": 600
          }
        ]
      }
    ]
  }
}

matcher는 이벤트를 필터링하는 정규식이다.

PreToolUsePostToolUse에서는 도구 이름에 매칭된다.

Bash로 설정하면 Bash 도구 호출 시에만 훅이 실행된다.

Edit|Write처럼 여러 도구를 OR로 묶을 수도 있고

MCP 도구는 mcp__memory__.* 같은 패턴을 쓴다.

훅 타입

4가지 타입이 있다.

command — 셸 커맨드 실행. stdin으로 JSON 입력을 받음
http — 지정된 URL로 POST 요청 전송
prompt — 단일 턴 LLM 평가
agent — 도구 접근이 가능한 서브에이전트 검증

대부분은 command 타입을 쓰게 된다.


7. 훅 실전 예제

위험한 명령어 차단

rm -rf가 포함된 Bash 명령을 자동으로 차단하는 훅이다.

.claude/hooks/block-dangerous.sh:

#!/bin/bash
COMMAND=$(jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q 'rm -rf'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "rm -rf 명령이 차단되었습니다"
    }
  }'
else
  exit 0
fi

settings.json 설정:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/block-dangerous.sh"
          }
        ]
      }
    ]
  }
}

훅 스크립트는 stdin으로 JSON 데이터를 받는다.

tool_input.command에 실행하려는 명령어가 들어있다.

exit 0이면 통과, exit 2면 차단이다. JSON 출력으로 세부 제어도 가능하다.

파일 수정 후 자동 린트

파일을 쓰거나 수정한 뒤 자동으로 린트를 실행하는 훅이다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/lint-check.sh"
          }
        ]
      }
    ]
  }
}

PostToolUse는 이미 실행된 후이므로 차단은 못하지만, 린트 결과를 Claude에게 전달하여 자동 수정을 유도할 수 있다.

세션 시작 시 컨텍스트 주입

세션을 시작할 때 최근 git 변경 사항을 자동으로 Claude에게 전달하는 훅이다.

#!/bin/bash
RECENT=$(git log --oneline -5 2>/dev/null)
jq -n --arg changes "$RECENT" '{
  hookSpecificOutput: {
    hookEventName: "SessionStart",
    additionalContext: "최근 커밋:\n\($changes)"
  }
}'
exit 0

additionalContext 필드에 넣은 내용이 Claude의 컨텍스트에 추가된다.

매 세션 시작마다 “최근에 뭘 했는지” 자동으로 알려줄 수 있다.

태스크 완료 전 테스트 게이트

태스크를 완료 처리하기 전에 테스트 통과 여부를 확인하는 훅이다.

#!/bin/bash
if ! npm test 2>&1; then
  echo "테스트가 실패했습니다. 수정 후 완료하세요." >&2
  exit 2
fi
exit 0

TaskCompleted 이벤트에 걸면 된다. 테스트가 실패하면 exit 2로 태스크 완료를 차단한다.


8. 훅 설정 위치와 우선순위

훅도 스킬과 마찬가지로 여러 위치에 설정할 수 있다.

글로벌: ~/.claude/settings.json → 모든 프로젝트
프로젝트 (공유): .claude/settings.json → 팀 전체
프로젝트 (로컬): .claude/settings.local.json → 나만
엔터프라이즈: 관리자 정책 설정 → 조직 전체 (비활성화 불가)

프로젝트 레벨의 .claude/settings.json에 훅을 넣으면 팀원 모두에게 적용된다.

위험한 명령어 차단이나 린트 자동화 같은 훅은 여기 두는 게 좋다.

개인적인 훅(세션 시작 시 환경 설정 등)은 ~/.claude/settings.json에 넣으면 된다.

모든 훅을 비활성화하려면 설정에 "disableAllHooks": true를 넣으면 되지만

엔터프라이즈 관리자가 설정한 정책 레벨 훅은 비활성화할 수 없다.

현재 설정된 훅 목록은 Claude Code에서 /hooks를 입력하면 확인할 수 있다.


9. 스킬 안에서 훅 정의하기

스킬 프론트매터에 훅을 직접 정의할 수도 있다.

이 훅은 해당 스킬이 실행 중일 때만 활성화되고 스킬 종료 시 자동으로 정리된다.

---
name: secure-operations
description: 보안 검사가 포함된 운영 작업
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/security-check.sh"
---

운영 환경 작업을 수행하세요.
모든 Bash 명령은 보안 검사를 거칩니다.

글로벌 훅과의 차이는 스코프다.

글로벌 훅은 항상 실행되지만 스킬 내 훅은 해당 스킬의 라이프타임에만 적용된다.


10. 공식 스킬 저장소와 오픈 스탠다드

Anthropic은 GitHub에 공식 스킬 저장소(anthropics/skills)를 운영하고 있다. 레퍼런스 스킬들이 Apache 2.0 라이선스로 공개되어 있다.

skill-creator — 새로운 스킬을 대화형으로 만들어주는 메타 스킬
frontend-design — UI 컴포넌트 설계 지침
algorithmic-art — 알고리즘 기반 아트 생성
docx, pdf, pptx, xlsx — 문서 생성·편집 스킬 (source-available)

특히 주목할 만한 것은 Agent Skills 오픈 스탠다드다.

Anthropic이 처음 개발하고 오픈 표준으로 공개한 이 포맷은

Claude Code 외에도 Cursor, VS Code, GitHub Copilot, Gemini CLI, OpenAI Codex, JetBrains Junie, Roo Code 등 30개 이상의 AI 도구에서 호환된다.

SKILL.md 하나 만들어두면 여러 도구에서 동시에 쓸 수 있다는 뜻이다.


마무리

정리하면

스킬은 SKILL.md 파일 하나로 Claude의 행동을 정의한다.

슬래시 커맨드로 직접 호출하거나,

Claude가 맥락에 맞춰 자동으로 로드하거나,

서브에이전트로 분리 실행할 수 있다.

은 settings.json에 이벤트-핸들러를 등록하여

도구 실행 전후, 세션 시작/종료, 태스크 완료 등 특정 시점에 자동으로 개입한다.

위험한 명령 차단, 자동 린트, 테스트 게이트 같은 가드레일을 걸 수 있다.

둘 다 복잡한 SDK 없이 마크다운 파일과 JSON 설정만으로 동작한다는 게 포인트다.

AI 코딩 에이전트를 코드 생성 도구가 아니라 자신만의 워크플로우 자동화 도구로 쓰고 싶다면

이 두 시스템을 한번 설정해보는 것을 권한다. 한번 세팅해두면 꽤 편하다.

참고 자료:
– Claude Code 공식 문서 — Skills: https://code.claude.com/docs/en/skills
– Claude Code 공식 문서 — Hooks: https://code.claude.com/docs/en/hooks
– Anthropic 공식 스킬 저장소: https://github.com/anthropics/skills
– Agent Skills 오픈 스탠다드: https://agentskills.io

댓글 남기기