AI 에이전트 TDD 루프, 실패 테스트부터 고치게 하려면
AI 에이전트 TDD 루프는 “코드부터 고치고 테스트는 나중에”가 아니라 실패하는 테스트(red) → 최소 수정으로 통과(green) → 정리(refactor) 순서를 프롬프트·Skill·Rule에 고정하는 방식입니다. 가격·플랜·사용 후기는 다루지 않습니다.
이 글은 특정 IDE 전용 버튼 설명이 아닙니다. 실패 로그를 어떻게 넘기고, 한 사이클을 언제 끝낼지, 무한 수정 루프를 어떻게 끊는지만 정리합니다.
실패 로그를 어떻게 넘기나?
한 줄 답: 에이전트에게 “전체 스위트 돌려 보고 알아서 고치라”보다 이미 실패한 명령의 stdout/stderr·실패 테스트 이름·관련 파일을 한 덩어리로 넘기고, 그 실패만 고치게 합니다.
넘길 최소 묶음:
| 항목 | 왜 필요한가 |
|---|---|
| 재현 명령 | npm test -- path/to/spec, pytest -k name, cargo test foo처럼 그대로 다시 실행할 수 있어야 함 |
| 실패 출력 | assertion·스택·exit code. “실패했다” 한 줄만 주면 추측이 늘어남 |
| 범위 | 고칠 파일·테스트 경로. 레포 전체를 열어 두지 않음 |
| 비목표 | “다른 flaky는 건드리지 말 것”, “새 의존성 추가 금지” 같은 하지 말 것 |
실무 전달 패턴:
- 로컬에서 실패를 먼저 재현한 뒤, 터미널 출력을 그대로 붙이거나 로그 파일을
@로 첨부합니다. - 프롬프트 첫머리에 목표 테스트 이름과 성공 시 재실행 명령을 적습니다.
- “관련 없어 보이는 테스트 실패는 보고만 하고 고치지 말 것”을 명시합니다.
- 가능하면 Skill/
SKILL.md에 “항상 실패 로그 → 최소 패치 → 같은 명령 재실행” 순서를 절차로 둡니다. 짧은 규범(“테스트 없이 done 금지”)은 Rule에 둡니다.
최소 프롬프트 뼈대:
Failing command (re-run exactly):
<paste command>
Output:
<paste failing stdout/stderr>
Scope: only make <test-name> pass.
Do not change unrelated tests or add dependencies.
Done when: the same command exits 0.
로그가 길면 첫 assertion·마지막 스택 프레임·파일:라인만 남기고 중간 노이즈를 잘라도 됩니다. 다만 재현 명령과 exit 조건은 지우지 않습니다.
한 사이클 성공 조건은?
한 줄 답: 한 사이클은 지정한 실패 테스트(들)가 같은 명령으로 통과하고, 합의된 범위 밖 변경이 없으며, 필요 시에만 작은 refactor까지 갔을 때 끝입니다. “뭔가 고쳤다”는 성공이 아닙니다.
사이클 정의(에이전트용):
| 단계 | 에이전트가 해야 할 일 | 완료 신호 |
|---|---|---|
| red | 실패 로그·명령을 확인하고, 실패가 재현됨을 전제로 원인 가설 1~2개만 세움 | “이 테스트가 왜 깨지는지”를 한 문장으로 적음 |
| green | 최소 패치로 해당 테스트만 통과 | 같은 재현 명령 exit 0 |
| refactor | 동작 유지한 채 중복·이름만 정리(선택) | 같은 명령 재통과 + 범위 밖 파일 미터치 |
성공 조건 체크리스트:
- 재현 명령이 greened — 사용자가 준 그 명령(또는 Skill에 고정한 동일 명령)이 성공.
- 스코프 준수 — diff가 합의 경로·테스트 주변으로 한정.
- 설명 가능 — “무엇을 바꿨고, 왜 그 실패가 사라졌는지”를 짧게 남김.
- 다음 사이클 분리 — 새 실패·새 기능은 새 red로 넘김. 한 턴에 몰아넣지 않음.
Skill에 넣을 완료 정의 예:
## Done when
- Re-run the exact failing command; exit code 0.
- Diff touches only files needed for that failure.
- Report: root cause (1–2 sentences) + files changed.
- If still failing after N attempts, stop and ask (see stop rules).
green 전에 refactor하지 않기, 테스트 출력을 바꾸거나 skip으로 “통과” 만들지 않기를 Rule/Skill에 같이 적어두면 한 사이클 의미가 흐려지지 않습니다.
무한 루프를 어떻게 끊나?
한 줄 답: 시도 횟수·동일 에러 반복·스코프 이탈에 하드 스톱을 걸고, stop 훅·loop_limit·프롬프트의 “N회 후 사람 호출”로 자동 이어가기를 막습니다.
끊는 신호(하나라도 해당하면 중단):
| 신호 | 조치 |
|---|---|
| 같은 실패 출력·같은 파일 수정이 N회(예: 3) 반복 | 중단 후 로그·가설을 사람에게 넘김 |
| 패치 후 새 실패가 연쇄로 늘고 원래 실패는 남음 | 롤백·스코프 축소, 새 사이클 금지 |
| 테스트 skip·assertion 삭제·타임아웃만 늘리기 | 금지 목록으로 즉시 중단 |
| 재현 명령이 바뀜(다른 스위트·다른 플래그) | “성공”으로 치지 않고 재확인 요청 |
프롬프트/Skill 스톱 규칙 예:
Stop rules:
- Max 3 patch→re-test attempts for this failure.
- If the error signature is unchanged after 2 attempts, stop and summarize.
- Never mark done by skipping tests or deleting assertions.
- Do not start a new feature while this red is open.
도구 쪽 보조:
- Cursor hooks의
stop/subagentStop에loop_limit을 두면 자동 follow-up이 무한히 이어지는 것을 제한할 수 있습니다(공식 Hooks 문서). - CI·로컬 스크립트에서 단일 실패 명령만 에이전트 입력으로 넘기고, full suite는 사람·파이프라인이 돌리게 역할을 나눕니다.
무한 루프의 흔한 원인은 “실패 로그 없이 추측 수정”과 “성공 조건이 ‘뭔가 고침’으로 흐림”입니다. 앞 두 절의 로그 묶음과 done when을 먼저 고정한 뒤 스톱 횟수를 걸면 됩니다.
마무리
AI 에이전트 TDD 루프의 핵심은 red→green→refactor를 말이 아니라 입력(실패 로그)·완료 조건·중단 규칙으로 고정하는 것입니다. 실패 명령을 그대로 넘기고, 같은 명령 exit 0을 한 사이클 성공으로 두며, N회·동일 시그니처·skip 금지로 무한 수정을 끊으면 됩니다. 절차는 Skill, 짧은 금지 규범은 Rule에 두는 편이 유지보수에 유리합니다.
출처
- Cursor Agent Skills — 다단계 절차를
SKILL.md로 고정 - Cursor Rules — 짧은 규범·금지 조항
- Cursor Hooks —
stop/loop_limit으로 자동 루프 제한