· 6 min read
Claude Code 구독으로 CI 파이프라인을 만들었다 Building a CI Pipeline with Claude Code Subscription
AI와 함께 코딩하니 테스트가 늘고, 테스트가 늘으니 CI가 필요해졌다. self-hosted runner에 Claude Code 구독을 물려서 테스트 자동화와 PR 변경 분석까지 돌리는 파이프라인. Coding with AI means more tests, which demands CI. A pipeline that runs test automation and PR change analysis on a self-hosted runner using a Claude Code subscription.

AI와 코딩하면 테스트가 늘어난다
Aethelgard(2D MMORPG)를 Claude Code와 함께 개발하고 있다. 내가 모든 코드를 직접 작성하는 게 아니다 보니 테스트의 비중이 커졌다. AI가 작성한 코드가 의도대로 동작하는지 확인하는 가장 확실한 방법이 테스트니까.
단위 테스트에서 시작해서 통합 테스트, Playwright 기반 E2E 테스트까지. 테스트도 AI가 작성하니 수가 빠르게 늘었다. E2E 테스트만 수십 개, 전체를 로컬에서 돌리면 몇 분씩 걸리게 됐다.
CI가 필요해졌다
테스트를 로컬에서만 돌리면 작업 흐름이 끊긴다. GitHub Actions로 옮겨서 PR마다 자동으로 돌리게 했는데, hosted runner의 minutes가 빠르게 쌓였다. E2E 테스트는 서버 빌드 + 브라우저 실행이라 무겁다.
집에 놀고 있는 Windows 컴퓨터에 self-hosted runner를 세팅했다. CI 비용이 $0이 됐다.
PR 변경 분석도 자동으로
self-hosted runner가 생기니 하나 더 할 수 있는 게 있었다. PR의 변경사항을 자동으로 분석하는 것.
솔로 개발에 worktree 4개를 동시에 돌리다 보면 PR이 자주 올라온다. 각 PR이 어떤 시스템을 건드렸고 뭘 바꿨는지를 매번 직접 diff를 읽으며 파악하는 건 번거롭다.
Claude Code CLI에는 --agent 옵션이 있다. self-hosted runner에 구독 세션으로 로그인해두면 추가 API 비용 없이 Agent를 돌릴 수 있다.
다만 이건 코드 리뷰를 AI에게 맡기는 게 아니다. 코드의 품질을 판단하는 건 내 몫이다. Agent가 하는 일은 “이 PR이 뭘 바꿨는지”를 빠르게 요약해주는 것에 가깝다.
구성
워크플로우
# pr-agent.yml
test:
uses: ./.github/workflows/test.yml # 유닛 + E2E
agent:
needs: test
if: always() # 테스트 실패해도 실행
runs-on: self-hosted
steps:
- run: |
claude --agent ci-agent \
-p "$PROMPT" \
--permission-mode bypassPermissions \
--max-turns 15 \
--output-format stream-jsontest job이 먼저 돌고, 결과와 무관하게 agent job이 변경사항을 분석한다. 테스트가 실패했을 때도 “뭐가 바뀌었는지”는 알아야 하니까.
Agent 정의
.claude/agents/ci-agent.md:
---
model: sonnet
maxTurns: 15
effort: high
allowedTools:
- Bash
- Grep
- Glob
- Read
---핵심은 read-only라는 점이다. 파일을 수정하거나 커밋하지 않는다. git diff main...HEAD로 변경사항을 읽고, 어떤 시스템이 영향을 받았는지, feature/bugfix/refactor 중 어떤 성격인지를 정리해서 PR 코멘트로 남긴다.
--permission-mode bypassPermissions로 CI에서 승인 없이 실행하되, allowedTools를 읽기 전용으로 제한했다.
PR 코멘트 구조
Agent 출력은 parse_agent_output.py가 마크다운으로 변환한다. 최종 PR 코멘트는 이런 구조:
## CI Agent Report
[OK] 10 turns | 0:01:03
### Test Results
| Suite | Result | Passed | Failed | Total |
|-------|--------|--------|--------|-------|
| Unit | ✅ Passed | 733 | 0 | 733 |
| E2E | ✅ Passed | 89 | 0 | 89 |
### Changes
- Projectile 시스템 히트 판정 로직 수정
- Systems affected: Combat, Physics
- MeleeHitSystem 실행 순서를 ProjectileHitSystem 앞으로 변경테스트 결과는 .trx 파일을 파이프라인이 직접 파싱한다. Agent는 테스트 분석을 하지 않는다 — 변경사항 요약만 담당한다.
실제 PR에 달리는 코멘트는 이렇게 생겼다:

E2E 테스트가 실패하면 실패한 테스트의 상세 정보도 함께 표시된다:

전체 흐름
태스크 시작부터 완료까지 터미널에서 처리된다.
/pick-task로 Notion에서 태스크를 시작하고, /pr로 PR을 올리면 CI가 테스트 + 변경 분석을 자동으로 돌린다. 머지하면 on-merge.yml이 Notion 태스크를 자동 완료 처리한다.
정리
| 항목 | 내용 |
|---|---|
| CI Agent 모델 | sonnet |
| 평균 분석 시간 | ~1분/PR |
| CI 비용 | $0 (self-hosted) |
| Agent 비용 | $0 (구독제) |
AI와 함께 개발하면 테스트와 CI의 중요성이 커진다. 내가 모든 코드를 한 줄씩 읽는 흐름이 아니니까, 테스트가 통과하는지, 어떤 시스템이 바뀌었는지를 자동으로 확인하는 파이프라인이 필요했다. self-hosted runner와 Claude Code 구독의 조합으로 추가 비용 없이 구성할 수 있었다.

