
Claude Code의 plan을 '설계 트리'로 만들어 PR에 삽입하는 OSS를 만들었다
요약
Claude Code의 plan 모드 출력을 트리 구조의 설계서로 변환하고, 구현 결과와 설계의 일치 여부를 검증하여 PR에 삽입하는 CLI 도구 cc-plan-tree를 소개합니다. 설계 결정 과정과 기각 사유를 기록하여 코드 리뷰 시 근거로 활용할 수 있게 돕습니다.
핵심 포인트
- Claude Code의 plan 모드 출력을 트리 구조의 JSON 및 시각적 도표로 변환
- 설계 트리와 git diff를 대조하여 구현 일치 여부를 검증하는 기능 제공
- Mermaid를 활용해 GitHub PR 본문에 설계 도표를 네이티브하게 삽입
- Pillow를 사용하여 의존성을 최소화한 PNG 이미지 생성 기능 구현
- 설계 결정 과정(Decision Node)을 기록하여 코드 리뷰의 근거로 활용 가능

Claude Code의 plan 모드 출력을 트리 구조의 설계서로 변환하고, 구현 후 코드와의 일치 여부를 검증하여 그대로 PR(Pull Request) 본문에 삽입하는 CLI 도구인 cc-plan-tree를 만들었습니다.

uv tool install cc-plan-tree && cc-plan-tree init
과제: plan 모드의 설계 판단은 사라진다
Claude Code의 plan 모드는 편리하지만, 출력은 긴 텍스트입니다. 그리고 가장 아까운 점은, 플랜 중의 설계 판단이 남지 않는다는 것입니다.
예를 들어 plan 모드 중에 Claude가 "리프레시 토큰(Refresh Token)의 저장 위치는 HttpOnly 쿠키와 localStorage 중 어느 것으로 하시겠습니까?"라고 물었고, 당신이 "쿠키(XSS 대책)"라고 대답했다고 가정해 봅시다. 이 "localStorage를 검토했으나, XSS 리스크를 이유로 기각했다"라는 정보는 세션이 끝나면 사라집니다. 몇 달 후 코드 리뷰에서 "왜 localStorage가 아닌가요?"라는 질문을 받아도 기록은 어디에도 없습니다.
만든 것
cc-plan-tree는 Claude Code에 3가지 슬래시 명령어(Slash Command)를 추가합니다.
| 명령어 | 역할 |
|---|---|
/plan-tree <태스크> | 플랜을 트리 구조의 JSON으로 기록. Claude의 질문은 결정 노드(Decision Node)가 되며, 채택한 선택지와 기각한 선택지(기각 이유 포함)가 모두 남음. 플랜 제시 시 인터랙티브(Interactive)한 HTML 트리가 브라우저에서 열림 |
/plan-verify | 구현 후, 설계 트리와 git diff를 대조하여 "일치 / 괴리 / 미구현"을 노드 단위로 보고. 괴리가 있다면 "코드를 수정할지, 트리를 수정할지"를 선택하여 해소. 마지막에 PR 본문으로 설계 트리를 삽입 |
/plan-export | 설계 트리를 PNG 이미지로 내보내기 (문서나 Slack용) |
포인트는 /plan-verify의 마지막 단계입니다.
GitHub는 PR 본문의 Mermaid 코드 블록을 네이티브하게 도표로 렌더링하기 때문에, 이미지 업로드 없이도 리뷰어가 설계의 전체 모습과 "채택하지 않은 선택지"를 도표로 볼 수 있습니다.
실제 PR에서의 모습은 여기에서 확인할 수 있습니다: https://github.com/natsu0529/cc-plan-tree/pull/1
기술적인 고안
헤드리스 브라우저를 사용하지 않는 PNG 생성
Mermaid 도표의 PNG화에는 통상적으로 mermaid-cli(내부에서 puppeteer=Chromium이 동작)를 사용하지만, pip install 한 번으로 동작하는 도구로 만들고 싶었기에 채택하지 않았습니다. 플랜의 데이터 구조는 자체 포맷이므로, 트리의 레이아웃 계산을 직접 구현하여 Pillow로 직접 그립니다. 의존성은 Pillow 단 하나뿐입니다.
일본어 라벨도 고려하여, 레이아웃 계산 시 CJK 문자를 반각 2글자 너비로 추정하고, 줄바꿈은 영어 단어 중간에서 끊기지 않도록 했습니다.
인터랙티브 HTML도 단일 파일·의존성 제로
/plan-tree가 브라우저에서 여는 트리는 CSS/JS를 모두 인라인화한 단일 HTML입니다. 노드 클릭으로 가지를 접을 수 있고, 기각 옵션에 호버(Hover)하면 기각 이유가 툴팁(Tooltip)으로 나타납니다. 트리의 렌더링은 flexbox와 의사 요소(Pseudo-element)만으로 구현하여 외부 라이브러리는 전혀 사용하지 않았습니다.
여기서 한 가지 함정에 빠졌습니다. justify-content: center로 트리를 중앙 정렬하면, 콘텐츠가 컨테이너보다 넓을 때 왼쪽 부분이 스크롤 불가능한 화면 밖으로 밀려납니다(flexbox의 유명한 함정). 이를 width: max-content; margin: 0 auto로 교체하여 해결했습니다.
슬래시 명령어의 "오래된 복사본" 문제
슬래시 명령어의 실체는 ~/.claude/commands/에 복사되는 markdown이므로, 패키지를 업데이트해도 이미 전개된 명령어는 옛날 상태 그대로입니다. 직접 도그푸딩(Dogfooding)을 하던 중 이 문제를 겪었기에, init이 전개하는 md에 버전 마커를 삽입하여 CLI 실행 시 불일치가 감지되면 경고를 띄우도록 했습니다.
릴리스는 Trusted Publishing
PyPI 공개는 GitHub Actions의 OIDC (Trusted Publishing)를 사용했으므로, API 토큰의 발행 및 보관이 전혀 필요하지 않습니다. git tag v0.2.0 && git push --tags 명령만으로 릴리스가 실행됩니다.
사용법
uv tool install cc-plan-tree # 또는 pip install cc-plan-tree
cc-plan-tree init # 슬래시 커맨드(slash command)를 ~/.claude/commands 에 전개
그 후 Claude Code에서
/plan-tree 로그인 API에 속도 제한(rate limit) 추가
와 같이 사용하기만 하면 됩니다.
향후 계획
- 다른 코딩 에이전트 (Codex CLI / Gemini CLI)용 어댑터 — 플랜의 JSON 포맷은 에이전트에 의존하지 않도록 설계되어 있으므로, 어댑터 추가는 컨트리뷰션(contribution)의 입구로서 최적입니다.
- 플랜의 버전 간 diff ("당초 설계"와 "실제 출하된 것"의 차이 가시화)
피드백 및 PR을 환영합니다!
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기