홈시리즈멘토링

© 2026 정기창. All rights reserved.

본 블로그의 콘텐츠는 CC BY-NC-SA 4.0 라이선스를 따릅니다.

☕후원하기소개JSON Formatter러닝 대기질개인정보처리방침이용약관

© 2026 정기창. All rights reserved.

콘텐츠: CC BY-NC-SA 4.0

☕후원하기
소개|JSON Formatter|러닝 대기질|개인정보처리방침|이용약관

Claude Code 사용 패턴, transcript jsonl 로 직접 진단해봤습니다

정기창·2026년 5월 7일

인프라는 늘어나는데, 정말 일하고 있는지 모르겠다

스킬, 서브에이전트, hook, 하네스 같은 단어가 익숙해질 무렵, 필요할 때마다 하나씩 만들어 등록하다 보니 어느새 제 환경에 등록된 인프라가 70개를 훌쩍 넘어 있었습니다. 처음에는 "필요한 만큼 늘어났겠지" 하고 가볍게 생각했는데, 곰곰이 생각해보니 어떤 것이 일하고 어떤 것이 자리만 차지하고 있는지 제 자신도 잘 모르고 있었습니다.

직관으로 "이건 잘 쓰고 있는 것 같다" 정도의 자평을 하고 있었는데, 솔직히 말하면 confirmation bias 에 휘둘리고 있는 것은 아닐까 의심스러웠습니다. 만든 의도와 실제 사용은 충분히 다를 수 있고, 객관적인 데이터로 들여다보지 않으면 인프라만 늘고 활용도는 그대로일 수 있겠다는 생각이 들었습니다. 그래서 한 번 측정해보자고 마음을 먹게 되었습니다.

Claude Code 는 모든 세션을 jsonl 로 자동 기록합니다

다행히 Claude Code 는 hook 을 따로 깔거나 옵트인을 하지 않아도, 모든 세션을 jsonl 로 자동 기록하고 있었습니다. 이 사실을 들여다보고 나서야 알게 되었는데, 이미 쌓여 있는 ground truth 가 있다는 것이 의외로 든든하게 느껴졌습니다.

~/.claude/projects/<encoded-cwd>/<session-id>.jsonl              # 메인 세션
~/.claude/projects/<encoded-cwd>/<session-id>/subagents/agent-*.jsonl  # sub-agent sidechain

encoded-cwd 는 작업 디렉토리의 / 를 - 로 치환한 형태입니다. 메인 세션과 sub-agent sidechain 이 분리되어 있어서, 어떤 호출에서 어떤 sub-agent 가 spawn 되었는지까지 따라갈 수 있습니다. 핵심은 이 데이터가 외부 의존성 없이 로컬에 이미 쌓여 있다는 점입니다. MCP 도, 옵저버빌리티 인프라도 필요 없습니다.

transcript 에서 끄집어낼 수 있는 시그널들

jsonl 한 줄 한 줄에는 적지 않은 정보가 있습니다. 처음에는 어디서부터 봐야 할지 막막했는데, 정리해보니 자가 진단에 쓸 만한 시그널은 대략 여섯 가지로 추릴 수 있었습니다.

시그널 출처 필드 알 수 있는 것
Agent 호출 type 분포 tool_use.input.subagent_type general-purpose 의존도
응답 길이 tool_result.content.length silent fail 후보 (200자 미만)
실제 스킬 호출 sidechain 의 attributionSkill 슬래시 트리거에 안 잡히는 자동 호출
Hook 동작 system.subtype=stop_hook_summary hookCount, hookErrors
Turn duration system.subtype=turn_duration 작업 무게의 분포
슬래시 vs 자연어 last-prompt.lastPrompt 첫 글자 호출 방식 비율

최근 7일치 메인 세션 파일 개수를 세는 것은 한 줄이면 됩니다.

find ~/.claude/projects -maxdepth 2 -name '*.jsonl' -mtime -7 | wc -l

서브에이전트 호출의 subagent_type 분포도 jq 한 줄로 충분합니다.

find ~/.claude/projects -name '*.jsonl' -mtime -7 -print0 \
  | xargs -0 cat \
  | jq -r 'select(.type=="assistant") | .message.content[]?
           | select(.type=="tool_use" and .name=="Agent")
           | .input.subagent_type // "general-purpose"' \
  | sort | uniq -c | sort -rn

이 정도만 돌려봐도 본인의 7일치 작업이 어떤 서브에이전트로 흘러갔는지가 한눈에 들어옵니다. 외부 도구나 MCP 없이 bash 와 jq 만으로 self-introspection 이 가능하다는 것은 의외로 큰 장점이었습니다.

general-purpose 와 전문 에이전트는 같은 토큰을 다르게 씁니다

이 분포에서 가장 먼저 눈에 들어온 것은 general-purpose 의 비중이었습니다. Agent 호출 시 subagent_type 을 명시하지 않으면 기본값이 general-purpose 인데, 도구는 다 갖고 있지만 도메인 system prompt 는 비어 있는 깡통에 가깝습니다. 반대로 전문 에이전트는 페르소나·체크리스트·산출물 포맷이 미리 박혀 있어, 같은 토큰을 쓰더라도 결과물의 결이 확연히 다릅니다. 같은 외주비로 "아무 일이나 할 줄 아는 막일꾼"에게 보내느냐, "도메인 전문가"에게 보내느냐의 차이라는 생각이 들었습니다.

경험적으로 general-purpose 호출 비중이 30% 를 넘으면 ROI 손실 신호로 볼 만했습니다. 명시적으로 전문 에이전트를 지정하기만 해도 같은 토큰으로 더 정돈된 결과를 얻을 수 있는데, 호출할 때는 귀찮아서 default 로 흘려보내는 경우가 많았습니다. 데이터로 비율을 보고 나니 다음부터는 좀 더 의식적으로 골라 쓰게 되었습니다.

dormant 스킬 — 등록만 해놓고 안 쓰는 것들

다음으로 들여다본 것은 dormant 스킬, 즉 등록만 해두고 7일치 transcript 에서 호출 흔적이 0인 스킬들입니다. 부끄럽지만 만들어놓고 한 번도 안 쓴 스킬이 적지 않았습니다. 원인은 대략 세 가지였습니다.

원인 처방
트리거 워딩이 평소 말투와 안 맞음 description 에 자연어 트리거 보강
만들 당시엔 필요했지만 지금 일에 안 맞음 archive 또는 삭제로 시스템 프롬프트 토큰 회수
다른 스킬에 자연스럽게 흡수됨 흡수된 사실 명시 후 dormant 측 정리

특히 두 번째가 인상적이었습니다. 만들 당시의 필요와 지금의 필요는 같지 않다는 사실을, 데이터로 확인하기 전까지는 잘 인정하지 않게 되더라는 것입니다. 시스템 프롬프트 토큰은 매 메시지마다 따라다니기 때문에, 안 쓰는 스킬을 그대로 두는 것은 보이지 않는 비용이 계속 새는 셈입니다.

슬래시 트리거만 보면 놓치는 것 — attributionSkill 이라는 ground truth

처음에는 lastPrompt 첫 글자가 / 인지 여부로 슬래시 호출과 자연어 호출 비율을 보려고 했습니다. 그런데 이렇게만 세면 큰 구멍이 생깁니다. 어떤 스킬은 사용자가 직접 부르는 것이 아니라, 다른 스킬이 내부에서 호출하거나 hook 이 자동으로 띄우는 식으로 동작하는데, 이 자동 호출은 lastPrompt 만 봐서는 보이지 않습니다. 다행히 sub-agent 의 sidechain jsonl 에는 attributionSkill 필드가 박혀 있어서, 이 값을 기준으로 집계해야 자동 오케스트레이터까지 포함된 진짜 사용 분포가 보입니다.

이 둘을 비교해보니 흥미로운 갭이 드러났습니다. 의식적으로 부르는 스킬과, 실제로 sub-agent 를 가장 많이 spawn 시키고 있는 스킬이 같지 않을 수 있다는 것입니다. 슬래시 호출은 거의 없는데 attributionSkill 기준으로는 상위에 있는 스킬도 있어서, "아 이 친구는 뒤에서 묵묵히 일하고 있었구나" 하는 발견을 하게 되었습니다.

짧은 응답이 다 silent fail 은 아닙니다

응답 길이가 200자 미만인 케이스를 silent fail 후보로 찍어두는 것까지는 자연스럽게 떠올렸습니다. 막상 항목을 들여다보니 "ok", "done", 단답형 검증 결과처럼 의도적으로 짧은 응답이 적지 않았습니다. 결국 응답 길이만 보고 silent fail 로 단정해서는 안 된다는 결론에 다다랐습니다. 의심 후보로 띄워주되, raw prompt 와 raw response 를 같이 보여주고 사람이 판단하게 만드는 편이 안전합니다.

측정은 자동, 판단은 사람. 이 경계를 흐리지 않는 것이 자가 진단 도구를 만들 때 의외로 중요했습니다.

OS 환경 차이도 같이 봐야 합니다

다른 환경에서도 돌려보려고 하니 운영체제별 차이가 한 가지 함정이었습니다. WSL 의 /mnt/c/... 에서 jsonl 을 훑을 때는 9P 프로토콜이 VM 경계를 넘는 비용 탓에 native 대비 5~10배 느려졌습니다. 반대로 Native Windows + Git Bash 는 MSYS2 의 POSIX 에뮬레이션이라 같은 비용이 없습니다. 같은 jq 한 줄이라도 환경에 따라 체감이 크게 달라질 수 있다는 점은, 다른 사람 환경에 넘기기 전에 한 번은 의식해둘 만했습니다.

측정 후 처방 세 가지 — 만들고 끝나지 않기

며칠치 transcript 를 들여다본 끝에, 자기 자신을 위한 처방 세 가지를 메모해두었습니다.

  • general-purpose 호출 비중이 높다면 전문 에이전트로 명시 위임한다. 같은 토큰으로 결과물 품질을 끌어올리는 가장 손쉬운 방법입니다.
  • dormant 스킬은 archive 하거나 트리거 워딩을 보강한다. 안 쓰는 스킬을 그대로 두는 것은 시스템 프롬프트 토큰을 계속 새게 두는 일입니다.
  • silent fail 후보는 단정하지 말고 raw 로 사람이 본다. 의도된 짧은 응답을 실패로 오해하지 않기 위한 최소한의 안전장치입니다.

돌이켜 생각해보면, 인프라를 만드는 시간만큼 그것이 일하고 있는지 확인하고 갱신하는 시간도 필요하다는 점을 그동안 가볍게 넘기고 있었습니다. 다행이었던 것은, 그 측정에 필요한 데이터가 이미 로컬에 자동으로 쌓이고 있었다는 점입니다. 결국 중요한 것은 도구의 화려함보다도, "내가 만든 게 정말 일하고 있나" 라는 질문을 한 번쯤 데이터로 확인해보는 습관이라는 생각이 들었습니다. 만들고 끝내지 말고, 가끔은 멈춰서 측정해봐야겠다고 다짐하게 됩니다.

Claude Codetranscript서브에이전트AI 자동화자가 진단운영 회고jq

관련 글

Claude Code에 설치한 SuperClaude, 정말 필요했을까?

Claude Code에 SuperClaude 프레임워크를 설치했지만, 15개 에이전트 중 14개가 내장 기능과 중복이었고 22개 커맨드는 의존성 미충족으로 작동하지 않았다. 안 쓰는 기능이 매 대화마다 컨텍스트 윈도우를 소비하고 있었다는 사실을 깨닫고 정리한 과정.

관련도 92%

Claude Code Skills - AI 코딩 도구에 행동 규칙을 심는 법

Claude Code에 Skills를 설치하면 AI가 코드를 작성하는 방식 자체가 바뀝니다. TDD를 강제하고, 버그를 체계적으로 추적하고, 보안을 실시간으로 검토하게 만드는 과정을 기록했습니다.

관련도 92%

대화 세션에서 돌리던 slash skill을 배치 자동화로 옮긴 이야기

매일 같은 slash skill을 손으로 돌리던 습관을 LaunchAgent 배치로 옮기면서 느낀 것은 기술 장벽보다 역할 재정의가 본질이라는 점이었습니다. 집행자에서 큐레이터로의 전환에 대한 기록입니다.

관련도 92%