나는 kdy1이라는 닉네임으로 활동하는 개발자다. 오픈소스 컴파일러 프로젝트인 SWC를 만들었고, 이전에는 Deno와 Vercel에서 일했다. 요즘은 Zephyr Cloud IO의 Labor0, Watchtower, theaiplatform.app을 함께 만들고 있다.
그중에서도 최근 가장 열심히 만드는 제품은 Labor0다. Labor0의 핵심 아이디어는 간단하다.
AI가 작업을 주도한다.
인간은 언제나 병목이다. 이것이 내 철칙이다.
물론 HITL(Human in the Loop)은 필수다. 제품과 기술에 관한 결정은 사람이 내려야 하고, PR도 사람이 최종 검토하고 머지해야 한다. 다만 AI가 작업하는 동안 사람을 호출하는 횟수는 가능한 한 줄여야 한다.
Labor0는 사람의 결정이 필요할 때 웹 푸시 등으로 질문을 보낸다. 사람이 한 PR을 검토하고 있는 동안에는 다음 작업을 자동으로 시작한다. 사람이 모든 과정에 계속 붙어 있는 대신, 꼭 필요한 결정 지점에만 참여하는 구조다.
AI에게 일을 시킬 때의 제1원칙
내가 AI에게 일을 시킬 때 가장 중요하게 생각하는 원칙은 언제나 같다.
작업을 충분히 작은 단위로 쪼개야 한다.
한 PR이 너무 크면 사람도 리뷰하기 어렵고 AI도 리뷰하기 어렵다. 결국 리뷰 품질이 떨어진다.
나는 AI가 등장하기 전부터 코드 리뷰를 아주 많이 했다. GitHub에 기록된 PR 리뷰 횟수가 1년에 5천 번을 넘을 정도였다. 그 경험을 통해 큰 PR에서는 제대로 된 리뷰가 어렵다는 것을 배웠다.
AI도 비슷하다. 컨텍스트 크기 같은 이유가 영향을 주는 것 같지만, 정확한 원인과 별개로 작업이 커질수록 결과를 검증하기 어려워지는 것은 분명하다.
유지 가능한 바이브 코딩을 하려면 작업을 나누는 과정이 필수다. Labor0는 이 과정을 플랫폼으로 만든다. 작업이 크면 여러 작업과 PR로 나누고, 작업 사이에 의존성이 있다면 그 순서에 맞춰 실행한다. 서로 독립적인 작업은 병렬로 진행한다.
다만 이렇게 많은 작업을 병렬로 돌리려면 입력부터 상세해야 한다. 내가 수십 개의 세션을 동시에 운영할 수 있는 중요한 이유도 이슈와 PRD가 매우 구체적이기 때문이다.
여기서 내가 항상 사용하는 것이 $add-issue와 Write PRD 스킬이다.
$add-issue는 확인된 버그를 재현 사례와 구현 범위가 포함된 상세한 GitHub 이슈로 만든다. Write PRD를 사용하면 필요한 결정을 둘러싼 대화가 이어진다. 결정은 모두 내가 직접 내리지만, 큰 프로젝트의 규모와 비교하면 사람이 내려야 하는 결정은 생각보다 많지 않다. 물론 프로젝트 자체가 크기 때문에 결정 횟수의 절대적인 수가 작은 것은 아니다.
오늘 첫 번째 작업: Labor0
오늘은 먼저 Labor0를 위한 PRD 세 개를 작성했다. PRD를 작성할 때는 GPT 5.6 Sol을 사용한다.
첫 번째는 Devin의 Knowledge 시스템과 비슷한 자동 학습 기능에 관한 PRD였다. 두 번째는 데스크탑과 Apple Watch 앱에서 사용할 음성 조작 기능에 관한 것이었다. 세 번째는 Slack과 Discord 연동을 강화하기 위한 비교적 큰 리팩터링이었다. Labor0의 작업 상태가 해당 메신저의 해당 스레드 안에서 자연스럽게 갱신되도록 만드는 작업이다.
이 가운데 메신저 연동 개선은 구현을 시작했고, 나머지 두 개는 아직 PRD만 작성했다.
Labor0는 24시간 돌아가는 소프트웨어 팩토리에 가깝다. 실제로 Labor0 자체 개발을 위한 세션만 평소 약 10개가 계속 실행되며 토큰을 사용한다. 그만큼 비용도 상당하다. 그래서 필요성이 확정된 작업부터 구현을 시작한다.
PRD는 단순한 문서가 아니다. 무엇을 만들지 결정하고, 아직 만들 필요가 없는 작업에는 토큰을 쓰지 않도록 경계를 세우는 역할도 한다.
두 번째 작업: Watchtower
그다음에는 Watchtower를 작업했다.
Watchtower는 Sentry와 호환되는 에러 모니터링 및 관측 시스템으로, 현재 Build in Public 방식으로 개발하고 있다. Watchtower 역시 Labor0와 마찬가지로 스펙 주도 개발 방식을 사용하며 Codex 자동 리뷰를 적극적으로 활용한다.
오늘은 Write PRD 스킬을 사용해 Watchtower 이슈 #13을 작성했다.
PRD를 만드는 과정에서 통신 방식에 관한 결정을 내려야 했다. 나는 강타입을 좋아해서 Connect RPC를 사용하고 싶었다. 그런데 대화 과정에서는 JSON과 HTTP 기반으로 가는 것이 권장됐다.
몇 차례 더 대화하면서 심각한 기술적 제약이 있는지 확인했다. 살펴보니 본질적인 문제라기보다 Protobuf와 관련 도구의 Rust 지원이 주된 이유였다. 그래서 필요한 것이 있다면 우리가 직접 구현하기로 하고, Protobuf와 HTTP를 사용하기로 결정했다. Connect는 스트리밍이 필요해지는 시점에 도입하기로 했다.
완성된 PRD는 Labor0를 통해 PR #31로 바뀌었고, 오늘 바로 검토해서 머지했다.
세 번째 작업: SWC
마지막으로 SWC를 작업했다.
Codex 데스크탑 앱에서 GPT 6 Astra를 사용해 ES minifier의 모든 파일을 검사하도록 요청했다. 실제로 사용한 프롬프트는 다음과 같다.
서브에이전트 적극적으로 활용해. ES minifier의 모든 파일 검사해줘. 할 일은 각 파일의 모든 분기 따져보고 각각에 대해서 혹시나 잘못된 조건이 있는지 검사하고, 혹시나 잘못된 조건이 있으면 예시 입력값 만들어서 $add-issue 해주는거야
Codex는 버그를 발견하면 $add-issue 스킬을 사용해 GitHub 이슈로 남겼다. 그 결과 오늘 하루 동안 46개의 버그를 찾았다.
그다음 Labor0에 한 문장을 입력했다.
오늘 kdy1이 만든 모든 es/minifier 이슈들 고쳐줘
46개 이슈는 45개의 Labor0 작업이 됐다. 스코프상 두 이슈를 함께 처리하는 편이 적절하다고 판단된 작업이 하나 있었기 때문이다.
45개 작업은 완전히 병렬로 실행됐고, 각각 하나의 PR을 만들어 총 45개의 PR이 열렸다. 작업이 진행되는 동안 나는 상황을 계속 지켜보지 않았다. 폰을 보고 게임을 하며 놀고 있어서, 모든 PR이 열리기까지 정확히 얼마나 걸렸는지도 모른다.
버그 탐색에는 GPT 6 Astra를 사용했지만, 45개 구현 작업을 전부 Astra가 처리한 것은 아니다. 간단한 작업이 많았기 때문에 GPT 5.6 Terra가 많이 사용됐고, 어려운 Premium 작업에는 Astra가 배정됐다.
이 글을 쓰는 시점에는 45개 PR 중 21개가 머지됐다. 닫아야 했던 PR은 없었다. 나머지는 Codex 자동 리뷰와 Labor0의 피드백 반영 루프를 기다리거나, 실패한 CI를 수정하는 중이다.
머지에 필수인 CI가 실패하면 Labor0가 수정한다. 머지 충돌이 생겨도 Labor0가 해결하고 다시 가져온다.
Codex의 +1을 기다린다
내가 작업하는 모든 저장소에는 공통된 리뷰 과정이 있다. SWC뿐 아니라 Labor0와 Watchtower에도 같은 방식을 사용한다.
Labor0가 수정 커밋을 올리면 Codex가 다시 자동 리뷰한다. 리뷰 항목이 발견되면 Labor0가 피드백을 반영하고 새 커밋을 올린다. 그러면 Codex가 그 커밋을 다시 리뷰한다.
이 과정은 Codex가 더 이상 리뷰 항목을 찾지 못할 때까지 반복된다. 충분히 리뷰했다고 판단하면 Codex는 PR에 +1 이모지를 남긴다.
저장소 설정에서는 chatgpt-codex-connector 봇이 남긴 리뷰를 자동으로 반영하도록 구성해 두었다. 이 설정 덕분에 리뷰가 나올 때마다 내가 승인하지 않아도 Labor0가 바로 후속 작업을 진행한다. 해당 설정이 없다면 Labor0는 프로젝트 권한이 있는 사람에게 리뷰를 반영할지 물어본다.
나는 +1이 달린 PR만 필터링해 최종 검토 대상으로 본다. 세션을 많이 실행하고 PR을 많이 만들다 보니, 이런 필터가 없으면 검토할 준비가 끝난 PR을 찾는 일 자체가 또 하나의 일이 된다.
SWC에서 머지한 21개 PR도 모두 Codex가 +1을 남긴 뒤 GitHub에서 코드를 직접 검토하고 수동으로 머지했다.
+1은 사람의 승인이 아니다
Codex가 +1을 남겼다고 해서 PR이 항상 올바른 것은 아니다. 정말 이상한 상태의 PR에도 +1이 달릴 때가 있다.
Codex는 내가 처음에 품었던 의도를 전부 알지 못한 채 리뷰를 시작한다. 그래서 코드만 보고 판단한 결과가 PR의 방향을 완전히 바꾸기도 한다.
한번은 내가 cut-over 마이그레이션을 하려던 PR이 있었다. Codex는 롤백하면 앱 데이터가 망가질 수 있다고 판단했고, 그 우려에 따라 PR의 방향을 바꿨다. Codex가 +1을 남겼을 때에는 그 잘못된 리뷰 내용이 Labor0를 통해 이미 PR에 반영된 상태였다.
나는 최종 검토에서 “이 작업은 cut-over이며 롤백하지 않을 것이니 해당 변경을 되돌려라”라는 리뷰를 남겼다. Labor0가 이를 반영했고, PR은 정상적으로 머지됐다.
그래서 +1은 머지해도 된다는 최종 승인이 아니다. 자동 리뷰 루프가 끝났고 사람이 검토할 차례가 됐다는 신호에 가깝다.
최종 리뷰에서는 AI가 테스트를 지나치게 추가하지 않았는지도 확인한다. AI가 스크립트의 텍스트를 하나씩 매칭하는 식으로 과도하고 취약한 테스트를 만들 때가 있기 때문이다. SWC PR에서는 Codspeed를 확인해 성능 문제가 생기지 않았는지도 꼭 본다.
AI는 자잘한 버그를 자동 리뷰 단계에서 많이 잡아준다. 덕분에 내가 받는 인지 부하는 예전에 혼자 모든 것을 검토하던 때보다 훨씬 작다. 그럼에도 원래 의도, 테스트의 적절성, 성능과 최종 머지 결정은 사람이 책임져야 한다.
토큰을 잔뜩 쓴 PR을 최종적으로 닫아야 할 때도 있다. 그래도 전체적인 효율은 지금 방식이 훨씬 높다. 엄청나게 빠르기 때문이다.
6개 세션에서 50개가 넘는 세션으로
예전에는 Claude Code CLI를 사용했다. 당시에는 세션을 6개만 돌려도 매우 피곤했다. 터미널은 원래 병렬 작업을 관리하기 위해 만들어진 UI가 아니어서, 여러 세션 사이를 계속 전환해야 했다.
Codex 데스크탑으로 옮긴 뒤에는 약 15개 세션까지 운영할 수 있었다.
지금은 특정 시점에 Labor0 세션이 50개를 넘어갈 때도 있지만 크게 힘들지 않다. SWC 작업 45개가 병렬로 실행되던 시점에는 Labor0 자체 개발 세션도 약 15개가 돌아가고 있었을 것이다. 두 프로젝트만 합쳐도 동시에 실행되거나 관리 중인 세션이 50개를 넘는다.
그 외에도 typescript-go를 typescript-rust로 포팅하는 프로젝트, Turborepo를 Effect 기반 TypeScript로 포팅하는 프로젝트, 여러 개인 프로젝트를 함께 진행하고 있다.
이 정도의 동시 작업이 가능한 것은 세션 수 자체보다 각 작업의 범위와 결정 사항이 상세하게 정리돼 있기 때문이다. $add-issue와 Write PRD가 큰 역할을 한다.
작업에 맞춰 모델을 배분한다
Labor0에서는 작업마다 하네스와 모델을 직접 지정하거나, AI가 난이도에 맞춰 선택하도록 설정할 수 있다. Cheap, Standard, Premium은 난이도에 따라 작업을 배분하기 위한 개념이다.
나는 Codex 리뷰 반영 작업을 Standard 티어로 실행한다. 여기에는 GPT 5.6 Terra나 GLM 5.3을 사용한다. CI 실패 수정과 머지 충돌 해결은 Cheap 티어로 두고 GPT 5.6 Luna의 high 또는 xhigh를 사용한다.
Premium 티어는 공급자에 따라 다르게 구성한다. Codex 기본 공급자에서는 GPT 5.6 Sol을 사용하고, OpenRouter를 연결한 Codex Custom Provider에서는 GLM 5.3 xhigh를 사용한다. SWC 프로젝트에서는 오늘 Astra를 써보고 싶어서 Premium 작업을 GPT 6 Astra로 설정했다.
Labor0와 Watchtower의 하네스도 Codex다. 다만 Labor0의 Codex Custom Provider 기능으로 OpenRouter에 연결하기 때문에 GLM 모델을 선택할 수 있다. 구현 작업은 GPT 5.6 Terra에서 더 가성비가 좋은 GLM 5.3으로 옮기는 중이다. Codex 데스크탑에서 직접 처리하는 잡다한 작업에는 GPT 5.6 Terra를 사용한다.
Labor0 세션은 AWS ECS Fargate의 격리된 환경에서 실행된다. 내 보안 모델에서는 이 격리 덕분에 오픈 모델 사용이 큰 위협이 되지 않는다고 본다.
모든 작업에 가장 비싼 모델을 사용할 필요는 없다. 작업을 충분히 작게 나누고, 상세한 스펙을 주고, 난이도에 맞는 모델을 배정하고, 자동 리뷰 루프를 거치게 하는 것이 내가 현재 사용하는 방식이다.
이 글은 현재 시점의 기록이다
Labor0가 더 발전하면 내 개발 프로세스는 또 바뀔 것이라고 생각한다. 그래서 지금의 방식을 기록해두고 싶었다.
나는 AI Native에 가까운 개발자로서 얻은 인사이트를 공유하고 싶다. 원래부터 사람을 돕고 지식을 나누는 일을 좋아했다. 어릴 때부터 후배들을 가르치고 코드를 리뷰하는 일을 많이 했다.
많은 사람이 이 글을 보고 AI 시대에 맞게 개발하는 방법을 각자의 환경에서 배울 수 있었으면 좋겠다.
지금 내가 도달한 결론은 명확하다.
사람은 언제나 병목이다. HITL은 필수지만, 루프에서 사람을 호출하는 횟수는 최소화해야 한다. AI가 작업을 주도하고, 사람은 의도와 결정을 책임진다. 그리고 이 방식을 유지 가능하게 만드는 첫 번째 조건은 언제나 같다.
작업을 충분히 작은 단위로 쪼개는 것.