0. 시킨 사람도, 받은 에이전트도 아닌 "누군가"의 문제

요즘 나는 코딩을 직접 안 한다. 대신 시킨다. 코딩 에이전트를 켜고 *"이 기능 만들어 줘"*라고 하면 코드가 나온다. 진짜 문제는 그다음에 시작된다.

에이전트: 네, 완료했습니다. 단위 테스트도 전부 통과했습니다.

나는 그 로그를 눈으로 본 적이 없다. 같은 대화 안에서 코드를 쓰고, 테스트를 돌리고, "통과했습니다"라고 보고한 존재가 "정말 통과했는지"를 내가 믿어야 하는 순간. 그리고 그 코드가 회귀를 일으키면, 다시 그 에이전트한테 물어봐야 한다.

코딩 에이전트에게 일을 시키면, 도대체 누가 그 에이전트를 검증하나요?
이 질문은 에이전트가 하나일 때도 성가시지만, 에이전트가 둘, 셋으로 늘면 운영의 피로로 번진다.
  • 에이전트마다 터미널(pane)을 띄우고, 세션마다 바뀌는 pane·tab·workspace ID를 손으로 들고 다닌다. 이 도구의 규율 문서는 아예 "고정 Pane ID를 쓰지 말고 매번 herdr pane list로 조회하라"고 못 박아 둔다. 그게 지옥인 이유는 — ID가 바뀌니까다.
  • "됐습니다"라는 보고를 판정해 줄 사람이 없다. 수정한 사람과 검증할 사람이 같은 컨텍스트에 있으면, 실패한 테스트를 "고쳐서" 통과시키는 지름길이 항상 열려 있다.
  • 그럼에도 에이전트를 놓을 수는 없다. 일이 많으니까. 그러면 남는 선택지는 "누가 누굴 검증하고, 누가 흐름을 중계하는가"라는 구조를 만드는 것뿐이다.
이 글은 그 구조를 실제로 만들어 쓰는 법을 소개한다. 오픈소스 herdr-team은 터미널 한 줄로 중계(taskmanager)·기획(planner)·구현(worker)·검증(reviewer) 네 역할을 맡는 4인 에이전트 팀을 만들고, 리뷰어가 **실행 로그를 첨부할 때만 승인([APPROVE])**하도록 강제한다. 한 번 보면 "아, 그래서 검증은 에이전트를 믿는 게 아니라 _구조_로 거는 거구나" 하는 순간이 온다.

1. 한 명의 에이전트의 한계: 작성과 검증이 같은 사람인 조직

코드 리뷰가 왜 팀에서만 통하는지 생각해 보자. 작성자와 리뷰어가 분리되어야 리뷰가 의미가 있다. 작성자가 자기가 쓴 코드를 스스로 리뷰하면, 모르는 사이에 자기 가정을 다시 확인할 뿐이다.

코딩 에이전트도 다르지 않다. 한 명의 에이전트에게 "구현하고, 테스트하고, 통과를 확인하고, 최종 보고하라"고 시키는 것은, 작성·검증·판정을 한 컨텍스트에 몰아넣는 것과 같다. 신뢰 문제가 아니라 구조 문제다. 에이전트가 나쁜 게 아니라, 견제가 없는 조직인 것이다.

실무에서 이 한계는 세 가지 모습으로 드러난다.

  1. 보고만 있고 로그가 없다. "테스트 통과했습니다"라는 문장은 커밋 히스토리에 남지 않는다. 나중에 깨졌을 때 "그때 진짜 돌렸나?"를 증명할 방법이 없다.
  2. 자기 검증의 유인이 없다. 같은 대화에서 테스트를 쓰고, 돌리고, 고치고, 다시 돌린다. 실패를 만나면 "테스트가 잘못됐다"고 고치는 게 가장 빠른 길이다.
  3. 회귀가 늦게 발견된다. 단위 테스트를 건너뛰고 "기능만" 납품하는 일이 반복되면, 문제는 통합·E2E·납품 직전에 터진다.
그렇다면 답은 "더 똑똑한 에이전트"가 아니라 역할을 분리한 팀일 수 있다. 그리고 그 팀을 직접 고용할 수 없다면 — 명령어로 만들면 된다.

2. 왜 '팀'인가: 역할 분리와 순차 파이프라인

herdr-team의 팀 모델은 단순하다. 코드를 쓰는 사람, 코드를 검증하는 사람, 흐름을 중계하는 사람을 분리한다. (dev 프리셋 기준)
역할하는 일하지 않는 일
taskmanager파이프라인 중계·드라이브. planner → worker → reviewer를 단계 완료 즉시 연결코드 수정 금지
planner요구사항을 설계 명세와 작업 분할(Task Breakdown)로직접 구현 금지
workerTDD(Red→Green→Refactor)로 구현, 단위 테스트 통과
reviewer정적 리뷰 + 빌드/단위/E2E 직접 실행 후 [APPROVE]/[REQUEST CHANGES] 판정코드 수정 금지

전체 협업은 아래처럼 순차 루프로 돈다. 사람이 개입하는 곳은 "목표를 던지고 결과를 받는" User ↔ PM 구간뿐이다.

핵심은 세 가지다.

첫째, 검증은 실행이다. 리뷰어 역할 문서는 이렇게 시작한다. *"정적 리뷰만으로 APPROVE 금지. 반드시 빌드/단위/E2E를 직접 실행하고 결과를 로그로 첨부"* 그리고 판정 규칙도 못 박혀 있다: *"[APPROVE]는 실행 커맨드·로그가 첨부된 경우에만 유효"* 이건 체험담이 아니라 문서에 강제된 계약이다. README도 같은 계약을 광고 문구로 내건다. 원문은 *"[APPROVE] only counts with execution logs — quality gate built into the workflow"*로, 우리말로는 "실행 로그가 없는 [APPROVE]는 무효 — 품질 게이트가 워크플로에 내장되어 있다"쯤 된다.
둘째, 승인과 반송은 구조로 흐른다. 검증에 실패하면 리뷰어는 재현 절차를 달아 [REQUEST CHANGES]로 되돌리고, worker가 고친 뒤 리뷰어가 다시 실행해 재판정한다. 반송·승인은 팀이 서로 직접 주고받지 않고 taskmanager를 경유한다.
셋째, 중계자가 있어 에이전트가 논다. taskmanager는 "각 에이전트가 작업 완료 후 idle로 방치되지 않도록 완료 즉시 다음 단계를 연결"하라는 무방치 원칙으로 움직인다.

이 구조가 잘 맞는 사람부터, 실제로 어떤 순간에 체감되는지 장면으로 옮겨 보자.


3. 이 환경이 필요한 사람 — 세 장면

민준 — 실무 개발자, 기능을 만들다 (dev 프리셋)

민준은 사내 프로젝트에서 코딩 에이전트로 기능을 만들기 시작했다. 에이전트가 코드는 잘 써주지만, 테스트와 회귀를 건너뛰어 납품 직전에 깨지는 일이 반복된다. 코드 리뷰를 직접 다 볼 수도 없다.

민준에게 필요한 것은 "worker가 코드를 쓰고, reviewer가 직접 실행해서 판정하는" 분리된 파이프라인이다. dev 프리셋은 이 체제 그대로다: taskmanager / planner / worker / reviewer 네 역할, TDD 강조. 민준은 ① PM pane에 앉아 목표만 던지고, worker가 만든 코드가 reviewer의 실행 검증을 통과했을 때만 "완료"로 받아들인다.

하늘 — 주말에 앱을 만드는 사람 (app 프리셋)

하늘은 주말에 아이디어 하나를 앱까지 만들고 싶다. app 프리셋은 dev와 동일한 4역할(taskmanager/planner/worker/reviewer)이지만, 배포·심사에 최적화되어 있다. planner가 릴리스 기획(스토어 심사 대응 포함)을 짜고, worker가 TDD로 구현하며, reviewer가 배포·E2E 실행 검증을 맡는다. 다만 실제 스토어 업로드 같은 운영 작업은 reviewer가 아니라, PM이 필요할 때 기동하는 on-demand ops가 승인 범위 안에서 대행한다. "코드는 worker·검증은 reviewer·운영은 ops"라는 분담이 하늘 같은 1인에게는 곧 "손이 덜 가는 출시 루틴"이다.

수진 — 코드 없이 의사결정을 검증받고 싶은 사람 (biz 프리셋)

수진은 스몰 비즈니스를 운영한다. 코드는 안 쓰지만, 업체·가격·옵션 비교처럼 "출처가 있어야 하는 조사"가 매일의 일이다. biz 프리셋은 여기에 맞춰 코드를 쓰는 상시 멤버가 없다. taskmanager가 흐름을 드라이브하고, planner가 조사 항목을 나누고, researcher가 출처(URL·버전·발췌)를 붙인 비교 보고서를 만들고, reviewer가 그 출처와 재현 절차를 재검증한다. 산출물은 코드가 아니라 조사 보고서다. 즉 수진의 세계에서 "빌드가 통과했다" 같은 코드 문법은 존재하지 않고, "이 주장의 출처가 실제로 그런지 reviewer가 재검증했다"는 로그가 검증 게이트가 된다.
당신은 어느 쪽인가요? 기능 개발이면 dev, 주말 앱 출시면 app, 코드 없는 조사·의사결정이면 biz. 셋 다 공통점은 "직원을 고용하지 않고 검증받을 팀"이 생긴다는 것이다.

4. 30초 시작법 — 그리고 그다음엔 당신이 감독자

시작은 실제로 빠르다. 전제는 하나: Herdr 세션 안의 빈 셸 pane에서 실행한다. (이 도구는 herdr라는 터미널 멀티플렉서 위에서 돌며, 세션 밖 일반 터미널에서 치면 "현재 Pane ID를 확인할 수 없습니다. Herdr 세션 안에서 실행하세요"라고 친절히 알려준다.)

설치: curl 1줄

curl -fsSL https://raw.githubusercontent.com/harry81/herdr-team/main/install.sh | HERDR_TEAM_REPO_URL=https://github.com/harry81/herdr-team.git bash
hts --help
엄밀히 말하면 이 1줄은 "설치"라기보다 부트스트랩이다. 파이프로 들어온 스크립트가 저장소를 클론하고 ~/binhts(및 herdr-team, ht) 심볼릭 링크를 만들고 PATH를 등록한다. 그 뒤부터는 어느 폴더에서든 hts가 동작한다. (Windows는 릴리스 zip을 받아 start-team.bat을 더블클릭하면 된다 — 터미널을 한 번도 열지 않는다.)

실행: hts

cd <프로젝트 폴더>
hts
그러면 질문이 두 개 나온다. (미리 말해 둔다 — "프리셋 하나 고르면 끝"이 아니라 두 번 고른다.)
Select AI team preset (1-3 or name, default: dev):
  1) dev - Software Development (개발 4인 팀, 기본값)
  2) app - Solo App & Idea Discovery (1인 앱/아이템)
  3) biz - Small Business Operations (스몰 비즈니스)

Select agent kind (1-4 or name, default: opencode):
  1) opencode / 2) claude / 3) codex / 4) agy ...
10초 무입력·EOF면 preset은 dev, kind는 opencode로 자동 진행되니 자동화에도 안전하다. 명령줄로 미리 정하고 싶다면 hts myproj --preset app --kind claude처럼 주면 메뉴를 건너뛴다. 폴더 이름을 안 주면 hts는 git 루트(또는 폴더) 이름에서 prefix를 자동으로 뽑는다(my-projectmp).

화면: "4분할"이 아니라 ① PM + 우측 4역할의 L자

hts가 끝나면 README의 장식용 다이어그램(4칸으로 나뉜 그림)을 떠올리기 쉽지만, 실제 화면은 다르다. 분할이 끝나면 각 pane에는 <prefix>-<역할> 형식의 라벨이 붙는다. 예를 들어 폴더가 my-projectmp-taskmanager, mp-planner, mp-worker, mp-reviewer가 된다. 아래 그림의 ②~⑤는 그 역할 pane을 가리킨다.
+---------------------------------+--------------------------------+
|                                 | ② taskmanager (mp-taskmanager)  |
|                                 |--------------------------------|
|     ① PM (당신이 앉는 자리)      | ③ planner    (mp-planner)      |
|                                 |--------------------------------|
|                                 | ④ worker     (mp-worker)       |
|                                 |--------------------------------|
|                                 | ⑤ reviewer   (mp-reviewer)     |
+---------------------------------+--------------------------------+
image.png

같은 배치를 다이어그램으로 그리면 이렇다. 왼쪽의 ① PM이 전체 높이를 차지하고, 오른쪽 컬럼에 네 역할이 위에서 아래로 쌓인다.

① PM pane이 왼쪽에 남고, 오른쪽 컬럼이 위에서 아래로 ② taskmanager → ③ planner → ④ worker → ⑤ reviewer 순서로 나뉘는 5-pane L자 배치다. hts는 현재 pane(당신)을 ① PM으로 이름 붙이고, 우측을 역할별로 분할·균등화한 뒤 각 pane에 에이전트를 시작한다. 자동으로 시작되는 것은 위 네 역할뿐이다 — ① PM에는 아무 에이전트도 자동 기동되지 않는다. 당신이 그 자리에 앉는다.
한 가지 정직한 구분이 필요하다. hts 한 줄은 "팀을 생성"까지다. 이 순간 작업이 시작되지는 않는다. 그다음엔 ① PM(당신)이 taskmanager에게 목표를 던지면, taskmanager가 planner → worker → reviewer를 끊김 없이 이어 간다. 즉 당신은 "코드 작성자"가 아니라 감독자가 된다. 무엇을 할지 미리 보고 싶다면 hts mp --dry-run처럼 붙이면 아무것도 변경하지 않고 "이렇게 분할하고 이렇게 시작하겠다"는 계획만 출력한다.

5. Aha moment — 실행 로그가 붙은 [APPROVE]

팀을 만들고 첫 기능을 시키면, 그 결정적 순간이 온다. dev 프리셋에서 작업이 끝나면 리뷰어 pane에 이런 보고서가 도착한다. (아래는 리뷰어 역할 문서가 강제하는 형식을 따른 예시다 — 실제 커맨드·로그는 그 프로젝트의 것.)

### [코드 리뷰 보고서]

#### 1. 최종 판정: [APPROVE]

#### 2. 실행 검증 결과 (Executable Verification) — 필수
- 실행한 테스트 커맨드:
  - `npm run build`          → PASS (12.3s, node v20)
  - `npm test -- --runInBand` → PASS (41 tests)
  - `npm run test:e2e`        → PASS (5 scenarios, playwright)
- 빌드/린트 상태: PASS
- 결과 로그 발췌:
  Test Suites: 4 passed, 4 total
  Tests:       41 passed, 41 total
worker가 "다 됐습니다"라고 한 것을 내가 믿는 게 아니라, 코드를 수정할 권한이 없는 리뷰어라는 별개 에이전트가 실제로 커맨드를 돌린 로그가 보고서에 실려 온다. 리뷰어는 코드를 고칠 수 없으므로, 그 로그를 "통과하도록 고쳐서" 만들 수 없다. 실행 로그 없는 [APPROVE]는 형식상 무효이기 때문이다.
여기서 한 가지 명확히: 이 "빌드/단위/E2E 실행 로그가 APPROVE의 조건"은 dev·app 프리셋 기준이다. 코드 대신 조사를 다루는 biz 프리셋에서는 검증 게이트가 "researcher가 단 출처·재현 절차를 reviewer가 재검증한 로그"로 바뀐다. 게이트의 _형태_가 프리셋마다 다를 뿐, "검증은 실행(또는 재현)으로 증명한다"는 원칙은 같다.

그리고 곧 두 번째 순간이 온다. 내가 던진 요구의 경계 조건을 worker가 놓쳤다면, 리뷰어는 이렇게 되돌린다.

### [코드 리뷰 보고서]
#### 1. 최종 판정: [REQUEST CHANGES]
#### 4. 개선 필요 사항 (High)
- src/calc.ts:41 — 소수점 누락 케이스
- 실패 재현: `node -e "..."` → 기대 0.3, 실제 0.30000000000000004
이 보고서는 taskmanager를 통해 worker로 즉시 반송되고, worker가 고친 뒤 리뷰어가 다시 실행해 APPROVE를 낸다. 처음 이 왕복을 목격하면 "실패 = 시스템이 고장"이 아니라 "실패 = 시스템이 정상 작동"으로 인식이 바뀐다. 내가 놓친 버그를 팀이 스스로 감지해 되돌려 보낸 것이다. 단일 에이전트에서는 잘 일어나지 않는 장면이다.

6. 동작 원리 — 별거 없다, 그리고 한계도 명확하다

원리는 네 단계로 요약된다.

  1. prefix 결정$1이 없으면 git 루트(없으면 폴더) 이름에서 2~4자 축약(my-projectmp).
  2. 템플릿 생성AGENTS.md와 역할 문서(agents/<prefix>-<역할>.md)를 {{PREFIX}} 치환으로 복사. 이미 있으면 생략(멱등).
  3. pane 분할 — 현재 pane을 ① PM으로 두고 우측을 역할 수만큼 세로 분할·균등화.
  4. 레이블 + 에이전트 시작 — ②~⑤로 이름 붙이고 각 pane에 herdr agent start <prefix>-<역할> (이미 떠 있으면 생략).
설치하면 ~/bin/hts 링크가 생기고, 실행은 항상 Herdr 세션 안에서 이뤄진다.
그리고 이 도구는 마케팅 카피보다 한계가 더 정직하다. 발행 전에 알아야 할 것만 짚는다.
  • Herdr 세션 안에서만 돈다. 일반 터미널에서 hts를 치면 pane ID를 찾지 못해 에러가 난다. Herdr이라는 전제가 있는 사용자(또는 Herdr을 써 볼 의향이 있는 사용자)를 위한 도구다.
  • jq가 필요하다. pane 분할 응답의 JSON에서 pane ID를 파싱하는 데 쓴다.
  • 기본은 순차 실행이다. 네 명(역할)이 같은 폴더에 동시에 쓰면 파일 충돌과 테스트 간섭이 생기기 때문이다. "병렬로 빨리"보다 "한 번에 한 명이 쓰고, 끝나면 다음"을 기본으로 삼는다. 이건 한계라기보다 의도된 설계지만, 처음 쓰는 사람이 "왜 동시에 안 돌아가지?"라고 느낄 수 있는 지점이라 짚어 둔다.

7. 끝맺음 — 터미널에 팀을, 당신에게는 감독의 자리를

다시 처음 질문으로 돌아가자. *"코딩 에이전트에게 일을 시키면, 도대체 누가 그 에이전트를 검증하나요?"*

herdr-team의 대답은 "에이전트를 하나 더 고용해서"가 아니라, 역할을 분리하고 실행을 게이트로 삼는 구조다. 코드를 쓰는 worker와 검증하는 reviewer를 갈라 놓고, 리뷰어는 로그를 붙일 때만 APPROVE한다. 그리고 taskmanager가 그 흐름을 놓치지 않게 중계한다. 검증을 "에이전트의 성실함"에 맡기지 않고 문서화된 계약과 실행 결과에 맡기는 것이다.

시도하는 법은 이 글 전체보다 짧다.

# 1) 설치 (부트스트랩)
curl -fsSL https://raw.githubusercontent.com/harry81/herdr-team/main/install.sh | HERDR_TEAM_REPO_URL=https://github.com/harry81/herdr-team.git bash

# 2) Herdr 세션 안에서, 프로젝트 폴더에서
hts            # 팀 생성 (preset·kind 선택 또는 기본값)

# 3) ① PM에서 목표 하나를 던진다
#    "로그인 기능을 planner → worker → reviewer로 한 사이클 돌려줘"

설치 전에 더 알고 싶다면 프로젝트의 한국어 가이드(README.ko.md)와 팀 문서(AGENTS.md)가 정본이다. 마음에 들었다면 GitHub 저장소에 스타 하나, 아니면 이 글이 사실과 다른 부분을 발견했을 때 이슈 하나 — 둘 다 이 오픈소스 팀에게는 검증 로그가 된다.