하네스 엔지니어링: 에이전트 퍼스트 세계에서 Codex 활용하기
저자: Ryan Lopopolo, OpenAI 기술 스태프
원문: "Harness engineering: leveraging Codex in an agent-first world"
한줄 요약
OpenAI 내부 팀이 사람이 직접 작성한 코드 0줄로, Codex 에이전트만을 사용해 약 5개월 만에 100만 줄 규모의 소프트웨어 제품을 구축·출시한 실험에서 얻은 교훈을 정리한 글이다.
1. 실험 개요
- 2025년 8월 말, 빈 Git 저장소에서 첫 커밋을 시작했다.
- 초기 스캐폴딩(리포 구조, CI 설정, 포맷 규칙, 패키지 매니저, 앱 프레임워크)부터 에이전트에게 지시하는
AGENTS.md파일까지 전부 Codex가 작성했다. - 5개월 후 결과:
- 약 100만 줄의 코드 (앱 로직, 인프라, 툴링, 문서, 내부 유틸 포함)
- 약 1,500개 PR 머지 (초기 엔지니어 3명 → 현재 7명)
- 엔지니어 1인당 하루 평균 3.5개 PR (팀이 커져도 처리량 증가)
- 내부 수백 명의 사용자가 실제 사용 중
- 수작업 대비 약 1/10 시간으로 구축한 것으로 추정한다.
핵심 철학: 사람은 방향을 잡고(steer), 에이전트가 실행한다(execute).
2. 엔지니어 역할의 재정의
기존에 코드를 직접 작성하던 엔지니어의 역할이 다음과 같이 바뀌었다.
| 기존 역할 | 새로운 역할 |
|---|---|
| 코드 작성 | 환경 설계 및 의도 명세 |
| 디버깅 | 에이전트가 작업할 수 있는 피드백 루프 구축 |
| 코드 리뷰 | 에이전트 간 리뷰 체계 관리 |
작업 방식
- 엔지니어가 프롬프트로 작업을 기술하면 Codex가 실행하여 PR을 연다.
- PR 완성까지: Codex가 자체 리뷰 → 다른 에이전트 리뷰 요청 → 피드백 반영 → 모든 리뷰어 승인까지 반복 (일명 "Ralph Wiggum Loop").
- 시간이 지나면서 리뷰도 거의 전부 에이전트 대 에이전트로 처리하게 되었다.
초기의 교훈
처음에 진행이 느렸던 이유는 Codex의 능력 부족이 아니라, 환경이 불충분했기 때문이었다. 무언가 실패하면 "더 노력하라"가 아니라 "에이전트에게 어떤 역량이 부족한가?"를 묻고, 그것을 읽을 수 있고 강제 가능한 형태로 만드는 것이 핵심이었다.
3. 애플리케이션 가독성 향상
코드 처리량이 늘면서 사람의 QA 능력이 병목이 되었다. 이를 해결하기 위해 에이전트가 직접 앱을 검증할 수 있도록 만들었다.
UI 검증
- Git worktree별로 앱을 부팅할 수 있게 해서, Codex가 변경사항마다 독립 인스턴스를 실행.
- Chrome DevTools Protocol을 에이전트 런타임에 연결 → DOM 스냅샷, 스크린샷, 내비게이션 스킬 제공.
- 버그 재현 → 수정 → UI 동작 검증까지 Codex가 직접 수행.
관측성(Observability)
- worktree별로 임시 관측성 스택 (로그, 메트릭, 트레이스) 제공.
- Codex가 LogQL, PromQL, TraceQL로 직접 쿼리.
- "서비스 시작이 800ms 내에 완료되도록 하라", "이 4개 핵심 사용자 여정에서 2초를 초과하는 스팬이 없도록 하라" 같은 프롬프트가 실행 가능해짐.
- 단일 Codex 실행이 6시간 이상 작업하는 경우도 빈번 (종종 사람이 자는 동안).
4. 저장소 지식을 단일 정보 원천으로
"거대한 AGENTS.md" 접근법의 실패
처음에 하나의 큰 AGENTS.md에 모든 지침을 넣어봤지만 예상대로 실패했다.
- 컨텍스트는 희소한 자원이다. 거대한 지침 파일이 실제 작업과 코드를 밀어낸다.
- 모든 것이 "중요"하면 아무것도 중요하지 않다. 에이전트가 의도적으로 탐색하지 않고 로컬 패턴 매칭에 빠진다.
- 즉시 부패한다. 유지보수가 안 되면서 낡은 규칙의 무덤이 된다.
- 검증하기 어렵다. 단일 덩어리는 기계적 검사(커버리지, 신선도, 소유권)에 적합하지 않다.
해결책: AGENTS.md를 "목차"로 사용
AGENTS.md는 약 100줄 정도의 짧은 "지도" 역할만 하고, 실제 지식은 구조화된 docs/ 디렉터리에 저장한다.
AGENTS.md ← 목차 (약 100줄)
ARCHITECTURE.md ← 아키텍처 최상위 지도
docs/
├── design-docs/ ← 설계 문서 (인덱스 + 핵심 원칙)
├── exec-plans/ ← 실행 계획 (활성/완료/기술 부채)
├── generated/ ← 자동 생성 문서 (예: DB 스키마)
├── product-specs/ ← 제품 사양
├── references/ ← 외부 참조 (디자인 시스템, 패키지 등)
├── DESIGN.md
├── FRONTEND.md
├── QUALITY_SCORE.md
├── RELIABILITY.md
└── SECURITY.md
핵심 원칙
- 점진적 공개(Progressive Disclosure): 에이전트는 작고 안정된 진입점에서 시작해 필요할 때 더 깊이 탐색.
- 기계적 강제: 린터와 CI 작업이 지식 베이스의 최신성, 교차 링크, 구조를 검증.
- 문서 정원사 에이전트: 정기적으로 낡거나 실제 코드와 맞지 않는 문서를 스캔하여 수정 PR을 자동 생성.
5. 에이전트 가독성이 목표
"에이전트가 볼 수 없으면 존재하지 않는다"
에이전트의 관점에서, 실행 중 컨텍스트에서 접근할 수 없는 것은 사실상 존재하지 않는다. Google Docs, Slack 대화, 사람의 머릿속 지식은 시스템에 보이지 않는다.
따라서 Slack에서 합의된 아키텍처 패턴도 저장소에 마크다운으로 인코딩하지 않으면, 3개월 후 합류한 신입 엔지니어에게도 보이지 않는 것과 마찬가지다.
기술 선택 기준
- "지루한" 기술을 선호: 구성 가능성, API 안정성, 학습 데이터 내 충분한 표현으로 에이전트가 모델링하기 쉬움.
- 경우에 따라 외부 라이브러리를 가져오는 대신 에이전트가 기능의 일부를 직접 재구현하는 것이 더 저렴할 때도 있다. (예:
p-limit대신 자체 동시성 헬퍼를 만들어 OpenTelemetry와 완전 통합, 100% 테스트 커버리지)
6. 아키텍처와 "맛(taste)" 강제
엄격한 아키텍처 모델
각 비즈니스 도메인을 고정된 레이어 세트로 나누고, 의존성 방향을 엄격하게 검증했다.
Types → Config → Repo → Service → Runtime → UI
교차 관심사(auth, connectors, telemetry, feature flags)는 Providers라는 단일 명시적 인터페이스를 통해서만 진입. 나머지는 금지하고 기계적으로 강제한다.
이런 수준의 아키텍처는 보통 수백 명의 엔지니어가 있을 때 도입하지만, 코딩 에이전트 환경에서는 초기 전제조건이다. 제약이 곧 부패 없는 속도를 가능하게 한다.
"맛 불변량(Taste Invariants)"
- 구조화된 로깅 강제
- 스키마·타입 네이밍 컨벤션
- 파일 크기 제한
- 플랫폼별 안정성 요구사항
커스텀 린터의 에러 메시지에는 에이전트가 읽을 수 있는 수정 지침을 포함시킨다.
경계 안에서의 자율성
- 경계, 정확성, 재현성은 중앙에서 강제
- 경계 내부에서는 에이전트(또는 팀)에게 상당한 표현의 자유 허용
- 에이전트가 생성한 코드가 사람의 스타일 선호와 다를 수 있지만, 정확하고 유지보수 가능하며 미래 에이전트 실행에 읽기 쉬우면 충분하다.
7. 처리량이 머지 철학을 바꾼다
- 최소한의 블로킹 머지 게이트 운영
- PR은 수명이 짧음
- 테스트 플레이크는 무한 블로킹 대신 후속 실행으로 해결
- 에이전트 처리량이 사람 주의력을 훨씬 초과하는 시스템에서는 수정이 저렴하고 대기가 비싸다
저처리량 환경에서는 무책임하겠지만, 여기서는 올바른 트레이드오프인 경우가 많다.
8. "에이전트 생성"의 실제 의미
에이전트가 생성하는 것은 코드만이 아니다.
- 제품 코드 및 테스트
- CI 설정 및 릴리스 툴링
- 내부 개발자 도구
- 문서 및 설계 이력
- 평가 하네스
- 리뷰 코멘트 및 응답
- 저장소 관리 스크립트
- 프로덕션 대시보드 정의 파일
사람은 항상 루프에 있지만, 이전과는 다른 추상화 수준에서 작업한다: 우선순위 설정, 사용자 피드백을 수용 기준으로 변환, 결과 검증.
9. 자율성의 수준 증가
최근 저장소가 의미 있는 임계점을 넘어, 단일 프롬프트로 Codex가 기능을 end-to-end로 구현할 수 있게 되었다.
단일 프롬프트로 가능한 흐름:
- 코드베이스 현재 상태 검증
- 보고된 버그 재현
- 실패를 보여주는 영상 녹화
- 수정 구현
- 앱을 구동해 수정 검증
- 해결을 보여주는 두 번째 영상 녹화
- PR 오픈
- 에이전트·사람 피드백 대응
- 빌드 실패 감지 및 해결
- 판단이 필요한 경우에만 사람에게 에스컬레이션
- 변경사항 머지
이 동작은 이 저장소의 특수한 구조와 툴링에 크게 의존하며, 비슷한 투자 없이는 일반화를 가정해서는 안 된다.
10. 엔트로피와 가비지 컬렉션
문제
Codex는 저장소에 이미 존재하는 패턴을 복제한다 — 불완전하거나 차선인 것까지도. 시간이 지나면 자연스럽게 드리프트(drift)가 발생한다.
초기 대응 (실패)
매주 금요일(주의 20%)을 "AI 슬롭" 정리에 사용했지만, 확장 불가능했다.
해결: 골든 원칙 + 자동화된 정리 프로세스
저장소에 "골든 원칙"을 직접 인코딩하고, 정기적인 정리 프로세스를 구축했다.
예시:
- 수작업 헬퍼 대신 공유 유틸 패키지 선호 → 불변량을 중앙화
- YOLO 방식의 데이터 탐색 금지 → 경계에서 검증하거나 타입이 있는 SDK에 의존
정기 cadence로 백그라운드 Codex 작업이:
- 일탈을 스캔
- 품질 등급을 업데이트
- 타깃 리팩토링 PR을 생성
대부분 1분 이내에 리뷰 가능하며 자동 머지된다.
기술 부채는 고금리 대출과 같다. 쌓아두고 한꺼번에 갚기보다, 매일 소액으로 갚는 것이 거의 항상 낫다.
11. 아직 배우고 있는 것들
확인된 것
- 소프트웨어 구축에는 여전히 규율이 필요하지만, 그 규율은 코드가 아니라 스캐폴딩(환경, 추상화, 피드백 루프)에서 나타난다.
- 코드베이스를 일관되게 유지하는 툴링과 제어 시스템이 점점 더 중요하다.
아직 모르는 것
- 완전 에이전트 생성 시스템에서 수년에 걸친 아키텍처 일관성이 어떻게 진화하는가.
- 사람의 판단이 어디에서 가장 큰 레버리지를 발휘하는가.
- 모델 성능이 계속 향상됨에 따라 이 시스템이 어떻게 진화할 것인가.
핵심 교훈 요약
| # | 교훈 |
|---|---|
| 1 | 에이전트에게 1,000페이지 매뉴얼이 아닌 지도를 줘라 |
| 2 | 에이전트가 볼 수 없으면 존재하지 않는다 — 모든 중요 지식을 저장소에 넣어라 |
| 3 | 문서가 한계에 도달하면, 규칙을 코드(린터, 테스트)로 승격시켜라 |
| 4 | "지루한" 기술이 에이전트에게는 최고의 기술이다 |
| 5 | 아키텍처 제약을 일찍 도입해야 부패 없는 속도가 가능하다 |
| 6 | 경계는 중앙에서 강제, 경계 내부는 자율 |
| 7 | 에이전트 시대에 수정은 저렴하고 대기는 비싸다 — 머지 철학을 바꿔라 |
| 8 | 기술 부채를 매일 조금씩 갚는 가비지 컬렉션 프로세스를 만들어라 |
| 9 | 에이전트에게 앱 UI, 로그, 메트릭을 직접 볼 수 있게 만들어라 |
| 10 | 사람의 역할은 코드 작성이 아니라 환경 설계와 의도 명세다 |