Claude Code 플러그인, 통째로 깔지 않고 알맹이만 빼왔다

지난 편 → 6편 — 챗GPT랑 클로드, 왜 서로 대화는 못 시킬까 Claude Code로 한동안 일하다 보면, 남이 만들어 둔 도구를 가져다 쓰고 싶어지는 순간이 옵니다. 마켓플레이스에 올라온 플러그인 중 하나가 눈에 들어왔습니다. 코드를 필요 이상으로 부풀리지 않게, "게으른 시니어 개발자"처럼 최소로만 짜도록 붙잡아 주는 도구였습니다. 마음에 들었습니다. 그런데 막상 설치하려니 손이 멈췄습니다. 제가 원한 건 그 안에 담긴 원칙 하나 였는데, 플러그인은 그것 말고도 이런저런 것들을 통째로 데려옵니다. 안 쓸 기능까지 제 환경에 얹히는 게 영 내키지 않았습니다. 그래서 깔지 않고, 열어서 필요한 알맹이만 빼내기로 했습니다. 그러려면 먼저 "플러그인"과 "스킬"이 뭐가 다른지부터 알아야 했습니다. 스킬과 플러그인은 뭐가 다른가 한 줄로 하면 이렇습니다. 스킬은 부품 하나, 플러그인은 부품을 담은 상자. 스킬(Skill) 은 최소 단위입니다. SKILL.md 라는 마크다운 파일 하나가 전부고, 필요하면 옆에 보조 파일(스크립트·데이터)을 둘 수 있습니다. 두는 곳도 단순합니다. 개인용: ~/.claude/skills/<이름>/SKILL.md 프로젝트용: .claude/skills/<이름>/SKILL.md 파일 맨 위 frontmatter에 "이 스킬을 언제 써야 하는지"를 적어두면, Claude가 상황을 보고 알아서 불러 씁니다. 아니면 /스킬이름 으로 직접 부를 수도 있습니다. 말하자면 "이 일은 이렇게 처리해라"라고 적어둔 지침 한 장 입니다. 플러그인(Plugin) 은 그 부품들을 담아 배포하는 상자입니다. .claude-plugin/plugin.json 이라는 매니페스트를 중심으로, 여러 종류의 구성요소를 한 번에 묶습니다. skills/ — 스킬들 agents/ — 커스텀 에이전트(서브에이전트...

음성으로 코딩하기 (4편) — 멀쩡한 마이크를 죽었다고 오판한 이유

3편에서 핀마이크로 음질 문제를 잡았다고 좋아했는데, 바로 다음 지옥이 열렸어요. 이번엔 멀쩡한 마이크를 자꾸 "죽었다"고 우기는 문제였습니다.

지난 편 → 3편 — 인식이 안 되던 진짜 범인은 마이크였다

음질을 잡았더니 이번엔 "끊김"이었어요

핀마이크가 잘 되나 싶었는데, 화면에 자꾸 "⚠ 마이크 입력 없음" 경고가 떴어요. 5초쯤 조용히 있으면 "끊겼다"고 판단하고 마이크를 다시 여는 동작을 무한 반복했죠. 정작 마이크는 멀쩡히 꽂혀 있는데도요.

hands-free로 쓰려면 잠깐씩 말을 멈추는 게 당연한데, 그 침묵을 "장치가 죽었다"고 오해하니 쓸 수가 없었어요.

진폭으로 살아있는지 판단했는데…

끊김을 감지하는 방식은 이랬어요. 마이크에서 들어오는 소리의 크기(진폭)를 보고, "의미 있는 소리"가 일정 시간 안 들어오면 끊긴 걸로 판단한다.

문제는 여기 있었어요. 핀마이크는 조용할 때도 아주 작은 신호(진폭 레벨 1)를 흘리는데, 제가 "이 정도(레벨 2) 이상은 돼야 살아있는 소리로 친다"고 임계값을 잡아둔 거예요. 그래서 정상적인 침묵을 "소리 없음 = 끊김"으로 오판한 거죠.

임계값을 낮췄더니 해결… 인 줄 알았죠

원인을 알았으니 간단해 보였어요. 임계값을 2에서 0으로 낮췄죠. 레벨 1도 살아있는 걸로 쳐주도록. 설정을 바꾸자마자(핫리로드) 끊김 경고가 사라졌어요. "해결!" 하고 넘어갔죠.

그런데 며칠 뒤, 앱을 재시작했더니 끊김 지옥이 그대로 돌아왔습니다.

어제는 되고 오늘은 안 되는 미스터리

설정 파일엔 분명 0이 그대로 있었어요. 그런데 어제는 되고 오늘은 안 됐죠. 이게 제일 헷갈렸어요.

범인은 설정값을 읽는 코드가 두 군데였고, 둘의 동작이 달랐다는 거예요.

언제0을 어떻게 처리?
설정을 바꿔 즉시 반영할 때(핫리로드)0 허용 ✅
앱을 껐다 켤 때(재시작)0 → 2로 덮어씀 ❌

어제 "해결"됐던 건 핫리로드 경로였고, 오늘 재시작하니 다른 경로가 0을 무시한 거였어요.

범인은 or 2 한 줄이었어요

재시작 경로의 코드는 대략 이랬어요.

alive_min_level = int(설정에서_읽기("...", 기본값 2) or 2)

파이썬에서 0은 falsy(거짓 취급) 예요. 그래서 0 or 2는 2가 됩니다. 즉 설정에 0을 넣어도, 재시작할 때 코드가 "0은 빈 값이네" 하고 2로 덮어쓴 거였죠. 핫리로드 경로는 if 값 >= 0으로 검사해서 0을 제대로 받았고요.

or 2 한 줄을 빼서 0을 유효값으로 받게 고치니, 재시작해도 멀쩡했습니다.

교훈 — 0은 falsy다, 그리고 두 경로를 다 봐라

며칠을 잡아먹은 버그의 교훈은 두 개예요.

  1. 0을 유효값으로 다룰 땐 or·falsy 검사를 조심하라. 값 or 기본값은 0을 삼켜버립니다.
  2. 같은 설정을 읽는 경로가 여러 개면 전부 확인하라. 핫리로드로만 검증하고 재시작은 안 봤더니, 이 불일치가 숨어 있었죠.

AI(Claude)가 코드는 빠르게 짜줬지만, "어제는 되고 오늘은 안 되는" 이 미묘한 불일치는 결국 제가 직접 재현하고 로그를 파야 잡혔어요.

다음 편

이번엔 소리가 아니라 침묵이 문제였어요. Claude가 분명 답했는데 TTS가 입을 꾹 다무는 미스터리. → 5편 — Claude가 답했는데 왜 조용하지?


(이전 편: 3편 — 인식이 안 되던 진짜 범인은 마이크였다)

댓글