코딩 에이전트 세 개를 처음 동시에 돌려보면, 실행은 더 이상 느린 부분이 아니게 된다. 버그 하나는 Claude Code에, 리팩터링은 Codex에, 테스트 커버리지 공백은 세 번째 Runtime에 맡기면 40분 뒤 세 개의 브랜치가 준비된다. 그런데 진짜 기다림은 그때부터다. 셋 모두 이제 당신을 기다리고 있기 때문이다. 첫 번째 diff를 읽고 승인하는 동안 나머지 둘은 놀고 있다. 실행은 병렬, 리뷰는 직렬이니 병렬성이 주는 이점은 거의 없다.
에이전트를 병렬로 잘 돌리게 된 팀이라면 누구나 빠지는 함정이다. 병목은 사라지지 않는다. “에이전트가 코드를 얼마나 빨리 작성하는가”에서 “사람이 결과를 얼마나 빨리 읽고 판단하고 받아들이는가”로 옮겨갈 뿐이다. 네 번째 에이전트를 추가하면 상황은 더 나빠진다. 완료된 작업의 대기열만 길어지고, 리뷰어는 여전히 한 명이다.
해결책은 더 빨리 리뷰하거나 더 많이 신뢰하는 게 아니다. 리뷰를 머릿속에만 맴도는 뒷전 생각이 아니라 워크플로의 명시적인 일부로 설계하는 것이다. 이 글에서 다루는 워크플로가 바로 그것이며, Sharkly가 겨냥하는 문제이기도 하다. 모든 에이전트 실행의 목표와 diff, 근거, 리뷰를 하나의 Task에 담아, 리뷰 대기열이 쌓여 있는 브라우저 탭 더미가 아니라 눈으로 보고 관리할 수 있는 대상이 되게 하는 것이다.
병렬 에이전트가 병목을 리뷰로 옮기는 이유
리뷰는 대기열이다. 완료된 에이전트 실행이 일정한 속도로 도착하고, 사람은 일정한 속도로 처리한다. 도착 속도가 처리 속도를 앞지르면 대기열은 끝없이 커진다. 이야기는 이게 전부이며, 그래서 에이전트의 순수 처리량은 최적화할 대상이 아니다. 한 시간에 에이전트 열 개가 작업을 끝내는데 당신이 한 시간에 신중하게 세 개의 변경만 받아들일 수 있다면, 하역장에 클립보드를 든 사람 하나만 있는 공장을 지은 셈이다.
대부분의 도구는 이 사실을 가려준다. 쌓여 있는 풀 리퀘스트는 작업을 보여주지만, 어떤 항목이 실제로 결정을 기다리는지, 아직 실행 중인지, 이미 머지되었는지는 알려주지 않는다. 대기열은 실제로 존재하지만 탭과 알림, 기억 속에 흩어져 있다. 첫 번째 설계 목표는 이를 눈에 보이게 만드는 것이다. 보이지 않는 병목은 관리할 수 없기 때문이다. 동시성이 높아질 때 벌어지는 일은 리뷰 용량 계산을 다룬 자매 글에서 확인할 수 있다.
운영 모델: 누가 할당하고, 누가 실행하고, 누가 리뷰하고, 누가 승인하는가
상태값을 손대기 전에 네 가지 역할에 먼저 이름을 붙여라. 서로 다른 역할이며, 이를 뒤섞는 것이 리뷰를 혼란스럽게 만든다.

누군가는 작업을 할당한다. 의도를 수용 기준이 있는 범위가 정해진 Task로 바꾼다. 무언가가 이를 실행한다. Agent가 Computer 위에서 Runtime으로 실행하며 변경 사항과 수행 기록을 남긴다. 누군가는 결과를 리뷰한다. diff와 근거를 읽고 수용 기준을 충족하는지 판단한다. 누군가는 이를 승인한다. 머지하고 릴리스하기로 결정하는 것으로, “코드가 괜찮아 보인다”와는 다른 결정이다.
Sharkly는 이 계약을 포스트잇에 적어 붙여둘 만한 한 문장으로 정리한다. 에이전트는 조사하고 실행하고 테스트하고 보고하며, 사람은 방향을 정하고 권한을 부여하고 결과를 승인한다. 팀의 판단이 필요한 지점에서 자동화는 멈춘다. 할당과 승인은 설계상 사람의 몫이다. 실행은 Agent의 몫이다. 리뷰는 대기열이 생기는 지점이기에 반드시 설계해야 하는 작업이다.
유용한 경계선이 하나 있다. 머지된 PR은 승인된 결과와 다르다. 머지는 git 작업이다. 승인은 변경 사항이 Task가 요구한 일을 하는지 사람이 판단하는 것이다. 이 둘이 클릭 한 번으로 합쳐지면, 리뷰 품질은 그 순간 리뷰어가 쏟을 수 있는 에너지만큼으로 떨어진다.
역할, 상태, 리뷰 게이트
에이전트와 사람이 오가는 몇 가지 상태를 Task에 부여해 대기열에 형태를 잡아주자. Task는 작업의 기본 단위로, 목표와 대화, 실행을 담는다. 상태의 핵심은 에이전트가 Task를 리뷰 게이트 직전까지 진행시킬 수 있지만, 그 너머로 옮길 수 있는 것은 사람뿐이라는 점이다.
| Status | Who moves it here | Meaning |
|---|---|---|
| Backlog | Person | Scoped, not started. No run happens here. |
| Ready | Person | Cleared to run; an Agent can claim it. |
| In progress | Agent | A run is executing in an isolated worktree. |
| Ready for review | Agent | Run finished, change and evidence attached, waiting for a person. |
| Changes requested | Person | Sent back with a comment; a follow-up run continues on the same Task. |
| Done | Person | Accepted, merged, released. |
게이트는 Ready for review로 들어가는 전환과 Done으로 나가는 전환이다. 에이전트는 스스로 게이트에 도달할 수 있지만, 통과할 수는 없다. 이 한 가지 규칙 덕분에 에이전트 열 개를 안전하게 돌릴 수 있다. 에이전트들은 Ready for review 칼럼을 병렬로 채우고, 당신은 품질을 지킬 수 있는 속도로 그 칼럼을 비운다. 칼럼의 길이가 바로 눈에 보이게 된 병목이다.
솔직한 판단 기준은 이렇다. 사용자에게 배포되거나 돈, 인증, 데이터 마이그레이션, 공개 API에 닿는 변경은 모두 게이트를 둔다. 일회성 스파이크, 어차피 다시 생성할 보일러플레이트, 아직 아무도 접근할 수 없는 플래그 뒤의 작업에는 게이트를 두지 않는다. 모든 것에 게이트를 두면 사람이 필요하지도 않았던 변경 때문에 병목이 다시 리뷰어에게로 되돌아온다. 위험도가 높은 작업에 정지 지점을 어디에 둘지는 승인 게이트에서 다룬다.
리뷰가 확장되도록 설계하라
병렬 에이전트의 결과물을 리뷰하는 것은 동료의 PR을 리뷰하는 것과 다르다. 양이 더 많고, 한꺼번에 몰려오며, 어떻게 만들어졌는지 아는 것도 대개 더 적다. 세 가지 방법이 항목당 리뷰어 비용을 낮춰준다.
근거는 기억이 아니라 Task에 붙여라. 실행은 변경 요약, 타입체크와 테스트 출력, 빌드 결과, 알려진 한계를 모두 기록으로 남겨야 한다. Ready for review 항목을 열면 무슨 일이 있었는지 재구성하는 것이 아니라 사건 파일을 읽는 셈이 된다. 이것이 Task 수준 근거로 리뷰하는 것과 신뢰를 되찾기 위해 모든 걸 직접 다시 돌리는 것의 차이다.
키 입력이 아니라 결정을 리뷰하라. 기계가 검사할 수 있는 속성, 포맷팅, 타입 안전성, 테스트 통과 여부는 Task가 당신에게 도달하기 전에 기계가 걸러내야 한다. Google의 코드 리뷰 가이드도 같은 구분을 한다. 도구가 검증할 수 있는 것은 자동화하고, 사람은 설계와 적합성에 주의를 쏟게 하라는 것이다. 한정된 판단력은 “컴파일이 됐는가”가 아니라 “이 변경이 옳은가”에 써야 한다.
진행 중인 작업에 상한을 두라. 동시에 In progress에 머무는 Task 수를 엄격히 제한하면 Ready for review 칼럼이 결코 넘어설 수 없는 벽이 되는 것을 막을 수 있다. 이는 칸반 WIP 제한 개념을 에이전트에 적용한 것이다. 다섯 개가 이미 당신을 기다리는 상황에서 여섯 번째 실행을 시작하는 것은 처리량을 늘리는 게 아니라 대기열을 숨기는 것이다. 또한 실행 중인 에이전트를 모니터링하면 멈춘 실행과 느린 실행을 게이트에 도달하기 전에 구분할 수 있어 도움이 된다.
티켓에서 머지된 PR까지: 예시 하나
그럴듯한 Task 하나를 보자. SH-312: “공개 검색 엔드포인트에 속도 제한을 적용한다.” 사람이 백로그에서 수용 기준(키당 분당 N회 요청 후 429, 문서화된 헤더, 테스트)과 함께 Task를 다듬고 Ready로 옮긴다.
세 개의 Agent가 같은 Space에서 병렬로 작업하고 있다. 하나가 SH-312를 집어 들고, 설정된 저장소를 Computer에 클론한 뒤 격리된 worktree에서 실행해 자신의 브랜치가 진행 중인 다른 두 실행과 충돌하지 않게 한다. 속도 제한기를 작성하고, 테스트를 추가하고, 타입체크와 테스트 스위트를 돌리고, 제목에 Task ID를 담은 PR을 열고, 변경 요약과 통과한 테스트 출력, 그리고 한 가지 알려진 한계(카운터가 인프로세스 방식이라 인스턴스 간에 공유되지 않음)를 기록해 SH-312를 Ready for review로 옮긴다.
당신은 탭 열다섯 개가 아니라 Task 하나를 연다. 근거가 바로 거기 있고, 알려진 한계 기록이 가장 유용한 부분이다. 테스트는 통과했지만 인스턴스 간 공유 상태는 당신이 내려야 할 설계 결정이다. 코멘트를 남기고 Changes requested로 옮긴다. 그 코멘트가 같은 Task에서 후속 실행을 시작한다. Agent는 카운터를 공유 저장소로 바꾸고 갱신된 근거를 가져온다. 이번에는 승인한다. SH-312를 Done으로 옮기는 것은 당신의 결정이며, git 머지의 조용한 부작용이 아니라 당신 이름이 붙은 상태 변경으로 기록된다.
그동안 나머지 두 Agent는 Ready for review에 머물러 있다. 대기열이 받은편지함이 아니라 칼럼이기 때문에, 흐름을 놓치지 않고 순서대로 처리할 수 있다.
사람에게 남겨두는 경계선
병렬 에이전트는 리뷰가 제약이 되는 순간까지는 처리량 이야기지만, 그 뒤로는 대기열 이야기가 된다. 여러 에이전트에서 가치를 얻는 팀은 리뷰를 설계된 인프라로 대한다. 명시적인 상태, 에이전트가 도달할 수는 있지만 넘을 수는 없는 게이트, Task에 붙는 근거, 사람보다 먼저 수행되는 기계 검사, 그리고 동시 진행 작업량에 대한 제한이 그것이다.
worktree와 브랜치 이름 규칙, 그리고 규율만으로 직접 구축할 수도 있다. 아니면 Sharkly가 워크플로를 관리하도록 맡길 수도 있다. 할당 가능한 Agents, 실행과 근거를 함께 담는 Tasks, 그리고 Ready for review가 당신이 비워내는 칼럼이 되는 보드를 통해, 에이전트는 조사하고 실행하고 테스트하고 보고하며 사람은 마지막 결정을 쥔다. 이미 여러 에이전트를 돌리고 있다면, 기억에 의존하는 대신 이 한 곳에서 각 에이전트의 작업과 결과를 관리할 수 있다.
FAQ
리뷰가 직렬이라면 에이전트를 병렬로 돌리는 게 시간을 아껴주나요? 완료된 실행이 당신이 받아들일 수 있는 속도보다 빠르게 도착하는 지점까지만 그렇습니다. 그 지점을 넘으면 에이전트를 더 늘려도 더 빨리 배포되는 것 없이 리뷰 대기열만 커집니다. 이득은 리뷰를 눈에 보이게 만들고 사람이 필요한 것만 게이트로 막는 데서 나옵니다.
모든 에이전트 변경에 사람이 리뷰해야 하나요? 아닙니다. 사용자에게 배포되거나 인증, 데이터, 돈, 공개 API에 닿는 변경은 게이트로 막으세요. 위험도가 낮거나 다시 생성할 수 있는 작업은 기계 검사만으로 통과시키세요. 모든 것에 게이트를 두면 사람이 필요하지도 않았던 변경 때문에 병목이 다시 리뷰어에게 돌아옵니다.
PR을 머지하는 것과 작업을 승인하는 것은 같은 것 아닌가요? 아닙니다. 머지는 git 작업이고, 승인은 변경이 Task의 기준을 충족한다고 사람이 판단하는 것입니다. 둘을 분리해 두면 작업량이 많을 때도 리뷰 품질이 유지됩니다. 사람의 결정을 어디에 남길지는 휴먼 인 더 루프 코딩 에이전트를 참고하세요.



