지난 글 ‘하네스 엔지니어링으로 AI 에이전트를 길들여봤습니다’에서 “프롬프트 엔지니어링은 끝났다”고 적으면서, 프롬프트만으로는 부족하고 시스템 레벨에서 hooks·권한·품질 게이트로 감싸야 한다고 정리했다. 그게 하네스 엔지니어링이다. 그 글을 쓴 지 몇 달이 지난 지금, 가장 크게 달라진 건 코드도 도구도 아니라 내 하루의 루틴이다.
요즘 내가 출근해서 가장 먼저 하는 일은 코드 에디터를 켜는 게 아니다. 봇을 켠다.미리 말해두면 이 글은 봇 자랑이 아니다. 봇 하나 붙인다고 하루가 바뀌지는 않는다. 실제로 하루가 바뀐 건 그 뒤에 누가 작업을 시작하든 같은 품질이 나오게 만든 하네스가 있었기 때문이다. 제목은 눈길을 끌려고 골랐고, 이 글은 사실 그 하네스로 인해 바뀐 내 일상 이야기다.

AI가 있기 전 내 오전 일과는 대략 이런 식이었다.
질문 하나에 길게는 반나절이 갔다. 게다가 그 반나절은 내 “진짜 일”이 아니라 남이 막힌 곳을 뚫어주는 일이었고, 컨텍스트 스위칭 비용은 덤이었다.
지금은 이렇게 바뀌었다.
여기까지만 보면 그냥 “편해졌네”다.

위임은 “맡기는 것”이 아니라 “맡겨도 같은 결과가 나온다는 보장”이 있을 때만 성립한다. 그 보장이 없으면 봇은 그냥 또 하나의 불안한 도구일 뿐이고, 결국 내가 일일이 다시 봐야 한다. 그 보장을 만든 게 하네스 엔지니어링이다.
다만 그 보장에는 범위가 있다. 뒤에 나올 장치들이 받치는 건 이 품질의 기술적 바닥까지다. 린트와 타입 검사, 위험 명령 차단은 “코드가 문법적으로 멀쩡하고 위험한 짓을 안 한다”까지는 보장한다. 하지만 “이 기능이 내가 의도한 대로 동작한다”까지는 보장하지 못한다. 그건 시스템의 몫이 아니라 정책 문서와 사람 리뷰의 몫이다. 의도적인 병목을 둔 것이다.
“코드를 안 쳐도 된다”는 말은 “아무렇게나 만들어도 된다”가 아니다. 오히려 반대다. 사람이 한 줄 한 줄 챙기지 않아도 품질의 바닥이 시스템으로 보장돼야, 비로소 손을 뗄 수 있다.
그 바닥이 실제로 차이를 만드는지는 한 번 대조해 봤다. 같은 요구사항(캠페인 등록 폼)을 아무 설정도 없는 프로젝트와 하네스를 깐 프로젝트에 각각 던졌다. 정산 기준이나 최소 금액 같은 정책은 프롬프트에 한 줄도 적지 않았다. 코드베이스의 다른 화면에 이미 구현돼 있었을 뿐이다.

모델이 똑똑해져서가 아니라, 코드베이스를 먼저 읽게 만들었느냐의 차이였다. 사람이 매번 “우리 정산은 28일이야”라고 일러주지 않아도 같은 답이 나온다면, 그 역할은 넘겨도 된다고 생각했다. 그 차이를 만든 장치에는 무엇이 있을까.
에이전트가 “다 했습니다”라고 응답하려는 바로 그 순간(Stop 이벤트)에 끼어드는 훅이 있다. 이번 작업에서 수정된 파일들을 모아, 자동 수정 가능한 건 ESLint --fix로 먼저 정리하고, 남은 린트 에러와 tsc --noEmit 결과를 에이전트에 돌려준다. 통과해야 응답이 나가고, 실패하면 통과할 때까지 이 검문을 다시 거친다.
사람이 “린트 돌렸어?”라고 물어볼 필요가 없다. 프롬프트로 “꼭 검사해”라고 부탁하는 것과, 통과 못 하면 응답 자체가 안 나가게 막는 것은 신뢰도가 완전히 다르다. 사람도 “다 됐다” 직전에 한 번 더 안 보면 같은 실수를 반복한다.
위험한 행동은 두 층위로 거른다. 프롬프트로 막는 게 아니라 훅이 거른다.
rm -rf, DROP TABLE, .env 파일 생성은 실행 자체를 차단한다.git push --force, --no-verify 같은 우회는 실행은 되지만 사람 확인을 거친다.
대장간으로 치면 용광로 둘레에 친 울타리(차단)와 “여기 뜨거움” 표지판(경고)의 차이다. 비개발자가 무심코 위험한 동선에 들어가도, 그 길이 시스템 레벨에서 끊긴다.

사고 모델을 에이전트 정의 안으로. 이게 의외로 컸다. 예전엔 “기존 코드를 먼저 확인하고, 검증하고, 안 되면 접근을 바꾼다”는 사고 모델이 프로젝트 루트 문서에만 있었다. 그런데 작업을 쪼개 서브에이전트를 부르면, 그 서브에이전트는 부모 문서를 상속받지 않아 제멋대로 움직이는 구멍이 있었다.
그래서 코드를 직접 만지는 에이전트의 정의 파일 안에 사고 모델을 직접 박았다. 누가, 어디서 스폰됐든 같은 사고 위에서 움직이게 만든 거다. 메인이든 서브든 기준이 같아야, 비개발자가 시작한 작업도 결국 같은 품질을 받는다.
봇은 별개 시스템이 아니다. Anvil은 내가 따로 만든 똑똑한 봇이 아니다. 내부적으로는 그냥 내가 평소에 쓰는 것과 똑같은 하네스를 헤드리스로 호출한다.
[QA가 Slack DM “이거 고쳐줘”]
→ Anvil (Node.js)
→ claude -p (헤드리스 모드)
→ 평소 쓰는 플러그인 그대로 활성화
(위험 명령 차단 · 사고 모델 · 품질 게이트)
→ MR 생성 → 담당자에게 DM
QA가 Slack에서 시작한 작업도, 내가 터미널에서 시작한 작업과 완전히 같은 훅, 같은 품질 게이트, 같은 사고 모델을 통과한다. 바깥 인터페이스(Slack DM)만 다를 뿐, 안쪽 기준은 다르지 않다. “인터페이스는 달라도 기준은 같다”가 위임의 전제였다.
그리고 그 통과 기록은 MR description에 자동으로 남는다. 어떤 에이전트가 몇 초 분석했는지, 코드 리뷰에서 무엇을 봤는지, lint와 build 결과가 무엇인지, 그리고 테스트를 안 돌렸다면 그 사유까지 적힌다.
테스트 전략
- 정책 키워드 감지: 없음 / 코어 모듈 변경: 없음
- 판정: 테스트 스킵 (사유: 매핑 로직만 변경)
내가 그 MR을 믿는 건 봇이 똑똑해서가 아니라, 안 한 것까지 이유가 남아 있어서다. 리뷰라기보다 감사 추적에 가깝다.

모든 변경을 똑같이 빠르게 통과시키면 그건 안전한 게 아니라 그냥 검증이 없는 거다. 그래서 영향 범위를 세 등급으로 나눴다.

원칙은 하나다. MAJOR에 일부러 병목을 두기 때문에, MINOR/MODERATE를 더 넓게 열 수 있다. 어느 등급인지는 프로젝트별 기준 파일(SSOT)이 코어 경로·정책 키워드를 보고 자동으로 판정한다. 덕분에 “사람이 꼭 봐야 하는 지점”이 좁아지고 명확해졌고, 나는 그 좁아진 지점에만 시간을 쓴다.

그래서 내 일이 사라졌느냐 하면, 아니다. 옮겨갔다. 아래는 정확한 측정이라기보다 내 체감에 가깝다.

키보드는 여전히 친다. 다만 코드가 아니라 정책 문서와 시나리오를 친다. 예전엔 “로그인 개선” 같은 요구사항을 받으면 곧장 컴포넌트 설계로 들어갔다면, 지금은 먼저 [사용자 흐름 / 입력 검증 규칙 / 에러 메시지 / 실패 케이스]를 마크다운으로 적는다. 그 문서가 곧 봇에게 주는 사양이 되니까.
무엇을 만들지를 모호함 없이 적는 일과 올라온 결과를 보는 일, 솔직히 이 둘은 사람이 직접 했을 때 결과가 더 좋아지는 종류의 일이다. 내 시간이 거기로 옮겨간 건, 손해가 아니라 이득에 가까웠다.
솔직히 말하면, 이게 마법은 아니다.
운영하면서 자잘하게 깨진 것도 많았다. 예컨대 모노레포가 여러 개인 환경에서 봇이 어느 레포를 고칠지 자동으로 못 정하면, 처음엔 에러만 띄우고 끝났다. 비개발자 입장에선 “그래서 뭘 어쩌라고”인 상황이라, 자동 판별이 실패하면 후보 레포를 버튼으로 띄워 고르게 바꿨다. 실패할 때의 사용자 경험까지가 설계 범위라는 걸 그때 배웠다.
하지만 이런 건 코드로 고쳐진다. 정작 사이클이 통째로 멈추는 날은 거의 항상 “도구가 멍청해서”가 아니라 “내 정책 문서가 모호해서”였다. 도메인의 암묵적인 규칙, 그러니까 “이건 당연히 이래야지” 싶어서 굳이 문서에 안 적은 것은 봇이 끝내 못 잡는다. 봇은 내 머릿속을 읽지 못하고, 내가 적어준 문서만 읽는다. 그래서 난 그럴수록 코드 수정이 아닌 정책과 하네스를 다듬었다.
자기 도메인을 명시화할 수 있을 만큼은 알아야 한다는 전제는 사라지지 않는다. 다만 그 명시화의 결과물이 곧장 동작하는 코드로 이어지는 환경을, 이번에 한 번 만들어본 거다.
그런데 앞에서 그어둔 선이 여기서 걸린다. 게이트가 받친 건 품질의 기술적 바닥이었지, 기능이 의도대로 도는지까지는 아니었다. 그래서 이 “코드 안 친” 작업의 결과물을 AI에 직접 코드 리뷰를 시켜 점수를 매겨봤다. 결과는 기술 완성도 85점, 명세 반영률 62.5%였다.
흥미로운 건 두 숫자가 같은 결과물을 보고도 전혀 다른 이야기를 했다는 점이다. 모달의 생명주기와 타입, 상태 관리, 테스트 구조는 꽤 단단했다. Jest 테스트 151개가 모두 통과했고, 6개 모달의 상태 정리도 빠진 곳이 없었다. 그런데 명세 40개를 코드와 하나씩 맞춰보니 실제로 반영된 건 25개였다. 구조는 프로덕션 수준이었지만, 카테고리 정책이나 직원의 담당 범위, 검색 필터처럼 기능의 의미를 결정하는 규칙 15개가 비어 있었다.
더 이상했던 건 AI가 이 누락을 몰랐던 것도 아니라는 점이다. 작업 보고서에는 카테고리, 담당자 표시, 저장 확인 같은 최우선 미완 항목이 이미 적혀 있었고, 실제 코드에서도 그대로 빠져 있었다. 스스로 간극을 발견하고 기록하는 데까지는 갔지만, 그 간극을 닫는 행동으로 연결하지는 못한 것이다. 기술적 게이트만으로는 잡히지 않는 종류의 실패였다.
시즌1에서 하네스를 “AI가 일하는 작업대”라고 불렀다. 이번 실패 뒤에는 그 작업대에 기능 검증을 위한 층을 하나 더 만들기 시작했다. 변경된 코드가 어느 정책에 닿는지 찾고, 연결된 테스트를 돌리며, 소스만 바뀌고 정책 문서가 따라오지 않으면 경고하는 구조를 품질 게이트에 넣었다. 아직 모든 프로젝트에서 실제로 굴러가는 단계는 아니고, 문서에 적히지 않은 암묵적인 규칙까지 자동으로 잡지도 못한다. 그래도 AI가 미완 항목을 보고서에만 남기고 지나가지 않도록 “무엇을 만족해야 끝인가”를 테스트와 연결하기 시작했다.
그 작업대가 단단해지니, 출근해서 봇을 먼저 켜는 건 내가 게을러져서가 아니라 그 작업대를 믿게 됐기 때문이 됐다. 이제 일을 “몇 줄을 쳤나”가 아니라 “무엇을 정확히 정의했나”로 다시 정의할 수 있게 됐다.
한편 이 작업대를 키우는 동안 또 다른 역설도 생겼다. 실패할 때마다 규칙과 훅, 에이전트를 하나씩 보태다 보니 어느 순간 하네스 자체가 모델이 먼저 통과해야 할 장애물이 됐다. 읽어야 할 지시와 도구가 많아질수록 컨텍스트와 토큰을 먼저 쓰고, 정작 중요한 것들은 희미해지는 것 같았다. 요즘은 그래서 모든 규칙들을 선두에서 주입하기보다 짧은 가이드만 넣어주고, 필요한 맥락들은 그때그때 꺼내 쓰며 모델이 판단할 여지를 남기는 쪽으로 흐름이 바뀌고 있다.

당장 유행을 따라 지금까지 만든 하네스를 한꺼번에 걷어낼 생각은 없다. 시행착오 끝에 생긴 규칙들 중 반드시 지켜야 할 것은 코드와 테스트들로 단단히 남겨놓고, 겹치는 설명들이나 발전한 모델들이 몇 달 전에는 못했지만 지금은 충분히 잘하는 일들은 덜어내고 싶다.
경계는 단단하게, 경계 안에서는 자유롭게 모델을 두는 것이다. 이제 내가 고민할 하네스 엔지니어링은 무엇을 더 강제할지가 아니라, 어디까지 강제하고 어디서부터 모델을 믿을지에 가까워질 것 같다.

바뀐 건 내 하루만이 아니었다. 얼마 전에는 내가 속하지 않은 다른 스쿼드의 기획자분이 Anvil을 통해 Slack DM만으로 신규 필드 추가를 시작해서, 영향 범위 분석부터 코드 수정, MR 생성, 배포 요청까지 한 흐름으로 밀고 갔다. 개발자가 한 명도 붙지 않은 채 상용까지 나간 첫 사례였다. 내가 만든 걸 내가 쓴 게 아니라, 내 손이 닿지 않는 곳에서 굴러간 거다.
개발자의 하루가 “코드부터”에서 “봇부터”로 바뀐 만큼, 비개발자가 일하는 방식은 또 어떻게 달라질까. 그게 솔직히 제일 궁금하고 제일 기대된다.
*이 글은 AI의 도움을 받아 작성했습니다.
<참고>
ⓒ요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.