Skip to content
Go back

AI 에이전트 하네스 개발기 #2 — Hook으로 에이전트에 고삐를 채우다

#1에서 스캐폴더를 만들었다. 룰과 스킬을 깔아줬지만 에이전트가 안 지켜도 막을 수 없었다. 이번에 진짜 고삐를 만들었다. 에이전트가 파일을 수정하면 자동으로 검증하고, 에러가 나면 즉시 수정하게 만드는 시스템이다.

Hook이 뭔데

Claude Code, Gemini CLI 같은 AI 코딩 에이전트들은 파일을 수정할 때 Hook을 실행할 수 있다. git hook이랑 비슷한데, 에이전트의 도구 사용 전후에 끼어드는 것이다.

에이전트가 파일 수정 시도
  → PreToolUse (수정 전에 실행) — 차단 가능
  → 파일 수정
  → PostToolUse (수정 후에 실행) — 피드백 전달

에이전트마다 이름이 다르지만 개념은 같다.

에이전트수정 전수정 후
Claude CodePreToolUsePostToolUse
Gemini CLIBeforeToolAfterTool
Codex CLIPreToolUsePostToolUse

중요한 건 같은 bash 스크립트로 모든 에이전트를 커버한다는 점이다. 설정 파일 포맷만 다르고, 실행되는 hook 스크립트는 동일하다.

5개의 Hook

Hook시점한 줄 요약
scope-guard파일 수정 전허용 범위 밖 파일 수정 차단
scaffold-guard파일 생성 전파일 네이밍 규칙 검증
post-write파일 수정 후lint + 타입체크 + 보안검사
session-init세션 시작프로젝트 컨텍스트 주입
stop-review응답 종료빌드 + 테스트 최종 검증

이 중에서 post-write가 핵심이다. 나머지는 보조.

post-write — 핵심 Hook

에이전트가 파일을 수정할 때마다 실행된다. 하는 일이 많다.

에이전트 Write → post-write.sh 실행
  ├── 0. Auto-format (biome/prettier로 자동 포맷)
  ├── 1. Lint 검사
  ├── 2. TypeScript type-check
  ├── 3. Import 위반 검사 (FSD/Clean 아키텍처 레이어 규칙)
  ├── 4. 블록체인 보안 검사 (.sol/.rs/.move)
  └── 5. codingStandards 위반 검사

에러가 없으면 clean을 기록하고 끝. 에러가 있으면 재밌어진다.

Self-heal — 에러 나면 알아서 고쳐

PostToolUse hook의 출력은 에이전트 컨텍스트에 자동 주입된다. Claude Code 기준으로 additionalContext 필드를 쓰면 에이전트가 다음 행동에 이 정보를 참고한다.

{
  "additionalContext": "⚠️ Type errors in src/ui/input.tsx:\nsrc/ui/input.tsx(3,1): error TS2322: ...\n\n즉시 수정하라."
}

에이전트가 파일을 쓰면 → hook이 에러를 발견하면 → “즉시 수정하라”를 에이전트에 전달하면 → 에이전트가 알아서 고친다. 이게 self-heal이다.

단, 보안 에러는 다르게 처리한다.

에러 종류동작
단순 에러 (TS2322, lint 위반 등)“즉시 수정하라” — 컨펌 없이 자동 수정
보안 에러 (SWC-115, reentrancy 등)“원인을 설명하고 수정 계획을 제시한 후 사용자 확인을 받아라”

tx.origin 사용이나 reentrancy 같은 보안 이슈는 에이전트가 맥락 없이 바꾸면 더 위험할 수 있어서, 사용자 확인을 거치게 했다.

scope-guard — 범위 밖 수정 차단

harness.config.jsonallowedScopes를 정의하면, 그 밖의 파일을 수정하려 할 때 exit 2로 차단한다.

{
  "agent": {
    "allowedScopes": ["src/**/*", "tests/**/*", "docs/**/*"]
  }
}

에이전트가 package.json이나 .gitignore를 건드리려 하면 막힌다. 단, harness.config.json, package.json, tsconfig.json 같은 설정 파일은 항상 허용 목록에 넣어뒀다.

이걸 만들면서 내가 먼저 당했다. Confluence 문서를 docs/에 쓰려는데 scope-guard가 막아서, 결국 templates/에 넣었다. 하네스가 제대로 동작한다는 증거이긴 하다.

scaffold-guard — 파일 네이밍 검증

파일을 생성할 때 네이밍 규칙을 검증한다. 여기서 까다로웠던 건 언어별로 강제되는 네이밍이 다르다는 것이다.

언어강제 네이밍이유
Gosnake_case언어 규약
Pythonsnake_casePEP 8
JavaPascalCase클래스명 = 파일명
SolidityPascalCase컨트랙트명 = 파일명
JS/TS사용자 선택팀 컨벤션에 따라 다름

모노레포에서 FE는 camelCase, Go API는 snake_case, Solidity 컨트랙트는 PascalCase를 써야 하는데, 하나의 설정으로 전체를 강제하면 안 된다. 그래서 fileNaming을 앱별 맵으로 만들었다.

{
  "rules": {
    "fileNaming": {
      "web": "camelCase",
      "api": "snake_case",
      "contracts": "PascalCase"
    }
  }
}

그리고 언어 규약으로 강제되는 파일명 패턴은 검증을 스킵한다. Go의 _test.go, Python의 test_*.py, Rust의 mod.rs 같은 건 네이밍 규칙과 무관하게 허용해야 한다. 이것도 실제 테스트 프로젝트에서 Go 테스트 파일이 inquiry-service-test.go로 생성되는 걸 보고 추가했다. Go 테스트는 반드시 _test.go여야 한다.

블록체인 보안 검사

post-write에서 .sol, .rs, .move 파일을 수정하면 보안 패턴을 자동으로 검사한다.

파일검사 항목
.soltx.origin(SWC-115), selfdestruct(SWC-106), delegatecall(SWC-112), floating pragma(SWC-103), reentrancy
.rs (Anchor)unchecked arithmetic, unwrap() in production
.movepublic entry without assert!

이건 linter가 아니라 grep 기반 패턴 매칭이다. 정밀도는 떨어지지만, slither나 mythril 같은 전문 도구를 설치하지 않아도 기본적인 위험 패턴은 잡을 수 있다.

Claude Code가 가장 잘 동작하는 이유

같은 hook 스크립트가 모든 에이전트에서 돌아가지만, Claude Code에서 가장 완전하게 동작한다. 이유는 PostToolUse의 additionalContext다.

Claude Code는 hook의 stdout을 파싱해서 additionalContext 필드를 에이전트 컨텍스트에 자동 주입한다. post-write가 “TS2322 에러가 있다, 즉시 수정하라”를 출력하면 에이전트가 다음 행동에서 이걸 보고 자동으로 수정한다.

다른 에이전트들은 hook 실행 + 메트릭 수집은 되지만, 에러 감지 후 “자동 수정 지시”를 에이전트 루프 안에서 전달하는 방식이 각각 다르다. Gemini CLI는 AfterTool에서 stdout을 읽지만, 에이전트 컨텍스트 주입이 Claude Code만큼 매끄럽지 않다.

다음

Hook이 에러를 잡아내는 건 됐다. 근데 같은 에러가 계속 반복되면? #3에서는 에이전트가 실수에서 학습하게 만든다 — learnings.json에 에러를 기록하고, 반복되면 규칙을 자동 추가하고, 메트릭으로 하네스의 효과를 측정하는 시스템을 다룬다.


Share this post on:

Comments


Previous Post
AI 에이전트 하네스 개발기 #3 — 에이전트가 실수에서 학습하게 만들기
Next Post
AI 에이전트 하네스 개발기 #1 — 20개 스택 × 3개 에이전트, 프로젝트 스캐폴더부터