Table of contents
- 왜 패키지인가
- 디렉토리 한 장 — 플러그인의 정체
- 가장 작은 플러그인 만들기
- 다른 컴포넌트 얹기
- 마켓플레이스 — 플러그인의 카탈로그
- 배포 — GitHub에 푸시하고 끝
- 운영에서 알아둘 것 — 스코프·버전·strict
- 공식 마켓플레이스 — Anthropic이 직접 관리하는 곳
- 디버깅이 안 될 때
- 마무리
- 참고 자료
왜 패키지인가
Claude Code에 자기 작업 환경을 박아 넣는 방법은 처음엔 단순했다. ~/.claude/ 밑에 스킬과 훅을 흩뿌리거나, 프로젝트 루트의 .claude/에 챙겨두는 식이다. 혼자 쓰는 동안엔 충분하다. 그런데 팀에 공유하려고 하면 갑자기 일이 된다. “그 폴더 복사해서 깔아라”가 안내의 전부고, 버전이 다르면 누구 환경에서는 동작하고 누구는 안 된다.
플러그인은 이 문제를 정면으로 푼다. 스킬, 에이전트, 훅, MCP 서버, LSP 서버를 한 묶음의 디렉토리로 패키징하고, 매니페스트 한 장으로 식별한다. 마켓플레이스는 그 묶음들을 모아 두는 카탈로그다. 사용자는 /plugin install 한 줄로 받아 가고, 작성자가 새 버전을 푸시하면 자동 업데이트가 흐른다.
flowchart LR
classDef src fill:#5ca45c,color:#fff,stroke:#3d7740
classDef mkt fill:#4a90d9,color:#fff,stroke:#2c5d8f
classDef user fill:#d4943a,color:#fff,stroke:#9c6a26
Dev[작성자]:::src
Plugin[플러그인 디렉토리<br/>.claude-plugin/plugin.json]:::src
MP[마켓플레이스<br/>.claude-plugin/marketplace.json]:::mkt
GH[GitHub 리포]:::mkt
User[사용자]:::user
Dev --> Plugin
Plugin --> MP
MP --> GH
GH -->|/plugin marketplace add| User
User -->|/plugin install| Plugin
이 글은 플러그인 한 개 만들기부터 마켓플레이스에 올려 배포까지를 한 흐름으로 따라간다. 공식 문서는 분리돼 있지만, 실제로는 한 번에 익히는 게 자연스럽다.
디렉토리 한 장 — 플러그인의 정체
플러그인은 디렉토리다. 그 안에 .claude-plugin/plugin.json 한 파일이 있으면 Claude Code가 그걸 플러그인으로 인식한다. 나머지는 컴포넌트다.
my-plugin/
├── .claude-plugin/
│ └── plugin.json ← 매니페스트 (필수)
├── skills/
│ └── hello/
│ └── SKILL.md ← 슬래시 커맨드형 스킬
├── agents/ ← 서브에이전트 정의
├── hooks/
│ └── hooks.json ← 이벤트 훅
├── .mcp.json ← MCP 서버
├── .lsp.json ← LSP 서버
├── monitors/
│ └── monitors.json ← 백그라운드 모니터
├── bin/ ← 활성화 시 PATH에 붙는 실행 파일
└── settings.json ← 기본 설정
쉽게 말해, 플러그인은 Claude Code 확장의 표준 박스 규격이다. USB-C에 어댑터·케이블·도크가 다 꽂히듯, 한 박스 안에 스킬·에이전트·훅·MCP가 같은 규약으로 들어간다.
자주 하는 실수 하나. commands/, agents/, skills/, hooks/를 .claude-plugin/ 안에 두지 않는다. .claude-plugin/에는 plugin.json만 들어가고, 나머지 디렉토리는 모두 플러그인 루트에 둔다.
가장 작은 플러그인 만들기
스킬 하나가 들어있는 플러그인을 처음부터 만들어 본다. 디렉토리부터 시작한다.
mkdir -p my-first-plugin/.claude-plugin
mkdir -p my-first-plugin/skills/hello
매니페스트 한 장을 적는다.
// my-first-plugin/.claude-plugin/plugin.json
{
"name": "my-first-plugin",
"description": "인사 스킬 — 플러그인 구조를 익히는 최소 예제",
"version": "1.0.0",
"author": { "name": "Your Name" }
}
| 필드 | 의미 |
|---|---|
name | 식별자이자 스킬 네임스페이스. 스킬은 /my-first-plugin:hello처럼 노출된다 |
description | 플러그인 매니저에서 보이는 한 줄 설명 |
version | 명시하면 이 값이 바뀔 때만 업데이트가 흐른다. 생략 시 git commit SHA가 버전 역할 |
author | 선택. 표시용 |
스킬을 추가한다. 폴더 이름이 곧 스킬 이름이다.
<!-- my-first-plugin/skills/hello/SKILL.md -->
---
description: 사용자를 따뜻하게 인사하고 도울 일이 있는지 물어본다
---
"$ARGUMENTS"라는 이름의 사용자를 따뜻하게 인사하고, 오늘 어떻게 도와줄 수 있는지 물어봐.
여기서 $ARGUMENTS가 슬래시 커맨드 뒤에 붙는 인자를 받아 준다.
로컬에서 바로 테스트한다. 설치 없이 디렉토리만 가리키면 된다.
claude --plugin-dir ./my-first-plugin
Claude Code가 켜지면 스킬이 네임스페이스 붙은 이름으로 잡힌다.
/my-first-plugin:hello Alex
스킬을 고쳤다면 /reload-plugins로 새로고침할 수 있다. 재시작이 필요 없다.
다른 컴포넌트 얹기
스킬만 들어있는 플러그인은 시작점이고, 실제 쓸 만한 묶음은 보통 훅과 에이전트까지 같이 들어간다. 두 가지를 짧게 본다.
훅 — 이벤트에 자동 반응
hooks/hooks.json에 이벤트 핸들러를 적는다. 형식은 .claude/settings.json의 hooks 객체와 동일하다.
// my-first-plugin/hooks/hooks.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs prettier --write"
}
]
}
]
}
}
Edit이나 Write 호출 직후, 수정된 파일에 prettier가 돌아간다. 명령은 stdin으로 훅 입력 JSON을 받으므로 jq로 파일 경로를 뽑아 쓴다.
에이전트 — 컨텍스트 격리된 서브 인스턴스
agents/ 밑에 마크다운 파일을 두면, 그 정의가 서브에이전트로 잡힌다.
<!-- my-first-plugin/agents/security-reviewer.md -->
---
name: security-reviewer
description: PR diff를 OWASP 체크리스트 기준으로 본다
tools: [Read, Grep, Bash]
---
당신은 보안 리뷰어다. 입력으로 받은 diff에서
1. 인증·인가 우회
2. 입력 검증 부재
3. 민감 데이터 노출
4. 안전하지 않은 의존성 호출
네 가지만 본다. 다른 영역은 다른 리뷰어가 본다.
/agents에서 이 에이전트가 잡히는지 확인할 수 있다.
MCP 서버 — 외부 서비스 연결
플러그인 루트의 .mcp.json에 MCP 서버를 적어 두면, 플러그인이 활성화될 때 같이 붙는다.
// my-first-plugin/.mcp.json
{
"mcpServers": {
"issue-tracker": {
"command": "npx",
"args": ["-y", "@my-org/issue-tracker-mcp"]
}
}
}
스킬·훅·MCP가 한 박스 안에서 같이 움직이는 게 플러그인의 본질이다. 배포 플러그인이라면 /deploy 스킬, 스테이징 상태를 보는 MCP, 배포 전 테스트 돌리는 훅이 한 번에 들어가 있다.
마켓플레이스 — 플러그인의 카탈로그
플러그인 하나만 쓸 거면 --plugin-dir로 끝이다. 하지만 팀에 뿌리거나 커뮤니티에 공유하려면 카탈로그가 필요하다. 카탈로그는 marketplace.json 한 파일이다.
리포 구조는 보통 이렇게 잡는다.
my-marketplace/
├── .claude-plugin/
│ └── marketplace.json ← 카탈로그 (필수)
└── plugins/
├── quality-review-plugin/
│ ├── .claude-plugin/
│ │ └── plugin.json
│ └── skills/
│ └── quality-review/
│ └── SKILL.md
└── deploy-plugin/
└── ...
마켓플레이스 매니페스트는 어떤 플러그인이 들어있고, 각각을 어디서 가져오는지를 기록한다.
// my-marketplace/.claude-plugin/marketplace.json
{
"name": "my-plugins",
"owner": {
"name": "Your Name",
"email": "you@example.com"
},
"plugins": [
{
"name": "quality-review-plugin",
"source": "./plugins/quality-review-plugin",
"description": "코드 품질 리뷰 스킬"
},
{
"name": "deployment-tools",
"source": {
"source": "github",
"repo": "your-org/deploy-plugin",
"ref": "v1.2.0"
},
"description": "배포 자동화 도구"
}
]
}
이름이 살짝 헷갈리는 두 개념을 정리해 둔다.
- 마켓플레이스 소스 —
marketplace.json카탈로그를 어디서 가져올지. 사용자가/plugin marketplace add로 등록할 때 지정한다 - 플러그인 소스 — 각 플러그인을 어디서 가져올지.
marketplace.json안의source필드
둘은 다른 리포를 가리킬 수 있다. 카탈로그는 acme-corp/plugin-catalog에 있고, 그 안에 적힌 플러그인은 acme-corp/code-formatter에서 가져오는 식이다.
플러그인 소스로 쓸 수 있는 타입은 다섯 가지다.
| 소스 | 형식 | 비고 |
|---|---|---|
| 상대 경로 | "./plugins/foo" | 마켓플레이스 리포 안의 디렉토리. ../로 바깥 참조 불가 |
github | { source: "github", repo, ref?, sha? } | 가장 흔한 형태 |
url | { source: "url", url, ref?, sha? } | GitLab/Bitbucket 등 임의 git URL |
git-subdir | { source: "git-subdir", url, path } | 모노레포의 한 디렉토리만 sparse clone |
npm | { source: "npm", package, version? } | npm 패키지로 받기 |
배포 — GitHub에 푸시하고 끝
마켓플레이스 리포를 GitHub에 푸시한다. 그게 끝이다. 사용자는 한 줄로 카탈로그를 등록하고, 또 한 줄로 플러그인을 설치한다.
# 사용자 입장
/plugin marketplace add your-org/my-marketplace
/plugin install quality-review-plugin@my-plugins
your-org/my-marketplace는 GitHub owner/repo 표기. 자체 호스팅 GitLab이면 풀 URL을 쓴다.
/plugin marketplace add https://gitlab.com/company/plugins.git
/plugin marketplace add https://gitlab.com/company/plugins.git#v1.0.0 # 특정 ref
로컬 개발 중에는 마켓플레이스도 디렉토리로 바로 붙일 수 있다.
/plugin marketplace add ./my-marketplace
설치 후 /plugin을 실행하면 탭형 매니저가 뜬다. Tab으로 Discover · Installed · Marketplaces · Errors 네 탭을 오간다. 설치한 플러그인을 끄고 켜고, 즐겨찾기를 표시하고, 로드 에러를 확인하는 곳이다.
출처: Plugins for Claude Code and Cowork — Anthropic 공식 블로그
위 스크린샷은 claude-code-marketplace에서 code-review · typescript-lsp · security-guidance 세 플러그인을 받아 둔 상태다. Space로 활성/비활성을 토글하고, u로 업데이트 표시, Delete로 제거 표시를 해 둔 뒤 한 번에 처리한다.
운영에서 알아둘 것 — 스코프·버전·strict
배포까지 끝났으면 어떻게 굴릴지가 남는다. 세 가지만 알면 된다.
설치 스코프. 사용자가 플러그인을 받을 때 세 가지 중 하나를 고른다.
| 스코프 | 의미 |
|---|---|
| User | 내 모든 프로젝트에서 활성 (기본값) |
| Project | 이 리포의 모든 협업자에게 배포 (.claude/settings.json에 기록되어 PR로 공유) |
| Local | 이 리포에서 나만 활성 |
팀 공통 도구라면 프로젝트 스코프가 자연스럽다. 협업자가 리포를 신뢰하는 순간 설치가 자동 제안된다.
// .claude/settings.json
{
"extraKnownMarketplaces": {
"my-team-tools": {
"source": { "source": "github", "repo": "your-org/claude-plugins" }
}
}
}
버전 관리. plugin.json의 version 필드를 적느냐 안 적느냐로 동작이 갈린다. 명시하면 그 값이 바뀔 때만 업데이트가 흐르고, 생략하면 git 호스팅 환경에서 모든 커밋이 새 버전이 된다. 릴리스 노트를 따로 관리할 거면 명시하는 쪽이 깔끔하다.
strict 모드. marketplace.json의 플러그인 엔트리에 strict: false를 두면 플러그인 리포에 plugin.json이 없어도 동작한다. 외부 리포를 자기 마켓플레이스에서 얇게 감싸 노출할 때 쓴다. 기본값은 true이고, 자기가 작성하는 플러그인은 그대로 두는 게 안전하다.
{
"name": "external-tool",
"source": { "source": "github", "repo": "third-party/tool" },
"description": "외부 도구를 우리 마켓플레이스에서 감싸 노출",
"strict": false,
"skills": "./skills",
"version": "1.0.0"
}
공식 마켓플레이스 — Anthropic이 직접 관리하는 곳
claude-plugins-official은 Claude Code가 시작될 때 자동으로 따라붙는 공식 카탈로그다. /plugin의 Discover 탭에서 바로 보인다.
여기엔 Anthropic이 직접 또는 파트너십으로 검수한 플러그인들이 들어 있다. 자주 쓰이는 묶음은 대체로 이 다섯 갈래다.
| 분류 | 예시 |
|---|---|
| Code Intelligence | typescript-lsp, pyright-lsp, gopls-lsp 등 LSP 통합 |
| External Integration | github, gitlab, linear, figma, sentry |
| Development Workflow | commit-commands, pr-review-toolkit, plugin-dev |
| Output Style | explanatory-output-style, learning-output-style |
| 사내 통합용 MCP | 조직 단위 배포 도구 |
자기 플러그인을 공식 마켓플레이스에 올리고 싶다면 두 가지 경로가 있다. 직접 자기 마켓플레이스를 운영하면서 사용자가 add 하게 두거나, 공식 디렉토리에 제출하거나. 후자는 claude.ai/settings/plugins/submit 또는 platform.claude.com/plugins/submit에서 폼으로 제출한다.
디버깅이 안 될 때
/plugin이 안 보임 —claude --version확인. Homebrew면brew upgrade claude-code, npm이면npm install -g @anthropic-ai/claude-code@latest- 스킬이 안 잡힘 —
/reload-plugins한 번. 그래도 안 되면rm -rf ~/.claude/plugins/cache후 재설치 - 상대 경로 플러그인이 설치 시 실패 — 마켓플레이스를 직접 URL로 add 했을 때 자주 발생. git 리포 형태로 add 하거나, 플러그인 소스를
github/url로 바꾼다 - 에러 탭에
Executable not found in $PATH— LSP 플러그인의 언어 서버 바이너리가 시스템에 없는 경우. 해당 바이너리를 설치하면 해결된다
--plugin-dir로 띄운 로컬 플러그인은 같은 이름의 설치된 플러그인보다 우선한다. 마켓플레이스에 올린 플러그인을 수정 중일 때 uninstall 없이 그 위에 덮어 테스트할 수 있다.
마무리
플러그인은 결국 디렉토리 하나고, 마켓플레이스는 그 디렉토리들의 목록이다. 구조만 익히면 만드는 데 한 시간이 안 걸리고, 한 번 만들면 팀 전체가 같은 환경 위에서 움직인다.
처음 시작할 만한 자리는 보통 이렇다. 내가 같은 SKILL.md 설정을 두 번째 프로젝트에서 또 꺼냈을 때. 거기서부터 .claude/를 my-plugin/으로 옮기고, plugin.json을 한 장 적고, 다음번엔 그 옆의 동료가 한 줄로 받아 간다. 그렇게 도구가 내 환경에서 팀의 환경으로 옮겨간다.




Loading comments...