ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Claude Code 스킬과 훅 — AI 코딩 도구에 왜 통제 체계가 필요한가
    IT 2026. 4. 22. 21:00
    Claude Code 스킬과 훅 — AI 코딩 도구에 왜 통제 체계가 필요한가

    AI 코딩 도구를 쓰다 보면 처음엔 단순한 질문-답변으로 시작한다. "이 코드 리팩토링해줘", "테스트 짜줘". 그런데 어느 순간부터 반복되는 패턴이 보이기 시작한다. 매번 같은 맥락을 설명하고, 같은 절차를 지시하고, 같은 실수를 교정한다.

    Claude Code를 본격적으로 쓰면서 이 문제를 해결하기 위해 스킬(Skill)훅(Hook) 시스템을 만들었고, 11개 스킬과 8개 파이프라인 검증 체계로 성장했다. 이 글은 그 과정에서 깨달은 것들을 정리한다.

    1. 스킬이 왜 필요한가 — 반복 지시의 제거

    Claude Code에게 "일정 노트를 동기화해줘"라고 말하면 이 한 문장 뒤에는 실제로 수십 줄의 절차가 숨어 있다.

    • Google Calendar API로 이벤트를 가져온다
    • 관련 참고 자료를 시간대 기준으로 매칭한다
    • 외부 AI에 프롬프트를 보내 노트를 구조화한다
    • RAG 시스템에서 관련 지식을 검색해 주입한다
    • @AI 질문에 답변을 생성한다
    • git commit & push 후 텔레그램으로 알린다

    이 절차를 매번 말로 지시하면 두 가지 문제가 생긴다. 첫째, 빠뜨림. "참고 자료 연결은 했어?" "텔레그램 알림은?" 매번 체크리스트를 머릿속에 들고 있어야 한다. 둘째, 변종. 어제는 이렇게 했는데 오늘은 저렇게 하면 결과물 품질이 들쭉날쭉해진다.

    스킬은 이 문제를 해결한다. 한 번 정의하면, 트리거 키워드로 전체 절차가 로딩된다. "데이터 동기화"라고 말하면 Claude Code가 6단계 파이프라인 전체를 알고 있는 상태에서 작업을 시작한다.

    스킬의 본질: 도메인 지식의 코드화

    스킬 파일(SKILL.md)은 프로그래밍 코드가 아니라 마크다운으로 작성된 절차서다. 어떤 명령을 실행하고, 어떤 순서로 진행하고, 어떤 조건에서 분기하는지가 자연어로 기술되어 있다. Claude Code는 이 문서를 읽고 맥락을 이해한 상태에서 작업한다.

    스킬이 어떤 식으로 쓰이는지 감을 잡기 위해, 전형적인 유형별 예시를 들어보겠다:

    유형 예시 하는 일
    데이터 동기화 외부 서비스 → 로컬 노트 API로 데이터를 가져와 마크다운 노트로 변환, 관련 자료 연결, AI 후처리
    콘텐츠 생성 노트 → 블로그 발행 원본 노트를 HTML로 변환, RAG로 지식 보강, 플랫폼에 자동 발행
    코드 품질 TDD 강제 워크플로우 코드 변경 감지 → 테스트 작성 → 통과 확인 → 커밋 허용
    외부 연동 GitHub 이슈/PR 관리 메신저에서 명령 → GitHub API 호출 → 결과 보고
    미디어 관리 사진 정리/분석 저장장치 스캔 → 중복 탐지 → AI 분석 → 라이브러리 구성

    이런 스킬이 하나둘 쌓이면 금방 10개 이상이 된다. 도메인이 다양해도 패턴은 비슷하다: 외부 데이터 수집 → 변환/처리 → 산출물 생성 → 저장/배포.

    2. 훅이 왜 필요한가 — "했다고 했는데 안 한" 문제

    스킬만으로는 부족한 지점이 있다. 스킬은 "무엇을 해야 하는지"를 알려주지만, "실제로 했는지"는 보장하지 않는다.

    실제로 겪은 상황이 이렇다. 데이터 동기화를 요청했는데, Claude Code가 Step 1(데이터 수집)과 Step 2(참고 자료 연결)는 했지만 Step 3(AI 콘텐츠 통합)을 건너뛰고 바로 git commit을 시도했다. 결과물은 원본 데이터가 그대로 복사된 미정리 노트였다.

    또 다른 사례: 블로그 드래프트를 생성했는데 본문이 마크다운으로 작성되어 있었다. 블로그 publisher가 HTML을 에디터에 직접 주입하는 구조였는데, 마크다운 텍스트가 그대로 노출됐다.

    이런 문제를 잡으려면 자동화된 검증 계층이 필요하다. 이것이 훅(Hook)이다.

    훅의 동작 원리

    Claude Code의 훅 시스템은 4개 시점에 개입할 수 있다:

    시점 역할 활용 예시
    PostToolUse 도구 실행 후 상태 추적 동기화 단계 마킹, 콘텐츠 생성 감지
    PreToolUse 도구 실행 전 차단 미완료 파이프라인에서 git commit 차단
    PostToolUse(Edit) 파일 편집 감지 노트 편집 시 리뷰 상태 생성, 프로젝트 코드 변경 감지
    Stop 세션 종료 전 검증 파이프라인 미완료 시 종료 차단

    훅 스크립트는 exit code로 의사를 전달한다. 0이면 통과, 2면 차단. 차단 시 stderr에 이유를 출력하면 Claude Code가 그 메시지를 받아 자기 교정한다.

    3. 디스패처가 왜 필요한가 — 스킬 확장의 필연적 귀결

    처음에는 데이터 동기화 스킬 하나에만 훅이 걸려 있었다. 4개 파일로 충분했다.

    그런데 스킬이 10개 이상으로 늘어나자 문제가 생겼다. 스킬마다 별도 훅 스크립트를 만들면 settings.json의 같은 matcher에 여러 훅이 등록되고, 매 도구 호출마다 모든 훅이 실행된다. ls -la 같은 단순 명령에도 10개 스크립트가 돌아간다면 성능 저하가 심각하다.

    해법은 통합 디스패처(Unified Dispatcher)다.

    hooks/
      common.py                   ← 공통 유틸 (세션 PID, 상태 관리)
      dispatcher_post_bash.py     ← Bash 명령 후 전체 파이프라인 분기
      dispatcher_pre_bash.py      ← git commit 전 검증
      dispatcher_post_edit.py     ← 파일 편집 감지
      dispatcher_stop.py          ← 종료 전 전체 검증
      pipelines/
        data_sync.py              ← 다단계 동기화 파이프라인 추적
        data_review.py            ← 노트 편집/AI 답변 검증
        content_publish.py        ← 콘텐츠 발행 품질 검증
        code_quality.py           ← TDD 강제 (테스트 통과 필수)
        report_pipeline.py        ← 리포트 산출물 확인
        media_manager.py          ← 미디어 관리 커맨드 추적
        ...

    디스패처는 하나의 진입점으로 모든 파이프라인을 처리한다. 핵심은 상태 파일(/tmp/.{pipeline}_state) 유무로 O(1) 분기하는 것이다. 활성 파이프라인이 없으면 즉시 종료(exit 0)하므로, 일반 명령에 대한 오버헤드가 거의 없다.

    통합 인터페이스

    모든 파이프라인 모듈은 동일한 4개 함수를 구현한다:

    def track_bash(cmd, data) → bool        # Bash 명령 추적
    def track_edit(file_path, data) → bool   # 파일 편집 추적
    def pre_commit(cmd, data) → (bool, str)  # 커밋 전 검증
    def check_completion(state) → list[str]  # 종료 전 완료 확인

    이 인터페이스 덕분에 새 스킬을 추가할 때 pipelines/에 모듈 하나만 만들면 된다. settings.json은 건드릴 필요가 없다.

    4. Harness Engineering의 실전 적용

    이 구조를 Harness Engineering 관점에서 보면, 정확히 Control Plane을 구축한 것이다.

    Harness 구성 요소 실제 구현
    Hook / Guardrail 4개 디스패처 (PreToolUse, PostToolUse, Stop)
    피드백 루프 상태 파일 기반 단계 추적 + additionalContext 주입
    HITL Policy pre_commit에서 미완료 단계 차단 → Claude가 자기 교정
    Governance 세션 PID 격리 (병렬 세션 간 간섭 방지)

    Martin Fowler가 쓴 Harness Engineering 글의 핵심 메시지는 이것이다: "모델을 바꾸기 전에 Harness를 바꿔라." 같은 Claude 모델이라도 스킬과 훅이 잘 설계되어 있으면 극적으로 다른 결과를 낸다.

    5. 실전에서 배운 것들

    노트 품질 감별이 핵심이다

    데이터 동기화에서 가장 중요한 검증은 "노트가 실제로 정리되었는가"였다. 단순히 "Step 3을 실행했는가"가 아니라, 산출물 자체를 검사해야 한다.

    구현한 감별 기준은 단순하다:

    • 본문이 200자 이상인데 ## 섹션이 1개 이하이고 Organized by 마커가 없으면 → 미정리
    • @AI 태그가 있는데 > [!ai] 응답이 없으면 → 미응답

    이 두 조건만으로 "원본 데이터를 그대로 복사해서 커밋한" 케이스를 정확히 잡아낸다.

    스킬마다 검증 강도가 다르다

    모든 스킬에 동일한 수준의 검증을 걸면 과도하다. 실제로 운영하면서 3단계로 분류했다:

    강도 검증 방식 스킬 예시
    강함 파이프라인 추적 + 커밋 차단 + 종료 차단 다단계 파이프라인 (예: 데이터 동기화, TDD 워크플로우)
    보통 산출물 존재 확인 + 종료 시 경고 콘텐츠 생성 (예: 블로그 발행, 리포트 생성)
    약함 실행 기록만 (차단 없음) 외부 API 연동 (결과가 즉시 확인되는 경우)

    세션 격리가 중요하다

    여러 터미널에서 Claude Code를 동시에 쓸 때, 한쪽의 파이프라인 상태가 다른 쪽을 차단하면 안 된다. _find_claude_pid()로 프로세스 트리를 거슬러 올라가 각 세션의 claude 메인 PID를 추적하고, 상태 파일에 기록된 PID와 비교해서 다른 세션이면 무시한다.

    마무리

    처음에는 스킬 하나, 훅 없이 시작했다. 스킬이 늘어나자 빠뜨림이 생겼고, 훅을 넣었다. 훅이 늘어나자 성능 문제가 생겼고, 디스패처를 만들었다. 디스패처가 생기자 공통 유틸이 필요했고, 인터페이스를 통일했다.

    이 진화 과정은 필연적이었다. AI 코딩 도구의 생산성은 프롬프트를 잘 쓰는 것만으로는 한계가 있다. 절차를 코드화(스킬)하고, 실행을 검증(훅)하고, 검증을 확장 가능하게 구조화(디스패처)하는 — 이 세 단계를 거쳐야 비로소 AI를 실무 파이프라인에 올릴 수 있다.

    Harness Engineering이라는 거창한 이름을 붙이지 않더라도, 실무에서 AI 도구를 심도 있게 활용하는 사람이라면 자연스럽게 이 방향으로 흘러갈 수밖에 없다. 왜냐하면 AI는 강력하지만 비결정적이기 때문이다. 그 비결정성을 프로덕션 수준으로 길들이려면, 결국 마구(Harness)가 필요하다.


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.