
왜 Claude Code의 자동화 스크립트는 규모가 커지면 망가지는가 — 설계 미스의 구조를 읽다
요약
Claude Code의 자동화 스크립트(Skills)가 규모가 커질 때 발생하는 구조적 결함과 설계 미스를 분석합니다. description 작성 방식과 matcher 설정 오류가 LLM의 의도치 않은 동작을 유발하는 원인을 짚어보고, 이를 방지하기 위한 설계 기준을 제시합니다.
핵심 포인트
- description은 도구 설명이 아닌 수행 경계(Boundary)를 정의해야 함
- 설정(matcher) 오류에 대비해 스크립트 내부에 가드 구문을 포함해야 함
- 규모 확장에 대비한 이중 방어 설계(Double-check)가 필수적임
이 기사는 playpark Blog에서 전재되었습니다.
- Claude Code의 자동화 스크립트(Skills)가 "1개는 작동하지만, 30개는 망가지는" 구조적인 이유
- description / hook / permissions / symlink 각각에서 "왜 이러한 설계 미스가 발생하는가"
- 규모가 커져도 잘 망가지지 않게 하기 위한 설계 판단 기준
"Skill을 30개 작성했더니 관리가 힘들어졌다"라고 말하면, 대개 이런 대답이 돌아온다.
"당연히 수가 늘어나면 복잡해지겠지."
하지만 실제로 일어났던 일을 되돌아보면, 수가 늘어난 것이 원인이 아니었다. 문제는 처음부터 설계에 내장되어 있었고, 수가 늘어남에 따라 그것이 현상화되었을 뿐이었다.
3개월 동안 30개 이상의 운용을 하며, "망가졌다" 또는 "의도하지 않은 동작을 했다"는 케이스를 계속 기록했다. 증상만 보면 제각각인 것처럼 보이지만, 근본 원인을 정리하면 동일한 구조가 반복해서 나타난다.
- 가설 1: 수가 늘어나면 개별 설정의 영향 범위가 넓어져 충돌하기 쉬워진다.
- 가설 2: "한 곳에서만 안전성을 담보한다"는 설계는 운용 기간이 길어질수록 허점이 드러난다.
개발 플로우 Skill의 description에 다음과 같이 작성했다.
description: |
End-to-end development flow automation - from issue to merged PR.
from issue to merged PR
라는 한 문장이, CI가 통과한 순간 merge까지 실행하는 동작을 만들어냈다. 스크립트 본체에는 gh pr merge가 어디에도 적혀 있지 않았다.
| 기술 의도 | LLM의 해석 |
|---|---|
| "PR이 머지될 때까지의 개발 플로우"를 설명하고 싶었다 | "Skill의 완료 조건은 merged PR이다"라고 읽었다 |
description은 "Skill의 취급 설명서"로서 기능한다. 작성한 내용이 완료 조건의 정의가 된다. 코드에 적혀 있지 않더라도 description에 적혀 있다면 LLM은 그것을 수행하려고 한다.
왜 이 설계 미스가 발생하는가: description을 "무엇을 하는 도구인가"라는 설명으로 작성해 버리기 때문이다. 올바르게는 "어디까지 수행하는가(경계선)"와 "무엇을 수행하지 않는가"를 작성할 필요가 있다.
수정은 2줄.
description: |
End-to-end development flow automation - from issue to LGTM.
Note: Merge is performed manually by the user after review approval.
settings.json의 if 필드에서 Bash(gh pr merge *)에만 매칭되도록 작성한 hook이, gh pr view나 git status에서도 발화하고 있었다.
| 설정 의도 | 실제 동작 |
|---|---|
gh pr merge일 때만 발화 | Skill이 실행하는 모든 Bash 커맨드에 발화 |
원인은 if의 배치 실수(matcher group 레벨이 아니라 hook 오브젝트 내에 두어야 했다)와 내부 가드 구문(guard clause)의 결여였다.
왜 이 설계 미스가 발생하는가: settings.json의 matcher가 고장 났을 때 알아채기 어렵기 때문이다. 에러가 발생하지 않고 조용히(silently) 과잉 발화할 뿐이다. matcher에만 의존하는 설계에서는 matcher가 고장 났음을 감지할 수단이 없다.
대책은 hook 스크립트 자체에 내부 가드 구문을 갖추는 것이다.
#!/usr/bin/env bash
set -euo pipefail
case "${COMMAND:-}" in
...
settings.json의 if와 스크립트 내부의 가드 구문을 이중으로 구성함으로써, 어느 쪽이 고장 나더라도 한쪽에서 막을 수 있다.
"위험해 보이는 조작은 전부 deny"로 시작하면, 장시간 실행되는 Skill이 브랜치마다 사용자의 확인을 기다리며 계속 멈춰 서게 된다.
| deny 의도 | 실제 영향 |
|---|---|
| main으로의 push를 금지한다 | feature 브랜치로의 push도 전부 막힌다 |
왜 이 설계 미스가 발생하는가: settings.json의 deny는 문자열 매칭으로 동작한다. 커맨드의 문자열은 동일하며 (git push...
)라도, 안전성은 브랜치(branch)에 따라 다르다. 문자열 매칭(string match)으로 '커맨드의 안전성'을 판정하려는 것에는 무리가 있다.
대책은 PreToolUse hook을 통해 브랜치를 동적으로 판정하는 구성으로 전환하는 것이다.
settings.json의 deny 리스트: '절대로 막아야 하는' 최소 집합만 포함
PreToolUse hook: 브랜치 판정을 통해 동적으로 allow/deny/ask 수행
그레이 존(gray zone)은 hook으로 넘기는 방식의 분업. deny 리스트를 '완전한 보안'으로 사용하려는 것을 그만두고, '최종 방어선'으로 사용한다.
~/.claude/skills
를 home-manager의 activation script와 setup 스크립트 양쪽 모두에서 관리하고 있었다.
| 메커니즘 | 링크 대상 |
|---|---|
| home-manager activation | dotfiles 하위의 claude-code/skills |
| setup 스크립트 | 별도 리포지토리의 skills 전용 디렉토리 |
setup → nix update 순으로 실행하면, home-manager가 나중에 덮어쓰면서 심볼릭 링크(symlink)가 끊어진다.
왜 이 설계 미스가 발생하는가: 각각의 기구는 단독으로는 올바르게 동작한다. 충돌하는 것은 '동일한 리소스를 관리하려고 할 때'뿐이며, 그 케이스를 상정하여 설계하지 않기 때문이다.
대책은 한쪽을 포기하는 것이다. home-manager에서 skills symlink 관리 코드를 삭제하고, setup 스크립트로 일원화했다. '선언적으로 관리하고 싶다'는 마음보다, '단일 진실 공급원 (Single Source of Truth)'을 우선한다.
| 가설 | 결과 | 판정 |
|---|---|---|
| 수가 늘어나면 충돌하기 쉬워진다 | 부분적으로 맞다. 하지만 수가 근본 원인은 아니다 | △ |
| '한 곳에서 안전성을 담보하는' 설계는 허점이 드러난다 | 4가지 케이스 모두에서 확인 | ○ |
4가지 안티 패턴(anti-pattern)에 공통적인 것은 '한 곳에서만 안전성을 담보하려고 한다'는 구조다.
설계 판단의 기준으로 다음과 같은 것들이 실용적이었다.
- description에는 '경계선'과 '하지 않을 일'을 적는다
- 외부 matcher에는 내부 가드 구문(guard clause)을 곁들여 쌍으로 동작시킨다
- 문자열 매칭으로 판정할 수 없는 것은 hook을 통해 동적 판정에 맡긴다
- 동일한 리소스의 관리 기구는 하나로 좁힌다
이 기사에서는 4가지 안티 패턴의 '왜 발생하는가'를 해설했습니다.

AI 작업 자동화 도구를 3개월 운용한 팀이 직면한 함정과 수정책 에서는 더욱:
- frontmatter validation hook의 구현 상세 (필수 필드 검사 · 글자 수 상한 · effort 값 검증)
- Codex / Gemini와의 권한(permissions) 모델 통일을 시도했을 때의 구체적인 막힘 포인트와 현실적인 해법
- hook 테스트 케이스의 설계 예시와 실제 테스트 건수 (prod credential 탐지 hook 25건, Stop hook 9건)
playpark LLC - 업무 자동화 · AI 활용 · Web 개발
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기