#프로덕트
구현부터 merge까지 자동화하자, 제가 일하는 시간이 절반 넘게 줄었어요

블로그 기능 1개의 설계부터 merge까지 진행하는 동안 제가 일한 시간은 47.0분에서 19.6분으로 줄었어요. 에이전트가 구현하는 동안 저는 다음 기능을 설계할 수 있어요.

issue에 label을 붙인 뒤 PR이 merge되기까지 실제로 실행되는 과정을 62초로 압축한 영상이에요.

TL;DR

• 작업 시작과 구현 → 리뷰 → merge 사이의 지시·확인을 자동화하면, 에이전트가 작업하는 동안 사람은 자리를 비우거나 다음 기능을 설계할 수 있어요. 블로그 기능 1개의 설계부터 merge까지 진행하며 제가 일한 시간을 1회 측정했더니, 47.0분에서 19.6분으로 줄었어요(merge 거절에 응대한 3.2분을 넣으면 22.8분).

• 에이전트가 앞 기능을 구현하는 동안 다음 기능을 설계하면, 기능 3개가 모두 완성되기까지 걸리는 시간도 140.9분에서 125.8분으로 줄어든다고 추정했어요(1회 측정값으로 계산). 기능 1개만 보면, 작업을 시작해 기능이 완성되기까지 걸린 시간은 47.0분에서 86.7분으로 늘었어요.

• 지시를 자동화하려면 사람이 눈으로 하던 확인도 code로 옮겨야 해요. 에이전트의 분류 결과 형식은 schema로, 구현 여부는 commit 수로 확인하고, 에이전트에게는 GitHub 쓰기 token을 주지 않아요. 설계는 여전히 사람이 맡고, 에이전트가 구현을 빠르게 끝낼수록 같은 시간에 리뷰할 PR이 늘어 PR 리뷰가 다음 병목이 될 수 있어요.

Reddit의 r/ClaudeCode에는 Claude Code가 끝나기를 기다리며 터미널을 지키는 일(babysitting the terminal)에 지쳤다는 글이 올라왔어요. 저도 그랬어요.

코딩 에이전트에게 구현을 맡겨도 저는 터미널 앞을 떠날 수 없었어요. issue 1개를 끝내려면 구현, 리뷰, merge 단계마다 제가 에이전트에게 지시해야 했거든요. 구현이 끝나면 결과를 확인하고 리뷰를 지시했어요. 리뷰가 끝난 뒤에도 결과를 확인하고 merge를 지시해야 했어요. 제가 자리를 비우면 다음 단계는 시작되지 않았어요.

단계마다 지시한 데는 이유가 있었어요. 구현은 implement skill(에이전트가 따를 작업 절차를 적어 둔 file)로 테스트를 먼저 쓰며 진행했어요. 구현부터 merge까지 1개의 session(에이전트와 나누는 대화 한 차례)에서 이어서 시킬 수도 있지만, 그러면 context(에이전트가 응답할 때 참고하는 대화와 작업 기록) 사용량이 많아져요. 제 경험에서는 context 사용량이 많아지면 에이전트의 성능이 떨어졌고, token(모델이 처리하는 텍스트 단위) 사용량이 늘어 비용도 커졌어요. 그래서 단계를 나누되, 다음 단계를 시작하는 지시는 제가 해야 했어요.

모든 단계를 한 번에 지시해도, 다음 issue를 언제 시작할지 정하는 일은 남았어요. 저는 쌓인 issue를 확인하고 지금 처리할 작업을 골라야 했고, 진행 중인 작업은 구현·리뷰·merge 중 무엇을 해야 할지 판단해 다시 지시해야 했어요.

지시를 자동화하기 전에도 저는 설계와 명세를 쓴 뒤 작업을 issue로 나눴어요. 그 가운데 에이전트에게 완전히 맡길 수 있는 작업을 AFK(Away From Keyboard) 작업이라고 불러요. 그런데 이름과 달리, 제가 자리를 비우면 AFK issue가 쌓여 있어도 몇 시간씩 아무 작업도 시작되지 않았어요. 필요한 것은 긴 지시 1개가 아니었어요. code를 push하면 CI/CD(빌드·검사·배포 자동화)가 시작되듯, issue에 label(GitHub의 issue나 PR에 붙이는 분류 표지)을 붙여 두면 처리할 조건이 됐을 때 다음 작업이 시작되는 자동화가 필요했어요.

GitHub Actions는 GitHub에서 개발 작업을 자동으로 실행하는 서비스예요. 설계는 제가 맡고, 구현을 시작하거나 구현 → 리뷰 → merge로 진행할 때 필요한 지시는 GitHub Actions가 하도록 바꿨어요. 그래서 에이전트가 일하는 동안 저는 자리를 비우거나 다음 기능을 설계할 수 있었어요. 사람이 에이전트에게 직접 지시하는 방식을 ‘수동 지시 방식’, GitHub Actions가 지시하는 방식을 ‘자동 지시 방식’이라고 부를게요.

GitHub Actions가 지시하면, 에이전트가 구현하는 동안 사람은 다음 기능을 설계할 수 있어요

2026년 11월 1일에 블로그 기능 1개(화면 2개)를 두 방식으로 각각 1회씩 개발하며 제가 일한 시간을 측정했어요. 수동 지시 방식에서는 47.0분, 자동 지시 방식에서는 19.6분이었어요.1

19.6분 가운데 18.4분은 에이전트와 대화하며 기능을 설계한 시간이고, 1.2분은 issue에 label을 붙인 시간이에요(issue마다 따로 붙이지 않아요. 설계를 마친 뒤 에이전트에게 요청하면, 에이전트가 gh CLI(GitHub을 터미널에서 다루는 명령줄 도구)로 선행 작업이 필요 없는 issue 여러 개에 한 번에 붙여요). 설계 시간 18.4분은 두 방식에 똑같이 포함했어요. 수동 지시 방식에서는 28.5분이 더 들었어요. 구현부터 merge까지 시작 지시를 내리고, 에이전트가 제 의도대로 작업하는지 검토한 시간이에요.

이 측정에서는 수동 지시 방식에서 에이전트가 일하는 동안 제가 검토한 시간도 일한 시간으로 셌어요. 검토하는 동안 다른 일을 하면 이 시간이 줄어든다고 볼 수도 있어요. 하지만 그때도 단계가 끝날 때마다 결과를 확인하고 다음 단계를 지시하는 일은 사람에게 남아요. 그 일을 하면서 다른 일까지 맡으면, 사람이 챙겨야 할 일은 오히려 늘어나요. 제가 줄이려는 것은 사람이 맡는 일 자체예요.

기능 1개가 완성되는 데 걸린 시간은 자동 지시 방식이 더 길었어요. 설계와 구현·리뷰·merge에 걸린 시간을 합하면, 수동 지시 방식은 47.0분, 자동 지시 방식은 86.7분이었어요. 자동 지시 방식에는 issue 분류, 실행 환경 준비, 사람의 응답을 기다리는 시간이 더해졌고, 리뷰와 수정에도 더 오래 걸렸기 때문이에요(자동 지시 방식 22.8분, 수동 지시 방식 7.8분).

하지만 서로의 구현 결과를 기다릴 필요가 없는 기능이라면 설계와 구현을 겹쳐 진행할 수 있어요. 수동 지시 방식은 사람이 구현부터 merge까지 검토한 뒤 다음 기능을 설계하고, 자동 지시 방식은 에이전트가 구현하는 동안 사람이 다음 기능을 설계한다고 가정해 계산했어요. 기능별 소요 시간은 이번 측정값을 썼어요. 여러 기능을 실제로 개발해 측정한 결과가 아니라 추정값이며, 표의 시간은 모두 작업을 시작한 때부터 측정한 시간이에요.

기능 수 · 제 일이 끝나기까지 걸린 시간 (수동 지시 → 자동 지시) · 모든 기능이 완성되기까지 걸린 시간 (수동 지시 → 자동 지시)

1개 · 47.0분 → 19.6분 · 47.0분 → 86.7분

3개 · 140.9분 → 58.8분 · 140.9분 → 125.8분

10개 · 469.5분 → 195.9분 · 469.5분 → 262.9분

issue에 붙은 label에 따라 GitHub Actions workflow가 구현·리뷰·merge를 이어서 진행해요

자동 지시 방식에서도 설계와 명세 작성은 제 일이에요. 그 뒤에는 설계에서 나온 작업이 issue로 등록되고, issue에 label이 붙으면 GitHub Actions가 label 추가 같은 사건에 맞춰 workflow(자동화 절차)를 실행해요. 각 issue를 처리할 때마다 제가 터미널에서 다시 지시할 필요가 없어요.

issue에 agent:explore가 붙으면 explore workflow가 시작돼요. 에이전트는 이 label이 붙은 열린 issue를 한꺼번에 읽고 분류해요. 바로 구현할 수 있다고 분류된 issue에는 workflow가 agent:implement를 붙여 구현을 시작해요. 사람이 issue를 하나씩 열어 구현할지 판단하고 지시하던 일을 이 분류와 label 변경으로 대신해요.

구현이 끝나면 implement workflow가 draft PR(아직 검토 전인 PR)을 열고 agent:review를 붙여 리뷰를 시작해요. 리뷰가 끝나면 merge gate workflow가 정해 둔 조건에 따라 merge 여부를 판정해요. 조건과 판정 방식은 다음에 더 자세히 다룰게요.

이 구성은 Matt Pocock의 sandcastle 저장소를 참고했어요. sandcastle은 에이전트를 sandbox(실행을 격리하는 환경) 안에서 실행하는 TypeScript library이고, 저장소에는 agent:implement label이 붙으면 시작하는 implement workflow도 있어요.

선행 issue가 끝나야 시작할 수 있는 작업은 agent:after-blockers label로 대기시켜요. 선행 issue가 모두 merge로 닫히면 promote workflow가 대기 중인 issue의 label을 agent:explore로 바꿔요. 사람뿐 아니라 workflow도 label을 붙여 다음 작업을 시작할 수 있으므로, 제가 선행 작업이 끝났는지 확인하고 후속 작업을 지시할 필요가 없어요.

flowchart TD
H1(["시작 요청<br/>issue에 agent:explore label"])
H2(["선행 작업 대기<br/>issue에 agent:after-blockers label"])
subgraph GA["GitHub Actions: 사람 없이 workflow가 이어서 실행"]
P["promote workflow<br/>앞 issue가 모두 merge되면 시작"]
E["explore workflow<br/>에이전트가 issue를 읽고 분류"]
I["implement workflow<br/>에이전트가 구현하고 draft PR 생성"]
R["review workflow<br/>새 에이전트가 검토하고 수정"]
G{"merge gate workflow<br/>에이전트 없이 규칙으로 판정"}
U["update-branch workflow<br/>PR에 main 반영"]
end
H1 --> E
H2 --> P
P -->|"agent:explore label"| E
E -->|"바로 구현 가능<br/>agent:implement label"| I
I -->|"agent:review label"| R
R -->|"review 종료"| G
G -->|"main보다 뒤처짐<br/>agent:update-branch label"| U
U -->|"agent:review label"| R
G -->|"조건 모두 충족"| M("main에 merge<br/>Vercel 운영 배포")
E -->|"그 밖<br/>needs-a-human label"| HH(["사람 차례"])
G -->|"조건 미달"| HH

그림의 needs-a-human은 에이전트가 바로 구현할 수 없다고 분류한 issue나, merge gate의 조건을 채우지 못한 PR에 붙는 label이에요. 뒤에서 볼 agent:blocked는 workflow의 검사가 실패한 issue에 붙어요. update-branch workflow는 PR이 main보다 뒤처졌을 때 main의 변경을 PR에 반영해요.

실제 실행 화면은 영상으로 볼 수 있어요. 영상에는 issue #98에 agent:explore를 붙이고 PR #99가 merge되기까지, 4개의 workflow가 차례로 실행되는 과정을 담았어요. 이 영상은 실제로 약 38분 걸린 과정을 62초로 압축해 보여 줘요.

이런 workflow를 직접 만들 때 주의할 점

GitHub Actions는 job(workflow 안에서 실행되는 작업 단위)마다 GitHub 작업을 인증하는 token을 자동으로 만들어요. 이름은 GITHUB_TOKEN이고, job이 끝나면 만료돼요. 이 인증 token은 모델의 텍스트 사용량을 세는 token과 다른 뜻이에요. 그런데 GITHUB_TOKEN으로 붙인 label은 다른 workflow를 시작하지 않아요(GitHub 문서). 그래서 다음 단계의 label을 붙일 때는 personal access token(사용자가 자기 계정에서 발급하는 인증 token) 같은 별도 인증 token을 써요.

workflow는 에이전트의 분류 결과 형식과 구현 commit을 code로 확인해요

다음 작업을 시작하는 지시를 자동화하려면, 앞 작업이 제대로 끝났는지 확인하는 일도 자동화해야 해요. 예를 들어 explore 에이전트가 issue를 분류하면, workflow는 분류 결과를 code로 읽고 다음 label을 정해야 해요. 에이전트가 prompt에서 정한 형식과 다르게 답하면 이 처리가 깨질 수 있어요. Anthropic 문서에도 prompt를 세심하게 써도 형식이 깨진 JSON(프로그램이 읽는 데이터 표기 형식)이 나올 수 있다고 적혀 있어요.

OpenAI의 2024년 발표에서도 schema(데이터 형식을 정한 규칙)를 따르도록 학습시킨 모델의 형식 준수율은 자체 평가에서 93%였어요. 그래서 OpenAI는 모델의 출력 자체를 schema에 맞게 제한하는 방식을 더했어요. 형식을 지키라는 지시만으로는 부족했던 사례예요.

explore workflow에서는 에이전트가 issue별 분류 결과를 JSON 문서인 plan으로 돌려줘요. 먼저 에이전트를 실행하는 script(자동 실행 프로그램)가 zod(TypeScript에서 데이터 형식을 검사하는 library)의 schema로 plan을 검사해요. 아래는 실제 schema에서 분류 결과인 tag를 정의한 부분이에요. .enum(...)에 나열한 easy-call, needs-a-human, blocked 3개의 값만 받아요.

tag: z
.enum(["easy-call", "needs-a-human", "blocked"])
.describe(
"The call. A duplicate takes the tag of the issue it duplicates."
),

형식이 맞지 않으면 script가 오류를 에이전트에게 돌려주고 최대 2회 다시 답을 받아요. 다음으로 에이전트가 없는 apply job이 plan을 다시 검사해요. 분류 대상인 issue가 빠짐없이 1회씩 들어 있는지, tag가 허용된 값인지, comment가 비어 있지 않은지 확인해요. 하나라도 어긋나면 label 변경과 comment 작성을 시작하지 않고 run(workflow 실행 1회)을 실패로 끝내요. 분류 대상 issue에는 모두 agent:blocked를 붙여 사람이 확인하게 해요.

분류 결과의 형식이 맞아도, 에이전트의 완료 보고가 실제 작업과 일치하는지는 따로 확인해야 해요. 한 실험에서는 모델 12개에게 여러 file을 검토하게 하고, 모두 1,140번 실행했어요. file을 다 읽지 않고 끝난 실행 가운데 52.8%는 모든 file을 검토했다고 보고했어요. 사람이 결과를 열어 확인하던 일도 완료 보고만으로 대신할 수는 없어요.

implement workflow에서는 에이전트가 구현을 마친 뒤 별도 step(job 안에서 순서대로 실행하는 명령 묶음)이 commit을 확인해요. 다음은 실제 검사 code예요. $BASE..HEAD는 구현을 시작한 commit부터 현재 commit까지의 범위예요. commit이 0개이거나 commit하지 않은 변경이 남으면 exit 1로 실패를 알리고 PR 생성을 중단해요.

commits=$(git rev-list --count "$BASE..HEAD")
if [ "$commits" -eq 0 ]; then
echo "::error::The agent finished without committing anything. Nothing to open a PR for."
git status --short
exit 1
fi
if [ -n "$(git status --porcelain)" ]; then
echo "::error::The agent left uncommitted changes. The PR would not contain them."
git status --short
exit 1
fi

이 검사에 실패하면 run은 실패로 표시되고, issue에는 agent:blocked가 붙어요. 다만 commit이 있다는 사실이 구현의 정확성까지 보장하지는 않아요. 요구한 대로 구현했는지는 다음 단계인 review workflow가 확인해요.

prompt injection에 대비해 입력 작성자를 제한하고, 에이전트에게 인증 token을 주지 않아요

에이전트를 사람 없이 workflow로 실행할 때는, 에이전트가 작업 지시가 아닌 글까지 지시로 받아들이는 경우에도 대비해야 해요. issue 본문이나 comment에 숨긴 지시로 에이전트를 조종하는 공격을 prompt injection이라고 불러요. Aikido는 Gemini CLI의 issue 분류 workflow를 재현해, issue에 숨긴 지시로 에이전트가 인증 token과 API key(서비스 접근용 인증 정보)를 issue 본문에 쓰게 했어요. Invariant Labs도 악성 issue를 읽은 에이전트가 private 저장소의 정보를 public PR로 옮기는 공격을 시연했어요.

이 글의 workflow는 prompt injection에 두 겹으로 대비해요.

첫 번째 방어는 저장소 접근 권한으로 입력 작성자와 실행 요청자를 제한하는 것이에요. 제가 쓰는 저장소는 private이라 접근 권한을 받은 사람만 issue를 열 수 있어요. issue comment는 작성자의 authorAssociation 값이 OWNER, MEMBER, COLLABORATOR인 것만 에이전트에게 넘겨요. 다음은 comment를 고르는 실제 code예요. 권한 조건에 더해, workflow의 상태 보고를 뜻하는 <!-- factory:status -->가 든 comment도 제외해요.

gh issue view "$ISSUE_NUMBER" --json number,title,body,labels,comments \
| jq '.comments |= map(select(
(.authorAssociation | IN("OWNER", "MEMBER", "COLLABORATOR"))
and (.body | contains("<!-- factory:status -->") | not)))' \
> /tmp/ticket.json

review workflow는 같은 저장소의 branch에서 연 PR만 받아요. fork(다른 계정으로 복제한 저장소)의 PR에는 GitHub Actions가 secret(별도로 등록한 인증 정보)을 전달하지 않아 review workflow가 실패해요. label 추가 권한도 저장소 권한으로 제한해요. workflow가 label을 붙일 때도 그 권한을 가진 계정의 인증 정보를 사용해요.

두 번째 방어는 GitHub 쓰기용 인증 token을 에이전트에게 주지 않는 것이에요. explore에서는 에이전트를 실행하는 job과 label·comment를 쓰는 job을 나눠요. implement와 review에서는 GitHub을 호출하는 step에만 인증 token을 전달하고 에이전트의 step에는 전달하지 않아요.

다만 implement와 review에서는 에이전트와 인증 token을 쓰는 step이 같은 기계에서 실행돼요. 에이전트가 뒤 step이 실행할 file을 남기면, 그 file이 인증 token에 접근할 수 있어요. 이 글의 workflow는 sandbox를 쓰지 않아요. sandcastle의 Docker sandbox를 써도 작업 폴더는 runner(workflow를 실행하는 기계)와 공유되므로, 에이전트가 그 폴더에 남긴 file이 뒤 step에서 실행될 수 있는 위험은 남아요.

에이전트가 구현을 빠르게 끝낼수록 PR 리뷰가 다음 병목이 될 수 있어요

블로그 기능 1개를 개발한 이 측정에서, PR 2개의 리뷰는 모두 review workflow가 맡았어요. merge는 PR 1개를 merge gate workflow가 했고, 나머지 PR 1개는 merge gate가 거절해 제가 거절된 원인을 확인한 뒤 직접 merge했어요.

자동 지시 방식이라고 기능 1개에서 나오는 PR이 늘어나는 것은 아니에요. 누가 구현하든 리뷰할 PR 수는 구현한 기능 수에 비례해요. 사람이 직접 구현할 때는 코드를 쓰는 속도에 한계가 있어서, 보통은 리뷰가 병목이 되지 않아요. 에이전트는 구현 코드를 훨씬 빠르게 써서, 같은 시간에 구현하는 기능 수와 코드 양이 늘어요. 그만큼 리뷰할 PR도 늘어서, 구현을 검토하고 다음 지시를 내리던 일을 줄여도 PR 리뷰가 다음 병목이 될 수 있어요.

Faros AI의 보고서는 AI 도입 정도가 높은 팀에서 더 많은 PR merge와 더 긴 리뷰 시간을 함께 관찰했어요. 다만 개발자 대부분이 자동완성 기능만 쓰던 데이터여서, 무인 에이전트 자동화의 효과를 보여 주는 자료는 아니에요. Faros AI는 개발 생산성 측정 도구를 파는 회사이고, 이 자료는 인과관계가 아닌 상관관계를 보고해요. 사람이 모든 PR을 리뷰하지 않아도 되려면 무엇이 필요한지는 다음에 더 자세히 다룰게요.

지금 쓰는 에이전트 작업에서 사람이 터미널 앞에 있어야 하는 순간을 적어 보세요. 구현을 시작하라고 지시할 때, 리뷰 결과를 읽고 merge를 지시할 때, 완료 보고와 실제 결과를 대조할 때를 떠올려 보세요. 그중 code로 자동화할 수 있는 지시와 확인은 무엇인가요?

1. 19.6분에는 CI 설정 결함으로 판단해 제외한 merge 거절 응대 3.2분이 빠져 있어요. 포함하면 22.8분으로, 수동 지시 방식보다 51% 줄었어요.

링크 복사
만들어봄 만들어봄 · Product Owner

프로덕트 빌더 · 써보는 사람 말고, 만들어보는 사람.

댓글 0
댓글이 없습니다.
추천 아티클
만들어봄 만들어봄 · Product Owner

프로덕트 빌더 · 써보는 사람 말고, 만들어보는 사람.