아빠노트

Claude Code 로컬 플러그인 만들고 불러오기 — claude plugin validate와 --plugin-dir 윈도우 실측

실측 2026-09-17처음 쓴 날 2026-09-17 · English version

공식 문서의 빠른 시작대로 plugin.json과 SKILL.md 두 파일만 만들면 claude plugin validate가 ✔ Validation passed를 냈습니다.

한 줄로

공식 문서의 빠른 시작대로 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을 고쳤는데 플러그인이 안 뜨는 이유를 찾는 분. 사용자 설정에 설치하지 않고 이번 실행에만 플러그인을 불러오고 싶은 분.

실측 환경

항목값
OSWindows 11 Home (10.0.26200)
셸Git Bash
Claude Code2.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-plugindescription을 descripton으로 오타⚠ Found 2 warnings → ✔ Validation passed with warnings0
typo-plugin + --strict같음✘ Validation failed (--strict treats warnings as errors)1
badtype-plugin"keywords": "greeting" (배열 자리에 문자열)❯ keywords: Invalid input → ✘ Validation failed1
noname-pluginname 없이 description만 있음❯ name: Invalid input → ✘ Validation failed1
wrongdir-pluginskills/를 .claude-plugin/ 안에 둠✔ Validation passed0
badskill-plugin (1차)SKILL.md에 description: [unclosed✔ Validation passed0
badskill-plugin (2차)SKILL.md 머리말을 더 망가뜨리고 agents/broken.md 추가✘ Validation failed1
no-such-dir없는 경로❯ file: File not found: ... → ✘ Validation failed1

오타 경고 문구는 이랬습니다.

  ❯ 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 does

badskill-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 inputnot found, 종료 코드 1
badskill-plugin (2차)(폴더 전체 로드에서) ✔ loadedSkills (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 input

validate에서 오류(종료 코드 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
오류가 있는 manifestvalidate (keywords 타입, name 누락)✘ Validation failed, 종료 코드 1
경고만 있는 manifestvalidate / validate --strict0 / 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의 토큰 수가 어떤 방식으로 계산됐는지.

함께 보기