클로드 코드 mods (화면과 도구 호출을 바꾸는 플러그인)
클로드 코드 mod는 Claude Code 안에서 실행되는 JavaScript 또는 TypeScript 함수를 담은 플러그인입니다. 도구 호출, 프롬프트, 명령과 화면 그리기 같은 이벤트를 관찰하거나 바꾸거나 직접 처리하며, 샌드박스 없이 사용자 권한으로 실행됩니다.
같은 말:Claude Code modsClaude Mods클로드 모드클로드 코드 모드클로드 코드 mod 만들기plugin-authoringclaude plugin validatehooks.json modules
목차
앤트로픽이 운영하는 code.claude.com/docs의 Mods 문서 9편을 한국어 사용자가 실무에 옮길 수 있도록 정리했습니다. 기능 이름과 설정 키는 2026년 10월 6일 공식 문서 기준이고, 실습 결과는 준이아빠블로그가 같은 날 macOS의 Claude Code v2.1.291에서 직접 실행해 확인했습니다. 원문 링크는 글 끝 참고 자료에 모았습니다.
🤔 훅, 스킬, MCP가 있는데 mod가 왜 중요한가요?
결론부터 말하면 mod는 Claude Code 자체를 바꾸는 첫 확장 방식이라서 중요합니다. 훅, 스킬, MCP는 Claude Code 바깥에서 스크립트를 실행하거나 Claude에게 지침과 도구를 건네는 방식이라, Claude가 무엇을 알고 무엇을 쓸 수 있는지는 바꿔도 Claude Code의 화면과 내부 동작은 그대로 둡니다. mod는 Claude Code 프로세스 안에서 실행되므로 화면에 창과 버튼을 그리고, 도구 호출을 보류하거나 대신 응답하고, Claude의 응답을 기다리지 않고 즉시 실행되는 명령을 추가합니다.
차이는 구체적인 장면에서 드러납니다. 훅으로 위험한 명령을 막고, 스킬으로 반복 지침을 줄이고, MCP로 외부 도구를 연결해도 작업 중에 컨텍스트가 얼마나 찼는지 차트로 보는 기능은 만들 수 없었습니다. rm -rf 같은 명령도 설정 훅으로는 막거나 통과시키는 것만 정할 수 있었지만, mod는 무엇이 지워지는지 화면에 보여 주고 사용자가 버튼으로 진행 여부를 고르게 합니다.
대신 위험도 그만큼 큽니다. mod는 샌드박스 없이 사용자 권한으로 실행되는 코드라 설치 전 점검이 필요하고, 막거나 기록만 하면 되는 일은 지금도 설정 훅으로 충분합니다. mod는 기존 기능을 대신하지 않고, 기존 기능으로 할 수 없던 화면과 동작 변경을 맡습니다.
2026년 10월 1일 npm에 배포된 Claude Code v2.1.287 변경 이력에는 "Added Claude Mods: plugins may now modify deeper behavior"라는 항목이 있습니다. 이 버전부터 플러그인이 Claude Code 내부 동작과 화면까지 바꿀 수 있게 됐고, 그 플러그인을 mod라고 부릅니다. 지금부터 mod가 무엇이고 훅, 스킬, MCP와 어떻게 다른지, 직접 만들고 설치할 때 무엇을 확인해야 하는지 정리합니다.
🔑 클로드 코드 mod의 정의
클로드 코드 mod는 Claude Code 안에서 실행되는 JavaScript 또는 TypeScript 함수를 담은 플러그인입니다. 도구 호출, 프롬프트, 명령과 화면 그리기 같은 이벤트를 관찰하거나 바꾸거나 직접 처리하며, 샌드박스 없이 사용자 권한으로 실행됩니다.
플러그인은 스킬, 명령, 에이전트, MCP 서버, 훅을 한 폴더에 묶어 /plugin으로 설치하고 공유하는 Claude Code의 배포 단위입니다. mod는 그 플러그인 안에 hooks/hooks.json의 modules 항목으로 코드 파일을 등록한 형태입니다. 그래서 설치, 업데이트, 마켓플레이스 등록 방법은 일반 플러그인과 같습니다.
한국어 공식 문서는 이 기능을 번역하지 않고 mod로 적습니다. 우리말로는 '모드'로 발음되어 권한 모드나 플랜 모드와 혼동하기 쉽지만 서로 관계없는 기능입니다. 권한 모드와 플랜 모드는 Claude가 승인 없이 무엇을 할 수 있는지 정하는 작동 방식이고, mod는 설치해서 Claude Code의 동작과 화면을 바꾸는 코드입니다.
공식 문서는 mod가 등록하는 함수도 '훅'이라고 부릅니다. 기존에 설정 파일에 적던 셸 명령 방식의 훅은 '설정 훅'으로 구분합니다. 지금부터도 같은 기준으로 씁니다.
🧩 mod로 할 수 있는 일
설정 훅, 스킬, 상태줄, MCP 서버는 Claude Code 바깥에서 스크립트를 실행하거나 Claude에게 텍스트와 도구를 건넵니다. mod는 Claude Code 프로세스 안에서 실행되므로 다음 일까지 맡습니다.
- 새 화면 그리기: 대화 기록(트랜스크립트) 옆의 창(pane)이나 프롬프트 위의 띠 영역(band)에 탭, 버튼, 텍스트 입력란을 배치합니다
- 기존 화면 바꾸기: 도구 호출 행, 스피너, Claude가 질문하는 대화 상자처럼 Claude Code가 원래 그리는 요소를 교체하거나 모양을 바꿉니다
- 도구 호출과 요청에 개입하기: 사용자에게 묻는 동안 도구 호출을 보류하거나, 도구를 실행하지 않고 대신 결과를 돌려주거나, 특정 요청을 다른 모델로 보냅니다
- 슬래시 명령 추가하기: Claude의 응답 차례(턴) 없이 즉시 실행되는
/명령을 만듭니다. Claude가 작업 중일 때도 실행됩니다 - 훅 사이에 데이터 공유하기: 한 파일 안의 훅은 변수를 함께 쓰므로, 한 훅이 도구 호출 횟수를 기록하고 다른 훅이 그 값을 스피너 옆에 표시합니다
앤트로픽은 claude-code-playground 저장소에 샘플 mod 세 개를 공개했습니다. 지원 없이 있는 그대로 공유하는 샘플입니다.
| 샘플 | 하는 일 |
|---|---|
token-weather | 프롬프트 위에 컨텍스트 창 사용량 예보를 그립니다 |
blast-radius | rm -rf나 강제 푸시 같은 위험한 셸 명령을 보류하고, 무엇이 바뀌는지 보여 준 뒤 진행과 취소 버튼을 띄웁니다 |
replay-theater | 직전 턴에서 Claude가 수정한 파일을 단계별로 다시 보는 /replay 명령을 추가합니다 |
⚖️ mod, 설정 훅, 스킬, MCP 서버 비교
네 기능은 겹치는 부분이 있어 처음에는 무엇을 골라야 할지 판단하기 어렵습니다. 공식 문서의 비교표를 옮기면 다음과 같습니다.
| 구분 | mod | 설정 훅 | 스킬 | MCP 서버 |
|---|---|---|---|---|
| 정의 | Claude Code가 자기 프로세스에서 호출하는 플러그인 속 함수 | 정해진 시점에 실행되는 셸 명령, HTTP 요청, 프롬프트 | Claude가 읽는 지침 파일(SKILL.md) | Claude에게 도구를 주는 외부 프로세스나 서비스 |
| 바꿀 수 있는 것 | 도구 호출, 프롬프트, 명령, 턴, 화면에 그려지는 내용 | 진행 여부, 도구 인수와 결과, 추가 컨텍스트 | Claude가 아는 것과 하는 것 | Claude가 쓸 수 있는 도구 |
| 화면에 그리기 | 가능 | 불가 | 불가 | 불가 |
| 작성 언어 | JavaScript, TypeScript | 스크립트와 settings.json | 마크다운 | 어떤 언어든 가능 |
| 고르는 경우 | 창, 띠 영역, 직접 만든 명령이 필요하거나 이벤트를 다시 써야 할 때 | 이미 있는 스크립트로 차단, 허용, 기록만 하면 될 때 | 같은 지침을 채팅에 반복해서 붙여 넣고 있을 때 | Claude가 외부 시스템에 접근해야 할 때 |
판단 순서는 간단합니다. 막거나 기록만 하면 되는 일은 설정 훅으로 충분하고, 화면에 무언가를 띄우거나 Claude Code의 기존 동작을 바꿔야 할 때 mod를 검토합니다. 하나의 플러그인에 mod, 스킬, MCP 서버를 함께 담아 배포할 수도 있습니다.
🗂️ mod를 이루는 세 파일과 코드 구조
가장 작은 mod는 파일 세 개로 이루어집니다.
first-mod/
├── .claude-plugin/
│ └── plugin.json
└── hooks/
├── hooks.json
└── register.jsplugin.json: 플러그인 이름, 버전, 설명을 적는 매니페스트입니다. mod라고 해서 특별한 필드가 필요하지는 않습니다hooks.json:modules키에 코드 파일 경로를 적습니다. 이 키가 있어야 플러그인이 mod로 인식됩니다register.js: 훅 모듈이라고 부르는 실제 코드입니다. 어떤 이벤트에서 어떤 함수를 실행할지 Claude Code에 알립니다
Claude Code는 .js와 .ts 파일을 직접 불러오므로 Node.js, 번들러, 빌드 과정이 필요하지 않습니다. 아래는 공식 문서의 예제에 한국어 주석을 붙이고 스피너 문구의 구분 기호만 괄호로 바꾼 코드입니다. Claude가 도구를 쓸 때마다 횟수를 기록하고, 작업 중 스피너 옆에 그 값을 표시합니다.
// 두 훅이 함께 쓰는 값
let calls = 0
// mod가 로드될 때 Claude Code가 한 번 호출하는 함수
export function register(on) {
// Claude가 도구를 쓰려 할 때마다 실행
on('tool.call', async ($, e, next) => {
calls += 1
// 화면을 다시 그려 달라고 요청해 새 값이 보이게 함
$.ui.invalidate('ui.render')
// 도구는 원래대로 실행
return next(e)
})
// Claude Code가 스피너를 그릴 때마다 실행
on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
// 원래 스피너를 유지하고 단어 뒤에 횟수만 덧붙임
return next({ ...e, props: { ...e.props, suffix: ' (tool calls: ' + calls + ')' } })
})
}on에 넘기는 함수가 훅이고, 모든 훅은 같은 인수 세 개를 받습니다. $는 화면 그리기, 명령 등록, 파일 읽기 같은 외부 작업을 요청하는 mods API입니다. e는 도구 이름과 인수처럼 이벤트에 담긴 데이터입니다. next는 이벤트를 다음 mod와 Claude Code의 원래 동작으로 넘기는 함수입니다. 두 번째 인수 { component: 'Spinner' }처럼 훅이 반응할 대상을 좁히는 조건은 matcher라고 부릅니다.
훅은 이벤트를 세 가지 방식으로 처리합니다.
| 방식 | 코드 | 예 |
|---|---|---|
| 관찰 | 기록만 하고 next(e)를 그대로 반환 | 도구 호출 횟수 기록 |
| 재작성 | 이벤트를 바꾼 복사본으로 next를 호출 | 스피너 문구에 횟수 추가 |
| 응답 | next를 부르지 않고 직접 결과를 반환 | 명령을 거부하고 이유를 Claude에게 전달 |
훅이 파일, 프로세스, 네트워크, 모델에 접근하는 통로는 mods API 하나뿐입니다. 그래서 Claude Code는 mod를 실행하지 않고도 그 mod가 무엇을 요청하는지 코드에서 찾아 나열합니다. 아래 안전 점검 절에서 이 기능을 씁니다.
🖥️ mod가 실행되는 곳과 그려지는 곳
훅은 플러그인을 불러오는 모든 세션에서 실행되지만, 화면 그리기는 터미널과 데스크톱 앱에서만 보입니다.
| 실행 환경 | 훅 실행 | 그린 내용 표시 |
|---|---|---|
터미널의 claude (에디터 통합 터미널, JetBrains 플러그인 포함) | 예 | 예 |
| 데스크톱 앱의 Code 탭 (WSL 세션 제외) | 예 | 예 (터미널 전용 요소 제외) |
| 데스크톱 앱의 WSL 세션 | 아니요 | 아니요 |
| VS Code 확장 프로그램의 채팅 패널 | 예 | 아니요 |
claude -p와 Agent SDK | 예 | 아니요 |
| claude.ai나 모바일 앱의 원격 제어(Remote Control) | 예 (내 컴퓨터의 세션에서 실행) | 내 컴퓨터의 터미널에 표시 |
| 클라우드 세션 | 클라우드로 전달되는 플러그인이면 예 | 아니요 |
예를 들어 위험 명령을 막는 mod는 VS Code 확장에서도 동작하지만, 버튼을 띄우는 부분은 보이지 않습니다. 화면을 그리는 mod는 실행 환경을 확인해 그릴 수 없는 곳에서는 트랜스크립트의 한 줄이나 명령의 텍스트 응답으로 대신하도록 만듭니다.
🛠️ mod를 시작하는 세 가지 방법
이미 들어 있는 내장 mod
Claude Code의 일부 기능은 그 자체가 mod입니다. /plugin의 Installed 탭에서 Built-in 아래에 보이며, 업데이트하거나 제거할 수는 없습니다.
/plugin에 보이는 이름 | 하는 일 |
|---|---|
cc-plugin-agents-md | 프로젝트의 AGENTS.md를 지침으로 불러옵니다 |
cc-plugin-diff | /diff 명령을 처리하고 변경 내용 창을 그립니다 |
cc-plugin-plugin-authoring | Claude에게 mod 작성용 plugin-authoring 스킬을 제공합니다 |
cc-plugin-sec-default | 사용자가 설치한 mod로부터 조직이 관리하는 항목을 보호합니다. 끌 수 없습니다 |
cc-plugin-telemetry | Claude Code와 내장 mod의 분석 기록을 전송합니다 |
cc-plugin-you-should-know | 긴 작업 중 보조 에이전트가 상황을 살펴 놓치기 쉬운 내용을 프롬프트 위에 알립니다. 기본은 꺼져 있습니다 |
cc-plugin-you-should-know는 조직에서 사용할 수 있는 경우 /plugin enable cc-plugin-you-should-know@builtin으로 켭니다. diff, agents-md, sec-default, telemetry의 소스는 anthropics/claude-code 저장소의 mods 폴더에 공개돼 있어 실제 mod 코드를 참고하기 좋습니다.
Claude에게 만들어 달라고 요청하기
대화형 Claude Code 세션에서 원하는 기능을 설명하면 Claude가 내장 plugin-authoring 스킬을 참고해 mod를 작성합니다. 공식 문서의 예시는 make a mod that shows the current git branch above the prompt입니다. /plugin-authoring을 입력해 스킬을 직접 불러올 수도 있습니다.
- Claude는
~/.claude/dev-mods/세션ID/mod이름/폴더에 파일을 만듭니다. 기본(default)과 편집 자동 승인(acceptEdits) 권한 모드에서는~/.claude가 보호된 경로라 파일마다 승인을 묻습니다 - 첫 파일을 저장하면 이 세션에서 핫 리로딩(코드가 바뀔 때마다 자동으로 다시 불러오기)을 켤지 묻습니다. Enable for this session을 고르면 턴이 끝날 때 mod가 로드되고, 이후 수정할 때마다 다시 로드됩니다. Not now를 고르면 다음에 그 세션을 시작할 때 로드됩니다
/plugin의 Installed 탭에서 mod가 보이는지 확인하고 기능을 써 봅니다. 마음에 들지 않으면 바꿀 내용을 Claude에게 말합니다
이렇게 만든 mod는 만든 세션에서만 로드되고, 세션 폴더가 cleanupPeriodDays 설정 기간보다 오래되면 삭제됩니다. 계속 쓰려면 폴더를 ~/mods/git-branch처럼 다른 곳에 복사한 뒤 claude --plugin-dir ~/mods/git-branch로 시작하거나 마켓플레이스에 올립니다. claude -p처럼 승인할 사람이 없는 세션, 신뢰하지 않은 작업 폴더, mod가 꺼진 세션에서는 Claude가 작성한 mod가 로드되지 않습니다.
마켓플레이스에서 설치하기
mod는 일반 플러그인처럼 플러그인 이름@마켓플레이스 이름으로 설치합니다. 세션 안에서는 /plugin install token-chart@your-org, 셸에서는 claude plugin install token-chart@your-org를 실행합니다. 세션이 열린 상태에서 셸로 설치하거나 업데이트했다면 그 세션에서 /reload-plugins를 실행해야 바로 반영됩니다.
샘플 mod를 써 보려면 claude-code-playground 저장소를 내려받은(clone) 뒤 claude --plugin-dir 경로로 한 세션 동안만 불러옵니다. 계속 쓰려면 내려받은 폴더의 claude-code/mods를 마켓플레이스로 추가하고 claude-code-playground-mods에서 설치합니다. 이 마켓플레이스는 내려받은 폴더를 가리키므로 폴더를 옮기거나 지우면 mod가 로드되지 않습니다.
🔐 설치 전에 확인할 안전 범위
mod는 샌드박스 없이 사용자 계정 권한으로 실행되는 코드입니다. 공식 문서가 밝힌 접근 범위는 다음과 같습니다.
- 사용자 계정이 접근할 수 있는 모든 파일을 읽고 쓰며, 프로그램을 실행하고 네트워크 요청을 보냅니다
- 환경 변수와 설정 파일에 들어 있는 API 키를 읽습니다
- 사용자가 보내는 모든 프롬프트와 Claude의 모든 도구 호출을 봅니다
- 프롬프트나 도구 호출을 다시 쓰고, 사용자가 입력한 것처럼 프롬프트를 보내고, 다른 세션으로 메시지를 보냅니다
- 확인을 묻기 전에 도구 호출을 승인합니다.
ask규칙이 확인을 요청할 호출이나 사용자의PreToolUse설정 훅이 막은 호출도 승인 대상에 들어갑니다 - 사용자의 요금제나 API 키로 모델을 호출해 사용량을 씁니다
운영체제 수준에서 명령의 파일과 네트워크 접근을 제한하는 샌드박싱을 켜도 격리되는 것은 Claude가 실행하는 Bash 명령이고, mod가 시작한 프로세스는 샌드박스 밖에서 실행됩니다. mod가 바꿀 수 없는 것은 권한 프롬프트입니다. 승인 창에 표시되는 내용은 mod가 고치지 못합니다.
그래서 설치 전에 claude plugin validate로 mod가 무엇을 하는지 먼저 봅니다. 이 명령은 mod를 실행하지 않고 처리하는 이벤트(hooks:)와 Claude Code에 요청하는 작업(calls:)을 나열합니다. 아래 실습에서 실제 출력을 확인합니다. calls:에 $.process(프로그램 실행), $.fs(파일 접근), 네트워크 요청이 보이면 그 호출이 왜 필요한지 코드에서 찾아봅니다.
막는 용도의 훅에는 한 가지 함정이 더 있습니다. 공식 문서에 따르면 훅이 next를 부르기 전에 오류를 내거나 시간 제한(10초)을 넘기면 Claude Code는 그 훅이 없었던 것처럼 건너뛰고 다음 처리를 이어 갑니다. 차단하려던 명령이 그대로 실행될 수 있다는 뜻입니다. 실패하면 막는 쪽으로 동작하게 하려면 .catch 오류 처리기를 붙입니다. v2.1.290부터 claude plugin validate는 이런 훅에 .catch가 있는지 함께 보여 줍니다.
// guard는 직접 작성한 차단 함수. 오류가 나면 실행하지 않고 거부한다
on('tool.call', { tool: 'Bash' }, guard).catch(async ($, e, next) => {
return { deny: 'The command guard failed, so this command was not run: ' + next.error.kind }
})🏢 조직에서 mod를 관리하는 설정
회사 관리 설정(managed settings)이 있는 컴퓨터이거나 Team 또는 Enterprise 요금제로 로그인한 경우, Claude Code는 사용자가 설치한 mod보다 먼저 sec-default 가드를 불러옵니다. 가드는 사용자 mod가 관리형 훅, 시스템 프롬프트, 관리형 CLAUDE.md, 관리형 MCP 서버의 도구를 바꾸지 못하게 막습니다. 가드가 있는 환경에서는 사용자 mod가 deny 규칙으로 거부된 호출을 승인할 수 없습니다.
다만 가드도 다른 제한은 추가하지 않습니다. 예를 들어 Read(.env)를 거부 규칙에 넣어도 이 규칙은 Claude의 도구 호출에만 적용되므로, mod가 $.fs.read로 같은 파일을 읽는 것은 막지 못합니다. 관리자가 고를 수 있는 정책은 다음과 같습니다.
| 원하는 결과 | 관리형 설정 |
|---|---|
| 사용자가 설치한 mod만 막고 설정 훅은 유지 | 가드 옵션 allowManagedModsOnly |
| 조직이 배포한 mod와 내장 mod만 허용 | allowManagedModsOnly와 조직 mod 설치. 더 넓게 막으려면 allowManagedHooksOnly (사용자 설정 훅도 차단) |
| 승인한 마켓플레이스의 mod만 허용 | 마켓플레이스 제한 유지와 disableSideloadFlags: true (--plugin-dir과 Claude가 세션 중 작성한 mod 거부) |
| 모든 mod와 훅 중지 | disableAllHooks: true (관리형 훅, 상태줄, /goal도 중지) |
| 모든 mod를 허용하되 조직 mod가 검사 | 조직 mod를 prependPlugins에 sec-default@builtin과 함께 등록 |
AGENTS.md 지원 같은 내장 mod는 이 설정의 영향을 받지 않고 각자의 스위치로 끕니다.
🔌 mod를 켜고 끄는 방법
mod는 기본으로 켜져 있습니다. 터미널은 Claude Code v2.1.287 이상, 데스크톱 앱은 내장 Claude Code v2.1.286 이상이 필요합니다. 터미널에서는 claude --version, 데스크톱 앱에서는 Code 탭 로컬 세션에서 /status를 입력해 Claude Code 행의 버전을 봅니다.
| 끄는 범위 | 방법 |
|---|---|
| mod 하나 | /plugin의 Installed 탭에서 해당 플러그인을 비활성화하거나 제거 |
| 설치한 모든 mod, 이번 세션만 | claude --safe-mode로 시작 (다른 사용자 설정도 함께 꺼짐) |
| 직접 설치한 모든 mod, 모든 세션 | ~/.claude/settings.json에 "disableAllHooks": true (설정 훅과 사용자 상태줄도 중지) |
disableAllHooks를 켜도 플러그인 자체는 설치된 상태로 남고, 같은 플러그인의 스킬, 명령, 에이전트, MCP 서버는 계속 로드됩니다. 얼리 액세스 때 CLAUDE_CODE_ENABLE_FUNCTION_HOOKS를 설정했다면 지웁니다. v2.1.287부터는 이 값을 무시하므로 0으로 둬도 mod가 꺼지지 않습니다. 현재 세션에 로드된 mod의 개수와 이름은 /plugin을 열었을 때 탭 아래의 흐린 줄(mods active)에 표시됩니다.
❓ 자주 묻는 질문
코딩을 몰라도 mod를 쓸 수 있나요?
설치해서 쓰는 것은 일반 플러그인과 같아 코딩 지식이 필요하지 않습니다. 만들 때도 원하는 기능을 말로 설명하면 Claude가 plugin-authoring 스킬로 코드를 작성하고 승인을 받아 바로 로드합니다. 다만 mod는 내 권한으로 실행되는 코드이므로, 설치 전 claude plugin validate 출력의 calls: 줄에서 파일, 프로세스, 네트워크 접근이 있는지 보고 이유를 Claude에게 물어보는 단계는 건너뛰지 않습니다.
이미 만든 설정 훅을 mod로 옮겨야 하나요?
옮길 필요는 없습니다. 기존 스크립트로 명령을 막거나 기록하는 일은 설정 훅으로 충분하고 두 방식은 함께 동작합니다. 화면에 확인 버튼을 띄우거나, 도구를 실행하지 않고 대신 결과를 돌려주거나, 직접 만든 슬래시 명령이 필요해질 때 mod를 검토합니다.
VS Code 확장이나 claude -p에서도 mod가 동작하나요?
훅은 실행되지만 mod가 그린 창, 띠 영역, 바뀐 행은 보이지 않습니다. 차단이나 기록처럼 화면이 필요 없는 기능은 그대로 동작하고, 명령의 텍스트 응답도 출력됩니다. 데스크톱 앱의 WSL 세션은 플러그인을 쓸 수 없어 훅도 실행되지 않습니다.
🧪 첫 mod를 만들고 실제로 막히는지 확인하기
macOS, Linux 또는 WSL의 새 빈 폴더 mod-practice에서 연습합니다. WSL은 Windows 안에서 Linux 환경을 쓰는 기능입니다. 실제 업무 폴더나 기존 플러그인 설정은 건드리지 않습니다. 터미널을 여는 방법과 폴더 이동이 익숙하지 않다면 CLAUDE.md 실습을 먼저 봅니다.
1단계: 버전 확인과 파일 만들기
터미널에서 claude --version을 입력해 2.1.287 이상인지 확인합니다. 낮으면 Claude Code를 업데이트한 뒤 진행합니다. 이어서 연습 폴더 안에서 폴더 두 개를 만듭니다. Windows PowerShell에서는 New-Item -ItemType Directory -Force first-mod\.claude-plugin, first-mod\hooks를 씁니다.
mkdir -p first-mod/.claude-plugin first-mod/hooks편집기로 아래 두 파일을 저장합니다. 첫 번째는 first-mod/.claude-plugin/plugin.json, 두 번째는 first-mod/hooks/hooks.json입니다. author를 빼도 동작하지만 점검 단계에서 작성자 정보가 없다는 경고가 나옵니다.
{
"name": "first-mod",
"version": "0.1.0",
"description": "Counts Claude's tool calls, shows the count beside the spinner, and adds a /tally command",
"author": { "name": "Your Name" }
}{
"description": "The first-mod hooks module",
"modules": ["./register.js"]
}first-mod/hooks/register.js에는 앞의 코드에 /tally 명령을 더한 아래 내용을 저장합니다.
let calls = 0
export function register(on) {
// 세션이 시작될 때 /tally 명령을 등록
on('session.start', async ($, e, next) => {
await $.command.register({ name: 'tally', description: 'Show how many tool calls Claude has made' })
return next(e)
})
// 도구 호출마다 횟수를 기록하고 화면을 다시 그리게 함
on('tool.call', async ($, e, next) => {
calls += 1
$.ui.invalidate('ui.render')
return next(e)
})
// /tally를 입력했을 때만 실행되어 횟수를 출력
on('command.run', { command: 'tally' }, async () => {
return { text: 'Claude has made ' + calls + ' tool calls since this mod loaded' }
})
// 스피너 문구 뒤에 횟수를 덧붙임
on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
return next({ ...e, props: { ...e.props, suffix: ' (tool calls: ' + calls + ')' } })
})
}2단계: 실행하지 않고 점검하기
mod-practice 폴더에서 다음 명령을 실행합니다.
claude plugin validate ./first-mod준이아빠블로그가 v2.1.291에서 실행했을 때 출력의 핵심 줄은 다음과 같았습니다.
❯ ./register.js hooks: session.start, tool.call, command.run{command=tally}, ui.render{component=Spinner}
❯ ./register.js gating hook without .catch: tool.call
❯ ./register.js calls: $.command.register, $.ui.invalidate
✔ Validation passedhooks: 줄은 이 mod가 반응하는 이벤트 네 개, calls: 줄은 Claude Code에 요청하는 작업 두 개입니다. 파일, 프로세스, 네트워크 호출이 없으니 이 mod는 화면과 명령만 다룬다는 사실을 실행 전에 확인했습니다. gating hook without .catch 줄은 tool.call 훅에 오류 처리기가 없다는 안내입니다. 이 예제는 아무것도 막지 않으므로 그대로 둬도 됩니다.
3단계: 명령과 스피너 확인하기
먼저 대화 없이 명령만 실행해 봅니다.
claude -p "/tally" --plugin-dir ./first-mod실제 결과는 first-mod: Claude has made 0 tool calls since this mod loaded였습니다. Claude Code가 명령 결과 앞에 플러그인 이름을 붙이고, 아직 도구를 쓰지 않았으므로 0이 나옵니다. 이 줄이 나오면 mod가 정상으로 로드된 것입니다.
다음으로 claude --plugin-dir ./first-mod로 대화형 세션을 열고 list the files here and read the README처럼 도구를 여러 번 쓰는 작업을 요청합니다. 공식 문서에 따르면 작업 중 스피너 문구 뒤에 도구 호출 횟수가 붙어 1, 2, 3 순으로 늘어나고, 작업이 끝난 뒤 /tally를 입력하면 실제 횟수가 나옵니다. 세션을 연 채로 register.js의 ' (tool calls: '를 ' (tools used: '로 고쳐 저장하면 트랜스크립트에 다시 로드됐다는 줄이 나오고 다음 스피너부터 새 문구가 보입니다. 다시 로드되면 calls는 0부터 새로 기록됩니다.
4단계: 삭제 명령을 막는 mod로 바꿔 보기
이번에는 응답 방식의 훅을 확인합니다. 연습 폴더에 guard-mod를 같은 구조로 만들고, plugin.json은 first-mod의 파일을 복사해 name만 guard-mod로 바꿉니다. hooks.json은 {"modules":["./register.js"]}만 있어도 됩니다. register.js는 다음과 같습니다.
export function register(on) {
// Bash 도구 호출만 검사
on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
if (/(^|\s)rm\s/.test(e.command)) {
// 트랜스크립트에 흐린 줄로 기록
$.ui.log('guard-mod blocked: ' + e.command)
// next를 부르지 않으므로 명령은 실행되지 않음. Claude는 이 문장을 도구 결과로 읽음
return { deny: 'Deleting files is not allowed in this folder. Tell the user the file was kept.' }
}
return next(e)
})
}시험용 폴더 work에 notes.txt를 만들고 그 폴더로 이동한 뒤 실행합니다. --allowedTools "Bash(rm:*)"는 mod가 없다면 rm 명령이 승인 없이 실행되도록 허용하는 옵션입니다. 이 실행은 모델을 한 번 호출하므로 요금제 사용량이 조금 차감됩니다.
mkdir work && echo hello > work/notes.txt && cd work
claude -p "Run this exact bash command: rm notes.txt" --plugin-dir ../guard-mod --allowedTools "Bash(rm:*)"
ls준이아빠블로그의 실행에서 Claude는 "이 폴더에서는 파일 삭제가 차단되어 있어서 notes.txt는 지워지지 않고 그대로 남아 있습니다"라고 답했고, ls 결과에도 notes.txt가 남아 있었습니다. 허용 규칙보다 mod의 tool.call 훅이 먼저 실행돼 명령을 거부했다는 뜻입니다. 이 mod를 claude plugin validate ./guard-mod로 점검하면 gating hook without .catch: tool.call{tool=Bash} 줄이 나옵니다. 막는 훅이므로 검사 부분을 guard라는 함수로 분리하고 앞 절의 예시처럼 .catch 처리기를 붙여 봅니다. 다시 점검했을 때 이 줄이 gating hook with .catch로 바뀌면 훅이 실패해도 명령을 거부하는 구조가 된 것입니다.
막혔을 때와 혼자 반복하기
| 증상 | 확인할 것 |
|---|---|
/tally가 명령 목록에 없음 | hooks.json의 modules 경로와 파일 이름, claude plugin validate 오류 |
--plugin-dir을 줬는데 아무 반응이 없음 | claude --version이 2.1.287 이상인지, --safe-mode나 disableAllHooks가 켜져 있지 않은지 |
| 처음 연 폴더에서 로드되지 않음 | 작업 폴더 신뢰 확인 창을 수락했는지 |
| 파일이 지워짐 | 정규식이 실제 명령과 맞는지, 훅이 오류로 건너뛰어지지 않았는지 (디버그 로그의 hook skipped 줄) |
Claude의 답만 보고 "막았다"고 판단하지 않습니다. ls처럼 파일이 실제로 남아 있는지 직접 확인합니다. 익숙해지면 claude --plugin-dir ./first-mod로 세션을 열고 add a /tally-reset command to this mod that sets the tally back to zero라고 요청해 Claude가 mod를 고치게 해 봅니다. Claude는 코드를 수정하고 claude plugin validate를 실행한 뒤 문제를 고치며, 턴이 끝나면 바뀐 mod가 다시 로드됩니다.
📋 3줄 요약
-
클로드 코드 mod는 2026년 10월 1일 배포된 v2.1.287부터 기본으로 켜지는 플러그인이며 JavaScript나 TypeScript 함수가 Claude Code 안에서 실행됩니다.
-
mod의 함수는 도구 호출과 프롬프트, 스피너 같은 이벤트를 받아 그대로 넘기거나 바꾸거나 직접 응답하고, 설치 전에는 claude plugin validate로 처리 이벤트와 호출 목록을 확인합니다.
-
mod는 샌드박스 없이 사용자 권한으로 파일과 네트워크, API 키에 접근하므로 신뢰할 수 있는 마켓플레이스의 mod만 설치합니다.
📚 참고 자료
- Mods 개요 (한국어): https://code.claude.com/docs/ko/plugins/mods/overview
- mod 만들기: https://code.claude.com/docs/ko/plugins/mods/create
- 이벤트에 반응하기: https://code.claude.com/docs/ko/plugins/mods/events
- 조직의 mod 관리하기: https://code.claude.com/docs/ko/plugins/mods/admin
- mods 참조 (이벤트, 메서드, 제한): https://code.claude.com/docs/ko/plugins/mods/reference
- mod 문제 해결: https://code.claude.com/docs/ko/plugins/mods/troubleshoot
- Claude Code 변경 이력 (v2.1.287 Claude Mods 추가): https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md
- 샘플 mod 저장소: https://github.com/anthropics/claude-code-playground/tree/main/claude-code/mods

제대로 이해했는지 한 문제로 확인해 볼까요?
답을 고르면 바로 풀이가 나와요.
클로드 코드 mod, 설정 훅, 스킬, MCP 서버 가운데 mod만 할 수 있는 일은 무엇일까요?
예제나 확인 질문을 직접 시도한 뒤 완료 표시해요. 더 연습할 내용이 남으면 표시하지 않고 다음 글을 읽어도 됩니다. 완료 버튼은 이해도를 채점하지 않으며 잘못 표시하면 취소할 수 있어요.

