AI 해결 노트 · 2026-09-17 · 실측 2026-09-17
Claude Code 로컬 플러그인 만들고 불러오기 — claude plugin validate와 --plugin-dir 윈도우 실측
한 줄로
공식 문서의 빠른 시작대로 plugin.json과 SKILL.md 두 파일만 만들면 claude plugin validate가 ✔ Validation passed를 냈습니다. --plugin-dir로 불러온 플러그인은 대화 세션을 열지 않아도 claude --plugin-dir <폴더> plugin list와 plugin details로 로드 여부를 볼 수 있었습니다. skills/를 .claude-plugin/ 안에 넣는 실수는 validate를 통과했지만, details에서 Skills (0)으로 드러났습니다.
이런 분께
마켓플레이스에 올리기 전에 내 PC에서 플러그인을 먼저 시험해 보고 싶은 분. plugin.json을 고쳤는데 플러그인이 안 뜨는 이유를 찾는 분. 사용자 설정에 설치하지 않고 이번 실행에만 플러그인을 불러오고 싶은 분.
실측 환경
| 항목 | 값 |
|---|---|
| OS | Windows 11 Home (10.0.26200) |
| 셸 | Git Bash |
| Claude Code | 2.1.274 (Claude Code) |
| 실험 폴더 | C:\Users\User\AppData\Local\Temp\longtail_B2\plugins |
| 참고 문서 | code.claude.com/docs/en/plugins , code.claude.com/docs/en/plugins-reference , code.claude.com/docs/en/plugin-marketplaces (모두 2026-09-17 확인) |
도움말에서 쓸 것 고르기
claude plugin --help에는 validate, details, list, init, install 등이 있습니다. 이번에 쓴 것과 쓰지 않은 것을 나눴습니다.
validate [options] <path> Validate a plugin or marketplace
manifest, or the skills, agents, and
commands in a directory
details [options] <name> Show a plugin's component inventory and
projected token cost
list [options] List installed plugins
init|new [options] <name> Scaffold a new plugin at
~/.claude/skills/<name>/ (auto-loads next
session as <name>@skills-dir)init은 도움말대로라면 사용자 폴더(~/.claude/skills/)에 파일을 만듭니다. 이번에는 init과 install을 쓰지 않고, 임시 폴더에 파일을 직접 작성했습니다. 불러오기에는 claude --help의 이 옵션을 썼습니다.
--plugin-dir <path> Load a plugin from a directory or .zip
for this session only; a folder of
plugins loads each child (repeatable:
--plugin-dir A --plugin-dir B.zip)claude plugin validate --help의 옵션은 --json(Output the validation report as JSON (same exit codes))과 --strict(Treat warnings as errors (exit 1))입니다.
1단계 — 최소 플러그인 만들기
문서(plugins)의 빠른 시작 예시를 그대로 옮겼습니다. 구조는 이렇습니다.
my-first-plugin/
├── .claude-plugin/
│ └── plugin.json
└── skills/
└── hello/
└── SKILL.md{
"name": "my-first-plugin",
"description": "A greeting plugin to learn the basics",
"version": "1.0.0",
"author": {
"name": "Your Name"
}
}---
description: Greet the user with a friendly message
disable-model-invocation: true
---
Greet the user warmly and ask how you can help them today.문서(plugins-reference)에는 "If you include a manifest, name is the only required field."라고 적혀 있습니다. 스킬 폴더 이름 hello가 스킬 이름이 되고, 플러그인 이름이 앞에 붙어 /my-first-plugin:hello가 된다고 설명합니다.
2단계 — claude plugin validate
$ claude plugin validate ./my-first-plugin
Validating plugin manifest: C:\Users\User\AppData\Local\Temp\longtail_B2\plugins\my-first-plugin\.claude-plugin\plugin.json
✔ Validation passed종료 코드는 0이었고, --strict를 붙여도 같았습니다. --json으로 받으면 이렇습니다.
{
"success": true,
"strict": false,
"target": "C:\\Users\\User\\AppData\\Local\\Temp\\longtail_B2\\plugins\\my-first-plugin\\.claude-plugin\\plugin.json",
"manifest": {
"file": "C:\\Users\\User\\AppData\\Local\\Temp\\longtail_B2\\plugins\\my-first-plugin\\.claude-plugin\\plugin.json",
"type": "plugin",
"errors": [],
"warnings": [],
"notes": []
},
"contents": []
}3단계 — 일부러 고장 낸 플러그인 검증
검증용 플러그인을 몇 개 더 만들었습니다. 대부분 정상 플러그인에서 한 군데만 바꿨고, noname-plugin은 plugin.json에 "description": "no name field"만 넣었습니다.
| 폴더 | 바꾼 것 | validate 결과 | 종료 코드 |
|---|---|---|---|
| typo-plugin | description을 descripton으로 오타 | ⚠ Found 2 warnings → ✔ Validation passed with warnings | 0 |
typo-plugin + --strict | 같음 | ✘ Validation failed (--strict treats warnings as errors) | 1 |
| badtype-plugin | "keywords": "greeting" (배열 자리에 문자열) | ❯ keywords: Invalid input → ✘ Validation failed | 1 |
| noname-plugin | name 없이 description만 있음 | ❯ name: Invalid input → ✘ Validation failed | 1 |
| wrongdir-plugin | skills/를 .claude-plugin/ 안에 둠 | ✔ Validation passed | 0 |
| badskill-plugin (1차) | SKILL.md에 description: [unclosed | ✔ Validation passed | 0 |
| badskill-plugin (2차) | SKILL.md 머리말을 더 망가뜨리고 agents/broken.md 추가 | ✘ Validation failed | 1 |
| no-such-dir | 없는 경로 | ❯ file: File not found: ... → ✘ Validation failed | 1 |
오타 경고 문구는 이랬습니다.
❯ descripton: Unknown field 'descripton' — did you mean 'description'? Claude Code ignores unrecognized fields at load time, so this field has no effect.
❯ description: No description provided. Adding a description helps users understand what your plugin doesbadskill-plugin 2차의 SKILL.md 머리말은 description: "unterminated로 따옴표를 닫지 않고, 들여쓰기가 어긋난 줄과 탭 줄을 넣은 것입니다. 결과는 이랬습니다.
Validating skill: C:\...\badskill-plugin\skills\hello\SKILL.md
✘ Found 1 error:
❯ frontmatter: YAML frontmatter failed to parse: YAML Parse error: Unexpected EOF. At runtime this skill loads with empty metadata (all frontmatter fields silently dropped).
Validating agent: C:\...\badskill-plugin\agents\broken.md
⚠ Found 1 warning:
❯ description: No description in frontmatter. A description helps users and Claude understand when to use this agent.눈여겨볼 점이 세 가지 있었습니다.
- wrongdir-plugin은 통과했습니다. 문서가 "Common mistake"로 꼽은 구조인데
validate만으로는 걸러지지 않았습니다. 아래 4단계에서details로 확인됩니다. - 1차의
description: [unclosed는 오류로 잡히지 않았습니다.agents/broken.md의name: [oops도 파싱 오류가 아니라 description이 없다는 경고만 나왔습니다. 대괄호가 안 닫힌 값을 왜 통과시켰는지는 확인하지 못했습니다. - 없는 경로는 종료 코드 1이었습니다. 문서(plugins-reference)는 "2 when the validation run itself fails, such as when the path you pass is unreadable"이라고 적고 있지만, 이번 없는 경로는 2가 아니라 검증 실패(1)로 처리됐습니다.
스킬 폴더만 따로 검증하는 방법도 문서(plugin-marketplaces)에 있습니다. claude plugin validate ./badskill-plugin/skills는 Validating components in: ... 뒤에 같은 frontmatter 오류를 내고 종료 코드 1이었습니다.
4단계 — --plugin-dir로 불렀을 때 실제로 로드됐나
문서의 테스트 방법은 claude --plugin-dir ./my-first-plugin으로 대화 세션을 여는 것입니다. 이번에는 대화 세션을 열지 않고, --plugin-dir을 plugin list·plugin details와 함께 줬습니다.
claude --plugin-dir ./my-first-plugin plugin list | grep -n -A4 'my-first-plugin'300: ❯ my-first-plugin@inline
301- Version: 1.0.0
302: Path: C:\Users\User\AppData\Local\Temp\longtail_B2\plugins\my-first-plugin
303- Status: ✔ loaded--json으로 받으면 "id": "my-first-plugin@inline", "scope": "session", "enabled": true였습니다. --plugin-dir 없이 claude plugin list --json을 돌리면 my-first-plugin은 0건이었습니다.
$ claude --plugin-dir ./my-first-plugin plugin details my-first-plugin
my-first-plugin 1.0.0
Description: A greeting plugin to learn the basics
Source: my-first-plugin@inline
Component inventory
Skills (1) hello
Agents (0)
Hooks (0)
MCP servers (0)
LSP servers (0)
Projected token cost
Always-on: ~27 tok added to every session--plugin-dir 없이 claude plugin details my-first-plugin을 치면 `Plugin "my-first-plugin" not found. Run claude plugin list to see installed plugins, or pass --plugin-dir <path> to load one from disk.`와 함께 종료 코드 1이었습니다.
고장 낸 플러그인들도 같은 방법으로 봤습니다.
| 폴더 | plugin list(--plugin-dir) | plugin details |
|---|---|---|
| wrongdir-plugin | (개별로는 보지 않음) | Skills (0), Always-on: ~0 tok |
| badtype-plugin | ✘ Failed to load plugin: Plugin badtype-plugin has an invalid manifest file at ... Validation errors: keywords: Invalid input | not found, 종료 코드 1 |
| badskill-plugin (2차) | (폴더 전체 로드에서) ✔ loaded | Skills (1) hello, Agents (1) broken |
wrongdir-plugin은 validate를 통과하고 로드도 됐지만 스킬이 0개였습니다. badskill-plugin은 머리말 파싱 오류가 있어도 스킬이 목록에 올라왔습니다. validate의 오류 문구대로라면 이 스킬은 머리말 값이 빠진 채로 로드됩니다.
5단계 — 플러그인 여러 개를 폴더째로
--plugin-dir에 플러그인들을 담은 상위 폴더를 주면 하위 폴더를 각각 불러온다고 도움말에 적혀 있습니다. 문서(plugins)는 이 기능에 v2.1.265 이상이 필요하다고 합니다.
claude --plugin-dir . plugin list | grep -n 'inline'300: ❯ badskill-plugin@inline
305: ❯ my-first-plugin@inline
310: ❯ typo-plugin@inline
315: ❯ wrongdir-plugin@inline
320: ❯ inline[1]: ✘ Failed to load plugin: Plugin badtype-plugin has an invalid manifest file at ...\badtype-plugin\.claude-plugin\plugin.json. Validation errors: keywords: Invalid input
322: ❯ inline[3]: ✘ Failed to load plugin: Plugin noname-plugin has an invalid manifest file at ...\noname-plugin\.claude-plugin\plugin.json. Validation errors: name: Invalid inputvalidate에서 오류(종료 코드 1)였던 두 개는 로드에 실패했고, 경고만 있던 typo-plugin은 로드됐습니다. 문서의 "A plugin with only unrecognized-field warnings still passes validation and loads at runtime."과 같은 결과입니다.
결과
| 확인 | 명령 | 결과 |
|---|---|---|
| 정상 플러그인 검증 | claude plugin validate ./my-first-plugin | ✔ Validation passed, 종료 코드 0 |
| 오류가 있는 manifest | validate (keywords 타입, name 누락) | ✘ Validation failed, 종료 코드 1 |
| 경고만 있는 manifest | validate / validate --strict | 0 / 1 |
구조 실수(.claude-plugin/skills) | validate → details | 통과 → Skills (0) |
| 로드 확인 | claude --plugin-dir <폴더> plugin list | @inline, Status: ✔ loaded |
| 로드 실패 확인 | 같음 | ✘ Failed to load plugin: ... |
| 사용자 설정 흔적 | ~/.claude.json, ~/.claude/settings.json, installed_plugins.json 문자열 건수 | 모두 0건 |
실패한 것
validate로 머리말 오류를 잡으려던 첫 시도(description: [unclosed)는 오류로 잡히지 않았습니다. 따옴표를 닫지 않은 두 번째 파일에서야 YAML frontmatter failed to parse가 나왔습니다.
확인하지 않은 것
- 대화 세션에서
/my-first-plugin:hello를 실제로 불러 보기,/reload-plugins,/plugin화면의 Errors 탭.--plugin-dir의 로드 여부는plugin list·details로만 봤습니다. .zip파일을--plugin-dir에 주는 방법과--plugin-url.claude plugin init으로 만들기,install로 설치하기,marketplace관리(init은--help만 확인).- hooks, MCP 서버, 에이전트를 넣은 플러그인의 동작.
- 종료 코드 2가 나오는 경우(읽을 수 없는 경로 등).
plugin details의 토큰 수가 어떤 방식으로 계산됐는지.