본문 바로가기
claudecode.to
문서 목록
실전 코스고급

하네스 엔지니어링 예시 — Claude Code 설정 7가지

하네스 엔지니어링이란 무엇이고 어떻게 구축하는지, Claude Code에 바로 붙여 쓸 수 있는 설정 예시 7가지로 정리합니다. CLAUDE.md·권한·훅·검증 서브에이전트·헤드리스 실행까지 복사해 쓸 수 있습니다.

23분2026-09-19 갱신

하네스 엔지니어링 기초에서 컨텍스트·권한·검증·피드백이라는 네 축을 봤다면, 이 글은 그 축을 실제 설정 파일로 옮긴 예시 모음입니다. 각 예시는 "상황 → 설정 → 효과" 순서로 정리했고, 코드 블록은 그대로 복사해 프로젝트에 맞게 경로와 명령만 바꾸면 됩니다.

하네스 엔지니어링이란

하네스 엔지니어링은 모델을 바꾸는 대신 모델이 일하는 환경을 설계하는 일입니다. 매번 프롬프트로 부탁하던 것을 설정으로 옮겨, 어떤 지침이 항상 들어가는지, 어떤 도구를 허락 없이 쓸 수 있는지, 무엇이 자동으로 막히는지, 언제 일을 끝낸 것으로 볼지를 고정합니다. 한 번 잘 만들어 두면 모든 요청에 똑같이 적용된다는 점이 프롬프트와의 가장 큰 차이입니다.

구분답하는 질문Claude Code에서의 재료영향 범위
프롬프트 엔지니어링어떻게 물을 것인가그때그때 입력하는 지시문요청 한 번
컨텍스트 엔지니어링무엇을 보여줄 것인가CLAUDE.md, 참조 파일, 대화 이력세션 전체
하네스 엔지니어링어떤 장치에서 돌릴 것인가권한 규칙, 훅, 서브에이전트, 실행 옵션모든 세션과 자동 실행

컨텍스트 엔지니어링은 하네스의 한 축입니다. 입력을 잘 골라도 위험한 명령을 막는 장치나 결과를 확인하는 검증 명령이 없으면 하네스는 반쪽입니다. 이 흐름을 루프까지 이어서 본 글은 그냥 자동화와의 차이, 그리고 하네스의 한 층 위입니다.

예시 1 — 검증 명령을 적은 CLAUDE.md

상황

"테스트 잘 돌려 주세요"라고 매번 말하지만 Claude가 어떤 명령으로 무엇을 확인해야 하는지 몰라 결과가 들쭉날쭉합니다.

설정

# 프로젝트 규칙

## 검증 명령 (작업을 끝내기 전에 모두 통과해야 함)
- 타입 체크: npm run typecheck
- 테스트: npm run test
- 린트: npm run lint

## 규칙
- src/ 아래 새 함수에는 같은 폴더에 *.test.ts 를 함께 만든다
- 환경 변수는 src/config/env.ts 를 통해서만 읽는다
- 외부 API 호출은 src/lib/http.ts 의 래퍼만 쓴다

효과

"깔끔하게 짜라" 같은 문장은 지켰는지 판단할 수 없지만, 위 규칙은 전부 사실 여부를 확인할 수 있습니다. 특히 검증 명령이 한 줄로 적혀 있으면 Claude가 실패 → 원인 파악 → 수정 → 재실행을 스스로 반복합니다. 파일을 어디에 두고 어떻게 나누는지는 CLAUDE.md 가이드CLAUDE.md 계층 구조를 참고하세요.

예시 2 — settings.json 권한 allow·ask·deny

상황

읽기와 테스트 실행까지 매번 승인 창이 떠서 흐름이 끊기고, 반대로 .env 파일이나 git push는 확실히 사람이 확인하고 싶습니다.

설정

.claude/settings.json에 둡니다.

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test *)",
      "Bash(npm run typecheck)"
    ],
    "ask": [
      "Bash(git push *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)"
    ]
  }
}

효과

공식 문서 기준으로 규칙은 deny → ask → allow 순서로 평가되고, 이 순서에서 처음 맞는 규칙이 결과를 정합니다. 그래서 허용 목록을 넓혀도 deny에 넣은 비밀 파일 읽기는 막힙니다. Bash(npm run test *)처럼 끝에 공백과 *를 붙이면 그 명령으로 시작하는 모든 호출이 매칭됩니다. 공백을 빼면 의도하지 않은 비슷한 이름의 명령까지 매칭될 수 있으니 주의합니다. 규칙 문법은 권한 설정settings.json 가이드에 자세히 있습니다.

예시 3 — PreToolUse 훅으로 파괴적 명령 차단

상황

권한 규칙만으로는 rm -rf나 강제 푸시 같은 명령을 모든 변형까지 잡기 어렵습니다. 실행 직전에 한 번 더 걸러 주는 장치가 필요합니다.

설정

.claude/settings.jsonhooks 항목입니다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-dangerous.sh"
          }
        ]
      }
    ]
  }
}

.claude/hooks/block-dangerous.sh 스크립트입니다. 실행 권한(chmod +x)을 줍니다.

#!/usr/bin/env bash
cmd=$(jq -r '.tool_input.command // ""')

if echo "$cmd" | grep -Eq 'rm -rf|git push .*--force|git reset --hard|DROP TABLE'; then
  echo "차단: 파괴적 명령입니다 ($cmd). 되돌릴 수 있는 방법으로 다시 계획하세요." >&2
  exit 2
fi
exit 0

효과

훅은 표준 입력으로 JSON을 받고, Bash 도구라면 실행하려는 명령이 tool_input.command에 들어 있습니다. PreToolUse에서 exit code 2로 끝내면 도구 호출이 막히고 표준 오류에 쓴 문장이 Claude에게 이유로 전달됩니다. exit code 1은 막지 않고 진행하는 비차단 오류로 처리되므로, 규칙을 강제하려면 반드시 2를 씁니다. 다만 문자열 패턴 검사는 우회될 수 있으므로 예시 2의 deny 규칙과 함께 쓰는 보조 장치로 봅니다. 종료 코드별 동작은 훅 exit code에 정리돼 있습니다.

예시 4 — PostToolUse 훅으로 편집 후 포맷·타입 체크

상황

Claude가 파일을 고칠 때마다 포맷이 흐트러지고, 타입 오류는 한참 뒤에야 발견됩니다.

설정

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/after-edit.sh"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env bash
file=$(jq -r '.tool_input.file_path // ""')
case "$file" in
  *.ts|*.tsx) ;;
  *) exit 0 ;;
esac

npx prettier --write "$file" >/dev/null 2>&1
if ! out=$(npm run -s typecheck 2>&1); then
  echo "타입 오류가 있습니다. 다음 내용을 고치세요:" >&2
  echo "$out" | tail -n 20 >&2
  exit 2
fi
exit 0

효과

matcherEdit|Write를 적으면 두 도구에 모두 발화하고, 편집된 파일 경로는 tool_input.file_path로 꺼냅니다. PostToolUse는 도구가 이미 실행된 뒤라 exit code 2로 편집을 되돌리지는 못하지만, 표준 오류 내용이 Claude에게 전달되므로 바로 다음 턴에서 오류를 고치게 됩니다. 오류 출력을 마지막 20줄로 자르는 것은 컨텍스트를 아끼기 위한 조치입니다. Prettier 연결을 단계별로 따라 하려면 PreToolUse·PostToolUse 훅을 보세요.

예시 5 — Stop 훅으로 테스트 통과 전 종료 거부

상황

Claude가 "완료했습니다"라고 말했는데 테스트를 돌려 보면 실패합니다. 끝내기 전에 검증을 강제하고 싶습니다.

설정

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/require-tests.sh"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env bash
input=$(cat)

# 이미 Stop 훅 때문에 이어서 일하는 중이면 다시 막지 않는다
if [ "$(echo "$input" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0
fi

if ! npm run -s test >/dev/null 2>&1; then
  jq -n '{decision: "block", reason: "테스트가 실패합니다. npm run test 를 실행해 실패 원인을 고친 뒤 끝내세요."}'
  exit 0
fi
exit 0

효과

Stop 훅이 최상위 필드 "decision": "block""reason"을 담은 JSON을 내보내면 Claude는 멈추지 않고 reason을 받아 작업을 이어갑니다. exit code 2와 표준 오류로도 같은 효과를 낼 수 있습니다. 입력의 stop_hook_active는 이미 Stop 훅 때문에 이어서 일하는 중일 때 true가 되므로, 이 값을 확인하지 않으면 영원히 끝나지 않는 조건에 갇힐 수 있습니다. 공식 문서에 따르면 연속 8번 막히면 Claude Code가 훅을 무시하고 턴을 끝냅니다. 자세한 동작은 Stop 훅에 있습니다.

예시 6 — 구현과 분리된 검증 서브에이전트

상황

직접 코드를 쓴 쪽이 스스로 검토하면 자기가 세운 가정을 그대로 믿어 버립니다. 만든 쪽과 확인하는 쪽을 나누고 싶습니다.

설정

.claude/agents/verifier.md 파일입니다.

---
name: verifier
description: 구현이 끝난 뒤 변경 사항을 검증한다. 코드를 수정한 작업이 끝나면 사용한다.
tools: Read, Grep, Glob, Bash
---

당신은 검증 담당입니다. 코드를 고치지 않습니다.
1. git diff 로 변경 범위를 확인합니다.
2. npm run typecheck, npm run test, npm run lint 를 실행합니다.
3. 요구 사항과 변경 내용이 맞는지 대조합니다.
결과는 "통과" 또는 "실패: 파일:줄 - 이유" 목록으로만 보고합니다.

효과

서브에이전트는 YAML 프론트매터(name, description, tools)와 본문의 시스템 프롬프트로 정의합니다. tools에 Edit·Write를 넣지 않았으므로 검증 담당은 파일을 고칠 수 없고, 보고만 합니다. 대화에서 "verifier 서브에이전트로 검증해 줘"라고 부르거나 @agent-verifier로 직접 지정할 수 있습니다. 설계 방법은 서브에이전트커스텀 에이전트를 참고하세요.

예시 7 — 스케줄 작업용 헤드리스 실행

상황

매일 아침 의존성 점검이나 테스트 실패 요약을 자동으로 받고 싶지만, 아무도 지켜보지 않는 실행에 모든 권한을 줄 수는 없습니다.

설정

#!/usr/bin/env bash
# 예: cron 으로 매일 09:00 실행
cd /path/to/repo || exit 1

claude -p "npm run test 를 실행하고 실패한 테스트와 추정 원인을 요약해 reports/daily.md 로 보고해 줘. 코드는 고치지 마." \
  --allowedTools "Read,Grep,Glob,Bash(npm run test *)" \
  --permission-mode dontAsk \
  --max-turns 15 \
  --output-format json > reports/daily.json

효과

-p는 대화 없이 한 번 실행하고 끝나는 비대화형 모드입니다. --allowedTools에 적은 도구만 승인 없이 실행되고, --permission-mode dontAsk는 원래 승인 창이 떴을 호출을 모두 거부하므로 무인 실행에서 권한이 새지 않습니다. --max-turns로 턴 수 상한을 걸어 헛도는 실행을 끊고, --output-format json으로 결과를 스크립트에서 다루기 쉽게 받습니다. 위 예시에는 파일 쓰기 권한이 없으므로, 보고서 파일까지 쓰게 하려면 해당 경로의 Write 권한을 좁게 추가하거나 표준 출력만 받도록 프롬프트를 바꿉니다. CI처럼 머신마다 같은 결과가 필요하면 --bare로 로컬 훅·CLAUDE.md 자동 로드를 끄는 방법도 있는데, 이 모드는 구독 로그인이 아니라 ANTHROPIC_API_KEY 환경 변수가 필요합니다. 기본 사용법은 헤드리스 모드에 있습니다.

내 하네스 점검 체크리스트

  • [ ] 검증 명령(테스트·타입 체크·린트)이 각각 한 줄로 실행되고 CLAUDE.md에 적혀 있는가
  • [ ] CLAUDE.md의 규칙이 전부 "지켰는지 확인할 수 있는" 문장인가
  • [ ] 자주 쓰는 안전한 명령은 allow, 되돌리기 어려운 명령은 ask, 비밀 파일은 deny에 있는가
  • [ ] 파괴적 명령을 막는 PreToolUse 훅이 exit code 2로 끝나는가
  • [ ] 편집 후 포맷·타입 체크가 자동으로 돌고, 오류 출력이 잘려서 전달되는가
  • [ ] Stop 훅이 stop_hook_active를 확인해 무한 반복을 피하는가
  • [ ] 구현과 검증을 다른 서브에이전트가 맡고, 검증 쪽은 편집 도구가 없는가
  • [ ] 무인 실행은 --allowedTools--permission-mode dontAsk, --max-turns로 범위가 좁혀져 있는가
  • [ ] 팀 공유 설정은 .claude/settings.json에, 개인 설정은 .claude/settings.local.json에 나뉘어 있는가
  • [ ] 오류 메시지가 "무엇이 왜 실패했고 다음에 무엇을 할지"를 알려 주는가

한 번에 다 갖출 필요는 없습니다. 검증 명령 → CLAUDE.md → 차단 훅 → 검증 서브에이전트 순서로 하나씩 더해 가면 됩니다. 훅 전반은 Hooks 가이드에서 이어서 볼 수 있고, 팀 단위로 하네스를 설계하는 실습이 필요하면 Claude Code 교육을 참고하세요.

이 글의 설정 키와 동작은 2026년 9월 기준 Claude Code 공식 문서(code.claude.com/docs)를 기준으로 확인했습니다.

자주 묻는 질문

하네스 엔지니어링하네스Hooks권한서브에이전트헤드리스