3줄 요약

  1. 꼼비(ggombee)가 AI 에이전트를 실무에 적용하며 만든 code-forge 프로젝트의 진화 과정을 기록한 글이다.
  2. 프롬프트 엔지니어링의 본질적 한계(자연어는 강제력이 없다)를 인식하고, 시스템 레벨에서 에이전트를 통제하는 하네스 엔지니어링으로 전환했다.
  3. hooks 3층 구조, 에이전트 빌드타임 컴파일, AGENTS.md 멀티모델 컨벤션까지 실전에서 검증된 구체적인 구현 사례를 제시한다.

프롬프트의 한계: 부탁에서 강제로

git add -A 쓰지 말라고 굵은 글씨로 적어놔도 에이전트는 가끔 그냥 쓴다. 프롬프트는 결국 자연어이고, 자연어로 된 지시에는 강제력이 없다. 저자는 이 경험에서 핵심 전제를 도출한다.

프롬프트가 쓸모없다는 게 아니다. 프롬프트만으로는 부족하다는 것이다.

그래서 “부탁하는 걸 그만두고” 에이전트가 실행되는 환경 자체를 설계하기 시작했다. 업계에서는 이를 하네스 엔지니어링이라 부른다. OpenAI가 2025년 2월에 소개하고, 마틴 파울러도 다룬 개념이다.

사고 모델 단순화: 6단계에서 4단계로

인지적 도제 이론 기반의 6단계 사고 모델(읽기\→반응\→분석\→재구조화\→구조화\→성찰)을 만들었으나 세 가지 문제가 터졌다.

  • 토큰 낭비: 버튼 색상 바꾸는데 “현재 구조를 분석합니다…”
  • 경계 모호: READ와 REACT의 차이를 만든 본인도 설명하기 애매
  • 실패 루프 부재: 검증에서 lint가 터지면 어디로 돌아가야 하는지 정의 안 됨

4단계로 줄인 결과:

GROUND → APPLY → VERIFY
  ↑                ↓
  └─── ADAPT ←─────┘
       (실패 시만)
  • GROUND: 코드를 먼저 읽는다. 기억에서 추론하지 않는다.
  • APPLY: 관찰한 패턴대로 구현. 5가지 불변 제약(읽기 우선, 패턴 준수, 정책 보존, 최소 변경, 스코프 준수).
  • VERIFY: lint/tsc/테스트를 도구로 확인.
  • ADAPT: 실패 원인 분석 후 GROUND로 복귀. 같은 원인 2회 실패 시 접근법 변경, 3회 시 사람에게 위임.

4개 파일 수백 줄이 1개 파일 99줄로 줄었고, 에이전트는 오히려 더 잘 따랐다. 저자의 결론: 줄였는데도 잘 되면 원래 그만큼만 필요했던 것이다.

모듈화와 에이전트 컴파일

컨벤션 모듈화

Emotion, Jotai 등 스택 컨벤션이 규칙 파일에 하드코딩되어 팀 공유가 불가능했다. modules/ 디렉터리로 추출하여 프리셋으로 조합하는 구조로 전환. 현재 13개 모듈(프레임워크 3, 디자인 시스템 2, 상태 관리 3, 스타일링 3, 테스팅 2). 에이전트와 사고 모델은 동일하게 두고 스택만 교체한다.

STATE/ACT 분리와 빌드타임 컴파일

에이전트를 STATE(아는 것)와 ACT(하는 것)로 분리하면 조합이 가능해진다.

code-reviewer = lang.typescript + framework.react + quality.review
implementor   = lang.typescript + framework.react + dev.implement

처음에는 런타임에 규칙 파일을 주입했으나 28개 파일 이중 관리 문제가 발생. “TypeScript를 매번 런타임에 해석하는 사람은 없다"는 발상으로 빌드타임 컴파일로 전환했다. /smith-build로 STATE+ACT 체인을 미리 계산하여 정적 .md 파일로 출력한다. 복잡성을 제거한 게 아니라 빌드타임으로 옮긴 것이다.

배포: Git 레포에서 플러그인으로

설정을 별도 Git 레포로 관리했으나 동기화 문제 발생. Claude Code 플러그인 공식 지원 이후 claude plugin install로 전면 교체. session-init.sh SessionStart 훅이 세션마다 리모트 버전을 확인하고 자동 업데이트한다.

하네스 엔지니어링: 핵심 구조

3층 아키텍처

Layer비유역할강제력
Layer 1 (hooks)소방 스프링클러시스템 레벨 가드레일무시 불가
Layer 2 (프롬프트)금연 표지판지시·컨벤션 안내대부분 따르지만 강제 아님
Layer 3 (에이전트)출입 카드권한 기반 접근 제어권한 없으면 불가

command 훅 + prompt 훅 = 2층 가드레일

  • command 훅(regex): 빠르고 확실. git add ., rm -rf 등 알려진 패턴 즉시 차단.
  • prompt 훅(haiku 기반 LLM): 느리지만 의미를 이해. “강제 푸시해줘” 같은 자연어도 판별.

두 개를 레이어로 쌓으면 regex가 놓치는 부분을 LLM이 잡는다.

exit 0 스텁에서 실동작 11개로

솔직히 처음에 hooks는 exit 0 4줄짜리 스텁 5개에 불과했다. 리팩터링하면서 기존 5개를 채우고 6개를 추가하여 11개 실동작 441줄이 되었다. 방향은 멀티모델 토론에서 나온 한마디가 잡았다.

“새로 만들 것은 최소한으로. 있는 것을 채우고 다듬는다.”

주목할 만한 훅 배치

  • SubagentStop: 서브 에이전트 완료 시 tsc 실행. 세션 종료가 아닌 각 에이전트 완료 시점에 타입 체크를 걸어 오류를 즉시 포착.
  • PreCompact: 컨텍스트 압축 직전에 브랜치·미커밋 파일·스테이지 상태를 스냅샷으로 주입. 압축 후에도 복귀 지점 보존.
  • Stop (quality-gate.sh): 응답 완료마다 eslint –quiet + tsc –noEmit 실행. 에이전트가 “잘 됐다"고 해도 린터가 최종 확인.

멀티모델 협업

같은 Claude 모델끼리는 비슷한 편향을 공유한다. Claude가 짠 구현 계획을 Codex(GPT)에게 보여주면 다른 시각에서 허점을 찾아낸다. 경험적으로 확인된 사실: 비판적 의견이 들어갔을 때 더 좋은 결과가 나온다.

AGENTS.md: AAIF 표준

CLAUDE.md는 Claude만 읽지만, AGENTS.md(AAIF 표준)는 Codex CLI·Cursor가 네이티브로 읽는다. /setup이 두 파일을 동시에 생성하고, CLAUDE.mdAGENTS.md를 임포트하는 구조. 어떤 모델이든 같은 하네스를 따르면 같은 아웃풋이 나오는 것이 목표다.

실제 토론 사례

  • 구조 검증: Codex가 “참조 파일 중복, @참조 매트릭스 과도” CONDITIONAL REJECT. Critic(Claude Opus)이 “무조건 줄이는 게 답이 아니다” 반론. 결과적으로 중복은 정리하되 역할별 참조는 유지.
  • v3.0 방향성: Builder(실용) vs Visionary(비전) vs Critic(비판) 3라운드. Critic의 “있는 것을 채우고 다듬는다"가 hooks 실구현의 방향을 결정.

가장 흥미로운 지점

이 글에서 가장 인상 깊은 부분은 “exit 0 스텁 5개에서 실동작 11개로” 가는 과정이다. 하네스를 설계했다고 말하면서 실제로는 껍데기에 의존하고 있었다는 솔직한 고백이 설득력을 높인다. 새 기능을 추가하는 것보다 있는 것을 실제로 채우는 것이 더 큰 효과를 낸다는 결론은, 소프트웨어 개발 전반에 통하는 이야기다.

command 훅(regex)과 prompt 훅(LLM)을 레이어로 쌓는 아이디어도 실용적이다. 알려진 패턴은 빠르게 잡고, 의미적 판단이 필요한 부분은 LLM에 맡기는 구조는 비용과 안전의 균형을 잘 잡는다.

출처

꼼비(ggombee), 2026년 4월 30일, 요즘IT 원문: https://yozm.wishket.com/magazine/detail/3733/ GitHub: https://github.com/ggombee/code-forge