2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
3> Use this file to discover all available pages before exploring further.3> Use this file to discover all available pages before exploring further.
4 4
5# 모드 만들기5# mod 만들기
6 6
7> Claude가 설명으로부터 Claude Code 모드를 작성하도록 하거나, 도구 호출을 세고 명령을 추가하는 모드를 직접 작성하세요. 다시 로드 및 검증 루프를 배웁니다.7> 설명을 바탕으로 Claude가 Claude Code mod를 작성하도록 하거나, 도구 호출 수를 세고 명령을 추가하는 mod를 직접 작성합니다. 다시 로드하고 검증하는 과정을 알아봅니다.
8 8
9모드는 Claude Code [플러그인](/docs/ko/plugins/overview)으로, 이벤트가 발생할 때 Claude Code가 호출하는 함수를 포함한 hooks 모듈이라는 항목 파일을 가집니다. 이는 JavaScript 또는 TypeScript 파일입니다. 모드를 만드는 방법은 두 가지입니다:9mod는 훅 모듈이라고 하는 진입 파일을 갖춘 Claude Code [플러그인](/docs/ko/plugins/overview)입니다. 훅 모듈은 이벤트가 발생할 때 Claude Code가 그 함수들을 호출하는 JavaScript 또는 TypeScript 파일입니다. mod를 만드는 방법은 다음과 같습니다.
10 10
11* **Claude에게 작성하도록 요청**: Claude Code 세션에서 [원하는 것을 설명](#ask-claude-for-a-mod)하세요11* **Claude에게 작성 요청하기**: Claude Code 세션에서 [원하는 내용을 설명합니다](#ask-claude-for-a-mod)
12* **직접 작성**: [튜토리얼을 따르세요](#write-a-mod-yourself) 모드의 코드가 어떻게 작동하는지 배우세요. Node.js, 번들러 또는 빌드 단계가 필요하지 않습니다. Claude Code는 `.js` 및 `.ts` 파일을 직접 로드하기 때문입니다.12* **직접 작성하기**: [튜토리얼을 따라](#write-a-mod-yourself) mod의 코드가 어떻게 동작하는지 알아봅니다. Claude Code가 `.js` 및 `.ts` 파일을 직접 로드하므로 Node.js, 번들러 또는 빌드 단계가 필요하지 않습니다.
13 13
14모드가 올바른 도구인지 아직 결정하지 못했다면, 먼저 [개요의 비교](/docs/ko/plugins/mods/overview#compare-mods-settings-hooks-skills-and-mcp-servers)를 읽으세요.14mod가 적합한 도구인지 아직 결정하지 않았다면 먼저 [개요의 비교](/docs/ko/plugins/mods/overview#compare-mods-settings-hooks-skills-and-mcp-servers)를 읽어 보십시오.
15 15
16<Note>16<Note>
17 모드는 Claude Code v2.1.287 이상이 필요합니다. 셸에서 `claude --version`을 실행하여 확인하세요. 모드가 로드될 수 있는지 확인하려면 [모드가 로드될 수 있는지 확인](/docs/ko/plugins/mods/troubleshoot#check-whether-mods-can-load)을 참조하세요.17 mod를 사용하려면 Claude Code v2.1.287 이상이 필요합니다. 셸에서 `claude --version`을 실행하여 확인합니다. 현재 환경에서 mod를 로드할 수 있는지 확인하려면 [mod를 로드할 수 있는지 확인하기](/docs/ko/plugins/mods/troubleshoot#check-whether-mods-can-load)를 참조하십시오.
18</Note>18</Note>
19 19
20<h2 id="ask-claude-for-a-mod">20<h2 id="ask-claude-for-a-mod">
21 Claude에게 모드 작성 요청21 Claude에게 mod 요청하기
22</h2>22</h2>
23 23
24대화형 Claude Code 세션에서 원하는 모드를 설명하면 Claude가 작성합니다. Claude는 `plugin-authoring`이라는 내장 [스킬](/docs/ko/skills)에서 작동하며, 이는 모드를 작성할 위치, 버전이 가진 이벤트 및 메서드, 모드가 로드되는 방식을 알려줍니다. Claude는 모드를 요청할 때 스킬을 로드할 수 있거나, Claude Code 프롬프트에서 `/plugin-authoring`을 실행하여 직접 로드할 수 있습니다.24대화형 Claude Code 세션에서 원하는 mod를 설명하면 Claude가 작성합니다. Claude는 `plugin-authoring`이라는 내장 [스킬](/docs/ko/skills)을 기반으로 작업하며, 이 스킬은 mod를 작성할 위치, 현재 버전에서 사용할 수 있는 이벤트와 메서드, mod가 로드되는 방식을 Claude에게 알려 줍니다. mod를 요청하면 Claude가 스킬을 로드할 수 있으며, Claude Code 프롬프트에서 `/plugin-authoring`을 실행하여 직접 로드할 수도 있습니다.
25 25
26모드는 승인하면 실행됩니다. 단, [Claude가 작성한 모드가 로드될 수 없는 세션](#sessions-that-skip-the-approval)은 제외됩니다.26mod는 승인한 후에 실행됩니다. 단, [Claude가 작성한 mod를 로드할 수 없는 세션](#sessions-that-skip-the-approval)은 예외입니다.
27 27
28<Steps>28<Steps>
29 <Step title="모드 설명">29 <Step title="mod 설명하기">
30 자신의 말로 모드를 요청하세요. 예를 들어 `현재 git 브랜치를 프롬프트 위에 표시하는 모드를 만들어`라고 할 수 있습니다. Claude는 세션의 모드 폴더에 있는 자신의 디렉토리에 모드를 작성합니다. 이는 `~/.claude/dev-mods/` 다음에 세션의 ID가 옵니다. 모드의 전체 경로는 `~/.claude/dev-mods/3f2a9c1e-5b7d-4e8a-9c21-6d0f4b8a7e13/git-branch/`와 같습니다.30 원하는 mod를 자유롭게 요청합니다. 예를 들어 `make a mod that shows the current git branch above the prompt`와 같이 요청할 수 있습니다. Claude는 세션의 mod 폴더 안에 mod 전용 디렉터리를 만들어 mod를 작성합니다. 세션의 mod 폴더는 `~/.claude/dev-mods/` 뒤에 세션 ID가 붙은 경로입니다. mod의 전체 경로는 `~/.claude/dev-mods/3f2a9c1e-5b7d-4e8a-9c21-6d0f4b8a7e13/git-branch/`와 같은 형태입니다.
31 31
32 <Note>32 <Note>
33 `default` 및 `acceptEdits` [권한 모드](/docs/ko/permission-modes#protected-paths)에서 Claude Code는 Claude가 모드의 각 파일을 생성하기 전에 요청합니다. `~/.claude`는 보호된 경로이기 때문입니다. 각 파일이 나타나면 승인하세요.33 `default` 및 `acceptEdits` [권한 모드](/docs/ko/permission-modes#protected-paths)에서는 `~/.claude`가 보호된 경로이므로, Claude가 mod의 각 파일을 생성하기 전에 Claude Code가 확인을 요청합니다. 표시되는 각 파일을 승인하십시오.
34 </Note>34 </Note>
35 </Step>35 </Step>
36 36
37 <Step title="모드 승인">37 <Step title="mod 승인하기">
38 Claude가 첫 번째 파일을 저장하면 Claude Code는 세션에 대해 핫 리로딩을 활성화할지 묻습니다. 핫 리로딩은 이 세션에서 Claude가 작성한 모드를 실행하고 나중에 변경 사항을 선택합니다.38 Claude가 첫 번째 파일을 저장하면 Claude Code가 해당 세션에서 핫 리로딩을 활성화할지 묻습니다. 핫 리로딩은 이 세션에서 Claude가 작성한 mod를 실행하고 이후의 각 변경 사항을 반영합니다.
39 39
40 다음 중 하나를 선택하세요:40 다음 중 하나를 선택합니다.
41 41
42 * **이 세션에 대해 활성화**: 세션의 모드 폴더에 있는 모드는 턴이 끝날 때 로드되고, 변경 사항이 있는 각 턴의 끝에 다시 로드됩니다. 답변은 세션 동안 지속되며, 재개한 후에도 지속됩니다.42 * **Enable for this session**: 세션의 mod 폴더에 있는 mod가 턴이 끝날 때 로드되고, mod를 변경하는 각 턴이 끝날 때마다 다시 로드됩니다. 이 선택은 세션을 재개한 후를 포함하여 세션 동안 유지됩니다.
43 * **지금은 아님**: 지금은 아무것도 로드되지 않습니다. 파일은 Claude가 작성한 위치에 남아 있으며, 모드는 해당 세션이 다음에 시작될 때 로드됩니다. 모드가 로드되지 않도록 하려면 해당 디렉토리를 삭제하세요.43 * **Not now**: 지금은 아무것도 로드되지 않습니다. 파일은 Claude가 작성한 위치에 그대로 남아 있으며, 해당 세션이 다음에 시작될 때 mod가 로드됩니다. mod가 로드되지 않도록 하려면 해당 디렉터리를 삭제하십시오.
44 </Step>44 </Step>
45 45
46 <Step title="모드가 로드되었는지 확인">46 <Step title="mod가 로드되었는지 확인하기">
47 Claude Code 프롬프트에서 `/plugin`을 실행하고 **Installed** 탭이 선택될 때까지 Tab을 누르세요. 모드가 나열되며, 여기서 끌 수 있습니다.47 Claude Code 프롬프트에서 `/plugin`을 실행하고 **Installed** 탭이 선택될 때까지 Tab 키를 누릅니다. 이 탭에 mod가 표시되며, 여기에서 mod를 끌 수 있습니다.
48 </Step>48 </Step>
49 49
50 <Step title="모드 시도">50 <Step title="mod 사용해 보기">
51 요청한 것을 사용하세요. 예제 프롬프트의 경우 현재 브랜치 이름이 프롬프트 상자 위에 나타납니다. 모드가 원하는 작업을 수행하지 않으면 Claude에게 변경할 사항을 알려주세요. 모드는 파일을 변경하는 각 턴의 끝에 다시 로드되므로 Claude가 완료되는 즉시 변경 사항을 시도할 수 있습니다.51 요청한 기능을 사용해 봅니다. 예시 프롬프트의 경우 현재 브랜치 이름이 프롬프트 상자 위에 표시됩니다. mod가 원하는 대로 동작하지 않으면 변경할 내용을 Claude에게 알려 주십시오. mod는 파일을 변경하는 각 턴이 끝날 때마다 다시 로드되므로, Claude가 작업을 마치는 즉시 변경 사항을 확인할 수 있습니다.
52 </Step>52 </Step>
53</Steps>53</Steps>
54 54
55<h3 id="use-the-mod-in-other-sessions">55<h3 id="use-the-mod-in-other-sessions">
56 다른 세션에서 모드 사용56 다른 세션에서 mod 사용하기
57</h3>57</h3>
58 58
59Claude가 작성한 모드는 모드를 만든 세션에서만 로드되며, Claude Code는 [`cleanupPeriodDays`](/docs/ko/settings-reference#cleanupperioddays)보다 오래되면 해당 세션의 모드 폴더를 삭제합니다. 모드를 유지하려면 모드 폴더에서 디렉토리를 `~/mods/git-branch`와 같은 자신의 위치로 복사하세요. 그런 다음 로드 방법을 선택하세요:59Claude가 작성한 mod는 해당 mod를 만든 세션에서만 로드되며, Claude Code는 세션의 mod 폴더가 [`cleanupPeriodDays`](/docs/ko/settings-reference#cleanupperioddays)보다 오래되면 삭제합니다. mod를 보관하려면 해당 디렉터리를 mod 폴더에서 `~/mods/git-branch`와 같은 별도 위치로 복사하십시오. 그런 다음 로드 방법을 선택합니다.
60 60
61* **시작하는 세션에서**: 셸에서 `claude --plugin-dir ~/mods/git-branch`를 실행하세요61* **직접 시작하는 세션에서**: 셸에서 `claude --plugin-dir ~/mods/git-branch`를 실행합니다
62* **다른 사람들을 위해**: [마켓플레이스에 추가](#share-your-mod)하여 설치할 수 있도록 하세요62* **다른 사람을 위해**: 다른 사람이 설치할 수 있도록 [마켓플레이스에 추가](#share-your-mod)합니다
63 63
64<h3 id="sessions-that-skip-the-approval">64<h3 id="sessions-that-skip-the-approval">
65 Claude가 작성한 모드가 로드될 수 없는 세션65 Claude가 작성한 mod를 로드할 수 없는 세션
66</h3>66</h3>
67 67
68Claude가 작성한 모드는 승인 후에만 로드되며, 모드가 실행될 수 있는 신뢰할 수 있는 작업 공간에서만 로드됩니다. 이 세션에서는 로드되지 않습니다:68Claude가 작성한 mod는 mod 실행이 허용된 신뢰할 수 있는 워크스페이스에서 사용자가 승인한 후에만 로드됩니다. 다음 세션에서는 로드되지 않습니다.
69 69
70* **승인할 사람이 없음**: `claude -p` 실행 또는 [`dontAsk` 모드](/docs/ko/permission-modes)와 같이 세션이 프롬프트를 표시할 수 없습니다70* **승인할 사람이 없는 경우**: `claude -p` 실행이나 [`dontAsk` 모드](/docs/ko/permission-modes)처럼 세션에서 프롬프트를 표시할 수 없는 경우
71* **작업 공간을 신뢰하지 않음**: 디렉토리에 대한 신뢰 프롬프트를 수락하지 않았습니다71* **워크스페이스를 신뢰하지 않는 경우**: 해당 디렉터리에 대한 신뢰 프롬프트를 수락하지 않은 경우
72* **모드가 중지됨**: `--safe-mode` 또는 `--bare`로 시작했거나, `disableAllHooks`를 설정했거나, 조직의 [관리 설정이 차단](/docs/ko/plugins/mods/admin#choose-how-much-to-allow)했습니다72* **mod가 비활성화된 경우**: `--safe-mode` 또는 `--bare`로 시작했거나, `disableAllHooks`를 설정했거나, 조직의 [관리형 설정에서 차단한](/docs/ko/plugins/mods/admin#choose-how-much-to-allow) 경우
73 73
74<h2 id="write-a-mod-yourself">74<h2 id="write-a-mod-yourself">
75 모드 직접 작성75 직접 mod 작성하기
76</h2>76</h2>
77 77
78이 튜토리얼에서는 Claude가 수행하는 도구 호출을 세고, Claude가 작동하는 동안 스피너 옆에 개수를 표시하고, 개수를 인쇄하는 `/tally` 명령을 추가하는 `first-mod`라는 모드를 빌드합니다. 그런 다음 Claude Code가 모드 옆에 작성한 타입 선언을 읽고 `claude plugin validate`를 실행합니다. 함께 버전이 제공하는 이벤트 및 메서드와 Claude Code가 코드에서 읽는 것을 보여줍니다.78이 튜토리얼에서는 Claude가 수행하는 도구 호출 횟수를 세고, Claude가 작업하는 동안 스피너 옆에 그 횟수를 표시하며, 횟수를 출력하는 `/tally` 명령을 추가하는 `first-mod`라는 mod를 만듭니다. 그런 다음 Claude Code가 mod 옆에 작성하는 타입 선언을 읽고 `claude plugin validate`를 실행합니다. 이 두 가지를 통해 사용 중인 버전이 제공하는 이벤트와 메서드, 그리고 Claude Code가 코드에서 읽어 들이는 내용을 확인할 수 있습니다.
79 79
80이 녹화는 완성된 모드를 보여줍니다. 스피너는 도구 호출을 세고, `/tally`는 개수를 인쇄하며, 코드 편집은 세션이 실행되는 동안 적용됩니다:80다음 녹화 영상은 완성된 mod를 보여 줍니다. 스피너가 도구 호출 횟수를 세고, `/tally`가 횟수를 출력하며, 세션이 실행되는 동안 코드를 수정하면 바로 적용됩니다.
81 81
82<Frame>82<Frame>
83 <video autoPlay muted loop playsInline controls className="w-full dark:hidden" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=eb561134afa90375777408453ba51c77" aria-label="Claude Code 세션에서 '여기 파일을 나열하고 README를 읽어'라는 프롬프트가 입력되고 전송됩니다. 스피너는 '생각 중 · 도구 호출: 1'을 읽고 Claude가 작동하면서 개수가 증가합니다. /tally 명령은 'first-mod: Claude가 이 모드가 로드된 이후 3개의 도구 호출을 했습니다'를 인쇄합니다. 한 줄은 first-mod가 다시 로드되었고 네 개의 hooks를 나열합니다. 다음 프롬프트에서 스피너는 '생각 중 · 사용된 도구: 1'을 읽습니다." data-path="images/mods-first-mod-light.mp4" />83 <video autoPlay muted loop playsInline controls className="w-full dark:hidden" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=eb561134afa90375777408453ba51c77" aria-label="Claude Code 세션에서 'list the files here and read the README' 프롬프트를 입력하고 전송합니다. 스피너에 'Thinking · tool calls: 1'이 표시되고 Claude가 작업하면서 횟수가 증가합니다. /tally 명령이 'first-mod: Claude has made 3 tool calls since this mod loaded'를 출력합니다. first-mod가 다시 로드되었다는 줄이 표시되고 네 개의 훅이 나열됩니다. 다음 프롬프트에서 스피너에 'Thinking · tools used: 1'이 표시됩니다." data-path="images/mods-first-mod-light.mp4" />
84 84
85 <video autoPlay muted loop playsInline controls className="w-full hidden dark:block" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-dark.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=09779dadc7ef66c2b1e2da0c2e31ac72" aria-label="Claude Code 세션에서 '여기 파일을 나열하고 README를 읽어'라는 프롬프트가 입력되고 전송됩니다. 스피너는 '생각 중 · 도구 호출: 1'을 읽고 Claude가 작동하면서 개수가 증가합니다. /tally 명령은 'first-mod: Claude가 이 모드가 로드된 이후 3개의 도구 호출을 했습니다'를 인쇄합니다. 한 줄은 first-mod가 다시 로드되었고 네 개의 hooks를 나열합니다. 다음 프롬프트에서 스피너는 '생각 중 · 사용된 도구: 1'을 읽습니다." data-path="images/mods-first-mod-dark.mp4" />85 <video autoPlay muted loop playsInline controls className="w-full hidden dark:block" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-dark.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=09779dadc7ef66c2b1e2da0c2e31ac72" aria-label="Claude Code 세션에서 'list the files here and read the README' 프롬프트를 입력하고 전송합니다. 스피너에 'Thinking · tool calls: 1'이 표시되고 Claude가 작업하면서 횟수가 증가합니다. /tally 명령이 'first-mod: Claude has made 3 tool calls since this mod loaded'를 출력합니다. first-mod가 다시 로드되었다는 줄이 표시되고 네 개의 훅이 나열됩니다. 다음 프롬프트에서 스피너에 'Thinking · tools used: 1'이 표시됩니다." data-path="images/mods-first-mod-dark.mp4" />
86</Frame>86</Frame>
87 87
88세 개의 파일을 작성합니다:88세 개의 파일을 작성합니다.
89 89
90```text theme={null}90```text theme={null}
91first-mod/91first-mod/
97```97```
98 98
99* **`plugin.json`**: 플러그인의 [매니페스트](/docs/ko/plugins/manifest-reference)99* **`plugin.json`**: 플러그인의 [매니페스트](/docs/ko/plugins/manifest-reference)
100* **`hooks.json`**: [코드 파일을 가리킵니다](/docs/ko/plugins/mods/reference#files)100* **`hooks.json`**: [코드 파일을 가리킴](/docs/ko/plugins/mods/reference#files)
101* **`register.js`**: 코드, hooks 모듈이라고 불립니다101* **`register.js`**: 훅 모듈이라고 부르는 사용자의 코드
102 102
103<Steps>103<Steps>
104 <Step title="플러그인 디렉토리 생성">104 <Step title="플러그인 디렉터리 만들기">
105 파일을 보관할 두 디렉토리를 생성하세요:105 파일을 담을 두 개의 디렉터리를 만듭니다.
106 106
107 <Tabs>107 <Tabs>
108 <Tab title="Bash or Zsh">108 <Tab title="Bash 또는 Zsh">
109 ```bash theme={null}109 ```bash theme={null}
110 mkdir -p first-mod/.claude-plugin first-mod/hooks110 mkdir -p first-mod/.claude-plugin first-mod/hooks
111 ```111 ```
119 </Tabs>119 </Tabs>
120 </Step>120 </Step>
121 121
122 <Step title="매니페스트 작성">122 <Step title="매니페스트 작성하기">
123 모드는 플러그인이며, 모드는 [매니페스트](/docs/ko/plugins/manifest-reference)가 필요합니다. 이 모드의 매니페스트에는 특별한 필드가 없습니다. 이를 `first-mod/.claude-plugin/plugin.json`으로 저장하세요:123 mod는 플러그인이며, mod에는 [매니페스트](/docs/ko/plugins/manifest-reference)가 필요합니다. 이 mod의 매니페스트에는 특별한 필드가 없습니다. 다음 내용을 `first-mod/.claude-plugin/plugin.json`으로 저장합니다.
124 124
125 ```json first-mod/.claude-plugin/plugin.json theme={null}125 ```json first-mod/.claude-plugin/plugin.json theme={null}
126 {126 {
132 ```132 ```
133 </Step>133 </Step>
134 134
135 <Step title="Claude Code에 코드 위치 알리기">135 <Step title="Claude Code에 코드 위치 알려 주기">
136 Claude Code가 플러그인을 로드할 때, 플러그인의 `hooks/hooks.json`을 읽습니다. 해당 파일의 `modules` 키는 코드의 경로를 제공하며, 이를 가지는 것이 플러그인을 모드로 만드는 것입니다. 한 경로를 나열하세요. `hooks.json`에 상대적입니다. 여기서는 다음 단계에서 작성할 `register.js`를 가리킵니다.136 Claude Code는 플러그인을 로드할 때 플러그인의 `hooks/hooks.json`을 읽습니다. 이 파일의 `modules` 키는 코드의 경로를 지정하며, 이 키가 있어야 플러그인이 mod가 됩니다. `hooks.json`을 기준으로 한 상대 경로 하나를 나열합니다. 여기서는 다음 단계에서 작성할 `register.js`를 가리킵니다.
137 137
138 이를 `first-mod/hooks/hooks.json`으로 저장하세요:138 다음 내용을 `first-mod/hooks/hooks.json`으로 저장합니다.
139 139
140 ```json first-mod/hooks/hooks.json theme={null}140 ```json first-mod/hooks/hooks.json theme={null}
141 {141 {
145 ```145 ```
146 </Step>146 </Step>
147 147
148 <Step title="코드 작성">148 <Step title="코드 작성하기">
149 이 파일은 모드의 코드이며, hooks 모듈이라고 불립니다. 모드가 로드될 때, Claude Code는 파일이 내보내는 `register` 함수를 호출하고 [`on`](/docs/ko/plugins/mods/reference#the-hook-function)이라는 함수를 전달합니다. `on`에 대한 각 호출은 이벤트 핸들러(hook이라고 불림)를 이름이 지정한 이벤트에 등록합니다.149 이 파일은 훅 모듈이라고 부르는 mod의 코드입니다. mod가 로드되면 Claude Code는 파일이 내보내는 `register` 함수를 호출하고 [`on`](/docs/ko/plugins/mods/reference#the-hook-function)이라는 함수를 전달합니다. `on`을 호출할 때마다 지정한 이벤트에 대한 이벤트 핸들러, 즉 훅이 등록됩니다.
150 150
151 이를 `first-mod/hooks/register.js`로 저장하세요:151 다음 내용을 `first-mod/hooks/register.js`로 저장합니다.
152 152
153 ```javascript first-mod/hooks/register.js theme={null}153 ```javascript first-mod/hooks/register.js theme={null}
154 // The count, shared by the hooks below154 // The count, shared by the hooks below
190 }190 }
191 ```191 ```
192 192
193 파일은 `calls`에 개수를 유지하고 네 개의 hooks를 등록합니다:193 이 파일은 `calls`에 횟수를 저장하고 네 개의 훅을 등록합니다.
194 194
195 * \*\*[`session.start`](/docs/ko/plugins/mods/reference#session)\*\*는 세션이 시작될 때, 첫 번째 프롬프트 전에 실행되며, 모드가 다시 로드될 때마다 실행됩니다. Claude Code에 `/tally` 명령을 추가합니다.195 * \*\*[`session.start`](/docs/ko/plugins/mods/reference#session)\*\*는 세션이 시작될 때 첫 프롬프트 전에 실행되며, mod가 다시 로드될 때마다 다시 실행됩니다. Claude Code에 `/tally` 명령을 추가합니다.
196 * \*\*[`tool.call`](/docs/ko/plugins/mods/reference#tools)\*\*는 Claude가 도구를 사용하려고 할 때마다 실행됩니다. `calls`에 1을 더하고 Claude Code에 인터페이스를 다시 그리도록 요청합니다.196 * \*\*[`tool.call`](/docs/ko/plugins/mods/reference#tools)\*\*은 Claude가 도구를 사용하려고 할 때마다 실행됩니다. `calls`에 1을 더하고 Claude Code에 인터페이스를 다시 그리도록 요청합니다.
197 * \*\*[`command.run`](/docs/ko/plugins/mods/reference#commands-and-configuration)\*\*은 `/tally`를 입력할 때 실행됩니다. 인쇄할 텍스트를 반환합니다.197 * \*\*[`command.run`](/docs/ko/plugins/mods/reference#commands-and-configuration)\*\*은 `/tally`를 입력할 때 실행됩니다. 출력할 텍스트를 반환합니다.
198 * \*\*[`ui.render`](/docs/ko/plugins/mods/reference#interface)\*\*는 Claude Code가 스피너를 그릴 때마다 실행됩니다. 스피너의 단어 뒤에 개수를 추가합니다.198 * \*\*[`ui.render`](/docs/ko/plugins/mods/reference#interface)\*\*는 Claude Code가 스피너를 그릴 때마다 실행됩니다. 스피너의 단어 뒤에 횟수를 추가합니다.
199 199
200 [예제 모드가 어떻게 작동하는지](#how-the-example-mod-works)는 각 hook이 취하는 세 개의 인수와 각각이 반환하는 것을 설명합니다.200 [예제 mod의 작동 방식](#how-the-example-mod-works)에서 각 훅이 받는 세 개의 인수와 각 훅이 반환하는 값을 설명합니다.
201 </Step>201 </Step>
202 202
203 <Step title="모드 로드">203 <Step title="mod 로드하기">
204 `--plugin-dir` 플래그로 Claude Code를 시작하세요. 이는 설치하지 않고 한 세션에 대해 플러그인 디렉토리를 로드합니다:204 `--plugin-dir` 플래그를 사용하여 Claude Code를 시작합니다. 이 플래그는 플러그인 디렉터리를 설치하지 않고 한 세션 동안 로드합니다.
205 205
206 ```bash theme={null}206 ```bash theme={null}
207 claude --plugin-dir ./first-mod207 claude --plugin-dir ./first-mod
208 ```208 ```
209 </Step>209 </Step>
210 210
211 <Step title="모드 시도">211 <Step title="mod 사용해 보기">
212 Claude에게 몇 가지 도구 호출을 수행하는 작업을 요청하세요. 예를 들어 `여기 파일을 나열하고 README를 읽어`. Claude가 작동하는 동안 스피너의 단어 뒤에 증가하는 개수가 나타납니다. 예를 들어 `생각 중 · 도구 호출: 2…`. Claude가 완료되면 `/tally`를 입력하고 Enter를 누르세요. 트랜스크립트는 `first-mod: Claude가 이 모드가 로드된 이후 2개의 도구 호출을 했습니다`를 표시하며, 자신의 개수가 있습니다. Claude Code는 플러그인의 이름을 명령의 텍스트 앞에 놓습니다.212 `list the files here and read the README`처럼 여러 번의 도구 호출이 필요한 작업을 Claude에게 요청합니다. Claude가 작업하는 동안 스피너의 단어 뒤에 `Thinking · tool calls: 2…`처럼 증가하는 횟수가 표시됩니다. Claude가 작업을 마치면 `/tally`를 입력하고 Enter 키를 누릅니다. 트랜스크립트에 실제 횟수와 함께 `first-mod: Claude has made 2 tool calls since this mod loaded`가 표시됩니다. Claude Code는 명령의 텍스트 앞에 플러그인 이름을 붙입니다.
213 213
214 대화형 세션 없이 명령을 확인하려면 비대화형 모드에서 실행하세요:214 대화형 세션 없이 명령을 확인하려면 비대화형 모드에서 실행합니다.
215 215
216 ```bash theme={null}216 ```bash theme={null}
217 claude -p "/tally" --plugin-dir ./first-mod217 claude -p "/tally" --plugin-dir ./first-mod
221 first-mod: Claude has made 0 tool calls since this mod loaded221 first-mod: Claude has made 0 tool calls since this mod loaded
222 ```222 ```
223 223
224 `/tally`가 명령 목록에 없으면 모듈이 로드되지 않았습니다. [모드가 아무것도 하지 않는 이유 찾기](/docs/ko/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing)를 참조하세요.224 명령 목록에 `/tally`가 없다면 모듈이 로드되지 않은 것입니다. [mod가 아무 동작도 하지 않는 원인 찾기](/docs/ko/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing)를 참조하세요.
225 </Step>225 </Step>
226 226
227 <Step title="세션이 실행되는 동안 코드 변경">227 <Step title="세션 실행 중에 코드 변경하기">
228 세션을 열어 두세요. `register.js`에서 `ui.render` hook의 `' · tool calls: '`를 `' · tools used: '`로 변경하고 저장하세요. 강조된 줄이 변경되는 줄입니다:228 세션을 열어 둔 상태로 `register.js`의 `ui.render` 훅에서 `' · tool calls: '`를 `' · tools used: '`로 변경하고 저장합니다. 강조 표시된 줄이 변경되는 줄입니다.
229 229
230 ```javascript first-mod/hooks/register.js {4} theme={null}230 ```javascript first-mod/hooks/register.js {4} theme={null}
231 // Runs each time Claude Code draws the spinner231 // Runs each time Claude Code draws the spinner
235 })235 })
236 ```236 ```
237 237
238 트랜스크립트의 한 줄은 `first-mod`가 다시 로드되었고 hooks를 나열하며, 다음 스피너는 새 텍스트를 사용합니다. 예를 들어 `생각 중 · 사용된 도구: 1…`.238 트랜스크립트에 `first-mod`가 다시 로드되었다는 줄과 함께 해당 훅 목록이 표시되고, 다음 스피너에는 `Thinking · tools used: 1…`처럼 새 텍스트가 사용됩니다.
239 </Step>239 </Step>
240</Steps>240</Steps>
241 241
242<h3 id="how-the-example-mod-works">242<h3 id="how-the-example-mod-works">
243 예제 모드가 어떻게 작동하는지243 예제 mod의 작동 방식
244</h3>244</h3>
245 245
246`on`에 전달하는 각 함수는 hook이며, 이는 이벤트 핸들러입니다. Claude Code는 모든 hook에 동일한 세 개의 인수를 전달합니다:246`on`에 전달하는 각 함수는 이벤트 핸들러인 훅입니다. Claude Code는 모든 훅에 동일한 세 개의 인수를 전달합니다.
247 247
248* **mods API**, `$`라고 이름 지어짐: 모드가 자신 외부에 도달하기 위해 호출할 수 있는 모든 메서드. `$.ui` 및 `$.command`와 같은 [네임스페이스](/docs/ko/plugins/mods/reference#mods-api-methods)에 있습니다248* **mods API**(`$`): mod가 외부에 접근하기 위해 호출할 수 있는 모든 메서드로, `$.ui`, `$.command`와 같은 [네임스페이스](/docs/ko/plugins/mods/reference#mods-api-methods)로 구성됩니다
249* **이벤트**, `e`라고 이름 지어짐: [이벤트의 입력](/docs/ko/plugins/mods/reference#events). 도구 호출의 이름 및 인수와 같은 일반 데이터249* **이벤트**(`e`): 도구 호출의 이름과 인수 등 [이벤트의 입력](/docs/ko/plugins/mods/reference#events)을 일반 데이터로 담고 있습니다
250* **다음 핸들러**, [`next`](/docs/ko/plugins/mods/events#how-a-hook-handles-an-event)라고 이름 지어짐: 이벤트를 다른 모드로 전달한 다음 Claude Code의 자체 동작으로 전달하고 결과를 반환하는 함수250* **다음 핸들러**([`next`](/docs/ko/plugins/mods/events#how-a-hook-handles-an-event)): 이벤트를 다른 mod로, 이어서 Claude Code 자체의 동작으로 전달하고 그 결과를 반환하는 함수입니다
251 251
252`first-mod`의 hooks는 hook이 할 수 있는 세 가지 방식으로 이벤트를 처리합니다:252`first-mod`의 훅은 다음과 같은 방식으로 이벤트를 처리합니다.
253 253
254* **관찰**: `session.start` hook은 명령을 등록하고, `tool.call` hook은 호출을 세고 다시 그리도록 요청합니다. 둘 다 `next(e)`를 반환하므로 세션이 시작되고 도구가 평소대로 실행됩니다.254* **관찰**: `session.start` 훅은 명령을 등록하고, `tool.call` 훅은 호출 횟수를 세고 다시 그리기를 요청합니다. 두 훅 모두 `next(e)`를 반환하므로 세션이 시작되고 도구가 평소대로 실행됩니다.
255* **답변**: `command.run` hook은 자신의 결과를 반환하고 `next`를 호출하지 않습니다. `on`의 두 번째 인수인 `{ command: 'tally' }`는 [matcher](/docs/ko/plugins/mods/events#filter-which-events-a-hook-handles)라고 불리는 필터이므로 hook은 `/tally`에 대해서만 실행됩니다.255* **응답**: `command.run` 훅은 자체 결과를 반환하며 `next`를 호출하지 않습니다. `on`의 두 번째 인수인 `{ command: 'tally' }`는 [matcher](/docs/ko/plugins/mods/events#filter-which-events-a-hook-handles)라고 부르는 필터이므로, 이 훅은 `/tally`에 대해서만 실행됩니다.
256* **다시 쓰기**: `ui.render` hook은 `e`의 복사본과 함께 `next`를 호출하며, 그 `suffix`는 개수를 보유하므로 Claude Code는 단어 뒤에 텍스트가 있는 일반적인 스피너를 그립니다256* **재작성**: `ui.render` 훅은 `suffix`에 횟수를 담은 `e`의 복사본으로 `next`를 호출하므로, Claude Code는 평소의 스피너를 그리되 단어 뒤에 사용자의 텍스트를 표시합니다
257 257
258Claude Code는 `--plugin-dir`으로 로드된 디렉토리를 감시하고 파일이 변경될 때 hooks 모듈을 핫 리로드합니다. 각 리로드는 `register`를 다시 실행하므로 `calls`는 `0`으로 돌아가고 `/tally`는 다시 세기 시작합니다. 리로드 전체에서 값을 유지하려면 [상태 유지](/docs/ko/plugins/mods/interface#keep-state)를 참조하세요.258Claude Code는 `--plugin-dir`로 로드된 디렉터리를 감시하며, 그 안의 파일이 변경되면 훅 모듈을 핫 리로드합니다. 다시 로드할 때마다 `register`가 다시 실행되므로 `calls`가 `0`으로 초기화되고 `/tally`는 처음부터 다시 횟수를 셉니다. 다시 로드해도 값을 유지하려면 [상태 유지하기](/docs/ko/plugins/mods/interface#keep-state)를 참조하세요.
259 259
260<h2 id="keep-working-on-a-mod">260<h2 id="keep-working-on-a-mod">
261 모드에서 계속 작업하기261 mod 계속 작업하기
262</h2>262</h2>
263 263
264모드가 로드되면 Claude가 변경하도록 할 수 있으며, 버전의 타입 정의에 대해 코드를 확인하고, Claude Code가 찾은 이벤트 및 호출을 나열하고, 테스트할 수 있습니다.264mod가 로드되면 Claude에게 mod 변경을 요청하고, 사용 중인 버전의 타입 정의에 맞춰 코드를 검사하고, Claude Code가 mod에서 찾은 이벤트와 호출을 나열하고, mod를 테스트할 수 있습니다.
265 265
266<h3 id="change-a-mod-with-claude">266<h3 id="change-a-mod-with-claude">
267 Claude로 모드 변경하기267 Claude로 mod 변경하기
268</h3>268</h3>
269 269
270이미 가지고 있는 모드를 변경하려면 `--plugin-dir`이 모드의 디렉토리를 가리키도록 하여 세션을 시작하세요. 그러면 Claude가 작성한 것이 동일한 세션에서 로드됩니다:270이미 있는 mod를 변경하려면 `--plugin-dir`이 mod의 디렉터리를 가리키도록 하여 세션을 시작합니다. 그러면 Claude가 작성한 내용이 같은 세션에서 로드됩니다.
271 271
272```bash theme={null}272```bash theme={null}
273claude --plugin-dir ./first-mod273claude --plugin-dir ./first-mod
274```274```
275 275
276그런 다음 변경을 요청하세요. 예를 들어 `이 모드에 /tally-reset 명령을 추가하여 tally를 0으로 설정하세요`. Claude는 hooks 모듈을 편집하고, `claude plugin validate`를 실행하고, 보고하는 것을 수정합니다. `--plugin-dir`으로 로드하는 디렉토리는 [보호된 경로](/docs/ko/permission-modes#protected-paths)이므로 `default` 및 `acceptEdits` 모드에서 모드에 대한 Claude의 각 편집을 승인하도록 요청받습니다. 보호된 경로 테이블은 다른 권한 모드의 결과를 제공합니다.276그런 다음 변경 사항을 요청합니다. 예를 들어 `add a /tally-reset command to this mod that sets the tally back to zero`와 같이 요청할 수 있습니다. Claude는 훅 모듈을 편집하고, `claude plugin validate`를 실행하고, 보고된 문제를 수정합니다. `--plugin-dir`로 로드한 디렉터리는 [보호된 경로](/docs/ko/permission-modes#protected-paths)이므로, `default` 및 `acceptEdits` 모드에서는 Claude가 mod를 편집할 때마다 승인을 요청받습니다. 다른 권한 모드에서의 결과는 보호된 경로 표에서 확인할 수 있습니다.
277 277
278Claude가 턴 중에 저장한 파일은 턴이 끝날 때 다시 로드되므로 Claude가 완료되는 즉시 `/tally-reset`을 시도할 수 있습니다.278Claude가 턴 중에 저장한 파일은 턴이 끝날 때 다시 로드되므로, Claude가 작업을 마치는 즉시 `/tally-reset`을 사용해 볼 수 있습니다.
279 279
280<h3 id="get-the-types-for-your-build">280<h3 id="get-the-types-for-your-build">
281 버전의 타입 정의 가져오기281 사용 중인 버전의 타입 정의 가져오기
282</h3>282</h3>
283 283
284Claude Code가 `--plugin-dir`에 전달한 디렉토리에서 모드를 로드하거나 다시 로드할 때마다, 또는 [Claude가 작성한 모드](#ask-claude-for-a-mod)일 때마다, `.d.ts`로 끝나는 TypeScript 선언 파일을 모드의 디렉토리 내 `.claude-plugin/types/`에 작성합니다. 이들은 실행 중인 Claude Code 버전의 정확한 이벤트, mods API 메서드 및 요소를 설명하므로 편집기는 hooks를 자동 완성하고 타입 확인할 수 있습니다. 선언을 온라인으로 탐색하려면 Claude Code 저장소의 [`mods/types/claude-code.d.ts`](https://github.com/anthropics/claude-code/blob/main/mods/types/claude-code.d.ts)를 읽으세요. 첫 번째 줄은 이를 작성한 버전의 이름을 지정합니다. 디렉토리는 다음 파일을 보유합니다:284Claude Code는 `--plugin-dir`에 전달한 디렉터리의 mod나 [Claude가 작성한](#ask-claude-for-a-mod) mod를 로드하거나 다시 로드할 때마다 `.d.ts`로 끝나는 TypeScript 선언 파일을 mod 디렉터리 안의 `.claude-plugin/types/`에 작성합니다. 이 파일은 실행 중인 Claude Code 버전의 정확한 이벤트, mods API 메서드, 요소를 기술하므로 편집기에서 훅을 자동 완성하고 타입 검사할 수 있습니다. 선언을 온라인에서 살펴보려면 Claude Code 저장소의 [`mods/types/claude-code.d.ts`](https://github.com/anthropics/claude-code/blob/main/mods/types/claude-code.d.ts)를 읽어 보세요. 이 파일의 첫 줄에는 파일을 작성한 버전이 명시되어 있습니다. 디렉터리에는 다음 파일이 있습니다.
285 285
286| 경로 | 선언하는 것 |286| 경로 | 선언 내용 |
287| :- | :- |287| :- | :- |
288| `claude-code/index.d.ts` | 모든 이벤트 및 입력과 결과, 모든 mods API 네임스페이스 및 메서드, 각 표면이 그릴 수 있는 요소 |288| `claude-code/index.d.ts` | 모든 이벤트와 그 입력 및 결과, 모든 mods API 네임스페이스와 메서드, 각 사용 환경에서 그릴 수 있는 요소 |
289| `claude-code-tools/index.d.ts` | 내장 도구의 입력 및 결과. `e.tool === 'Bash'` 확인이 `e`를 좁히도록 |289| `claude-code-tools/index.d.ts` | 기본 제공 도구의 입력과 결과. `e.tool === 'Bash'`를 검사하면 `e`의 타입이 좁혀집니다 |
290| `claude-code-mcp/index.d.ts` | 모드에서 파일을 마지막으로 저장했을 때 연결된 MCP 도구의 입력 |290| `claude-code-mcp/index.d.ts` | mod의 파일을 마지막으로 저장했을 때 연결되어 있던 MCP 도구의 입력 |
291| 플러그인 이름의 디렉토리에 있는 `index.d.ts` | 해당 플러그인이 mods API에 추가하는 것. `plugin.json`이 `dependencies` 아래에 나열하는 각 플러그인에 대해 하나의 디렉토리가 있습니다. |291| 플러그인 이름을 딴 디렉터리의 `index.d.ts` | 해당 플러그인이 mods API에 추가하는 내용. `plugin.json`의 `dependencies`에 나열된 플러그인마다 디렉터리가 하나씩 있습니다. |
292| `tsconfig.json` | hooks 모듈에 맞는 컴파일러 옵션 |292| `tsconfig.json` | 훅 모듈에 맞는 컴파일러 옵션 |
293 293
294모드에 자신의 `tsconfig.json`이 없으면 Claude Code는 생성된 것을 확장하는 모드의 루트에 하나를 추가하므로 편집기와 `tsc -p ./first-mod`는 추가 설정 없이 모드를 타입 확인합니다.294mod에 자체 `tsconfig.json`이 없으면 Claude Code는 생성된 파일을 확장하는 `tsconfig.json`을 mod의 루트에 추가하므로, 추가 설정 없이 편집기와 `tsc -p ./first-mod`로 mod를 타입 검사할 수 있습니다.
295 295
296이벤트 및 메서드는 릴리스 간에 변경될 수 있으므로 불일치할 때 이 페이지를 포함한 모든 페이지보다 이 파일을 신뢰하세요.296이벤트와 메서드는 릴리스마다 바뀔 수 있으므로, 이 페이지를 포함한 어떤 페이지와 내용이 다르다면 이 파일을 신뢰하세요.
297 297
298`claude-code/index.d.ts`는 모든 mods API 메서드에 대한 주석 및 예제가 있는 빌드의 가장 완전한 참조입니다. 무언가를 찾으려면 파일에서 이름(예: `'tool.call'`)을 검색하세요.298`claude-code/index.d.ts`는 사용 중인 빌드에 대한 가장 완전한 참조 자료로, 모든 mods API 메서드에 대한 설명과 예제를 포함합니다. 항목을 찾으려면 `'tool.call'`처럼 이름으로 파일을 검색하세요.
299 299
300<h3 id="check-what-claude-code-reads-from-your-mod">300<h3 id="check-what-claude-code-reads-from-your-mod">
301 Claude Code가 모드에서 읽는 것 확인하기301 Claude Code가 mod에서 읽는 내용 확인하기
302</h3>302</h3>
303 303
304모드를 Claude Code가 보는 방식으로 보려면, 코드를 실행하거나 세션을 시작하지 않고 `claude plugin validate`를 사용하세요. 매니페스트를 확인하고 Claude Code가 모드를 로드할 때 실행하는 hooks 모듈의 소스에 대해 동일한 정적 분석을 실행합니다. 셸에서 모드의 디렉토리에서 실행하세요:304코드를 실행하거나 세션을 시작하지 않고 Claude Code가 보는 방식 그대로 mod를 확인하려면 `claude plugin validate`를 사용합니다. 이 명령은 매니페스트를 검사하고, Claude Code가 mod를 로드할 때 실행하는 것과 동일한 정적 분석을 훅 모듈의 소스에 대해 실행합니다. 셸에서 mod의 디렉터리를 대상으로 실행합니다.
305 305
306```bash theme={null}306```bash theme={null}
307claude plugin validate ./first-mod307claude plugin validate ./first-mod
308```308```
309 309
310`first-mod`의 경우 출력에는 다음 줄이 포함됩니다.310`first-mod`의 경우 출력에 다음 줄이 포함됩니다.
311 311
312```text theme={null}312```text theme={null}
313 ❯ ./register.js hooks: session.start, tool.call, command.run{command=tally}, ui.render{component=Spinner}313 ❯ ./register.js hooks: session.start, tool.call, command.run{command=tally}, ui.render{component=Spinner}
316✔ Validation passed316✔ Validation passed
317```317```
318 318
319`hooks:` 줄은 모듈이 hook하는 이벤트를 나열하며, 각각은 중괄호에 필터가 있습니다. `calls:` 줄은 호출하는 모든 mods API 메서드를 나열합니다. 환경 변수를 읽거나 설정하는 모듈도 `env reads:` 및 `env writes:` 줄을 가지며, [`$.state`](/docs/ko/plugins/mods/interface#keep-state)를 사용하는 모듈은 `state reads:` 및 `state writes:` 줄을 가집니다.319`hooks:` 줄에는 모듈이 훅하는 이벤트가 중괄호 안의 필터와 함께 나열됩니다. `calls:` 줄에는 모듈이 호출하는 모든 mods API 메서드가 나열됩니다. 환경 변수를 읽거나 설정하는 모듈에는 `env reads:` 및 `env writes:` 줄도 표시되고, [`$.state`](/docs/ko/plugins/mods/interface#keep-state)를 사용하는 모듈에는 `state reads:` 및 `state writes:` 줄이 표시됩니다.
320 320
321hook하려고 한 이벤트가 첫 번째 줄에서 누락되면 Claude Code도 해당 hook을 호출하지 않습니다. 일반적인 원인은 철자가 잘못된 이벤트 이름이며, 명령은 `"tool.calls" is not an event`와 같은 오류로 보고합니다.321처리하려던 이벤트가 첫 번째 줄에 없다면 Claude Code도 해당 훅을 호출하지 않습니다. 일반적인 원인은 이벤트 이름의 오타이며, 이 명령은 이를 `"tool.calls" is not an event`와 같은 오류로 보고합니다.
322 322
323정적 분석이 모든 hook과 호출을 찾을 수 있도록 다음 규칙을 따르세요:323정적 분석이 모든 훅과 호출을 찾을 수 있도록 다음 규칙을 따르세요.
324 324
325* 각 mods API 호출을 완전히 철자하세요: `$`, 네임스페이스, 메서드. 예를 들어 `$.store.get('notes')`. `$`를 동일한 파일의 최상위 수준에서 선언된 함수로 전달할 수 있으며, `loadNotes`라는 함수의 경우 `calls:` 줄은 `$.store.get (via loadNotes)`를 읽습니다. `$`를 메서드, 함수 내부에서 정의된 함수, 또는 파일의 다른 부분에서 가져온 함수로 전달하면 검증이 실패합니다. [`$.state`](/docs/ko/plugins/mods/interface#keep-state)가 사용하는 `read` 및 `update` 함수는 이를 취할 수 있는 가져오기입니다. `$` 또는 네임스페이스 중 하나를 변수에 할당하거나, 구조 분해하거나, 계산된 이름으로 인덱싱하지 마세요. `const ui = $.ui`는 `$.ui is used as a value`로 실패합니다.325* 각 mods API 호출은 `$.store.get('notes')`처럼 `$`, 네임스페이스, 메서드 순으로 전체를 작성합니다. 같은 파일의 최상위에 선언된 함수에는 `$`를 전달할 수 있으며, `loadNotes`라는 함수의 경우 `calls:` 줄에 `$.store.get (via loadNotes)`로 표시됩니다. 메서드, 훅 안에서 정의된 함수, 또는 다른 파일에서 가져온 함수에 `$`를 전달하면 검증에 실패합니다. [`$.state`](/docs/ko/plugins/mods/interface#keep-state)가 사용하는 `read` 및 `update` 함수는 `$`를 받을 수 있는 가져온 함수입니다. `$`나 그 네임스페이스를 변수에 할당하거나, 구조 분해하거나, 계산된 이름으로 인덱싱하지 마세요. `const ui = $.ui`는 `$.ui is used as a value` 오류로 실패합니다.
326* 각 `on` 호출에서 이벤트 이름을 문자열 리터럴로 작성하세요. 예를 들어 `'tool.call'`. 변수 또는 이름 목록에 대한 루프는 `the event name passed to on() is not a string literal`로 실패합니다.326* 각 `on` 호출의 이벤트 이름은 `'tool.call'`처럼 문자열 리터럴로 작성합니다. 변수나 이름 목록에 대한 반복문을 사용하면 `the event name passed to on() is not a string literal` 오류로 실패합니다.
327* `register` 내부에서 `on`이라는 두 번째 변수 또는 매개변수를 선언하지 마세요. 검증은 `"on" is declared again (shadowed)`로 실패합니다.327* `register` 안에서 `on`이라는 이름의 변수나 매개변수를 다시 선언하지 마세요. 검증이 `"on" is declared again (shadowed)` 오류로 실패합니다.
328* 상대 경로로 플러그인 디렉토리 내 파일에서만 가져오세요. 허용되는 유일한 베어 가져오기는 타입 및 몇 가지 도우미를 위한 `claude-code`입니다.328* 플러그인 디렉터리 안의 파일만 상대 경로로 가져옵니다. 허용되는 유일한 bare import는 타입과 몇 가지 헬퍼를 위한 `claude-code`입니다.
329* 파일의 맨 위에 `import` 선언을 사용하세요. 예를 들어 `import { name } from './file.js'`. 동적 `import()`는 `a dynamic import(); a hooks module imports its own files with an import declaration`로 실패합니다.329* `import { name } from './file.js'`처럼 파일 상단에 `import` 선언을 사용합니다. 동적 `import()`는 `a dynamic import(); a hooks module imports its own files with an import declaration` 오류로 실패합니다.
330* 모든 파일을 ES 모듈로 작성하세요. `import`를 사용하고 `require`는 사용하지 마세요. [참조](/docs/ko/plugins/mods/reference#files)는 Claude Code가 로드하는 파일 확장자를 나열합니다.330* 모든 파일은 `require`가 아닌 `import`를 사용하는 ES 모듈로 작성합니다. Claude Code가 로드하는 파일 확장자는 [참조](/docs/ko/plugins/mods/reference#files)에 나열되어 있습니다.
331 331
332<h3 id="test-the-mod">332<h3 id="test-the-mod">
333 모드 테스트하기333 mod 테스트하기
334</h3>334</h3>
335 335
336모드에 대한 자동화된 테스트를 작성하고 세션, 로그인 또는 네트워크 없이 셸에서 `claude plugin test`로 실행할 수 있습니다. 테스트는 hooks가 처리하는 이벤트를 발생시키고 hooks가 수행한 작업을 확인합니다.336mod에 대한 자동화된 테스트를 작성하고 셸에서 `claude plugin test`로 실행할 수 있으며, 세션, 로그인, 네트워크가 필요하지 않습니다. 테스트는 훅이 처리하는 이벤트를 발생시키고 훅이 수행한 작업을 검사합니다.
337 337
338이 테스트는 두 개의 도구 호출을 발생시키고, `/tally`를 실행하고, 회신이 둘 다 세는지 확인합니다. 이를 `first-mod/tests/first-mod.test.ts`로 저장하세요:338다음 테스트는 두 개의 도구 호출을 발생시키고, `/tally`를 실행하고, 응답이 두 호출을 모두 세는지 확인합니다. `first-mod/tests/first-mod.test.ts`로 저장합니다.
339 339
340```typescript first-mod/tests/first-mod.test.ts theme={null}340```typescript first-mod/tests/first-mod.test.ts theme={null}
341import { expect, test } from 'claude-code/testing'341import { expect, test } from 'claude-code/testing'
344 // Answer each tool call in Claude Code's place, so no tool runs344 // Answer each tool call in Claude Code's place, so no tool runs
345 on('tool.call', () => ({ result: 'ok' }))345 on('tool.call', () => ({ result: 'ok' }))
346 346
347 // Raise two tool calls, which the mod's tool.call hook counts347 // Fire two tool calls, which the mod's tool.call hook counts
348 await $.tool.call({ tool: 'Bash', command: 'ls' })348 await $.tool.call({ tool: 'Bash', command: 'ls' })
349 await $.tool.call({ tool: 'Read', file_path: 'README.md' })349 await $.tool.call({ tool: 'Read', file_path: 'README.md' })
350 350
354})354})
355```355```
356 356
357셸에서 `first-mod` 디렉토리에서 테스트를 실행하세요:357셸의 `first-mod` 디렉터리에서 테스트를 실행합니다.
358 358
359```bash theme={null}359```bash theme={null}
360claude plugin test360claude plugin test
361```361```
362 362
363출력은 각 테스트와 통과 여부를 이름으로 지정하며, 실행 간에 다양한 타이밍이 있습니다:363출력에는 각 테스트의 이름과 통과 여부가 표시되며, 소요 시간은 실행할 때마다 달라집니다.
364 364
365```text theme={null}365```text theme={null}
366tests/first-mod.test.ts:366tests/first-mod.test.ts:
371Ran 1 test across 1 file. [0.19s]371Ran 1 test across 1 file. [0.19s]
372```372```
373 373
374[모드 테스트](/docs/ko/plugins/mods/test)는 모델 호출 또는 저장소를 스텁하고, 타이머 및 그리기를 테스트하는 것을 다룹니다.374모델 호출이나 스토어를 스텁으로 대체하는 방법과 타이머 및 그리기를 테스트하는 방법은 [mod 테스트하기](/docs/ko/plugins/mods/test)에서 다룹니다.
375 375
376<h2 id="share-your-mod">376<h2 id="share-your-mod">
377 모드 공유377 mod 공유하기
378</h2>378</h2>
379 379
380모드는 플러그인이므로 매니페스트에서 버전을 지정하고 사람들은 `/plugin` 명령으로 설치하고 업데이트합니다. 다른 사람들에게 제공하려면 [마켓플레이스에 추가](/docs/ko/plugins/publish)하세요.380mod는 플러그인이므로 매니페스트에서 버전을 관리하며, 다른 사람들은 `/plugin` 명령으로 이를 설치하고 업데이트합니다. 다른 사람들에게 배포하려면 [마켓플레이스에 추가](/docs/ko/plugins/publish)하십시오.
381 381
382그 전에 플러그인의 `name`을 확인하세요: `claude plugin validate`는 [Anthropic의 자체 것처럼 보이는](/docs/ko/plugins/manifest-reference#name) 이름(예: `claude-`로 시작하는 이름)을 실패합니다. 이벤트 및 메서드는 릴리스 간에 변경될 수 있으므로 README는 테스트한 Claude Code 버전을 말하는 곳입니다.382그 전에 플러그인의 `name`을 확인하십시오. `claude-`로 시작하는 이름처럼 [Anthropic 자체 플러그인 이름으로 보이는](/docs/ko/plugins/manifest-reference#name) 이름은 `claude plugin validate` 검사를 통과하지 못합니다. 이벤트와 메서드는 릴리스마다 변경될 수 있으므로, 테스트에 사용한 Claude Code 버전은 README에 명시하십시오.
383 383
384설치된 복사본이 아닌 `--plugin-dir`이 있는 디렉토리에 대해 계속 개발하세요. Claude Code는 설치된 플러그인을 버전별로 캐시하므로 버전을 올리고 다시 설치할 때까지 편집 사항이 설치된 복사본에 도달하지 않습니다.384설치된 사본이 아닌 디렉터리를 대상으로 `--plugin-dir`를 사용하여 계속 개발하십시오. Claude Code는 설치된 플러그인을 버전별로 캐시하므로, 버전을 올리고 다시 설치하기 전까지는 수정 사항이 설치된 사본에 반영되지 않습니다.
385 385
386<h2 id="next-steps">386<h2 id="next-steps">
387 다음 단계387 다음 단계
388</h2>388</h2>
389 389
390* [인터페이스에 그리기](/docs/ko/plugins/mods/interface): 창을 열고, 프롬프트 위에 그리고, 버튼 및 텍스트 필드 추가390* [인터페이스에 그리기](/docs/ko/plugins/mods/interface): 창을 열고, 프롬프트 위에 그리고, 버튼과 텍스트 필드를 추가합니다
391* [이벤트에 반응](/docs/ko/plugins/mods/events): 도구 호출, 프롬프트 및 턴 hook391* [이벤트에 반응하기](/docs/ko/plugins/mods/events): 도구 호출, 프롬프트, 턴에 훅을 연결합니다
392* [mods API 사용](/docs/ko/plugins/mods/api): 명령 및 도구 추가, 모델 호출, 타이머에서 작업 실행392* [mods API 사용하기](/docs/ko/plugins/mods/api): 명령과 도구를 추가하고, 모델을 호출하고, 타이머로 작업을 실행합니다
393* [모드 테스트](/docs/ko/plugins/mods/test): Claude Code가 답변할 것을 스텁하고, 타이머 및 그리기 테스트393* [mod 테스트하기](/docs/ko/plugins/mods/test): Claude Code가 응답할 내용을 스텁으로 대체하고, 타이머와 그리기를 테스트합니다
394* [모드 문제 해결](/docs/ko/plugins/mods/troubleshoot): 모드가 아무것도 하지 않는 이유 및 디버그 로그394* [mod 문제 해결하기](/docs/ko/plugins/mods/troubleshoot): mod가 아무 동작도 하지 않는 이유와 디버그 로그를 다룹니다
395* [내장 모드의 소스 읽기](/docs/ko/plugins/mods/overview#read-the-source-of-built-in-mods): 완전한 플러그인. 각각 hooks 모듈 및 테스트 포함395* [기본 제공 mod의 소스 읽기](/docs/ko/plugins/mods/overview#read-the-source-of-built-in-mods): 각각 훅 모듈과 테스트를 포함한 완전한 플러그인입니다