Skip to content

하네스 개발 방법론

프로젝트에 하네스 개발 방법론(Harness Engineering)을 적용하는 절차를 정리한다.

하네스(harness)는 AI 에이전트가 일하는 환경 전체를 설계하는 것이다. AI에게 규칙을 알려주는 CLAUDE.md를 기본으로, 반복되는 절차는 스킬로 묶고, 절대 어기면 안 되는 규칙은 훅으로 막고, 실행해도 되는 명령은 권한으로 정한다. 규칙을 문서로 적어두는 것만으로는 AI가 놓칠 수 있으므로, 규칙의 성격에 맞는 장치를 골라 함께 쓴다.

구성 요소 위치 언제 동작하나 강제력 이 프로젝트의 예
CLAUDE.md 저장소 루트 CLAUDE.md 세션 시작 시 항상 읽힘 안내 (AI가 따르길 기대) 브랜치 전략, 커밋 규칙, 문서 작성 기준
스킬 .claude/skills/<이름>/SKILL.md /이름으로 실행하거나 AI가 설명을 보고 호출 절차를 문서대로 수행 /git-publish, /git-deploy 등 Git 스킬 4개
커스텀 명령 .claude/commands/<이름>.md /이름으로 실행 절차를 문서대로 수행 없음 (참조 저장소 모두 스킬로 일원화)
훅 .claude/settings.json의 hooks 도구 실행 전후 등 정해진 이벤트마다 자동 강제 (명령 차단 가능) master 직접 커밋 차단 훅
권한 .claude/settings.json의 permissions 도구를 실행할 때마다 강제 (허용·확인·거부) pnpm build, git status 등 자동 허용
서브에이전트 .claude/agents/<이름>.md 메인 AI가 작업을 위임할 때 역할·도구를 제한 dictionary-api의 build-validator
MCP 서버 .mcp.json AI가 외부 도구를 쓸 때 쓸 수 있는 도구를 늘림 dictionary-api의 IntelliJ(idea) 연동
flowchart LR
  user["사용자 요청"] --> claude["Claude Code"]
  claudemd["CLAUDE.md<br/>(항상 읽힘)"] -.-> claude
  skill["스킬 · 커스텀 명령<br/>(/git-publish 등)"] -.-> claude
  claude -- "도구 호출" --> pre{"PreToolUse 훅"}
  pre -- "차단" --> claude
  pre -- "통과" --> perm{"권한 규칙<br/>(allow · ask · deny)"}
  perm -- "거부" --> claude
  perm -- "허용" --> tool["도구 실행<br/>(Bash · Edit · MCP 도구)"]
  tool --> post["PostToolUse 훅"]
  post --> claude
  claude -- "작업 위임" --> sub["서브에이전트<br/>(별도 컨텍스트)"]
  sub -- "결과만 반환" --> claude
  • CLAUDE.md AI가 지켜야 할 규칙 (항상 읽힘)
  • .mcp.json 프로젝트에서 쓰는 MCP 서버
  • Directory.claude/
    • settings.json 권한(permissions)과 훅(hooks) 등록 — 저장소에 커밋해서 공유
    • settings.local.json 개인 설정 — 커밋하지 않음
    • Directoryskills/
      • Directorygit-publish/
        • SKILL.md 스킬 본문 (frontmatter + 절차)
    • Directorycommands/
      • <이름>.md 커스텀 명령 (새로 만들 때는 스킬을 쓴다)
    • Directoryagents/
      • build-validator.md 서브에이전트 정의
    • Directoryhooks/
      • block-master-direct-commit.sh 훅 스크립트

아래에서는 먼저 기본이 되는 CLAUDE.md에 규칙을 정리하는 방법을 설명하고, 이어서 이를 보완하는 스킬 · 훅 · 그 밖의 기법을 설명한다.

  1. 프로젝트 초기에 아래 항목들을 CLAUDE.md에 정리하고, 규칙을 확정한 뒤 개발을 시작한다.
  2. 프로젝트 중반에 규칙을 바꾸면 리팩터링이 필요해지고, 그 부작용으로 없던 버그까지 생겨 수정에 많은 시간이 든다. AI는 바뀌기 전 규칙으로도 코드를 빠르게 많이 만들어내므로, 늦게 바꿀수록 고쳐야 할 분량이 커진다.

프레임워크

구성 요소가 충분히 통합된 안정된 프레임워크를 고르고, 계층 구조(프런트엔드·백엔드·데이터베이스 3계층)와 성공·실패 시 쓸 HTTP 응답 코드처럼 모든 계층에 공통인 약속을 정한다. → 프레임워크 규칙

형상관리 브랜치 규칙 정리

작업·master·deploy 브랜치의 역할, 브랜치 이름 형식(<type>/<설명>), 커밋 메시지 형식(Conventional Commits), --no-ff 병합 방향과 배포 시점을 확정한다. → 형상관리 브랜치 규칙

프런트엔드 개발 규칙 정리

디렉토리 구조(Atomic Design, 훅 접미사), 코딩 컨벤션(Prettier·oxlint), 컴포넌트·커스텀 훅 작성법, 백엔드 연동·예외 처리·세션 규칙, 토스트·다이얼로그·모달·그리드 같은 공통 UI 사용법을 정한다. → 프런트엔드 코딩 규칙

백엔드 개발 규칙 정리

기능(feature) 단위 패키지 구조, 코딩 컨벤션(Spotless, final), 예외 처리(BizException), 세션·인가, 스프링 프로파일, 로깅, 설정값 암호화(ENC(...)), 배포 규칙을 정한다. → 백엔드 코딩 규칙

템플릿 코드 작성

CRUD를 비롯해 여러 형태의 API를 갖춘 기능 하나(이 프로젝트는 board)를 템플릿으로 지정하고 규칙에 적어둔다. AI는 새 기능을 만들 때 이 코드를 참조해 같은 패턴으로 작성한다. → 템플릿 코드 작성 규칙

데이터베이스 개발 규칙 정리

계정·권한 발급, 테이블(t_ 접두어)·컬럼(스네이크 케이스, Y/N 플래그는 CHAR(1))·인덱스·함수 네이밍, 감사 컬럼, Flyway 마이그레이션, 테스트·개발·운영 DB의 구분을 정한다. → 데이터베이스 코딩 규칙

인터페이스 개발 규칙 정리

외부 API 호출 방식(RestClient)과 클라이언트 위치(interfaces 패키지), 인증키 관리(암호화한 프로퍼티), API별 응답 형식 정규화, 실제 호출 테스트의 분리, 호출량 제한 점검을 정한다. → 인터페이스 코딩 규칙

테스트

계층별 테스트 방식(Service는 Mockito, Repository는 @DataJpaTest, Controller는 RestAssured), 커버리지 측정(Jacoco), 테스트 데이터(H2 + Flyway), 외부 API 연동 테스트 분리, 테스트 실행 시점을 정한다. → 테스트 규칙

문서로 정리

위 항목마다 AI가 지켜야 하는 규칙은 CLAUDE.md에, 개발자를 위한 사용법과 배경 설명은 README.md 같은 개발 가이드에 나눠 적는다. 영역별로 어느 문서에 무엇을 남길지 정한다. → 문서 작성 규칙

Claude Code 프롬프트에서 아래처럼 요청하면 된다. 결과적으로 CLAUDE.md만 갱신되면 되므로, 다른 방식을 써도 된다.

  1. 규칙을 프롬프트에 직접 적고, 규칙에 추가해 달라고 요청한다.

    커밋 메시지 포매팅 규칙은 `Conventional Commits` 방식을 따른다. 규칙에 등록하고 엄격하게 적용해 줘
  2. 먼저 “○○에 대해 어떻게 생각해?“라고 물어 AI의 검토 결과를 확인한 뒤, 규칙에 추가해 달라고 요청한다.

    master 브랜치에 직접 push하는것에 대해 어떻게 생각해?
    ... AI의 출력 리포트 확인...
    그러면 규칙에 추가하고 엄격하게 적용해 줘

CLAUDE.md는 세션마다 읽히지만, 대화가 길어지거나 상황이 애매하면 AI가 규칙을 놓칠 수 있다. 이를 보완하는 장치들이다. 각 장치의 위치와 동작 시점은 위 하네스 구성 요소의 표를 참고한다.

스킬 — 반복되는 절차를 묶는다

Section titled “스킬 — 반복되는 절차를 묶는다”
  1. 스킬은 AI가 따라야 할 절차서다. .claude/skills/<이름>/SKILL.md에 목표·절차·제약 사항을 적어두면, /이름으로 실행했을 때 AI가 그 문서대로 작업한다. 커밋 → 병합 → push처럼 단계가 많고 매번 같은 순서로 해야 하는 작업에 알맞다.
  2. frontmatter로 이름과 호출 방식을 정한다.
    .claude/skills/git-commit/SKILL.md
    ---
    name: git-commit
    description: 현재 작업 브랜치의 변경 사항을 분석해 `Conventional Commits` 형식의 한국어 커밋 메시지를 자동으로 작성하고 커밋한다. ... 자동 호출되지 않으며 `/git-commit`으로만 실행할 수 있다.
    disable-model-invocation: true
    ---
    • description: AI가 “지금 이 스킬을 써야 하나”를 판단하는 근거다. 언제 쓰는 스킬인지 구체적으로 쓴다.
    • disable-model-invocation: true: AI가 스스로 판단해 호출하지 못하게 하고, 사용자가 /이름으로 실행할 때만 동작하게 한다. push·배포처럼 되돌리기 어려운 작업을 하는 스킬에는 반드시 붙인다.
  3. 스킬 폴더에 참고 파일을 함께 둘 수 있다. 스크립트, 템플릿, 긴 참고 문서를 같은 폴더에 두고 SKILL.md에서 가리키면, 필요할 때만 읽히므로 평소 컨텍스트를 차지하지 않는다.
  4. CLAUDE.md와 역할을 나눈다. 항상 지켜야 하는 원칙(예: master 직접 커밋 금지)은 CLAUDE.md에, 특정 작업을 할 때만 필요한 긴 절차(예: 병합 전 동기화 순서)는 스킬에 둔다. CLAUDE.md가 길어질수록 매 세션의 컨텍스트를 차지하기 때문이다.

이 프로젝트의 Git 스킬 4개가 어떤 작업을 맡는지는 AI용 Git 스킬 참고.

커스텀 명령은 .claude/commands/<이름>.md 파일 하나로 /이름 명령을 만드는 방식이다. Claude Code에서 커스텀 명령은 스킬로 통합되었다. .claude/commands/deploy.md와 .claude/skills/deploy/SKILL.md는 둘 다 /deploy를 만들고 같은 방식으로 동작한다. 기존 커스텀 명령 파일도 그대로 동작하지만, 스킬에만 있는 기능이 몇 가지 더 있다.

구분 커스텀 명령 스킬
위치 .claude/commands/<이름>.md 파일 하나 .claude/skills/<이름>/ 폴더 (SKILL.md 필수)
실행 방법 사용자가 /이름으로 실행 사용자의 /이름 실행 + AI가 description을 보고 스스로 호출
호출 제어 없음 (사용자가 실행할 때만 동작) disable-model-invocation: true로 AI 자동 호출을 막을 수 있음
참고 파일 둘 수 없음 (본문에 모두 적어야 함) 스크립트·템플릿·참고 문서를 폴더에 두고 필요할 때만 읽힘
공통 frontmatter description, allowed-tools, argument-hint, model 등 커스텀 명령과 같음
이름이 겹칠 때 스킬에 가려짐 스킬이 우선
참조 저장소 현황 dictionary-app·dictionary-api 모두 제거 Git 스킬 4개 등을 사용

훅 — 어기면 안 되는 규칙을 강제한다

Section titled “훅 — 어기면 안 되는 규칙을 강제한다”
  1. 훅은 특정 이벤트가 일어날 때마다 자동으로 실행되는 명령이다. AI의 판단과 상관없이 항상 실행되므로, CLAUDE.md의 “하지 마라”를 실제로 못 하게 만들 수 있다.
  2. 주요 이벤트
    • PreToolUse: 도구 실행 직전. 명령을 검사해서 차단할 수 있다.
    • PostToolUse: 도구 실행 직후. 수정된 파일에 포매터를 돌리는 등 후처리에 쓴다.
    • UserPromptSubmit: 사용자가 프롬프트를 보낼 때. 추가 컨텍스트를 붙이거나 요청을 검사한다.
    • SessionStart: 세션이 시작될 때. 작업에 필요한 정보를 미리 불러온다.
    • Stop: AI가 응답을 마칠 때. 마무리 검사를 돌린다.
  3. .claude/settings.json에 등록한다. matcher로 대상 도구를, if로 대상 명령을 좁힌다.
    .claude/settings.json
    {
    "hooks": {
    "PreToolUse": [
    {
    "matcher": "Bash",
    "hooks": [
    {
    "type": "command",
    "command": "bash .claude/hooks/block-master-direct-commit.sh",
    "if": "Bash(git *)"
    }
    ]
    }
    ]
    }
    }
  4. 차단하는 방법은 두 가지다. 훅 스크립트는 실행하려는 도구 정보(tool_input.command 등)를 표준 입력의 JSON으로 받는다.
    • 표준 출력에 hookSpecificOutput.permissionDecision: "deny"와 사유(permissionDecisionReason)를 JSON으로 쓴다. 이 프로젝트의 check-master-guard.cjs가 이 방식이다.
    • 종료 코드 2로 끝내고 사유를 표준 에러에 쓴다. 검사기(node) 실행 자체가 실패했을 때 이 방식으로 예방적으로 차단한다.
    • 차단 사유는 AI에게 그대로 전달되므로, AI가 무엇을 대신 해야 하는지 알 수 있게 구체적으로 쓴다.
  5. 이 프로젝트의 예: master 보호 훅. 현재 브랜치가 master일 때 AI가 git commit, cherry-pick, revert, rebase를 실행하거나 master 위에서 deploy를 병합하려 하면 막는다. 작업 브랜치 병합이나 status·log·push 같은 명령은 막지 않는다.
  6. 훅은 가볍고 확실하게 만든다. 모든 도구 호출마다 실행될 수 있으므로 빨리 끝나야 하고, 검사 도구가 없어서 검사를 못 했다면 조용히 통과시키지 말고 차단하는 쪽(fail-closed)을 택한다.
  1. 권한 설정(permissions) — .claude/settings.json에 자동으로 허용할 명령(allow), 매번 확인받을 명령(ask), 금지할 명령(deny)을 적는다. 이 프로젝트는 pnpm build, git status·git diff·git log 같은 읽기·빌드 명령을 allow에 넣어, 자주 쓰는 안전한 명령에서 확인 창이 뜨지 않게 했다. 반대로 위험한 명령은 deny에 넣으면 훅 없이도 막을 수 있다.
  2. 서브에이전트 — .claude/agents/<이름>.md에 역할, 쓸 수 있는 도구(tools), 모델(model)을 정해 둔 보조 AI다. 메인 AI가 작업을 위임하면 별도의 컨텍스트에서 일하고 결과만 돌려주므로, 긴 빌드 로그처럼 양이 많은 출력이 메인 대화를 차지하지 않는다. dictionary-api의 build-validator는 Bash와 Read만 쓸 수 있고, ./gradlew build 결과를 요약해서 보고한다.
  3. MCP 서버 — .mcp.json에 외부 도구(IDE, 데이터베이스, 브라우저, 이슈 트래커 등)를 연결해 AI가 쓸 수 있는 도구를 늘린다. dictionary-api는 IntelliJ(idea)를 연결해 IDE의 검사·리팩터링 기능을 쓸 수 있게 했다.
  4. 자동 검증 수단 — 포매터(Prettier, Spotless), 린터(oxlint), 타입 검사, 테스트, 빌드처럼 AI가 직접 돌려서 결과를 확인할 수 있는 도구를 갖춰 둔다. AI가 스스로 실패를 발견하고 고칠 수 있어야 사람이 검토할 부분이 줄어든다.
  5. CLAUDE.md 계층 — 사용자 전역(~/.claude/CLAUDE.md)과 프로젝트(저장소 루트)의 CLAUDE.md는 세션을 시작할 때 함께 읽히고, 하위 폴더에 둔 CLAUDE.md는 AI가 그 폴더의 파일을 다룰 때 읽힌다. 모든 프로젝트에 공통인 개인 취향은 전역에, 팀과 공유할 규칙은 프로젝트 CLAUDE.md에, 특정 영역에만 해당하는 규칙은 하위 폴더에 둔다. @경로 문법으로 다른 문서를 불러올 수도 있다.
  1. 하나의 요청에는 하나의 목적만 담는다. 여러 작업을 한 번에 요청하면 결과를 검증하기 어렵고, 문제가 생겼을 때 원인을 특정하기도 어렵다. 범위가 너무 넓으면 컨텍스트가 부족해 끝까지 완료하지 못할 수도 있다.
  2. 요청 전에 관련 파일 경로나 기존 코드/문서를 먼저 언급해서 컨텍스트를 좁혀준다. AI가 불필요한 탐색 과정 없이 정확한 위치에서 작업을 시작할 수 있다.
  3. “정리해줘”, “잘 만들어줘”처럼 애매한 표현보다는 구체적인 조건과 기대 결과를 명시한다(예: “OO 규칙에 맞춰 XX 항목을 추가해줘”).
  4. 결과물을 받으면 바로 다음 요청으로 넘어가지 말고 리뷰 후 피드백을 준다. 반복할수록 규칙과 컨벤션이 정교해진다.