
GitHub 라벨을 스테이트 머신(State Machine)으로 만들어 Claude Code를 상주시키기 — 무인 구현·자동 리뷰·자동 버그
요약
GitHub 라벨을 상태 저장소(State Store)로 활용하여 Claude Code를 무인 개발 루프로 상주시키는 설계 방식을 소개합니다. 라벨 조작만으로 AI의 작업 흐름을 제어하며, 세션 중단 시에도 상태를 유지할 수 있는 안정적인 에이전트 워크플로우를 구축합니다.
핵심 포인트
- GitHub 라벨을 유일한 상태 저장소로 사용하여 시스템 복잡도 최소화
- auto-develop, auto-review, auto-bugfix 등 3가지 핵심 루프 설계
- 구현 전 적성 판정 및 사전 조사를 통한 토큰/시간 낭비 방지
- 세션 크래시 발생 시에도 라벨 기반으로 작업 재개 가능
#5와의 차이점: 「버튼을 누르는 사람」조차 없애기
#5에서는 /feature-idea
→ /develop-issue
→ /close-issue
라는 skill의 컨베이어 벨트를 만들었습니다. 하지만 그것은 아직 사람이 명령어를 입력하는 흐름입니다.
이번에는 그 너머, 「Issue에 라벨을 붙이는」 것 이외의 인간 조작을 전부 없앱니다. Claude Code를 /loop로 상주시켜, 라벨 상태를 보고 알아서 일을 가져가게 하는 구성입니다.
인간이 할 일:
아침: 오늘 돌릴 Issue에 auto-develop 라벨을 붙인다 (선택만 함)
낮: 완성된 PR을 리뷰하고 머지(Merge)한다 (판단만 함)
...
상주 루프는 3개가 있습니다.
| 루프 | 입구 라벨 | 하는 일 | 출구 |
|---|---|---|---|
| auto-develop-loop | auto-develop | 사전 조사 → 무인 구현 → 셀프 리뷰 → PR | 인간 머지 대기 |
| auto-review-loop | needs-review | 인간의 PR을 포함한 모든 PR에 다각도 리뷰 코멘트 | 코멘트만 작성 (push 하지 않음) |
| auto-bugfix-loop | bug-fix | 장애 조사 → 재현 테스트 → 수정 → PR | 인간 머지 대기 |
세 번째 입구(Datadog 알람 → bug-fix Issue 자동 생성)는 지난 기사에서 배선해 두었습니다.
핵심 설계: 라벨 = 유일한 상태 저장소 (State Store)
3가지 루프 모두 동일한 설계 원칙으로 동작합니다. 파이프라인의 상태를 GitHub 라벨 이외의 그 어디에도 두지 않는다.
DB를 세우지 않는다 · 채팅 문맥에 두지 않는다 · 세션 메모리에 두지 않는다. 이유는 3가지가 있습니다.
- 판(Board)이 모두에게 보인다 — 「지금 어떤 Issue가 어느 공정인가」가 GitHub의 Issue 목록 그 자체입니다. AI 전용 관리 화면이 필요 없습니다.
- 인간의 개입 수단이 라벨 조작만으로 충분하다 — 멈추고 싶으면 라벨을 제거하고, 우선순위를 높이고 싶으면 붙입니다. 비엔지니어라도 개입할 수 있습니다.
- 세션이 죽어도 상태가 남는다 — Claude Code의 세션은 크래시(Crash)가 나기도 하고 PC를 닫기도 합니다. 재시작된 루프는 라벨을 보는 것만으로 이어서 재개할 수 있습니다.
세 번째가 실운용에서는 가장 효과적입니다. 상주 AI의 설계는 「중단될 것을 전제」로 상태를 외부에 두는 것이 정답이었습니다.
루프 1: auto-develop-loop (무인 구현)
이중 게이트로 「구현 전에」 걸러내기
무인 구현에서 가장 무서운 것은, 실패할 Issue에 뛰어들어 토큰과 시간을 낭비하는 것입니다. 그래서 구현을 시작하기 전에 2단계 게이트를 둡니다.
게이트 1: 승격 시의 적성 판정. Go 판정이 완료된 Issue 재고에서 auto-develop으로 승격시킬 때, picker skill이 「무인 구현에 적합한가」를 ✅/⚠️/🛑 3단계로 판정하여 제시합니다. 인간은 목록에서 선택하기만 하면 됩니다.
게이트 2: 착수 시의 사전 조사. 루프가 Issue를 가져오면, 구현 에이전트(Agent)를 기동하기 전에 BE/FE 조사 에이전트를 병렬로 실행하여, 설계 미확정 사항을 코드베이스로부터 스스로 해결하게 합니다. 판정표는 다음과 같습니다:
| 조사 결과 | 판정 |
|---|---|
| 구현 방법이 판명됨 / 기존 패턴을 유용할 수 있음 | ✅ 구현 계속 |
| ... |
🛑는 auto-dev-failed 라벨로 교체하고, 이유를 Issue에 코멘트하며, Slack으로 담당자에게 멘션을 보내 중단합니다. 「망설여지면 멈춰서 사람에게 돌려준다」가 무인 운전의 대전제입니다.
구현 페이즈의 구성
- 구현은 BE/FE 에이전트를 git worktree 분리로 병렬 기동 (메인 작업 트리를 더럽히지 않음)
- 동시 구현은 최대 4건. CI 실패나 중단이 계속되면 2건으로 좁혀 원인을 먼저 해결
- 브랜치는 반드시 fetch 후의
origin/development기점 (로컬 기점은 조상 회귀(Regression) 사고의 원인) - 모델 계층에서 비용을 배분: 판단(조사 판정 · 지적 트리아지 · 수렴 판정)은 상위 모델의 메인 루프, 구현은 중위 모델의 에이전트, 라벨 교체나 CI 폴링(Polling) 같은 기계적 작업은 에이전트를 기동하지 않고 Bash 직접 처리
셀프 리뷰와 수렴 조건
PR을 생성하면, 별도의 LLM (codex CLI)과 Claude 자신의 코드 리뷰, 그리고 차분에 따른 전문 에이전트(silent-failure 헌터, 테스트 분석 등)를 병행시켜 지적 사항을 자동 수정 후 push 합니다. 여기서 중요한 것은 수렴 조건(convergence condition)을 미리 결정해 두는 것입니다.
- CRITICAL + WARNING이 0이 되면 종료
- 2회차 이후부터는 "CRITICAL 0 이고 WARNING ≤ 2"라면 남은 과제로 PR에 기록하고 종료
이것이 없으면 AI는 무한히 다듬기만 합니다. "완벽"이 아니라 "머지(merge) 판단에 충분한 품질"에서 끊어내는 것이 요령입니다.
CI 판정의 함정
gh pr checks --watch의 exit code는 신뢰해서는 안 됩니다. 완료되지 않은 CI를 성공으로 오판할 수 있습니다. check-runs API를 통해 각 작업(job)의 conclusion을 명시적으로 확인합니다:
gh api repos/<owner>/<repo>/commits/<sha>/check-runs \
--jq '.check_runs[] | {name, conclusion, status}'
# 전부 conclusion == "success"가 될 때까지 대기
CI가 실패하면 실패 유형별로 자동 수정(lint → --fix, 테스트 실패 → 버그 수정. 테스트를 완화하는 방향의 수정은 금지)하여 재 push 하며, 3회 시도 내에 고쳐지지 않으면 중단합니다.
루프 2: auto-review-loop (댓글만 다는 자동 리뷰)
두 번째는 성격이 조금 달라서, 사람이 작성한 PR을 포함한 모든 리포지토리의 Open PR을 대상으로 합니다. needs-review 라벨을 붙이면 누구의 PR이든 동일한 품질의 리뷰가 댓글로 달리는 공유 인프라입니다.
"댓글만" 남기도록 하네스(Harness) 레벨에서 보장하기
이 루프의 절대 규칙은 수정 push도 머지도 하지 않는 것입니다. 타인의 작업 브랜치에 AI가 멋대로 commit을 하면 신뢰가 깨집니다.
흥미로운 점은, 이를 "프롬프트로 부탁하는" 것이 아니라 skill의 frontmatter로 강제할 수 있다는 것입니다:
---
name: auto-review-loop
description: ...
...
disallowed-tools를 선언하면, 이 skill이 실행되는 동안에는 파일 편집 도구 자체가 Claude Code의 하네스 레벨에서 무효화됩니다. **"고쳐 쓰지 마"가 아니라 "고쳐 쓸 수 없음"**입니다. 무인 운전의 가드레일은 가능한 한 프롬프트가 아닌 구조(mechanism)로 구현해야 합니다.
별도 LLM과의 대조를 통한 리뷰 신뢰도 확보
리뷰는 codex(별도 LLM)와 Claude를 병행시켜 지적 사항을 대조합니다:
| 상황 | 처리 방식 |
|---|---|
| 양쪽 모두가 찾아낸 지적 사항 | 신뢰도 높음 → must-fix로 명시 |
| 한쪽만 찾아낸 지적 사항 | 중요도에 따라 must / should / nit로 분류, 망설여지면 남겨둠 |
| 설계 트레이드오프(trade-off)를 동반하는 지적 사항 | "논점"으로 남기고, 결론은 인간에게 맡김 |
단일 모델의 리뷰는 "그럴듯한 오지적(false positive)"이 섞이는 것이 약점이지만, 독립된 2개 계통이 같은 지점을 가리킨다면 대부분 진짜입니다. 인간의 더블 체크와 같은 원리입니다.
SHA 마커로 재리뷰 수렴시키기
상주 리뷰에서 은근히 어려운 것이 "같은 PR을 반복해서 리뷰하며 문제를 다시 꺼내는" 문제입니다. 해결책은 Issue 생성 시와 마찬가지로 **비가시 마커(invisible marker)**를 사용하는 것입니다:
<!-- auto-review:reviewed-sha=abc1234 -->
리뷰 댓글 끝에 리뷰가 완료된 head SHA를 심어두고, 다음 폴링(polling) 시 SHA가 같다면 아무것도 하지 않습니다. 새로운 commit이 쌓였다면 재리뷰를 수행하지만, 이때도 "이전 지적 사항 → 이번 대응의 OK/NG"와 "신규 must-fix"만 확인하며, 한 번 기각한 지적 사항은 다시 제안하지 않는다는 규칙을 세웁니다. 이를 통해 무한 리뷰 루프를 방지할 수 있습니다.
또 다른 고안으로, 리뷰 댓글에는 "🤖 자동 리뷰 결과"와 같은 헤더를 붙이지 않습니다. 1인칭 리뷰어 문체로 작성하게 합니다. 받는 사람에게 중요한 것은 지적의 내용이지, 그것이 AI가 만든 것인지에 대한 안내가 매번 붙으면 노이즈가 되기 때문입니다 (팀 내에서는 구조로서 이미 공유되었다는 전제하에 진행합니다).
스스로 만든 PR는 스스로 고치게 한다
auto-develop-loop가 만든 PR에 리뷰가 달린 경우에만, 종료 라벨을 (review-done이 아니라 reviewed-commented로) 변경하여, auto-develop-loop 측이 다음 폴링(Polling)에서 이를 포착해 지적 사항을 자동으로 수정합니다. 인간의 PR은 "코멘트를 남기고 끝"이지만, AI의 PR은 "코멘트를 바탕으로 스스로 고치는" 방식입니다. 루프(Loop)들이 라벨을 통해 대화하는 구조입니다.
루프 3: auto-bugfix-loop (자동 버그 수정)
세 번째는 지난 기사의 연장선으로, bug-fix 라벨이 붙은 장애 Issue를 포착합니다. auto-develop-loop와 골격은 같지만, 전 단계가 조사와 재현으로 대체됩니다:
- 조사: Issue의 증상과 코드를 통해 근본 원인을 특정 (부족할 경우 Datadog의 APM·로그를 참조)
- 재현: 수정하기 전에, 해당 결함으로 인해 실패하는 테스트를 작성한다. 재현할 수 없다면 수정하지 않고
bug-fix-failed로 인간에게 반환 - 수정: 원인을 고치고, 재현 테스트가 green이 되는 것을 확인한 뒤 PR 생성
"재현할 수 없는 버그는 고치지 않는다"가 가장 중요한 규칙입니다. 추측에 의한 수정은 디그레션(Regression, 퇴보)의 온상이 되므로, 실패하는 테스트를 통해 원인 확인이 완료된 경우에만 수정하도록 합니다.
3개 루프 공통 가드레일 (Guardrail)
과거의 사고를 바탕으로 규약화하여, skill 본문에 심어둔 내용입니다.
| 규칙 | 이유 |
|---|---|
| 머지는 절대로 자동화하지 않는다 | 운영 환경에 들어가는 마지막 관문은 인간이다. AI는 "머지해도 좋은 상태"까지 운반하는 역할 |
| 착수 시의 라벨 변경은 처리 시작 전에 수행 | 폴링의 이중 실행으로 인해 동일한 Issue에 두 마리의 AI가 착수하는 사고 방지 |
| 상태 변경 계열의 gh 조작은 순차 실행 | 병렬 배치(Batch)는 한 개의 실패가 다른 것들을 휘말리게 하여 취소시키고, 어중간한 상태를 만듦 |
| 파생 Issue의 자동 생성은 금지 | 무인 실행 중에는 승인을 받을 수 없다. 남은 과제는 원래 Issue에 코멘트하고, 인간이 판단한 후 생성 |
| 정지 시에는 반드시 이유 코멘트 + Slack 알림 | "조용히 멈춰 있는 것"이 가장 곤란하다. 인간의 개입이 필요한 순간에만 끼어든다 |
| commit 전에 build / vet / test EXIT 0 | 망가진 코드를 push 하지 않는다. Edit의 성패는 빌드로 확인한다 |
운용해 본 소감
- 인간의 하루 가동 시간은 "아침의 선택 10분 + 일중의 머지 판단" 내로 수렴합니다. 체감상, 파이프라인이 돌아가는 동안 인간은 다른 업무(설계·고객 대응)를 하고 있다가, 알림이 왔을 때만 상황을 확인하는 느낌입니다. "이 Issue는 인간의 의사결정이 필요하다"는 것을 알 수 있다는 것 자체에 가치가 있으며, 정지 이유 코멘트가 그대로 다음 논의의 초안이 됩니다.
auto-dev-failed는 실패가 아니라 성과입니다. - 루프는 로컬
/loop실행이므로 세션을 닫으면 정지합니다. 라벨에 상태가 있으므로 재개는 순식간이지만, 완전히 상주시키고 싶다면/schedule(클라우드 cron)에 동일한 사양을 전달하는 구성이 됩니다. 그 경우에도 "머지 비자동화" 게이트만큼은 절대로 제거하지 말 것.
요약
- 상주 AI의 상태 관리는 GitHub 라벨 한 장이면 충분하다. 보이고, 개입할 수 있으며, 중단되어도 사라지지 않는다.
- 무인 구현은 구현 전에 걸러내기 (적성 판정 × 사전 조사라는 이중 게이트)와 망설여지면 멈추기로 사고율이 결정된다.
- 자동 리뷰의 신뢰도는 별도의 LLM과 대조하여 구축하며, "코멘트만 남기기" 보장은
disallowed-tools를 통해 시스템으로 구현한다. - 버그 수정은 실패하는 재현 테스트를 작성할 수 있는 것만 고친다.
- 아무리 자동화해도, 머지만은 인간이 한다. 이 원칙을 지키기에 나머지를 전부 맡길 수 있다.
라벨을 하나 붙이면 PR이 생성되어 있고, 리뷰 코멘트도 달려 있으며, 인간은 머지 버튼 앞에서 생각만 하면 되는——이런 상태는 한 번 경험하면 다시 돌아갈 수 없습니다.
Discussion

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