Claude Code를 내 입맛대로 고치는 mods 입문
출처: claude.dev Blog (Addy Osmani)
원문: https://claude.dev/blog/getting-started-with-claude-code-mods/
작성자: 팔복소프트-김팔복
한눈에 보기
- Claude Code 2.1.287부터 세션 안에 상주하면서 동작을 바꾸는 확장 단위인 mods를 쓸 수 있고, 기본으로 켜져 있습니다.
- mod의 정체는 플러그인 안에 들어 있는 JavaScript/TypeScript 훅 모듈 하나입니다.
- 훅은 미들웨어처럼 체인을 이루며, 이벤트를 지켜보거나(observe), 고쳐서 넘기거나(rewrite), 직접 응답해 막을(answer) 수 있습니다.
- 도구 호출뿐 아니라 화면 렌더링에도 끼어들 수 있어서 터미널과 데스크톱 앱에 자기 UI를 그릴 수 있습니다.
- AGENTS.md 지원,
/diff패널 같은 Claude Code 기본 기능 일부도 mod로 만들어져 있고 소스가 공개돼 있습니다. - 배포는 기존 플러그인 마켓플레이스 방식 그대로이며, 설치한 mod는 Claude Code와 같은 권한으로 내 PC에서 돌아갑니다.
배경
Claude Code는 이미 설정 파일, 권한 규칙, 슬래시 커맨드, skills, 상태 표시줄, 그리고 이벤트마다 셸 명령을 실행하는 settings hooks로 커스터마이즈할 수 있었습니다. 다만 settings hooks는 이벤트가 올 때마다 명령을 새로 실행하고 stdin/stdout JSON으로만 주고받는 구조라, 상태를 들고 있거나 화면을 그리는 일에는 맞지 않았습니다. mods는 이 빈자리를 채웁니다.
주요 내용
기존 방식과 무엇이 다른가
| 방식 | 실행 방식 | 상태 유지 | UI | 할 수 있는 개입 |
|---|---|---|---|---|
| 설정·권한 규칙 | 선언형 | 해당 없음 | 불가 | 허용/거부 |
| settings hooks | 이벤트마다 셸 명령 실행 | 직접 파일 등으로 처리 | 불가 | JSON 응답 범위 안에서 |
| mods | 세션에 한 번 로드되어 상주 | $.state로 유지 |
패널, 프롬프트 위 영역 등 | 관찰·수정·대체, 슬래시 커맨드나 모델용 도구 등록 |
구조
폴더 자체는 평범한 플러그인입니다. .claude-plugin/plugin.json 매니페스트가 있고, hooks/hooks.json의 modules에 모듈 하나를 지정합니다. 모듈은 register(on)을 export하고, 그 안에서 on(이벤트, 조건, 훅)으로 훅을 붙입니다. 훅은 ($, e, next)를 받는데 $는 UI·세션·상태·파일·프로세스 등을 다루는 API, e는 이벤트 데이터, next는 체인의 다음 단계입니다. 모듈은 DOM도 Node도 없는 샌드박스에서 돌기 때문에 바깥 세계와의 접점은 전부 $입니다.
예를 들어 terraform apply를 에이전트가 직접 실행하지 못하게 하는 최소 형태는 이 정도입니다.
export function register(on) {
on("tool.call", { tool: "Bash" }, async ($, e, next) => {
if (/terraform\s+apply/.test(String(e.command ?? ""))) {
return { deny: "terraform apply는 사람이 직접 실행합니다." };
}
return next(e);
});
}
원문이 소개한 예제 세 가지
| 이름 | 하는 일 | 핵심 기법 |
|---|---|---|
| Token Weather | 컨텍스트 윈도 사용률을 프롬프트 위 한 줄에 날씨 아이콘으로 표시 | 턴 종료 관찰, 렌더링 훅, $.state |
| Blast Radius | rm -rf, git reset --hard, force push, DB 마이그레이션 등을 붙잡고 영향 범위를 보여준 뒤 진행/취소 선택 |
호출 보류, $.process.run 드라이런, 버튼 패널 |
| Replay Theater | 한 턴 동안의 Edit/Write를 기록했다가 /replay로 diff를 한 단계씩 재생 |
턴 시작·종료 묶기, 슬래시 커맨드 등록 |
만들 때 알아둘 점
- Claude에게 원하는 mod를 말로 설명하면 대신 작성해 줍니다. 이렇게 만든 mod는 그 세션 한정이고 폴더도 나중에 정리되므로, 남기려면 폴더를 옮겨 플러그인으로 설치해야 합니다.
- 저장하면 재시작 없이 다시 로드됩니다. 대신 모듈 변수는 초기화되니 남길 데이터는
$.state에 두고, 그 키는 타입 선언(.d.ts)에 등록해야 합니다. claude plugin validate는 모듈이 어떤 이벤트를 훅하고 무엇을 호출하는지 보고하고,claude plugin test는 실제 런타임에서 테스트를 돌립니다.- 훅 하나는 디스패치마다 자체 실행 시간 10초를 받고,
$호출 안에서 기다리는 시간은 여기에 들어가지 않습니다. - API는 릴리스마다 바뀔 수 있습니다. 로드할 때 현재 빌드의 타입 선언이
.claude-plugin/types/에 생성되니 이것을 기준으로 삼으면 됩니다.
배포와 보안
marketplace.json을 둔 GitHub 저장소가 곧 마켓플레이스가 되고, 사용자는 /plugin marketplace add, /plugin install, /reload-plugins 세 단계로 설치합니다. Claude 디렉터리에도 제출할 수 있습니다. 원문도 강조하듯 mod는 Anthropic이 아니라 게시자가 쓴 코드이고 Claude Code와 같은 권한으로 실행되니, 패키지를 설치할 때처럼 출처를 확인해야 합니다.
팔복소프트 관점
- 가장 먼저 쓸 곳은 가드입니다. 운영 클러스터 kubectl 컨텍스트,
flyway migrate,terraform apply처럼 팀마다 "에이전트가 바로 실행하면 곤란한 명령"이 있습니다. 다만 위 예제처럼 명령 문자열을 보는 방식은$(…), alias, 스크립트로 쉽게 우회됩니다(원문도 Blast Radius를 권한 시스템이 아니라 안전망이라고 선을 긋습니다). 막아야 하는 건 권한 규칙으로 막고, mod는 확인 단계를 더하는 보조 장치로 두세요. - 팀 배포 전에 버전 고정부터. API가 릴리스마다 바뀔 수 있다고 원문이 직접 밝히고 있습니다. 개인용 mod는 지금 만들어도 되지만, 팀 표준으로 깔 생각이라면 Claude Code 버전을 맞추고
claude plugin test를 CI에 붙여 업그레이드 때 깨지는지 확인하는 체계가 먼저입니다. - 보안 심의가 까다로운 조직이라면.
$API에는 HTTP 호출도 포함돼 있어서, 악의적인 mod는 세션 내용을 밖으로 보낼 수 있습니다. 금융·공공처럼 내부 통제가 강한 곳은 외부 mod 설치를 개인 판단에 맡기기보다, 사내 GitLab이나 GitHub Enterprise에 검토를 마친 mod만 모은 마켓플레이스를 두는 편이 현실적입니다. - settings hooks를 다 옮길 필요는 없습니다. 셸 스크립트로 잘 돌고 있는 훅은 그대로 두고, 상태나 화면이 필요해질 때 mod로 옮기면 충분합니다. Git pre-commit 훅이 커밋 시점에 개입한다면, mod는 에이전트가 명령을 실행하기 직전에 개입한다는 점이 다릅니다.
- 한글 환경의 폭 문제. 원문은 정렬을 위해 이모지 대신 한 칸짜리 기호를 쓰라고 권하지만, 모호 폭 문자를 두 칸으로 처리하도록 설정된 터미널이나 일부 한글 고정폭 폰트에서는 기호가 두 칸으로 그려질 수 있습니다. 한글은 한 글자가 두 칸이므로
bodyColumns기준으로 폭을 계산할 때 글자 수가 아니라 표시 폭으로 세야 합니다.
정리
mods는 Claude Code를 "설정하는" 단계에서 "코드로 고치는" 단계로 넘어가는 확장 방식입니다. 기억할 건 세 가지입니다. 플러그인 안의 훅 모듈이라는 점, 관찰·수정·대체라는 세 가지 개입 방식, 그리고 내 PC에서 Claude Code와 같은 권한으로 돈다는 점입니다. 처음이라면 동작을 바꾸지 않는 관찰형 mod부터 만들어 보는 것을 권합니다.
아직 댓글이 없습니다.