6 6
7> Claude Code 플러그인에 skills, hooks, MCP 서버 및 다른 모든 컴포넌트 유형을 추가하고, 각각에 대해 검증하는 예제를 포함합니다.7> Claude Code 플러그인에 skills, hooks, MCP 서버 및 다른 모든 컴포넌트 유형을 추가하고, 각각에 대해 검증하는 예제를 포함합니다.
8 8
9export const Piece = ({id, children}) => <div className="pe-piece" data-piece={id}>{children}</div>;
10
11export const PluginExplorer = ({children}) => {
12 const PIECES = [{
13 id: 'manifest',
14 name: 'Manifest',
15 path: '.claude-plugin/plugin.json',
16 lines: [{
17 depth: 0,
18 kind: 'folder',
19 text: '.claude-plugin/'
20 }, {
21 depth: 1,
22 kind: 'file',
23 text: 'plugin.json'
24 }],
25 href: '/en/plugins/manifest-reference#manifest-file',
26 linkText: 'Go to the manifest reference'
27 }, {
28 id: 'skills',
29 name: 'Skills',
30 path: 'skills/review/SKILL.md',
31 lines: [{
32 depth: 0,
33 kind: 'folder',
34 text: 'skills/'
35 }, {
36 depth: 1,
37 kind: 'folder',
38 text: 'review/'
39 }, {
40 depth: 2,
41 kind: 'file',
42 text: 'SKILL.md'
43 }],
44 href: '/en/plugins/components#skills',
45 linkText: 'Go to the Skills section'
46 }, {
47 id: 'commands',
48 name: 'Commands',
49 path: 'commands/about.md',
50 lines: [{
51 depth: 0,
52 kind: 'folder',
53 text: 'commands/'
54 }, {
55 depth: 1,
56 kind: 'file',
57 text: 'about.md'
58 }],
59 href: '/en/plugins/components#commands',
60 linkText: 'Go to the Commands section'
61 }, {
62 id: 'agents',
63 name: 'Agents',
64 path: 'agents/security-reviewer.md',
65 lines: [{
66 depth: 0,
67 kind: 'folder',
68 text: 'agents/'
69 }, {
70 depth: 1,
71 kind: 'file',
72 text: 'security-reviewer.md'
73 }],
74 href: '/en/plugins/components#agents',
75 linkText: 'Go to the Agents section'
76 }, {
77 id: 'hooks',
78 name: 'Hooks',
79 path: 'hooks/hooks.json',
80 lines: [{
81 depth: 0,
82 kind: 'folder',
83 text: 'hooks/'
84 }, {
85 depth: 1,
86 kind: 'file',
87 text: 'hooks.json'
88 }],
89 href: '/en/plugins/components#hooks',
90 linkText: 'Go to the Hooks section'
91 }, {
92 id: 'monitors',
93 name: 'Monitors',
94 path: 'monitors/monitors.json',
95 lines: [{
96 depth: 0,
97 kind: 'folder',
98 text: 'monitors/'
99 }, {
100 depth: 1,
101 kind: 'file',
102 text: 'monitors.json'
103 }],
104 href: '/en/plugins/components#monitors',
105 linkText: 'Go to the Monitors section'
106 }, {
107 id: 'output-styles',
108 name: 'Output styles',
109 path: 'output-styles/terse.md',
110 lines: [{
111 depth: 0,
112 kind: 'folder',
113 text: 'output-styles/'
114 }, {
115 depth: 1,
116 kind: 'file',
117 text: 'terse.md'
118 }],
119 href: '/en/plugins/components#themes-and-output-styles',
120 linkText: 'Go to the Themes and output styles section'
121 }, {
122 id: 'themes',
123 name: 'Themes',
124 path: 'themes/dracula.json',
125 lines: [{
126 depth: 0,
127 kind: 'folder',
128 text: 'themes/'
129 }, {
130 depth: 1,
131 kind: 'file',
132 text: 'dracula.json'
133 }],
134 href: '/en/plugins/components#themes-and-output-styles',
135 linkText: 'Go to the Themes and output styles section'
136 }, {
137 id: 'workflows',
138 name: 'Workflows',
139 path: 'workflows/audit-routes.js',
140 lines: [{
141 depth: 0,
142 kind: 'folder',
143 text: 'workflows/'
144 }, {
145 depth: 1,
146 kind: 'file',
147 text: 'audit-routes.js'
148 }],
149 href: '/en/workflows#distribute-a-workflow-in-a-plugin',
150 linkText: 'Go to Distribute a workflow in a plugin'
151 }, {
152 id: 'bin',
153 name: 'Executables',
154 path: 'bin/hello-plugin',
155 lines: [{
156 depth: 0,
157 kind: 'folder',
158 text: 'bin/'
159 }, {
160 depth: 1,
161 kind: 'file',
162 text: 'hello-plugin'
163 }],
164 href: '/en/plugins/components#executables',
165 linkText: 'Go to the Executables section'
166 }, {
167 id: 'scripts',
168 name: 'Scripts',
169 path: 'scripts/format.sh',
170 lines: [{
171 depth: 0,
172 kind: 'folder',
173 text: 'scripts/'
174 }, {
175 depth: 1,
176 kind: 'file',
177 text: 'format.sh'
178 }],
179 href: '/en/plugins/components#hooks',
180 linkText: 'Go to the Hooks section'
181 }, {
182 id: 'settings',
183 name: 'Default settings',
184 path: 'settings.json',
185 lines: [{
186 depth: 0,
187 kind: 'file',
188 text: 'settings.json'
189 }],
190 href: '/en/plugins/components#default-settings',
191 linkText: 'Go to the Default settings section'
192 }, {
193 id: 'mcp',
194 name: 'MCP servers',
195 path: '.mcp.json',
196 lines: [{
197 depth: 0,
198 kind: 'file',
199 text: '.mcp.json'
200 }],
201 href: '/en/plugins/components#mcp-servers',
202 linkText: 'Go to the MCP servers section'
203 }, {
204 id: 'lsp',
205 name: 'LSP servers',
206 path: '.lsp.json',
207 lines: [{
208 depth: 0,
209 kind: 'file',
210 text: '.lsp.json'
211 }],
212 href: '/en/plugins/components#lsp-servers',
213 linkText: 'Go to the LSP servers section'
214 }];
215 const [selectedId, setSelectedId] = useState('manifest');
216 const [isFullscreen, setIsFullscreen] = useState(false);
217 const rootRef = useRef(null);
218 useEffect(() => {
219 const onFsChange = () => setIsFullscreen(!!document.fullscreenElement);
220 document.addEventListener('fullscreenchange', onFsChange);
221 return () => document.removeEventListener('fullscreenchange', onFsChange);
222 }, []);
223 const toggleFullscreen = () => {
224 if (!rootRef.current) return;
225 if (document.fullscreenElement) document.exitFullscreen(); else rootRef.current.requestFullscreen().catch(() => {});
226 };
227 const selected = PIECES.find(p => p.id === selectedId) || PIECES[0];
228 const onTreeKeyDown = e => {
229 const keys = ['ArrowDown', 'ArrowUp', 'Home', 'End'];
230 if (keys.indexOf(e.key) === -1) return;
231 const i = PIECES.findIndex(p => p.id === selectedId);
232 let next = i;
233 if (e.key === 'ArrowDown') next = Math.min(PIECES.length - 1, i + 1);
234 if (e.key === 'ArrowUp') next = Math.max(0, i - 1);
235 if (e.key === 'Home') next = 0;
236 if (e.key === 'End') next = PIECES.length - 1;
237 e.preventDefault();
238 if (next === i) return;
239 const id = PIECES[next].id;
240 setSelectedId(id);
241 const el = document.getElementById('pe-node-' + id);
242 if (el) el.focus();
243 };
244 const FolderIcon = () => <svg className="pe-icon" width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" aria-hidden="true">
245 <path d="M1.5 4.5a1 1 0 0 1 1-1h3.2l1.3 1.5h6a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1h-10.5a1 1 0 0 1-1-1z" />
246 </svg>;
247 const FileIcon = () => <svg className="pe-icon" width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" aria-hidden="true">
248 <path d="M4 1.5h5.5L13 5v9.5H4z" />
249 <path d="M9.5 1.5V5H13" />
250 </svg>;
251 return <div ref={rootRef} className={isFullscreen ? 'pe-root pe-fullscreen not-prose' : 'pe-root not-prose'} data-selected={selected.id}>
252 <style>{`
253 .pe-root {
254 --pe-mono: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
255 --pe-accent: #D97757;
256 --pe-accent-text: #A8502F;
257 --pe-accent-bg: rgba(217,119,87,0.10);
258 --pe-bg: #FFFFFF;
259 --pe-surface: #FAFAF7;
260 --pe-hover: #F0EEE6;
261 --pe-border: #E8E6DC;
262 --pe-text: #141413;
263 --pe-text-2: #3D3D3A;
264 --pe-text-3: #5E5D59;
265 font-family: inherit;
266 background: var(--pe-bg);
267 color: var(--pe-text);
268 border: 1px solid var(--pe-border);
269 border-radius: 12px;
270 margin: 1.5rem 0;
271 overflow: hidden;
272 box-sizing: border-box;
273 }
274 .dark .pe-root {
275 --pe-accent-text: #EBA98F;
276 --pe-accent-bg: rgba(217,119,87,0.18);
277 --pe-bg: #1A1918;
278 --pe-surface: #232221;
279 --pe-hover: #2E2D2B;
280 --pe-border: #3A3936;
281 --pe-text: #F1EFE9;
282 --pe-text-2: #D6D4CA;
283 --pe-text-3: #B8B5AD;
284 }
285 .pe-root *, .pe-root *::before, .pe-root *::after { box-sizing: border-box; }
286 .pe-head { display: flex; align-items: flex-start; gap: 12px; padding: 18px 24px 16px; border-bottom: 1px solid var(--pe-border); }
287 .pe-head-text { flex: 1; min-width: 0; }
288 .pe-fs-btn { flex-shrink: 0; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--pe-border); border-radius: 6px; background: var(--pe-surface); color: var(--pe-text-2); font-size: 15px; line-height: 1; cursor: pointer; }
289 .pe-fs-btn:hover { background: var(--pe-hover); }
290 .pe-fs-btn:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: 2px; }
291 .pe-fullscreen { border-radius: 0; height: 100vh; display: flex; flex-direction: column; overflow: auto; }
292 .pe-fullscreen .pe-body { flex: 1; }
293 .pe-title { font-size: 19px; font-weight: 600; line-height: 1.3; color: var(--pe-text); margin: 0; }
294 .pe-sub { font-size: 15px; line-height: 1.5; color: var(--pe-text-3); margin: 4px 0 0; }
295 .pe-sub code { font-family: var(--pe-mono); font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--pe-surface); border: 1px solid var(--pe-border); }
296 .pe-body { display: flex; align-items: stretch; }
297 .pe-tree-pane { width: 270px; flex-shrink: 0; background: var(--pe-surface); border-right: 1px solid var(--pe-border); padding: 16px 0 12px; }
298 .pe-panel { flex: 1; min-width: 0; padding: 16px 24px 24px; }
299 .pe-caption { font-size: 13px; font-weight: 600; color: var(--pe-text-3); margin: 0 0 10px; }
300 .pe-tree-pane .pe-caption { padding: 0 16px; }
301 .pe-rootline { display: flex; align-items: center; gap: 7px; padding: 3px 16px; font-family: var(--pe-mono); font-size: 13.5px; color: var(--pe-text-3); }
302 .pe-node {
303 display: block; width: 100%; margin: 0; padding: 3px 16px 3px 30px; text-align: left; cursor: pointer;
304 background: transparent; color: var(--pe-text-2);
305 border: none; border-left: 3px solid transparent;
306 font-family: var(--pe-mono); font-size: 13.5px; line-height: 1.4;
307 }
308 .pe-node:hover { background: var(--pe-hover); }
309 .pe-node:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: -2px; }
310 .pe-node[aria-pressed="true"] { background: var(--pe-accent-bg); border-left-color: var(--pe-accent); color: var(--pe-accent-text); font-weight: 600; }
311 .pe-line { display: flex; align-items: center; gap: 7px; padding: 2px 0; }
312 .pe-line-tree { flex-wrap: wrap; }
313 .pe-line-tree .pe-req { flex-basis: 100%; margin: 2px 0 0 22px; white-space: normal; width: fit-content; max-width: calc(100% - 22px); }
314 .pe-line span { overflow-wrap: anywhere; }
315 .pe-piece { display: none; font-size: 16px; line-height: 1.6; color: var(--pe-text-2); }
316 .pe-root[data-selected="manifest"] .pe-piece[data-piece="manifest"],
317 .pe-root[data-selected="skills"] .pe-piece[data-piece="skills"],
318 .pe-root[data-selected="commands"] .pe-piece[data-piece="commands"],
319 .pe-root[data-selected="agents"] .pe-piece[data-piece="agents"],
320 .pe-root[data-selected="hooks"] .pe-piece[data-piece="hooks"],
321 .pe-root[data-selected="monitors"] .pe-piece[data-piece="monitors"],
322 .pe-root[data-selected="output-styles"] .pe-piece[data-piece="output-styles"],
323 .pe-root[data-selected="themes"] .pe-piece[data-piece="themes"],
324 .pe-root[data-selected="workflows"] .pe-piece[data-piece="workflows"],
325 .pe-root[data-selected="bin"] .pe-piece[data-piece="bin"],
326 .pe-root[data-selected="scripts"] .pe-piece[data-piece="scripts"],
327 .pe-root[data-selected="settings"] .pe-piece[data-piece="settings"],
328 .pe-root[data-selected="mcp"] .pe-piece[data-piece="mcp"],
329 .pe-root[data-selected="lsp"] .pe-piece[data-piece="lsp"] { display: block; }
330 .pe-piece p { margin: 0 0 10px; }
331 .pe-piece p:last-child { margin-bottom: 0; }
332 .pe-piece code { font-family: var(--pe-mono); font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--pe-surface); border: 1px solid var(--pe-border); }
333 .pe-piece .code-block { margin: 12px 0 0; }
334 .pe-piece pre code { padding: 0; border: none; background: none; }
335 .pe-piece a { color: var(--pe-accent-text); }
336 .pe-line-compact { display: none; }
337 .pe-icon { flex-shrink: 0; }
338 .pe-req { margin-left: 8px; padding: 0 6px; border-radius: 999px; font-size: 11px; line-height: 18px; letter-spacing: .02em; color: var(--pe-accent-text); border: 1px solid var(--pe-border); background: var(--pe-surface); white-space: nowrap; font-weight: 500; vertical-align: middle; }
339 .pe-name { font-size: 22px; font-weight: 600; line-height: 1.25; letter-spacing: -0.2px; color: var(--pe-text); margin: 0; }
340 .pe-path { font-family: var(--pe-mono); font-size: 13.5px; color: var(--pe-accent-text); margin: 4px 0 0; overflow-wrap: anywhere; }
341 .pe-block { margin: 20px 0 0; }
342 .pe-link {
343 display: inline-block; margin: 24px 0 0; padding: 8px 14px; border-radius: 8px;
344 font-size: 14.5px; font-weight: 600; text-decoration: none;
345 color: var(--pe-accent-text); background: var(--pe-accent-bg); border: 1px solid var(--pe-accent);
346 }
347 .pe-link:hover { filter: brightness(0.97); }
348 .pe-link:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: 2px; }
349 @media (max-width: 700px) {
350 .pe-head { padding: 16px 16px 14px; }
351 .pe-body { flex-direction: column; }
352 .pe-tree-pane { width: 100%; border-right: none; border-bottom: 1px solid var(--pe-border); }
353 .pe-line-tree { display: none; }
354 .pe-line-compact { display: flex; }
355 .pe-panel { padding: 16px 16px 20px; }
356 }
357 `}</style>
358
359 <div className="pe-head">
360 <div className="pe-head-text">
361 <div className="pe-title">What goes in a plugin</div>
362 <div className="pe-sub">This example plugin, <code>my-plugin</code>, has one of every kind of component, each in its default location. Select a file or folder to read what it’s for and see what goes in it.</div>
363 </div>
364 <button type="button" className="pe-fs-btn" onClick={toggleFullscreen} aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'} title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
365 {isFullscreen ? '⤡' : '⛶'}
366 </button>
367 </div>
368
369 <div className="pe-body">
370 <div className="pe-tree-pane">
371 <div className="pe-caption" id="pe-tree-caption">Plugin directory</div>
372 <div role="group" aria-labelledby="pe-tree-caption" onKeyDown={onTreeKeyDown}>
373 <div className="pe-rootline"><FolderIcon /><span>my-plugin/</span></div>
374 {PIECES.map(p => <button key={p.id} id={'pe-node-' + p.id} type="button" className="pe-node" aria-pressed={p.id === selected.id} aria-label={p.name + ', ' + p.path} onClick={() => setSelectedId(p.id)}>
375 {p.lines.map((line, i) => <span key={i} className="pe-line pe-line-tree" style={{
376 paddingLeft: line.depth * 18 + 'px'
377 }}>
378 {line.kind === 'folder' ? <FolderIcon /> : <FileIcon />}
379 <span>{line.text}</span>
380 {p.required && i === p.lines.length - 1 ? <span className="pe-req">{p.required}</span> : null}
381 </span>)}
382 <span className="pe-line pe-line-compact">
383 <FileIcon />
384 <span>{p.path}</span>
385 {p.required ? <span className="pe-req">{p.required}</span> : null}
386 </span>
387 </button>)}
388 </div>
389 </div>
390
391 <div className="pe-panel" role="region" aria-labelledby="pe-panel-caption" aria-live="polite" aria-atomic="true">
392 <div className="pe-caption" id="pe-panel-caption">Selected piece</div>
393 <div className="pe-name">{selected.name}{selected.required ? <span className="pe-req">{selected.required}</span> : null}</div>
394 <div className="pe-path">{selected.path}</div>
395
396 <div className="pe-block">{children}</div>
397
398 <a className="pe-link" href={selected.href}>{selected.linkText}</a>
399 </div>
400 </div>
401 </div>;
402};
403
404Claude Code 플러그인은 skills, agents, hooks, MCP 서버와 같은 컴포넌트로 구성됩니다. 각 컴포넌트는 플러그인의 기본 폴더, `.claude-plugin/plugin.json`의 선택적 manifest 키(해당 폴더를 대체하거나 추가함), 그리고 사용자가 보는 이름을 가집니다. 각 키의 전체 필드 테이블은 [manifest 참조](/docs/ko/plugins/manifest-reference#fields)를 참조하십시오.9Claude Code 플러그인은 skills, agents, hooks, MCP 서버와 같은 컴포넌트로 구성됩니다. 각 컴포넌트는 플러그인의 기본 폴더, `.claude-plugin/plugin.json`의 선택적 manifest 키(해당 폴더를 대체하거나 추가함), 그리고 사용자가 보는 이름을 가집니다. 각 키의 전체 필드 테이블은 [manifest 참조](/docs/ko/plugins/manifest-reference#fields)를 참조하십시오.
405 10
406이 페이지를 사용하여 이미 로드되는 플러그인에 컴포넌트를 추가합니다.11이 페이지를 사용하여 이미 로드되는 플러그인에 컴포넌트를 추가합니다.
407 12
408컴포넌트를 추가한 후, 실행 중인 세션에서 `/reload-plugins`를 실행하거나 새 세션을 시작하여 Claude Code가 이를 로드하도록 합니다. 로드하기 전에 컴포넌트의 파일을 확인하려면 플러그인 디렉토리에서 셸에서 [`claude plugin validate .`](/docs/ko/plugins/cli-reference#plugin-validate)를 실행합니다.13컴포넌트를 추가한 후, 실행 중인 세션에서 `/reload-plugins`를 실행하거나 새 세션을 시작하여 Claude Code가 이를 로드하도록 합니다. 로드하기 전에 컴포넌트의 파일을 확인하려면 플러그인 디렉토리에서 셸에서 [`claude plugin validate .`](/docs/ko/plugins/cli-reference#plugin-validate)를 실행합니다.
409 14
410<Note>15> [!NOTE]
411 다음 경우는 다른 페이지에서 다룹니다:16>
412 17> 다음 경우는 다른 페이지에서 다룹니다:
413 * **첫 번째 플러그인 구축**: [플러그인 생성](/docs/ko/plugins/create)으로 시작합니다18>
414 * **다른 사람의 플러그인 설치**: [플러그인 설치](/docs/ko/plugins/install)를 참조합니다19> * **첫 번째 플러그인 구축**: [플러그인 생성](/docs/ko/plugins/create)으로 시작합니다
415 * **플러그인의 사용자가 claude.ai 또는 Cowork에 있음**: 다른 컴포넌트 세트가 로드됩니다. [플러그인 구조 및 테스트](https://claude.com/docs/plugins/build) 및 [컴포넌트 지원 테이블](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app)을 참조합니다20> * **다른 사람의 플러그인 설치**: [플러그인 설치](/docs/ko/plugins/install)를 참조합니다
416</Note>21> * **플러그인의 사용자가 claude.ai 또는 Cowork에 있음**: 다른 컴포넌트 세트가 로드됩니다. [플러그인 구조 및 테스트](https://claude.com/docs/plugins/build) 및 [컴포넌트 지원 테이블](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app)을 참조합니다
417 22
418<h2 id="explore-the-plugin-directory">23## 플러그인 디렉토리 탐색
419 플러그인 디렉토리 탐색
420</h2>
421 24
422탐색기는 기본 위치에 모든 종류의 구성 요소 중 하나씩 포함하는 예제 플러그인 `my-plugin`을 보여줍니다:25탐색기는 기본 위치에 모든 종류의 구성 요소 중 하나씩 포함하는 예제 플러그인 `my-plugin`을 보여줍니다:
423 26
433 36
434각 파일은 해당 형식의 가장 작은 유효한 예제이며, 유용하기보다는 형태를 보여주기 위한 것입니다: 실제 스킬이나 에이전트는 전체 지침을 포함하고 종종 지원 파일을 포함하며, 실제 훅이나 모니터는 실제 작업을 수행합니다. 탐색기 이후의 섹션은 동일한 파일을 예제로 사용하고 더 완전한 파일로 연결됩니다. 파일이나 폴더를 선택하여 그 용도를 읽고, 그 안에 무엇이 들어가는지 확인하고, 그것을 다루는 섹션을 찾습니다.37각 파일은 해당 형식의 가장 작은 유효한 예제이며, 유용하기보다는 형태를 보여주기 위한 것입니다: 실제 스킬이나 에이전트는 전체 지침을 포함하고 종종 지원 파일을 포함하며, 실제 훅이나 모니터는 실제 작업을 수행합니다. 탐색기 이후의 섹션은 동일한 파일을 예제로 사용하고 더 완전한 파일로 연결됩니다. 파일이나 폴더를 선택하여 그 용도를 읽고, 그 안에 무엇이 들어가는지 확인하고, 그것을 다루는 섹션을 찾습니다.
435 38
436<PluginExplorer>39What goes in a plugin
437 <Piece id="manifest">
438 [매니페스트](/docs/ko/plugins/manifest-reference)는 플러그인의 `.claude-plugin/` 디렉토리에 있는 `plugin.json` 파일입니다. 플러그인의 메타데이터와 Claude Code가 사용자에게 요청하는 `userConfig` 값을 포함합니다. Claude Code는 매니페스트 없이도 플러그인을 로드합니다. 파일 내에서 `name`만 필수입니다. 이 파일에서 `description`은 `/plugin`의 플러그인에 대해 사용자가 보는 텍스트이고, `version`은 변경할 때까지 사용자를 해당 버전에 유지합니다:
439 40
440 ```json theme={null}41This example plugin, `my-plugin`, has one of every kind of component, each in its default location. Select a file or folder to read what it’s for and see what goes in it.
441 {42
43Plugin directory
44
45my-plugin/
46
47Selected piece
48
49[매니페스트](/docs/ko/plugins/manifest-reference)는 플러그인의 `.claude-plugin/` 디렉토리에 있는 `plugin.json` 파일입니다. 플러그인의 메타데이터와 Claude Code가 사용자에게 요청하는 `userConfig` 값을 포함합니다. Claude Code는 매니페스트 없이도 플러그인을 로드합니다. 파일 내에서 `name`만 필수입니다. 이 파일에서 `description`은 `/plugin`의 플러그인에 대해 사용자가 보는 텍스트이고, `version`은 변경할 때까지 사용자를 해당 버전에 유지합니다:
50
51```json theme={null}
52{
442 "name": "my-plugin",53 "name": "my-plugin",
443 "version": "1.0.0",54 "version": "1.0.0",
444 "description": "Review, formatting, and database tools for this team"55 "description": "Review, formatting, and database tools for this team"
445 }56}
446 ```57```
447 </Piece>
448 58
449 <Piece id="skills">59[스킬](/docs/ko/skills)은 `SKILL.md` 파일입니다. 각 스킬을 `skills/` 아래의 자체 디렉토리에 저장합니다. Claude는 모든 스킬의 `description`을 읽고, 사용자가 요청한 내용이 설명과 일치할 때(예: 여기서 Claude에게 풀 요청을 검토하도록 요청할 때), Claude는 스킬의 지침을 로드하고 따릅니다. 사용자는 `/my-plugin:review`로 직접 실행할 수도 있습니다:
450 [스킬](/docs/ko/skills)은 `SKILL.md` 파일입니다. 각 스킬을 `skills/` 아래의 자체 디렉토리에 저장합니다. Claude는 모든 스킬의 `description`을 읽고, 사용자가 요청한 내용이 설명과 일치할 때(예: 여기서 Claude에게 풀 요청을 검토하도록 요청할 때), Claude는 스킬의 지침을 로드하고 따릅니다. 사용자는 `/my-plugin:review`로 직접 실행할 수도 있습니다:
451 60
452 ```markdown theme={null}61```markdown theme={null}
453 ---62---
454 description: Reviews a pull request for style and test coverage. Use when asked to review code.63description: Reviews a pull request for style and test coverage. Use when asked to review code.
455 ---64---
456 65
457 Review the changed files. Report style problems first, then missing tests.66Review the changed files. Report style problems first, then missing tests.
458 ```67```
459 </Piece>
460 68
461 <Piece id="commands">69명령은 사용자가 이름으로 실행하는 단일 Markdown 파일입니다. 명령은 이전 형식입니다: 스킬은 같은 방식으로 이름으로 실행되며 자체 디렉토리에 지원 파일을 포함할 수도 있으므로 새로운 것은 스킬로 작성하고 이미 있는 파일은 `commands/`에 유지합니다. 이 파일은 `/my-plugin:about`이 되고 스킬과 동일한 프론트매터를 사용합니다:
462 명령은 사용자가 이름으로 실행하는 단일 Markdown 파일입니다. 명령은 이전 형식입니다: 스킬은 같은 방식으로 이름으로 실행되며 자체 디렉토리에 지원 파일을 포함할 수도 있으므로 새로운 것은 스킬로 작성하고 이미 있는 파일은 `commands/`에 유지합니다. 이 파일은 `/my-plugin:about`이 되고 스킬과 동일한 프론트매터를 사용합니다:
463 70
464 ```markdown theme={null}71```markdown theme={null}
465 ---72---
466 description: Summarize the repository73description: Summarize the repository
467 ---74---
468 75
469 Summarize what this repository does in three sentences.76Summarize what this repository does in three sentences.
470 ```77```
471 </Piece>
472 78
473 <Piece id="agents">79[서브에이전트](/docs/ko/sub-agents)는 자체 지침과 자체 컨텍스트 윈도우를 가진 별도의 어시스턴트이며, Claude가 작업을 위임하고 결과를 다시 받을 수 있습니다. `agents/` 아래의 각 Markdown 파일은 하나를 정의합니다: 프론트매터는 이름을 지정하고 사용 시기를 말하며, 본문은 시스템 프롬프트입니다. 이 파일은 `my-plugin:security-reviewer`로 명명되며, 사용자는 `@agent-my-plugin:security-reviewer`로 호출할 수 있습니다:
474 [서브에이전트](/docs/ko/sub-agents)는 자체 지침과 자체 컨텍스트 윈도우를 가진 별도의 어시스턴트이며, Claude가 작업을 위임하고 결과를 다시 받을 수 있습니다. `agents/` 아래의 각 Markdown 파일은 하나를 정의합니다: 프론트매터는 이름을 지정하고 사용 시기를 말하며, 본문은 시스템 프롬프트입니다. 이 파일은 `my-plugin:security-reviewer`로 명명되며, 사용자는 `@agent-my-plugin:security-reviewer`로 호출할 수 있습니다:
475 80
476 ```markdown theme={null}81```markdown theme={null}
477 ---82---
478 name: security-reviewer83name: security-reviewer
479 description: Reviews code changes for security issues. Use after edits to authentication or input handling.84description: Reviews code changes for security issues. Use after edits to authentication or input handling.
480 model: sonnet85model: sonnet
481 ---86---
482 87
483 You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.88You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.
484 ```89```
485 </Piece>
486 90
487 <Piece id="hooks">91[훅](/docs/ko/hooks-guide)은 파일 편집 후와 같이 Claude Code의 라이프사이클의 특정 지점에서 자동으로 무언가를 실행합니다: 셸 명령, HTTP 요청, MCP 도구 호출, 모델에 대한 프롬프트, 또는 서브에이전트. 플러그인의 훅을 플러그인 루트의 `hooks/hooks.json`에 저장합니다. 이 파일은 Claude가 파일을 작성하거나 편집한 후 플러그인의 `scripts/format.sh`를 실행합니다:
488 [훅](/docs/ko/hooks-guide)은 파일 편집 후와 같이 Claude Code의 라이프사이클의 특정 지점에서 자동으로 무언가를 실행합니다: 셸 명령, HTTP 요청, MCP 도구 호출, 모델에 대한 프롬프트, 또는 서브에이전트. 플러그인의 훅을 플러그인 루트의 `hooks/hooks.json`에 저장합니다. 이 파일은 Claude가 파일을 작성하거나 편집한 후 플러그인의 `scripts/format.sh`를 실행합니다:
489 92
490 ```json theme={null}93```json theme={null}
491 {94{
492 "hooks": {95 "hooks": {
493 "PostToolUse": [96 "PostToolUse": [
494 {97 {
502 }105 }
503 ]106 ]
504 }107 }
505 }108}
506 ```109```
507 </Piece>
508 110
509 <Piece id="monitors">111모니터는 세션이 시작될 때 Claude Code가 백그라운드에서 시작하고 세션이 끝날 때까지 계속 실행하는 셸 명령입니다. 출력하는 내용은 Claude에게 알림으로 전달됩니다. `when` 필드는 대신 명명된 스킬이 처음 실행될 때 시작할 수 있습니다. 이 파일은 오류 로그를 추적합니다:
510 모니터는 세션이 시작될 때 Claude Code가 백그라운드에서 시작하고 세션이 끝날 때까지 계속 실행하는 셸 명령입니다. 출력하는 내용은 Claude에게 알림으로 전달됩니다. `when` 필드는 대신 명명된 스킬이 처음 실행될 때 시작할 수 있습니다. 이 파일은 오류 로그를 추적합니다:
511 112
512 ```json theme={null}113```json theme={null}
513 [114[
514 {115 {
515 "name": "error-log",116 "name": "error-log",
516 "command": "tail -F ./logs/error.log",117 "command": "tail -F ./logs/error.log",
517 "description": "Application error log"118 "description": "Application error log"
518 }119 }
519 ]120]
520 ```121```
521 </Piece>
522 122
523 <Piece id="output-styles">123플러그인은 [출력 스타일](/docs/ko/output-styles)을 포함할 수 있으며, 이는 Claude가 응답을 포맷하고 표현하는 방식을 변경합니다. 각 출력 스타일을 `output-styles/<name>.md`로 저장합니다. 이 파일은 `/output-style`에 `my-plugin:terse`로 나타납니다:
524 플러그인은 [출력 스타일](/docs/ko/output-styles)을 포함할 수 있으며, 이는 Claude가 응답을 포맷하고 표현하는 방식을 변경합니다. 각 출력 스타일을 `output-styles/<name>.md`로 저장합니다. 이 파일은 `/output-style`에 `my-plugin:terse`로 나타납니다:
525 124
526 ```markdown theme={null}125```markdown theme={null}
527 ---126---
528 name: terse127name: terse
529 description: Answer in as few words as possible128description: Answer in as few words as possible
530 keep-coding-instructions: true129keep-coding-instructions: true
531 ---130---
532 131
533 Keep every reply short. Skip preambles and summaries.132Keep every reply short. Skip preambles and summaries.
534 ```133```
535 </Piece>
536 134
537 <Piece id="themes">135플러그인은 Claude Code 인터페이스용 [색상 테마](/docs/ko/terminal-config#create-a-custom-theme)를 포함할 수 있습니다. 각 테마를 `themes/<slug>.json`으로 저장합니다. 이 파일은 `/theme`에 `Dracula`로 나타나며, `my-plugin`에서 온 것으로 표시됩니다:
538 플러그인은 Claude Code 인터페이스용 [색상 테마](/docs/ko/terminal-config#create-a-custom-theme)를 포함할 수 있습니다. 각 테마를 `themes/<slug>.json`으로 저장합니다. 이 파일은 `/theme`에 `Dracula`로 나타나며, `my-plugin`에서 온 것으로 표시됩니다:
539 136
540 ```json theme={null}137```json theme={null}
541 {138{
542 "name": "Dracula",139 "name": "Dracula",
543 "base": "dark",140 "base": "dark",
544 "overrides": {141 "overrides": {
545 "claude": "#bd93f9",142 "claude": "#bd93f9",
546 "error": "#ff5555"143 "error": "#ff5555"
547 }144 }
548 }145}
549 ```146```
550 </Piece>
551 147
552 <Piece id="workflows">148`workflows/` 폴더는 [워크플로우](/docs/ko/workflows) `.js` 파일을 보유합니다: `meta` 블록, 그 다음 여러 서브에이전트를 조율하는 스크립트 본문. 이 파일은 `/my-plugin:audit-routes`로 실행됩니다:
553 `workflows/` 폴더는 [워크플로우](/docs/ko/workflows) `.js` 파일을 보유합니다: `meta` 블록, 그 다음 여러 서브에이전트를 조율하는 스크립트 본문. 이 파일은 `/my-plugin:audit-routes`로 실행됩니다:
554 149
555 ```javascript theme={null}150```javascript theme={null}
556 export const meta = {151export const meta = {
557 name: 'audit-routes',152 name: 'audit-routes',
558 description: 'Audit every route handler for missing auth checks',153 description: 'Audit every route handler for missing auth checks',
559 }154}
560 155
561 const found = await agent('List every .ts file under src/routes/.', {156const found = await agent('List every .ts file under src/routes/.', {
562 schema: { type: 'object', required: ['files'], properties: { files: { type: 'array', items: { type: 'string' } } } },157 schema: { type: 'object', required: ['files'], properties: { files: { type: 'array', items: { type: 'string' } } } },
563 })158})
564 159
565 const audits = await pipeline(found.files, file =>160const audits = await pipeline(found.files, file =>
566 agent(`Audit ${file} for missing authentication checks.`, { label: file }),161 agent(`Audit ${file} for missing authentication checks.`, { label: file }),
567 )162)
568 163
569 return audits.filter(Boolean)164return audits.filter(Boolean)
570 ```165```
571 </Piece>
572 166
573 <Piece id="bin">167`bin/`은 플러그인이 명령줄 도구를 제공하는 방법입니다. 플러그인이 활성화되어 있는 동안 Claude Code는 이 폴더를 실행하는 셸의 `PATH`에 넣으므로 Claude 또는 스킬의 지침이 사용자가 아무것도 설치하지 않고도 이름으로 도구를 실행할 수 있습니다. 이 [실행 파일](#executables)이 있으면 `hello-plugin`은 Claude가 실행할 수 있는 명령입니다:
574 `bin/`은 플러그인이 명령줄 도구를 제공하는 방법입니다. 플러그인이 활성화되어 있는 동안 Claude Code는 이 폴더를 실행하는 셸의 `PATH`에 넣으므로 Claude 또는 스킬의 지침이 사용자가 아무것도 설치하지 않고도 이름으로 도구를 실행할 수 있습니다. 이 [실행 파일](#executables)이 있으면 `hello-plugin`은 Claude가 실행할 수 있는 명령입니다:
575 168
576 ```bash theme={null}169```bash theme={null}
577 #!/bin/bash170#!/bin/bash
578 echo "hello from my-plugin"171echo "hello from my-plugin"
579 ```172```
580 </Piece>
581 173
582 <Piece id="scripts">174`hooks/hooks.json`의 훅은 스크립트를 실행하고, 이 폴더는 예제가 이를 유지하는 곳입니다. `scripts/` 이름은 관례이지 Claude Code가 찾는 것이 아닙니다: 훅은 파일을 경로 `${CLAUDE_PLUGIN_ROOT}/scripts/format.sh`로 가리킵니다. 포매터 스크립트는 다음과 같을 수 있습니다:
583 `hooks/hooks.json`의 훅은 스크립트를 실행하고, 이 폴더는 예제가 이를 유지하는 곳입니다. `scripts/` 이름은 관례이지 Claude Code가 찾는 것이 아닙니다: 훅은 파일을 경로 `${CLAUDE_PLUGIN_ROOT}/scripts/format.sh`로 가리킵니다. 포매터 스크립트는 다음과 같을 수 있습니다:
584 175
585 ```bash theme={null}176```bash theme={null}
586 #!/bin/bash177#!/bin/bash
587 npx prettier --write .178npx prettier --write .
588 ```179```
589 </Piece>
590 180
591 <Piece id="settings">181플러그인 루트의 `settings.json`은 플러그인이 활성화되어 있는 동안 적용되는 [설정](/docs/ko/settings-reference)을 보유하므로 플러그인은 세션의 동작 방식을 변경할 수 있고 구성 요소만 추가하는 것이 아닙니다. 플러그인에서 적용되는 키는 [`agent`](/docs/ko/settings-reference#agent)와 [`subagentStatusLine`](/docs/ko/settings-reference#subagentstatusline) 두 개뿐입니다; 다른 모든 키는 삭제됩니다. [기본 설정](#default-settings)을 참조합니다.
592 플러그인 루트의 `settings.json`은 플러그인이 활성화되어 있는 동안 적용되는 [설정](/docs/ko/settings-reference)을 보유하므로 플러그인은 세션의 동작 방식을 변경할 수 있고 구성 요소만 추가하는 것이 아닙니다. 플러그인에서 적용되는 키는 [`agent`](/docs/ko/settings-reference#agent)와 [`subagentStatusLine`](/docs/ko/settings-reference#subagentstatusline) 두 개뿐입니다; 다른 모든 키는 삭제됩니다. [기본 설정](#default-settings)을 참조합니다.
593 182
594 이 파일은 `agent`를 설정하며, 이는 세션의 주 스레드를 플러그인 자체의 `security-reviewer` 에이전트로 실행하므로 해당 에이전트의 시스템 프롬프트, 도구 제한 및 모델이 전체 세션에 적용됩니다:183이 파일은 `agent`를 설정하며, 이는 세션의 주 스레드를 플러그인 자체의 `security-reviewer` 에이전트로 실행하므로 해당 에이전트의 시스템 프롬프트, 도구 제한 및 모델이 전체 세션에 적용됩니다:
595 184
596 ```json theme={null}185```json theme={null}
597 {186{
598 "agent": "security-reviewer"187 "agent": "security-reviewer"
599 }188}
600 ```189```
601 </Piece>
602 190
603 <Piece id="mcp">191[MCP 서버](/docs/ko/mcp)는 Claude에게 외부 시스템의 도구를 제공합니다. 플러그인 루트의 `.mcp.json`에서 선언합니다. 이 파일은 플러그인 내부의 스크립트에서 로컬 서버를 시작하며, `/mcp`에 `plugin:my-plugin:db`로 나타납니다:
604 [MCP 서버](/docs/ko/mcp)는 Claude에게 외부 시스템의 도구를 제공합니다. 플러그인 루트의 `.mcp.json`에서 선언합니다. 이 파일은 플러그인 내부의 스크립트에서 로컬 서버를 시작하며, `/mcp`에 `plugin:my-plugin:db`로 나타납니다:
605 192
606 ```json theme={null}193```json theme={null}
607 {194{
608 "mcpServers": {195 "mcpServers": {
609 "db": {196 "db": {
610 "command": "node",197 "command": "node",
611 "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"]198 "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"]
612 }199 }
613 }200 }
614 }201}
615 ```202```
616 </Piece>
617 203
618 <Piece id="lsp">204LSP 서버는 Claude에게 언어에 대한 [진단 및 코드 네비게이션](/docs/ko/plugins/code-intelligence)을 제공합니다. 플러그인 루트의 `.lsp.json`에서 서버를 선언합니다. 이 파일은 `.go` 파일에 대해 Go 언어 서버를 연결합니다:
619 LSP 서버는 Claude에게 언어에 대한 [진단 및 코드 네비게이션](/docs/ko/plugins/code-intelligence)을 제공합니다. 플러그인 루트의 `.lsp.json`에서 서버를 선언합니다. 이 파일은 `.go` 파일에 대해 Go 언어 서버를 연결합니다:
620 205
621 ```json theme={null}206```json theme={null}
622 {207{
623 "gopls": {208 "gopls": {
624 "command": "gopls",209 "command": "gopls",
625 "args": ["serve"],210 "args": ["serve"],
627 ".go": "go"212 ".go": "go"
628 }213 }
629 }214 }
630 }215}
631 ```216```
632 </Piece>
633</PluginExplorer>
634 217
635<h2 id="add-each-kind-of-component">218## 각 유형의 구성 요소 추가하기
636 각 유형의 구성 요소 추가하기
637</h2>
638 219
639아래 각 섹션은 한 가지 유형의 구성 요소를 다룹니다. 플러그인에서 해당 파일을 두는 위치, 검증을 통과하는 예시, 플러그인이 로드된 후 사용자에게 보이는 내용, 기본 위치를 변경하는 매니페스트 키를 설명합니다. 플러그인에 필요한 것만 추가하면 되며, 필수 항목은 없습니다.220아래 각 섹션은 한 가지 유형의 구성 요소를 다룹니다. 플러그인에서 해당 파일을 두는 위치, 검증을 통과하는 예시, 플러그인이 로드된 후 사용자에게 보이는 내용, 기본 위치를 변경하는 매니페스트 키를 설명합니다. 플러그인에 필요한 것만 추가하면 되며, 필수 항목은 없습니다.
640 221
641<h3 id="skills">222### Skills
642 Skills
643</h3>
644 223
645[스킬](/docs/ko/skills)은 설명이 작업과 일치할 때 Claude가 로드할 수 있는 `SKILL.md` 파일입니다. 사용자가 명령으로 직접 실행할 수도 있습니다. 각 스킬은 `skills/` 아래의 개별 디렉터리에 저장합니다.224[스킬](/docs/ko/skills)은 설명이 작업과 일치할 때 Claude가 로드할 수 있는 `SKILL.md` 파일입니다. 사용자가 명령으로 직접 실행할 수도 있습니다. 각 스킬은 `skills/` 아래의 개별 디렉터리에 저장합니다.
646 225
679 258
680frontmatter 필드와 보조 파일에 대해서는 [Skills](/docs/ko/skills)를 참조하십시오.259frontmatter 필드와 보조 파일에 대해서는 [Skills](/docs/ko/skills)를 참조하십시오.
681 260
682<h3 id="commands">261### Commands
683 Commands
684</h3>
685 262
686명령은 사용자가 `/my-plugin:about`처럼 이름으로 실행하는 단일 Markdown 파일입니다.263명령은 사용자가 `/my-plugin:about`처럼 이름으로 실행하는 단일 Markdown 파일입니다.
687 264
688<Note>265> [!NOTE]
689 명령은 이전 형식이며, 새로운 작업에서는 [스킬](#skills)이 이를 대체합니다. 스킬도 같은 방식으로 이름으로 실행되며, 디렉터리에 보조 파일을 함께 담을 수도 있습니다. `commands/`는 `.claude/commands/`에서 옮겨 오는 파일에만 사용하십시오.266>
690</Note>267> 명령은 이전 형식이며, 새로운 작업에서는 [스킬](#skills)이 이를 대체합니다. 스킬도 같은 방식으로 이름으로 실행되며, 디렉터리에 보조 파일을 함께 담을 수도 있습니다. `commands/`는 `.claude/commands/`에서 옮겨 오는 파일에만 사용하십시오.
691 268
692명령을 `commands/<file>.md`에 저장하면 `/<plugin>:<file>`이 됩니다. 하위 디렉터리는 세그먼트를 추가하므로 `commands/db/migrate.md`는 `/my-plugin:db:migrate`가 됩니다.269명령을 `commands/<file>.md`에 저장하면 `/<plugin>:<file>`이 됩니다. 하위 디렉터리는 세그먼트를 추가하므로 `commands/db/migrate.md`는 `/my-plugin:db:migrate`가 됩니다.
693 270
694명령 파일은 스킬과 동일한 frontmatter를 사용합니다.271명령 파일은 스킬과 동일한 frontmatter를 사용합니다.
695 272
696<h4 id="define-commands-in-the-manifest">273#### 매니페스트에서 명령 정의하기
697 매니페스트에서 명령 정의하기
698</h4>
699 274
700이 방법은 명령 파일을 `commands/`가 아닌 다른 위치에 두거나, 별도의 Markdown 파일 없이 `plugin.json` 안에 짧은 명령을 정의하려는 경우에만 필요합니다. `commands` 매니페스트 키를 설정하면 Claude Code는 `commands/`를 스캔하는 대신 이 키를 읽습니다. 이 키는 경로, 경로 배열, 또는 각 명령 이름을 `source` 파일이나 인라인 `content`에 매핑하는 객체를 받습니다.275이 방법은 명령 파일을 `commands/`가 아닌 다른 위치에 두거나, 별도의 Markdown 파일 없이 `plugin.json` 안에 짧은 명령을 정의하려는 경우에만 필요합니다. `commands` 매니페스트 키를 설정하면 Claude Code는 `commands/`를 스캔하는 대신 이 키를 읽습니다. 이 키는 경로, 경로 배열, 또는 각 명령 이름을 `source` 파일이나 인라인 `content`에 매핑하는 객체를 받습니다.
701 276
717 292
718전체 키 구문은 [`commands`](/docs/ko/plugins/manifest-reference#commands)를 참조하십시오.293전체 키 구문은 [`commands`](/docs/ko/plugins/manifest-reference#commands)를 참조하십시오.
719 294
720<h3 id="agents">295### Agents
721 Agents
722</h3>
723 296
724[서브에이전트](/docs/ko/sub-agents)는 자체 지침과 컨텍스트 윈도우를 가진 별도의 어시스턴트로, Claude가 작업을 위임할 수 있습니다. `agents/` 아래의 각 Markdown 파일이 하나의 서브에이전트를 정의합니다.297[서브에이전트](/docs/ko/sub-agents)는 자체 지침과 컨텍스트 윈도우를 가진 별도의 어시스턴트로, Claude가 작업을 위임할 수 있습니다. `agents/` 아래의 각 Markdown 파일이 하나의 서브에이전트를 정의합니다.
725 298
737 310
738`agents` 매니페스트 키는 `agents/` 스캔을 대체합니다.311`agents` 매니페스트 키는 `agents/` 스캔을 대체합니다.
739 312
740<h4 id="organize-agents-in-subfolders">313#### 하위 폴더로 에이전트 정리하기
741 하위 폴더로 에이전트 정리하기
742</h4>
743 314
744플러그인 에이전트 파일을 `agents/`의 하위 폴더에 둘 수 있습니다. Claude Code는 이를 [재귀적으로 로드](/docs/ko/sub-agents#choose-the-subagent-scope)하며, 플러그인 이름, 각 하위 폴더 이름, 파일 이름을 콜론으로 연결하여 에이전트의 범위 지정 이름을 만듭니다. 예를 들어 `my-plugin`이라는 플러그인의 `agents/review/security.md`는 `my-plugin:review:security`로 로드됩니다. 다음 두 가지 설정이 이 이름을 변경합니다.315플러그인 에이전트 파일을 `agents/`의 하위 폴더에 둘 수 있습니다. Claude Code는 이를 [재귀적으로 로드](/docs/ko/sub-agents#choose-the-subagent-scope)하며, 플러그인 이름, 각 하위 폴더 이름, 파일 이름을 콜론으로 연결하여 에이전트의 범위 지정 이름을 만듭니다. 예를 들어 `my-plugin`이라는 플러그인의 `agents/review/security.md`는 `my-plugin:review:security`로 로드됩니다. 다음 두 가지 설정이 이 이름을 변경합니다.
745 316
746* Frontmatter `name`: 파일 이름만 대체하므로 `agents/review/security.md`의 `name: audit`는 `my-plugin:review:audit`로 로드됩니다317* Frontmatter `name`: 파일 이름만 대체하므로 `agents/review/security.md`의 `name: audit`는 `my-plugin:review:audit`로 로드됩니다
747* 매니페스트 [`agents`](/docs/ko/plugins/manifest-reference#fields) 필드: 여기에 나열한 파일은 하위 폴더 이름 없이 로드되므로 `"agents": "./custom/review/security.md"`는 `my-plugin:security`로 로드됩니다318* 매니페스트 [`agents`](/docs/ko/plugins/manifest-reference#fields) 필드: 여기에 나열한 파일은 하위 폴더 이름 없이 로드되므로 `"agents": "./custom/review/security.md"`는 `my-plugin:security`로 로드됩니다
748 319
749<h4 id="frontmatter-fields-in-plugin-agents">320#### 플러그인 에이전트의 frontmatter 필드
750 플러그인 에이전트의 frontmatter 필드
751</h4>
752 321
753플러그인 에이전트의 frontmatter는 다음 규칙을 따릅니다.322플러그인 에이전트의 frontmatter는 다음 규칙을 따릅니다.
754 323
758 327
759각 필드의 역할과 우선순위 규칙은 [Subagents](/docs/ko/sub-agents#supported-frontmatter-fields)를 참조하십시오.328각 필드의 역할과 우선순위 규칙은 [Subagents](/docs/ko/sub-agents#supported-frontmatter-fields)를 참조하십시오.
760 329
761<h3 id="hooks">330### Hooks
762 Hooks
763</h3>
764 331
765[훅](/docs/ko/hooks-guide)은 파일을 편집할 때마다와 같이 Claude Code 수명 주기의 특정 시점에 셸 명령, HTTP 요청, MCP 도구 호출, 모델에 대한 프롬프트 또는 서브에이전트를 자동으로 실행합니다. 플러그인의 훅은 플러그인 루트의 `hooks/hooks.json`에 최상위 `"hooks"` 키 아래에, `settings.json`의 `hooks` 객체와 동일한 형태로 저장합니다. 따라서 기존 설정 훅을 그대로 복사해 넣을 수 있습니다.332[훅](/docs/ko/hooks-guide)은 파일을 편집할 때마다와 같이 Claude Code 수명 주기의 특정 시점에 셸 명령, HTTP 요청, MCP 도구 호출, 모델에 대한 프롬프트 또는 서브에이전트를 자동으로 실행합니다. 플러그인의 훅은 플러그인 루트의 `hooks/hooks.json`에 최상위 `"hooks"` 키 아래에, `settings.json`의 `hooks` 객체와 동일한 형태로 저장합니다. 따라서 기존 설정 훅을 그대로 복사해 넣을 수 있습니다.
766 333
794 361
795Claude Code 내부에서 실행되고 인터페이스에 그릴 수 있는 JavaScript 함수로 훅을 작성하려면, 같은 `hooks/hooks.json`의 `modules` 키 아래에 모듈 파일을 나열합니다. 이러한 모듈이 있는 플러그인이 mod입니다. [mod 만들기](/docs/ko/plugins/mods/create)를 참조하십시오.362Claude Code 내부에서 실행되고 인터페이스에 그릴 수 있는 JavaScript 함수로 훅을 작성하려면, 같은 `hooks/hooks.json`의 `modules` 키 아래에 모듈 파일을 나열합니다. 이러한 모듈이 있는 플러그인이 mod입니다. [mod 만들기](/docs/ko/plugins/mods/create)를 참조하십시오.
796 363
797<h4 id="when-plugin-hooks-fire">364#### 플러그인 훅이 실행되는 시점
798 플러그인 훅이 실행되는 시점
799</h4>
800 365
801플러그인의 훅은 플러그인의 스킬이나 명령이 사용될 때까지 기다리지 않습니다. Claude Code는 세션이 플러그인을 로드할 때 훅을 등록하며, 그 이후부터 해당 이벤트에서 훅이 실행됩니다. 훅의 실행 시점을 제한하려면 `matcher`의 범위를 좁히십시오.366플러그인의 훅은 플러그인의 스킬이나 명령이 사용될 때까지 기다리지 않습니다. Claude Code는 세션이 플러그인을 로드할 때 훅을 등록하며, 그 이후부터 해당 이벤트에서 훅이 실행됩니다. 훅의 실행 시점을 제한하려면 `matcher`의 범위를 좁히십시오.
802 367
803훅이 전혀 실행되지 않는다면 [실행되지 않는 훅](/docs/ko/plugins/troubleshooting#failed-to-load-hooks-from-and-hooks-that-dont-fire)을 참조하십시오.368훅이 전혀 실행되지 않는다면 [실행되지 않는 훅](/docs/ko/plugins/troubleshooting#failed-to-load-hooks-from-and-hooks-that-dont-fire)을 참조하십시오.
804 369
805<h4 id="environment-quoting-and-matching-mcp-tools">370#### 환경, 따옴표 처리 및 MCP 도구 매칭
806 환경, 따옴표 처리 및 MCP 도구 매칭
807</h4>
808 371
809훅의 환경, `${CLAUDE_PLUGIN_ROOT}`의 따옴표 처리, 플러그인 자체 MCP 도구에 대한 matcher는 다음과 같이 작동합니다.372훅의 환경, `${CLAUDE_PLUGIN_ROOT}`의 따옴표 처리, 플러그인 자체 MCP 도구에 대한 matcher는 다음과 같이 작동합니다.
810 373
812* **따옴표 처리**: `command`에 `args`가 없으면 셸을 통해 실행되므로, [Hooks](#hooks)의 `hooks/hooks.json` 예시처럼 `${CLAUDE_PLUGIN_ROOT}` 경로를 큰따옴표로 감싸 확장된 경로가 하나의 셸 단어로 유지되도록 하십시오. 대신 `args`를 전달하면 각 요소가 셸 없이 하나의 인수로 전달되므로 따옴표가 필요하지 않습니다. [exec 형식과 셸 형식](/docs/ko/hooks#exec-form-and-shell-form)을 참조하십시오375* **따옴표 처리**: `command`에 `args`가 없으면 셸을 통해 실행되므로, [Hooks](#hooks)의 `hooks/hooks.json` 예시처럼 `${CLAUDE_PLUGIN_ROOT}` 경로를 큰따옴표로 감싸 확장된 경로가 하나의 셸 단어로 유지되도록 하십시오. 대신 `args`를 전달하면 각 요소가 셸 없이 하나의 인수로 전달되므로 따옴표가 필요하지 않습니다. [exec 형식과 셸 형식](/docs/ko/hooks#exec-form-and-shell-form)을 참조하십시오
813* **플러그인 자체 MCP 도구 매칭**: [이 플러그인이 선언한 MCP 서버](#mcp-servers)의 도구 이름은 `mcp__plugin_<plugin>_<server>__<tool>`이므로, matcher에 이 전체 이름을 작성하십시오. 서버 이름만으로 된 matcher는 절대 실행되지 않습니다. [MCP 도구 매칭](/docs/ko/hooks#match-mcp-tools)을 참조하십시오376* **플러그인 자체 MCP 도구 매칭**: [이 플러그인이 선언한 MCP 서버](#mcp-servers)의 도구 이름은 `mcp__plugin_<plugin>_<server>__<tool>`이므로, matcher에 이 전체 이름을 작성하십시오. 서버 이름만으로 된 matcher는 절대 실행되지 않습니다. [MCP 도구 매칭](/docs/ko/hooks#match-mcp-tools)을 참조하십시오
814 377
815<h3 id="mcp-servers">378### MCP servers
816 MCP servers
817</h3>
818 379
819MCP 서버는 외부 시스템의 도구를 Claude에 제공합니다. 플러그인 루트의 `.mcp.json`에 [프로젝트 `.mcp.json`](/docs/ko/mcp#project-scope)과 동일한 형태로 선언합니다. 다음 `.mcp.json`은 `db`라는 서버 하나를 선언합니다.380MCP 서버는 외부 시스템의 도구를 Claude에 제공합니다. 플러그인 루트의 `.mcp.json`에 [프로젝트 `.mcp.json`](/docs/ko/mcp#project-scope)과 동일한 형태로 선언합니다. 다음 `.mcp.json`은 `db`라는 서버 하나를 선언합니다.
820 381
839 400
840`mcpServers` 매니페스트 키는 인라인 서버 맵, JSON 파일 경로, 또는 이들의 배열을 받습니다. 매니페스트 서버가 `.mcp.json`의 서버와 이름이 같으면 매니페스트 서버가 이를 대체합니다.401`mcpServers` 매니페스트 키는 인라인 서버 맵, JSON 파일 경로, 또는 이들의 배열을 받습니다. 매니페스트 서버가 `.mcp.json`의 서버와 이름이 같으면 매니페스트 서버가 이를 대체합니다.
841 402
842<h4 id="reach-users-on-claude-ai-and-cowork">403#### claude.ai 및 Cowork 사용자에게 제공하기
843 claude.ai 및 Cowork 사용자에게 제공하기
844</h4>
845 404
846[MCP servers](#mcp-servers)의 `db` 서버와 같은 로컬 stdio 서버는 Claude Code와 Claude Desktop 앱에서 사용자의 컴퓨터로 실행되는 Cowork 세션에서는 실행되지만 claude.ai에서는 실행되지 않습니다. 해당 사용자에게도 제공하려면 [Bundle an MCP connector with its skill](https://claude.com/docs/plugins/build#bundle-an-mcp-connector-with-its-skill)에 나온 것처럼 `https://` URL로 원격 서버를 참조하십시오. claude.ai와 Cowork는 이를 사용자에게 커넥터로 제공합니다.405[MCP servers](#mcp-servers)의 `db` 서버와 같은 로컬 stdio 서버는 Claude Code와 Claude Desktop 앱에서 사용자의 컴퓨터로 실행되는 Cowork 세션에서는 실행되지만 claude.ai에서는 실행되지 않습니다. 해당 사용자에게도 제공하려면 [Bundle an MCP connector with its skill](https://claude.com/docs/plugins/build#bundle-an-mcp-connector-with-its-skill)에 나온 것처럼 `https://` URL로 원격 서버를 참조하십시오. claude.ai와 Cowork는 이를 사용자에게 커넥터로 제공합니다.
847 406
848<h4 id="server-names-tool-names-and-reloads">407#### 서버 이름, 도구 이름 및 다시 로드
849 서버 이름, 도구 이름 및 다시 로드
850</h4>
851 408
852서버의 이름, 변수 치환, 다시 로드 동작은 다음 규칙을 따릅니다.409서버의 이름, 변수 치환, 다시 로드 동작은 다음 규칙을 따릅니다.
853 410
856* **치환**: `${CLAUDE_PLUGIN_ROOT}`와 기타 [경로 변수](#path-variables-and-persistent-data)는 `command`, `args`, `env`에서 치환됩니다. `args`에서는 각 요소가 하나의 인수로 전달되므로 따옴표가 필요하지 않습니다413* **치환**: `${CLAUDE_PLUGIN_ROOT}`와 기타 [경로 변수](#path-variables-and-persistent-data)는 `command`, `args`, `env`에서 치환됩니다. `args`에서는 각 요소가 하나의 인수로 전달되므로 따옴표가 필요하지 않습니다
857* **다시 로드**: 사용자가 `/reload-plugins`를 실행하고 [다시 로드가 적용되면](/docs/ko/plugins/cli-reference#reloads-that-change-mcp-tools), 구성이 변경되지 않은 서버는 연결을 유지합니다. 구성이 변경된 서버는 다시 연결되고, 제거한 서버는 연결이 해제됩니다414* **다시 로드**: 사용자가 `/reload-plugins`를 실행하고 [다시 로드가 적용되면](/docs/ko/plugins/cli-reference#reloads-that-change-mcp-tools), 구성이 변경되지 않은 서버는 연결을 유지합니다. 구성이 변경된 서버는 다시 연결되고, 제거한 서버는 연결이 해제됩니다
858 415
859<h4 id="include-a-packaged-mcpb-server">416#### 패키징된 MCPB 서버 포함하기
860 패키징된 MCPB 서버 포함하기
861</h4>
862 417
863`mcpServers` 키는 확장자가 `.mcpb` 또는 이전 형식인 `.dxt`인 [MCPB 파일](https://github.com/modelcontextprotocol/mcpb)로 패키징된 서버도 받습니다. 키가 플러그인 내부 경로 또는 `https://` URL로 파일을 가리키도록 지정합니다.418`mcpServers` 키는 확장자가 `.mcpb` 또는 이전 형식인 `.dxt`인 [MCPB 파일](https://github.com/modelcontextprotocol/mcpb)로 패키징된 서버도 받습니다. 키가 플러그인 내부 경로 또는 `https://` URL로 파일을 가리키도록 지정합니다.
864 419
880 435
881전송 방식과 인증에 대해서는 [MCP](/docs/ko/mcp#plugin-provided-mcp-servers)를 참조하십시오.436전송 방식과 인증에 대해서는 [MCP](/docs/ko/mcp#plugin-provided-mcp-servers)를 참조하십시오.
882 437
883<h3 id="lsp-servers">438### LSP servers
884 LSP servers
885</h3>
886 439
887LSP 서버는 특정 언어에 대한 진단과 코드 탐색 기능을 Claude에 제공합니다. [공식 코드 인텔리전스 플러그인](/docs/ko/plugins/code-intelligence)이 이미 해당 언어를 지원한다면 직접 작성하는 대신 그 플러그인을 설치하십시오. 그렇지 않으면 플러그인 루트의 `.lsp.json`에 서버를 선언합니다.440LSP 서버는 특정 언어에 대한 진단과 코드 탐색 기능을 Claude에 제공합니다. [공식 코드 인텔리전스 플러그인](/docs/ko/plugins/code-intelligence)이 이미 해당 언어를 지원한다면 직접 작성하는 대신 그 플러그인을 설치하십시오. 그렇지 않으면 플러그인 루트의 `.lsp.json`에 서버를 선언합니다.
888 441
915 468
916Claude Code는 두 제한 중 하나를 초과하거나 stdout에 프로토콜이 아닌 출력을 쓰는 서버의 연결을 끊고, 이 연결 해제를 `restartOnCrash` 및 `maxRestarts`에 대한 충돌로 집계합니다. `--debug`로 실행하면 Claude Code가 원인을 명시한 오류를 디버그 로그에 기록합니다.469Claude Code는 두 제한 중 하나를 초과하거나 stdout에 프로토콜이 아닌 출력을 쓰는 서버의 연결을 끊고, 이 연결 해제를 `restartOnCrash` 및 `maxRestarts`에 대한 충돌로 집계합니다. `--debug`로 실행하면 Claude Code가 원인을 명시한 오류를 디버그 로그에 기록합니다.
917 470
918<h3 id="executables">471### Executables
919 Executables
920</h3>
921 472
922플러그인 루트의 `bin/`에 있는 파일은 플러그인이 활성화된 동안 Bash 도구 셸의 `PATH`에 포함되므로, Claude가 이를 단독 명령으로 실행할 수 있습니다. 실행 가능한 스크립트를 추가합니다.473플러그인 루트의 `bin/`에 있는 파일은 플러그인이 활성화된 동안 Bash 도구 셸의 `PATH`에 포함되므로, Claude가 이를 단독 명령으로 실행할 수 있습니다. Claude가 [샌드박스](/docs/ko/sandboxing) 외부에서 [PowerShell 도구](/docs/ko/tools-reference#powershell-tool)로 실행하는 명령도 `PATH`에서 이 파일을 찾을 수 있지만, 샌드박스 안에서 실행되는 PowerShell 명령은 찾을 수 없습니다. 실행 가능한 스크립트를 추가합니다.
923 474
924```bash bin/hello-plugin theme={null}475```bash bin/hello-plugin theme={null}
925#!/bin/bash476#!/bin/bash
932 483
933claude.ai와 Cowork는 최상위 `bin/` 디렉터리가 있는 플러그인을 설치하지 않으며, [claude.ai 조직 설정을 통해 배포](https://claude.com/docs/plugins/org-sync#keep-executables-out-of-the-top-level-bin-directory)하는 플러그인도 마찬가지입니다.484claude.ai와 Cowork는 최상위 `bin/` 디렉터리가 있는 플러그인을 설치하지 않으며, [claude.ai 조직 설정을 통해 배포](https://claude.com/docs/plugins/org-sync#keep-executables-out-of-the-top-level-bin-directory)하는 플러그인도 마찬가지입니다.
934 485
935<h3 id="default-settings">486### Default settings
936 Default settings
937</h3>
938 487
939플러그인이 활성화된 동안 적용되는 기본값을 설정하려면 플러그인 루트에 `settings.json`을 추가하거나, 같은 객체를 `settings` 매니페스트 키에 인라인으로 넣습니다. 적용되는 키는 `agent`와 `subagentStatusLine` 두 가지이며, 그 외의 키는 모두 제외됩니다.488플러그인이 활성화된 동안 적용되는 기본값을 설정하려면 플러그인 루트에 `settings.json`을 추가하거나, 같은 객체를 `settings` 매니페스트 키에 인라인으로 넣습니다. 적용되는 키는 `agent`와 `subagentStatusLine` 두 가지이며, 그 외의 키는 모두 제외됩니다.
940 489
958 507
959`subagentStatusLine`의 형태는 [서브에이전트 상태줄](/docs/ko/statusline#subagent-status-lines)을 참조하십시오.508`subagentStatusLine`의 형태는 [서브에이전트 상태줄](/docs/ko/statusline#subagent-status-lines)을 참조하십시오.
960 509
961<h3 id="themes-and-output-styles">510### Themes and output styles
962 Themes and output styles
963</h3>
964 511
965플러그인에는 색상 테마와 출력 스타일을 포함할 수 있습니다. 둘 다 사용자 자체의 항목과 같은 선택기에 표시됩니다. 두 경우 모두 매니페스트 키를 설정하면 폴더 스캔이 대체됩니다.512플러그인에는 색상 테마와 출력 스타일을 포함할 수 있습니다. 둘 다 사용자 자체의 항목과 같은 선택기에 표시됩니다. 두 경우 모두 매니페스트 키를 설정하면 폴더 스캔이 대체됩니다.
966 513
984}531}
985```532```
986 533
987<h3 id="channels">534### Channels
988 Channels
989</h3>
990 535
991[채널](/docs/ko/channels)을 사용하면 채팅 앱과 같은 외부 시스템이 세션으로 메시지를 보낼 수 있습니다. 플러그인에서 채널은 MCP 서버 중 하나와, 이에 바인딩되며 자체 구성을 요청할 수 있는 `channels` 항목으로 구성됩니다. 다음 매니페스트는 채널을 `telegram` 서버에 바인딩하고 봇 토큰을 요청합니다.536[채널](/docs/ko/channels)을 사용하면 채팅 앱과 같은 외부 시스템이 세션으로 메시지를 보낼 수 있습니다. 플러그인에서 채널은 MCP 서버 중 하나와, 이에 바인딩되며 자체 구성을 요청할 수 있는 `channels` 항목으로 구성됩니다. 다음 매니페스트는 채널을 `telegram` 서버에 바인딩하고 봇 토큰을 요청합니다.
992 537
1020 565
1021서버가 구현해야 하는 사항과 사용자가 채널 플러그인을 활성화하는 방법은 채널 레퍼런스의 [플러그인으로 패키징하기](/docs/ko/channels-reference#package-as-a-plugin)를 참조하십시오. 필드 표는 [`channels`](/docs/ko/plugins/manifest-reference#channels)를 참조하십시오.566서버가 구현해야 하는 사항과 사용자가 채널 플러그인을 활성화하는 방법은 채널 레퍼런스의 [플러그인으로 패키징하기](/docs/ko/channels-reference#package-as-a-plugin)를 참조하십시오. 필드 표는 [`channels`](/docs/ko/plugins/manifest-reference#channels)를 참조하십시오.
1022 567
1023<h3 id="monitors">568### Monitors
1024 Monitors
1025</h3>
1026 569
1027모니터는 세션 전체 동안 백그라운드에서 실행되는 셸 명령입니다. 모니터가 출력하는 내용은 알림으로 Claude에 전달되므로, Claude는 감시하라는 요청을 받지 않아도 로그나 상태 변경에 대응할 수 있습니다. 항목은 `monitors/monitors.json`에 저장합니다.570모니터는 세션 전체 동안 백그라운드에서 실행되는 셸 명령입니다. 모니터가 출력하는 내용은 알림으로 Claude에 전달되므로, Claude는 감시하라는 요청을 받지 않아도 로그나 상태 변경에 대응할 수 있습니다. 항목은 `monitors/monitors.json`에 저장합니다.
1028 571
1048 591
1049`when` 트리거와 기타 필드는 [`monitors`](/docs/ko/plugins/manifest-reference#monitors)를 참조하십시오.592`when` 트리거와 기타 필드는 [`monitors`](/docs/ko/plugins/manifest-reference#monitors)를 참조하십시오.
1050 593
1051<h2 id="user-configuration">594## 사용자에게 구성 값을 요청합니다
1052 사용자에게 구성 값을 요청합니다
1053</h2>
1054 595
1055플러그인이 사용자로부터 필요로 하는 값을 `userConfig` manifest 키에서 선언하여, 사용자가 `settings.json`을 자신들이 편집하지 않도록 합니다. 각 옵션은 `title`을 레이블로 하고 `description`을 아래에 가진 대화 상자에 나타납니다.596플러그인이 사용자로부터 필요로 하는 값을 `userConfig` manifest 키에서 선언하여, 사용자가 `settings.json`을 자신들이 편집하지 않도록 합니다. 각 옵션은 `title`을 레이블로 하고 `description`을 아래에 가진 대화 상자에 나타납니다.
1056 597
1077}618}
1078```619```
1079 620
1080<h3 id="when-the-configuration-dialog-appears">621### 구성 대화 상자가 나타날 때
1081 구성 대화 상자가 나타날 때
1082</h3>
1083 622
1084대화 상자는 대화형 `/plugin` 인터페이스의 일부입니다. 사용자가 다음 중 하나를 수행할 때 아직 설정되지 않은 옵션에 대해 열립니다:623대화 상자는 대화형 `/plugin` 인터페이스의 일부입니다. 사용자가 다음 중 하나를 수행할 때 아직 설정되지 않은 옵션에 대해 열립니다:
1085 624
1097 636
1098옵션 필드, 각 값이 저장되는 위치, 컴포넌트가 저장된 값을 참조하는 방법, `${user_config.*}`를 거부하는 필드의 경우, [사용자 구성](/docs/ko/plugins/manifest-reference#user-configuration)을 참조합니다.637옵션 필드, 각 값이 저장되는 위치, 컴포넌트가 저장된 값을 참조하는 방법, `${user_config.*}`를 거부하는 필드의 경우, [사용자 구성](/docs/ko/plugins/manifest-reference#user-configuration)을 참조합니다.
1099 638
1100<h2 id="path-variables-and-persistent-data">639## 플러그인 경로 참조 및 데이터 저장
1101 플러그인 경로 참조 및 데이터 저장
1102</h2>
1103 640
1104플러그인이 어디에 설치될지 모르므로, 고정 경로보다는 이 변수를 통해 파일과 데이터를 참조합니다. 이들은 skill, 명령, agent 콘텐츠에서, hook과 모니터 명령에서, MCP와 LSP 서버 구성에서 대체됩니다. 또한 hook, MCP, LSP 프로세스로 내보내집니다:641플러그인이 어디에 설치될지 모르므로, 고정 경로보다는 이 변수를 통해 파일과 데이터를 참조합니다. 이들은 skill, 명령, agent 콘텐츠에서, hook과 모니터 명령에서, MCP와 LSP 서버 구성에서 대체됩니다. 또한 hook, MCP, LSP 프로세스로 내보내집니다:
1105 642
1111 648
1112Windows에서, 대체된 경로는 셸이 백슬래시를 이스케이프로 읽지 않도록 전진 슬래시를 사용합니다.649Windows에서, 대체된 경로는 셸이 백슬래시를 이스케이프로 읽지 않도록 전진 슬래시를 사용합니다.
1113 650
1114<h3 id="install-dependencies-into-the-data-directory">651### 데이터 디렉토리에 종속성 설치
1115 데이터 디렉토리에 종속성 설치
1116</h3>
1117 652
1118마켓플레이스 설치 플러그인의 경우, Claude Code는 플러그인을 캐시할 때 적격 [Node.js 패키지 종속성](/docs/ko/plugins/loading#node-js-package-dependencies)을 자동으로 설치하므로, 자신이 설치할 필요가 없을 수 있습니다. 할 때, 이 `SessionStart` hook은 첫 실행 시 `${CLAUDE_PLUGIN_DATA}`에 `node_modules`를 설치하고 업데이트가 `package.json`을 변경한 후 다시 설치합니다:653마켓플레이스 설치 플러그인의 경우, Claude Code는 플러그인을 캐시할 때 적격 [Node.js 패키지 종속성](/docs/ko/plugins/loading#node-js-package-dependencies)을 자동으로 설치하므로, 자신이 설치할 필요가 없을 수 있습니다. 할 때, 이 `SessionStart` hook은 첫 실행 시 `${CLAUDE_PLUGIN_DATA}`에 `node_modules`를 설치하고 업데이트가 `package.json`을 변경한 후 다시 설치합니다:
1119 654
1136 671
1137첫 번째 세션 후, `~/.claude/plugins/data/<id>/node_modules`이 존재합니다. MCP 서버는 그 다음 `NODE_PATH`를 `${CLAUDE_PLUGIN_DATA}/node_modules`로 설정할 수 있습니다. 어느 필드가 어느 변수를 대체하는지의 경우, [환경 변수](/docs/ko/plugins/manifest-reference#environment-variables)를 참조합니다.672첫 번째 세션 후, `~/.claude/plugins/data/<id>/node_modules`이 존재합니다. MCP 서버는 그 다음 `NODE_PATH`를 `${CLAUDE_PLUGIN_DATA}/node_modules`로 설정할 수 있습니다. 어느 필드가 어느 변수를 대체하는지의 경우, [환경 변수](/docs/ko/plugins/manifest-reference#environment-variables)를 참조합니다.
1138 673
1139<h2 id="next-steps">674## 다음 단계
1140 다음 단계
1141</h2>
1142 675
1143* [플러그인 manifest 참조](/docs/ko/plugins/manifest-reference): `plugin.json` 필드, 경로 규칙, 표준 레이아웃676* [플러그인 manifest 참조](/docs/ko/plugins/manifest-reference): `plugin.json` 필드, 경로 규칙, 표준 레이아웃
1144* [evals로 플러그인 테스트](/docs/ko/plugin-evals): 추가한 컴포넌트가 Claude의 동작을 의도한 방식으로 변경하는지 확인합니다677* [evals로 플러그인 테스트](/docs/ko/plugin-evals): 추가한 컴포넌트가 Claude의 동작을 의도한 방식으로 변경하는지 확인합니다