Capstone 16 — 깃허브 이슈에서 PR로 가는 자율 에이전트(GitHub Issue-to-PR Autonomous Agent)

AWS Remote SWE Agents, Cursor Background Agents, OpenAI Codex cloud, Google Jules는 2026년 모두 같은 제품 형태로 수렴합니다. 이슈(issue)에 라벨을 붙이면 풀 리퀘스트(Pull Request; PR)가 돌아옵니다. 에이전트(agent)는 클라우드 샌드박스(cloud sandbox)에서 실행되어 테스트(test) 통과를 검증한 뒤, 변경 근거(rationale)를 담은 리뷰 준비 완료 PR을 올립니다. 어려운 부분은 저장소(repo)의 빌드 환경(build environment)을 자동으로 재현하는 것, 자격 증명 유출(credential leakage)을 막는 것, 저장소별 예산(budget)을 강제하는 것, 그리고 에이전트가 강제 푸시(force-push)할 수 없게 만드는 것입니다. 이 캡스톤은 자체 호스팅(self-hosted) 버전을 만들고, 호스티드(hosted) 대안과 비용 및 통과율(pass rate)을 비교합니다.

유형: Capstone 언어: Python(에이전트), TypeScript(GitHub App), YAML(Actions) 선수 지식: Phase 11(LLM 엔지니어링), Phase 13(도구), Phase 14(에이전트), Phase 15(자율 시스템), Phase 17(인프라) 실습 Phase: P11 · P13 · P14 · P15 · P17 예상 시간: 30시간

문제

비동기 클라우드 코딩 에이전트(async cloud coding agent)는 대화형 코딩 에이전트(interactive coding agent; capstone 01)와는 다른 별도의 제품 범주입니다. 사용자 경험(UX)의 출발점은 깃허브 라벨(GitHub label)입니다. 이슈에 @agent fix this 라벨을 붙이면 작업자(worker)가 클라우드 샌드박스에서 기동하고, 저장소를 클론(clone)하고, 테스트를 실행하고, 파일을 수정하고, 검증을 마친 뒤, 에이전트의 변경 근거를 본문에 담은 PR을 엽니다. 대화형 루프(interactive loop)도 터미널(terminal)도 없습니다. AWS Remote SWE Agents, Cursor Background Agents, OpenAI Codex cloud, Google Jules, Factory Droids가 모두 이 형태로 수렴하고 있습니다.

엔지니어링 과제는 구체적입니다. 환경 재현(environment reproduction)이 필요합니다. 에이전트는 캐시된 개발 이미지(cached dev image) 없이도 저장소를 처음부터 빌드할 수 있어야 합니다. 플레이키 테스트(flaky test)는 재실행하거나 격리해야 합니다. 자격 증명 범위 제한(credential scoping)은 최소한의 세분화 권한(fine-grained permission)만 가진 GitHub App으로 처리해야 합니다. 저장소별 일일 예산 강제(budget enforcement)도 필요하고, 강제 푸시 금지 정책(no-force-push policy)도 필요합니다. 이 캡스톤은 호스티드 대안과 비교해 통과율, 비용, 안전성(safety)을 측정합니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.비동기 이슈-PR 에이전트가 개인 접근 토큰(personal access token) 대신 세분화 설치 토큰(fine-grained installation token)을 가진 깃허브 앱(GitHub App)을 사용하는 이유는 무엇인가요?

2.환경 추론(environment inference, 언어·패키지 매니저 감지 및 Dockerfile 합성)이 비동기 클라우드 에이전트에 핵심적인 단계인 이유는 무엇인가요?

0/2 답변 완료

개념

트리거(trigger)는 깃허브 웹훅(webhook)입니다. 이슈 라벨이나 PR 코멘트(comment)가 될 수 있습니다. 디스패처(dispatcher)는 작업을 ECS Fargate 또는 Lambda로 큐잉(enqueue)합니다. 작업자는 저장소를 Daytona 또는 E2B 샌드박스로 가져오고, 저장소에서 언어와 프레임워크를 추론해 범용 Dockerfile을 만듭니다. 에이전트는 Claude Opus 4.7 또는 GPT-5.4-Codex 위에서 mini-swe-agent 또는 SWE-agent v2 루프(loop)를 실행합니다. 반복 흐름은 코드 읽기, 수정 제안, 패치(patch) 적용, 테스트 실행입니다.

검증(verification)이 게이트(gate)입니다. PR이 열리기 전에 샌드박스 안에서 전체 CI가 통과해야 합니다. 커버리지 변화량(coverage delta)을 계산해, 임계값보다 크게 떨어지면 PR은 열되 needs-review 라벨이 붙습니다. 에이전트는 PR 본문(description)에 변경 근거를 적고, 리뷰어가 후속 질문을 위해 멘션(ping)할 수 있는 @agent 스레드도 함께 둡니다.

안전성은 두 가지 깃허브 표면(surface)을 통해 범위가 정해집니다. 깃허브 앱(GitHub App)은 workflows: read와 좁게 제한된 저장소 콘텐츠/PR 권한을 가진 단기 설치 토큰(short-lived installation token)을 제공합니다. "메인 브랜치(main)에 직접 쓰기 금지"와 "강제 푸시 금지"는 앱 권한이 아니라 브랜치 보호(branch protection)로 강제합니다. 앱은 우회 목록(bypass list)에 절대로 추가하지 않습니다. .github/workflows에 대한 경로 범위 읽기 전용 접근(path-scoped read-only access)은 실제 깃허브 앱 기본기(primitive)가 아니므로, 작업자가 파일 편집 허용 목록(allow-list)으로 직접 강제해야 합니다. 저장소별 일일 예산 상한(예: 저장소당 하루 최대 5개 PR, PR당 20달러)은 디스패처에서 강제합니다.

아키텍처

GitHub issue labeled `@agent fix` or PR comment
            |
            v
    GitHub App webhook -> AWS Lambda dispatcher
            |
            v
    ECS Fargate task (or GitHub Actions self-hosted runner)
       - pull repo
       - infer Dockerfile (language, package manager)
       - Daytona / E2B sandbox with target runtime
       - clone -> git worktree -> agent branch
            |
            v
    mini-swe-agent / SWE-agent v2 loop
       Claude Opus 4.7 or GPT-5.4-Codex
       tools: ripgrep, tree-sitter, read/edit, run_tests, git
            |
            v
    verify CI passes in-sandbox + coverage delta check
            |
            v (verified)
    git push + open PR via GitHub App
       PR body = rationale + diff summary + trace URL
       label: needs-review
            |
            v
    operator reviews; can @-mention agent for follow-ups

스택

  • 트리거(trigger): 세분화 토큰(fine-grained token)을 가진 깃허브 앱과, Lambda 또는 Fly.io 웹훅 리시버(receiver)를 사용합니다.
  • 작업자(worker): ECS Fargate 태스크나 깃허브 액션(GitHub Actions) 자체 호스팅 러너(self-hosted runner)를 사용합니다.
  • 샌드박스(sandbox): 태스크마다 Daytona 데브컨테이너(devcontainer) 또는 E2B 샌드박스를 새로 만들어 씁니다.
  • 에이전트 루프(agent loop): Claude Opus 4.7 / GPT-5.4-Codex 위에서 mini-swe-agent 베이스라인(baseline) 또는 SWE-agent v2를 실행합니다.
  • 검색(retrieval): tree-sitter 저장소 맵(repo-map)과 ripgrep를 조합합니다.
  • 검증(verification): 샌드박스 안에서 전체 CI를 실행하고, 커버리지 변화량 게이트를 둡니다.
  • 관측성(observability): PR별 트레이스 아카이브(trace archive)를 Langfuse에 남기고, PR 본문에서 링크로 연결합니다.
  • 예산(budget): 저장소별 일일 비용 상한과 저장소별 일일 최대 PR 수를 강제합니다.

직접 만들기

  1. 깃허브 앱(GitHub App). 세분화 설치 토큰의 권한은 issues: read+write, pull_requests: write, contents: read+write, workflows: read로 둡니다. "메인에 직접 푸시 금지"와 "강제 푸시 금지"는 브랜치 보호로 강제합니다. 앱은 우회 목록에 넣지 않습니다. 깃허브 앱 권한은 경로 범위(path-scoped)가 아니므로, 작업자가 제안된 변경(proposed diff)의 허용 목록 검사로 .github/workflows 아래 쓰기를 막습니다.

  2. 웹훅 리시버(webhook receiver). Lambda 함수가 이슈 라벨 / PR 코멘트 웹훅을 받습니다. @agent fix this 라벨로 필터링한 뒤 SQS에 큐잉합니다.

  3. 디스패처(dispatcher). SQS에서 작업을 꺼냅니다. 저장소별 일일 예산을 강제합니다. 저장소 URL, 이슈 본문, 새로 만든 Daytona 샌드박스를 포함하는 ECS Fargate 태스크를 띄웁니다.

  4. 환경 추론(environment inference). 언어(Python, Node, Go, Rust)와 패키지 매니저(uv, pnpm, go mod, cargo)를 감지합니다. Dockerfile이 없으면 즉석에서 합성(synthesize)합니다.

  5. 에이전트 루프. Claude Opus 4.7을 사용하는 mini-swe-agent 또는 SWE-agent v2를 돌립니다. 도구는 ripgrep, tree-sitter 저장소 맵, read_file, edit_file, run_tests, git입니다. 하드 리밋(hard limit)은 비용 20달러, 벽시계 시간(wall-clock) 30분, 에이전트 턴 30회입니다.

  6. 검증. 루프가 끝나면 샌드박스에서 전체 테스트 묶음(test suite)을 실행합니다. jacoco나 coverage.py로 커버리지 변화량을 계산합니다. CI가 빨강(red)이면 중단하고 PR을 열지 않습니다. 커버리지가 2%보다 더 떨어지면 needs-review 라벨을 붙여 PR을 엽니다.

  7. PR 게시. 에이전트 브랜치를 푸시합니다. GitHub API로 제목, 변경 근거, 변경 요약(diff summary), 트레이스 URL, 비용, 턴 수를 담아 PR을 엽니다.

  8. 자격 증명 위생(credential hygiene). 작업자는 단기 깃허브 앱 설치 토큰으로 실행합니다. 로그는 아카이브 전에 비밀(secret) 스크럽을 거칩니다.

  9. 평가(eval). 난이도가 다양한 사내 시드 이슈(seeded internal issue) 30건으로 평가합니다. 통과율, PR 품질(변경 크기, 스타일, 커버리지), 비용, 지연 시간(latency)을 측정합니다. 같은 이슈 묶음에서 Cursor Background Agents, AWS Remote SWE Agents와 비교합니다.

사용해보기

# on github.com
  - user labels issue #842 with `@agent fix this`
  - PR #1903 appears 14 minutes later
  - body:
    > Fixed NPE in widget.dedupe() caused by null comparator entry.
    > Added regression test widget_test.go::TestDedupeNullComparator.
    > Coverage delta: +0.12%
    > Turns: 7  Cost: $1.80  Trace: langfuse:...
    > Label: needs-review

산출물 만들기

outputs/skill-issue-to-pr.md가 제출 산출물입니다. 라벨이 붙은 이슈를 제한된 비용(bounded cost)과 범위가 좁혀진 자격 증명(scoped credential)으로 리뷰 준비 완료 PR로 바꾸어 주는 깃허브 앱과 비동기 클라우드 작업자(async cloud worker)를 함께 만들어야 합니다.

가중치기준측정 방법
2530개 이슈 통과율끝-끝(end-to-end) 성공: CI 통과 + 커버리지 양호
20PR 품질변경 크기, 커버리지 변화량, 스타일 일관성
20해결 이슈당 비용과 지연 시간PR당 달러 비용과 PR당 벽시계 시간
20안전성범위 제한 토큰, 저장소별 예산, 강제 푸시 금지, 자격 증명 위생
15운영자 UX변경 근거 코멘트, 재시도 인터페이스(retry affordance), @-멘션 후속
100

연습문제

  1. (쉬움) "플레이키 테스트 안정화(fix flaky test)" 모드를 추가하세요. @agent stabilize-flake TestX 라벨이 붙으면 샌드박스에서 해당 테스트를 50번 실행하고, 플레이크(flake)를 안정화하는 최소 변경을 제안하게 합니다.

  2. (중간) 세 개의 공유 이슈(shared issue)에서 Cursor Background Agents와 비용을 비교하세요. 어떤 도구가 어디서 우위인지 보고합니다.

  3. (중간) 예산 대시보드(budget dashboard)를 구현하세요. 저장소별 일일 비용과 사용자별 비용을 보여 주고, 이상치(anomaly)에는 알림(alert)을 보냅니다.

  4. (어려움) "드라이런(dry-run)" 모드를 만드세요. CI를 실행하지 않고 초안(draft) PR을 열어, 리뷰어가 적은 비용으로 계획만 검토할 수 있게 합니다.

  5. (어려움) 보존 정책(retention policy)을 추가하세요. 7일 동안 병합되지 않은 PR 브랜치를 자동으로 삭제합니다.

핵심 용어

용어흔한 설명실제 의미
깃허브 앱(GitHub App)"범위 제한된 봇 정체성(scoped bot identity)"세분화 권한과 단기 설치 토큰을 함께 갖는 봇 형태의 정체성이다.
비동기 클라우드 에이전트(Async cloud agent)"백그라운드 에이전트(background agent)"터미널이 아니라 클라우드 샌드박스에서 동작하는 비대화형 작업자이다.
환경 추론(Environment inference)"Dockerfile 합성(Dockerfile synthesis)"언어와 패키지 매니저를 감지하고, 없으면 Dockerfile을 생성하는 과정이다.
검증(Verification)"샌드박스 안에서의 CI(CI-in-sandbox)"PR을 열기 전에 작업자 내부에서 전체 테스트 묶음을 실행하는 게이트이다.
커버리지 변화량(Coverage delta)"커버리지 보존(coverage preservation)"기준 브랜치(base branch)에서 에이전트 브랜치로 갈 때 테스트 커버리지(%)의 변화량이다.
저장소별 예산(Per-repo budget)"일일 상한(daily ceiling)"디스패처가 강제하는 달러 한도와 PR 수 상한이다.
변경 근거(Rationale)"PR 본문 설명(PR body explanation)"무엇을 왜 바꿨는지 에이전트가 PR 본문에 적는 요약으로, 본문에 반드시 포함된다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

issue-to-pr

Build an async GitHub issue-to-PR agent that runs in a cloud sandbox, reproduces the build, verifies tests, and opens review-ready PRs within strict per-repo budgets.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.브랜치 보호(branch protection)가 '메인에 직접 푸시 금지'와 '강제 푸시 금지'를 강제하며, 깃허브 앱은 우회 목록(bypass list)에 절대 추가되지 않습니다. 이 아키텍처가 에이전트의 프롬프트에 의존해 이런 동작을 피하게 하는 것보다 안전한 이유는 무엇인가요?

2.에이전트 브랜치가 모든 테스트를 통과했지만 커버리지가 3% 떨어졌습니다. 시스템은 PR을 차단하는 대신 'needs-review' 라벨을 붙여 엽니다. 이 설계 선택의 이유는 무엇인가요?

3.디스패처(dispatcher)가 저장소별 일일 예산(최대 5개 PR, PR당 20달러)을 강제합니다. 에이전트 수준이 아닌 디스패처 수준에서 예산을 강제하는 이유는 무엇인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다