본문으로 바로가기
반응형

Claude Code에서 작업 중인 스피너에 도구 호출 횟수를 붙이고 싶다면 Mod를 사용할 수 있습니다. Anthropic 공식 문서가 정의하는 Mod는 JavaScript·TypeScript 이벤트 핸들러를 Claude Code 내부에서 실행하는 플러그인입니다. 이 글에서는 터미널에서 호출 횟수를 표시하고 /tally 명령으로 읽는 예제를 만듭니다.

플러그인·Hooks·Skills·MCP는 무엇이 다른가요?

공식 Plugins·Mods 문서에 따르면 플러그인은 확장 기능을 묶는 단위입니다. 아래 기능을 서로 대체하는 제품으로 보면 선택이 어려워집니다.

용어역할과 선택 기준

Plugin 여러 확장 구성요소를 묶어 설치·로딩하는 패키지
Skill 반복 작업의 절차나 지식을 담은 SKILL.md 지침
Settings hook 특정 이벤트에 명령·HTTP 요청 등을 실행하는 설정 기반 자동화
MCP server 외부 도구를 Claude Code에 제공하는 서버
Mod 내부 이벤트를 처리하고 UI나 동작을 바꾸는 코드가 포함된 플러그인

Skills·설정 훅·MCP는 플러그인 없이도 쓸 수 있습니다. 작업 절차를 알려주려면 Skill, 이벤트에 맞춰 기존 명령을 실행하려면 설정 훅, 외부 도구를 연결하려면 MCP부터 검토하면 됩니다. UI와 내부 동작을 직접 확장할 때 Mod가 필요합니다.

Mod 문서의 hook은 코드로 등록하는 이벤트 핸들러를 뜻합니다. 설정 파일의 기존 Hooks와 구분해야 합니다.

첫 mod를 세 파일로 작성하기

터미널용 Mods의 최소 버전은 v2.1.287입니다. claude --version으로 버전을 확인하세요. 조직 정책이나 설정에 따라 로딩이 제한될 수 있습니다. Mods는 샌드박스에 격리되지 않고 사용자 권한으로 실행되므로 신뢰하는 코드만 로딩하세요.

아래 코드는 공식 Create a mod의 카운터 예제를 간추린 미실행 예제입니다. 별도 Node.js 설치나 빌드 없이 JS 파일을 로딩하는 구성입니다.

1. 폴더와 설정 파일 만들기

작업 폴더 안에 다음 구조를 만듭니다.

first-mod/
├── .claude-plugin/
│   └── plugin.json
└── hooks/
    ├── hooks.json
    └── register.js

first-mod/.claude-plugin/plugin.json에는 이름과 버전을 넣습니다.

{"name":"first-mod","version":"0.1.0"}

first-mod/hooks/hooks.json에는 실행할 모듈을 지정합니다. 경로 기준은 hooks.json이 있는 폴더입니다.

{"modules":["./register.js"]}

2. 이벤트 핸들러 작성하기

first-mod/hooks/register.js를 아래 내용으로 저장합니다.

let calls = 0;

export function register(on) {
  on('session.start', async ($, e, next) => {
    await $.command.register({
      name: 'tally', description: '도구 호출 횟수'
    });
    return next(e);
  });

  on('tool.call', async ($, e, next) => {
    calls += 1;
    $.ui.invalidate('ui.render');
    return next(e);
  });

  on('command.run', { command: 'tally' }, async () => {
    return { text: '도구 호출: ' + calls };
  });

  on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
    return next({
      ...e, props: { ...e.props, suffix: ' · 호출: ' + calls }
    });
  });
}

tool.call 이벤트가 발생하면 카운터를 올립니다. 따라서 성공한 작업 수를 집계하는 코드는 아닙니다. next(e)는 이벤트 처리를 다음 핸들러와 Claude Code에 이어줍니다. /tally 핸들러는 자체 출력만 반환합니다.

3. 로딩하고 동작 확인하기

first-mod의 상위 폴더에서 실행합니다.

claude --plugin-dir ./first-mod

열린 세션에 “현재 폴더의 파일 목록을 보고 README를 읽어줘”라고 요청한 뒤 /tally를 입력하세요. 기대 동작은 스피너와 명령 출력에 호출 횟수가 나타나는 것입니다. 숫자는 실제 도구 호출에 따라 달라집니다.

별도 터미널에서는 정적 검사를 할 수 있습니다.

claude plugin validate ./first-mod

이 명령은 정적 검사를 수행합니다. 통과하더라도 실제 동작이나 보안 검증을 마쳤다는 뜻은 아닙니다.

수정 후 숫자가 초기화되는 이유

--plugin-dir로 로딩한 모듈은 파일 변경 시 다시 로딩됩니다. 이 예제의 메모리 변수 calls도 0으로 돌아갑니다. 누적 기록이 필요한 기능으로 확장하려면 상태 보존을 별도로 설계해야 합니다.

API가 맞지 않으면 로딩 시 생성되는 .claude-plugin/types/를 확인하세요. 공식 작성 문서는 페이지 설명과 설치 버전의 타입이 다를 때 생성된 타입을 우선하도록 안내합니다.

먼저 이 카운터의 로딩과 /tally 출력부터 확인하세요. 이후 스피너 문구 하나를 바꿔 보면 파일 수정이 UI에 반영되는 흐름까지 익힐 수 있습니다.

참고 링크

반응형