0. 하네스가 무엇인가
하네스라는 용어 자체는 말에게 씌우는 마구를 뜻하지만 AI Agent에서의 하네스는 다음과 같이 표현할 수 있다.
AI Agent=Model + Harness
모델이 “생각하고 생성하는 엔진”이라면, 하네스는 그 모델이 실제 작업을 수행하도록 둘러싼 도구, 컨텍스트, 실행 환경, 권한, 테스트, 검증, 로그, 피드백 루프, 사람의 개입 지점 전체다.
하네스 등장은 아래 두 글에서 화제였다. OpenAI, Anthropic에서 쓴 글인데, 둘 다 시사하는 바는 다음과 같다.
- https://openai.com/ko-KR/index/harness-engineering/
- https://www.anthropic.com/engineering/harness-design-long-running-apps
모델의 능력이 좋아져도, 하네스 없이는 복잡한 기능 구현을 안정적으로 수행할 수 없다.
OpenAI는 2026년 2월 공개한 글에서, 5개월 동안 사람이 직접 작성한 코드 없이 Codex가 애플리케이션 코드, 테스트, CI 설정, 문서, 관측성 도구 등을 생성했고, 인간의 역할은 코딩 자체보다 환경 설계, 의도 명세, 피드백 루프 구축으로 이동했다고 설명한다.
실제로 Viv Trivedy의 팀은 하네스만 교체해서 Terminal Bench 2.0 순위를 30위권에서 5위권으로 끌어올렸고, 동일 모델(Claude Opus 4.6)도 Claude Code 기본 하네스보다 커스텀 하네스에서 훨씬 높은 점수를 기록했다.
“하네스의 모든 구성 요소는 ’모델이 혼자 못하는 것’에 대한 가정을 인코딩한다.
모델이 좋아지면 가정을 재검증해야 한다.” — Anthropic
이 문서에서 소개하는 각 구성 요소 (rules, skills, hooks, subagents, MCP)
는 모두 현재 모델의 한계를 보완하기 위한 것입니다. 모델이 발전하면
불필요해진 규칙은 과감히 정리해야 하네스 자체가 단순해집니다.
1. 하네스 프레임워크는 왜 등장했나?
진화의 흐름은 다음과 같다.
- Prompt Engineering: AI에게 규칙 전달 + 질문을 잘하면 답이 좋아짐
- Context Engineering: AI에게 무엇을 보여주는가에 따라 결과가 달라짐
- Harness Engineering: AI 외부 시스템을 설계하여 작업 환경을 만들어줘서 에이전트가 올바른 길을 갈 수 있게 환경을 제공해준다.
Harness Engineering>Context Engineering>Prompt Engineering
하네스 엔지니어링은 AI 코딩 에이전트에게 “잘 해봐”라고 말하는 대신, 잘할 수밖에 없는 작업 환경과 검증 루프를 만드는 엔지니어링이다.
Harness engineering은 AI agent와 워크플로우에 대한 행동 제약과 개선 순환을 포함하는 시스템 설계를 의미한다. 에이전트 내부(컨텍스트, 프롬프트)가 아닌 외부 시스템을 설계하여 에이전트가 안전하고, 관찰 가능하고, 테스트 가능하고, 재현 가능하게 동작하도록 감싸는 실행·검증 구조를 만드는 일이다.
2. 하네스 전 vs 하네스 후: 실제 작업 흐름 비교
| 단계 | 하네스 전 | 하네스 후 |
|---|---|---|
| 작업 시작 | “이 기능 고쳐줘” → 코드만 보고 바로 수정 | CLAUDE.md → 관련 docs 읽음 → 계획 세움 → 수정 |
| 코드 수정 | 코드만 작성, 테스트는 생략하거나 나중에 | 수정 → 관련 테스트 확인 → 테스트 추가 → verify.sh 실행 |
| PR 리뷰 | 수동 diff 읽기, 누락 발생 | /review 스킬 → code-reviewer 서브에이전트 → severity 별 findings |
| 프로덕션 에러 | Sentry 접속 → 에러 복사 → 붙여넣기 → 구현 | MCP 로 Sentry 직접 조회 → repo 연결 → 원인 분석 → PR 생성 |
| 파일 수정 | 중요 파일 실수 수정 가능 | PreToolUse hook 으로 보호 파일 수정 차단 |
| 완료 판단 | “코드 작성 완료” = 끝 | verify.sh 통과 + quality gate marker + 요약 보고 |
핵심 차이: 하네스 전에는 “코드 작성”이 끝이었고, 하네스 후에는 “검증 통과 + 문서화”가 끝이다.
하네스 엔지니어링의 핵심 사고
모델이 틀리거나, 테스트를 작성하지 않고 테스트를 완료했다고 거짓말하거나 변경 내역을 한번에 커밋한다던가 이런 잘못된 행동을 할 때 “다음부턴 그러지마, 다음부터는 꼭 OOO를 하도록 해”가 아니라, 에이전트가 다음부턴 그런 행동을 하지 않도록 하네스 환경에 어떤 제약, 도구, 피드백, 문서를 추가해야하는지를 고민해야 한다.
OpenAI 사례에서도 Codex가 실패했을 때 “더 열심히 해”가 아니라, 어떤 capability가 부족한지, 그것을 에이전트에게 legible하고 enforceable하게 만들 방법이 무엇인지를 물었다고 설명한다.
여기서 중요한게 legiblilty, 즉 에이전트가 이해 가능한 형태로 시스템을 드러내는 것이다. 에이전트 관점에서 실행 중 컨텍스트로 잡근할 수 없는 정보는 사실상 존재하지 않는 것과 같다고 한다. 그래서 에이전트와 함께 일하기 위해서는 Notion, Slack, 사람 머릿속에만 있는 지식을 repo-local 문서, schema, 실행 계획, markdown 등으로 옮기는 것이 중요해졌다.
3. 하네스의 전체 구성도
하네스의 구성요소는 프로젝트마다 다르겠지만, 개념적으로는 아래 구성요소가 있다.
| 영역 | Claude Code 구성 요소 | 역할 |
|---|---|---|
| 지속 지침 | CLAUDE.md |
매 세션 로드되는 프로젝트 규칙 |
| 세부 규칙 | .claude/rules/ |
경로/언어/도메인별 규칙 |
| 반복 작업 | .claude/skills/ |
재사용 가능한 워크플로우 |
| 자동화 | hooks | 특정 이벤트마다 실행되는 자동 작업 |
| 전문 작업자 | subagents | 독립 context에서 일하는 하위 에이전트 |
| 외부 연결 | MCP | GitHub, DB, Slack, Sentry 등 외부 도구 연결 |
| 권한 통제 | permissions / settings | 파일 수정, 명령 실행, 네트워크 요청 제어 |
| 검증 | scripts / CI | 테스트, 린트, 타입체크, 빌드 |
| 감사 로그 | .claude/audit/ |
도구 사용 기록, 세션 종료 로그 (hook 에 의해 자동 생성) |
4. .claude 디렉터리와 프로젝트 구조
프로젝트/
├── CLAUDE.md # 프로젝트 전체 지침 (매 세션 로드)
├── .mcp.json # MCP 서버 설정 (외부 시스템 연결)
├── .claude/
│ ├── settings.json # 프로젝트 공통 설정 (권한, hooks, plugin)
│ ├── settings.local.json # 로컬 전용 설정 (개인 환경 변수)
│ ├── rules/ # 경로별 규칙 (backend.md, frontend.md, ...)
│ ├── skills/ # 재사용 가능한 워크플로우 (review, write-tests, ...)
│ ├── agents/ # custom subagent 정의 (code-reviewer, ...)
│ ├── hooks/ # lifecycle 자동화 스크립트
│ │ ├── protect-harness-files.sh
│ │ ├── post-edit-quality-gate.sh
│ │ ├── audit-tool-use.sh
│ │ ├── notify.sh
│ │ └── stop-log.sh
│ └── audit/ # 감사 로그 (hook 에 의해 자동 생성)
│ ├── tool-use.log
│ ├── session-end.log
│ └── last-quality-ok
├── docs/ # 상세 기술 문서
│ ├── architecture.md # 시스템 구조
│ ├── domain.md # 도메인 용어 정의
│ ├── adr/ # Architecture Decision Records
│ ├── api/ # API 명세
│ └── runbooks/ # 장애 대응 매뉴얼
├── references/ # 배경 지식 문서 (API conventions, errors, ...)
├── scripts/ # 실행 스크립트
│ ├── verify.sh # 전체 검증 (test → lint → build)
│ ├── verify-fast.sh # 빠른 검증 (test 만)
│ └── validate-*.py # 도메인 검증 스크립트
└── tools/ # 도구
└── mcp/ # MCP 서버 구현
위 디렉터리의 목적은 역할이 명확한 폴더링을 통해 AI가 언제 어떤 폴더에 접근하면 되는지 판단하기 쉽기 때문에 시간이 지날수록 유지보수의 난이도가 치솟는걸 방지하며 높은 퀄리티의 결과를 기대할 수 있다.
5. CLAUDE.md 프로젝트의 기본 운영 지침
CLAUDE.md는 Claude code가 매 세션 시작 시 읽는 프로젝트 지침 파일이다. 매번 프롬포트로 반복 요청하는 부분에 대해서 적으면 좋다. 하지만 말그대로 지침일 뿐이라 에이전트의 행동을 유도할 뿐이지, 시스템적으로 차단하지는 못한다. 반드시 막야하 하는 것은 settings.json나 hook으로 처리해야 안전하다.
CLAUDE.md는 Claude Code가 세션 시작 시 읽는 프로젝트 지침 파일이며 너무 길면 준수율이 떨어질 수 있어서 간결하고 구체적으로 쓰는 것이 좋다. Claude에게 모든 하네스 지식을 넣는 파일이 아니라, 어떤 문서를 보고 어떤 검증을 해야 하며 무엇을 절대 추론하면 안 되는지 알려주는 작업 지도로 사용되어야 한다.
# CLAUDE.md
## Project context
This repository supports automotive wire harness engineering.
It contains:
- harness design data
- connector / terminal / wire libraries
- pin-map and circuit information
- validation scripts
- BOM generation logic
- ECAD/CAD export files
- engineering reports
Treat all harness data as engineering-controlled information.
---
## Start here
Before modifying harness-related files, read:
- `docs/harness-map.md`
- `docs/data-dictionary.md`
- `docs/validation-rules.md`
- `docs/change-control.md`
- `docs/naming-conventions.md`
Use these documents to understand product structure, naming rules, validation
logic, and release workflow.
---
## Source of truth
Use sources in this order:
1. Released ECAD / harness data in `exports/released/`
2. Approved connector, terminal, and wire libraries in `libraries/`
3. ECO / ECN records in `changes/`
4. Validation rules in `docs/validation-rules.md`
5. Generated reports in `reports/`
Do not treat generated reports as authoritative unless they are explicitly
marked as released.
---
## Do not infer
Never invent or guess:
- connector part numbers
- terminal part numbers
- connector cavity assignments
- pin numbers
- wire gauge
- wire color
- splice topology
- shield / drain wire requirements
- fuse ratings
- ground point assignments
- option-code applicability
- release status
If information is missing, mark it as `TBD` and identify the missing source.
---
## Editing rules
When editing engineering data:
- Keep changes minimal and traceable.
- Preserve existing circuit IDs unless the task explicitly requires renaming.
- Do not reorder pins, cavities, or BOM rows for cosmetic reasons.
- Do not manually edit generated files.
- Do not mix electrical connectivity changes with mechanical routing changes.
- Include ECO / ECN references when available.
---
## Validation commands
Run the relevant checks after changes:
'''bash
python scripts/validate_[schema.py](http://schema.py)
python scripts/check_[connectors.py](http://connectors.py)
python scripts/check_[continuity.py](http://continuity.py)
python scripts/check_[bom.py](http://bom.py)
make validate-harness
'''
When validation fails, report:
- command run
- failing file
- failing rule
- affected harness
- affected circuit ID
- affected connector / pin / cavity
- likely cause
- proposed fix
---
## Review focus
Pay special attention to changes involving:
- power circuits
- ground circuits
- airbag / safety circuits
- high-voltage circuits
- splice changes
- connector cavity changes
- fuse or protection changes
- option-code variants
- files under exports/released/
For unclear safety-critical changes, stop and ask for human engineering review.
---
## Claude-specific behavior
Before making changes to released harness data, connector libraries, BOM logic,
or validation scripts:
1. inspect the affected files
2. explain the intended change
3. identify required validation commands
4. make the smallest possible edit
5. summarize engineering impact
Do not produce large tables in chat unless requested. Prefer concise summaries
with file paths and affected IDs.
| 섹션 | 목적 |
|---|---|
Project context |
Claude가 이 저장소를 일반 소프트웨어 프로젝트가 아니라 하네스 엔지니어링 데이터 저장소로 인식하게 함 |
Start here |
작업 전에 봐야 할 문서를 지정함 |
Source of truth |
엑셀, CAD export, 리포트, 라이브러리 중 무엇을 기준으로 삼을지 정함 |
Do not infer |
핀맵, 와이어 사양, 커넥터 품번 같은 위험한 추론을 방지함 |
Editing rules |
변경 범위를 작게 유지하고 추적 가능하게 만듦 |
Validation commands |
수정 후 어떤 검증을 실행해야 하는지 명확히 함 |
Review focus |
전원, 접지, 안전, HV 등 리스크 높은 변경을 강조함 |
Claude-specific behavior |
Claude Code가 무작정 수정하지 않고 먼저 분석·계획·검증하게 유도함 |
실제 엔트로픽에서도 CLAUDE.md는 200라인 이하로 유지하고, 복잡한 내용은 docs/로 빼던가 rules/로 분리하라고 권장한다.
6. Context Engineering: rules, docs
.claude/rules/
모든 규칙을 CLAUDE.md에 몰아넣으면 context가 커지고 에이전트에게 모든것이 중요하다고 알려주면 정작 중요한 것은 아무것도 없다고 받아들인다. Claude Code의 rules는 YAML frontmatter의 paths(glob 패턴도 지원된다)로 특정 파일 패턴에 범위를 걸 수 있고, paths 또는 glob 패턴이 없으면 무조건 로드된다.
경로 예시는 다음과 같다.
.claude/
└── rules/
├── backend.md
├── frontend.md
├── testing.md
└── database-migration.md
---
paths:
- "src/main/kotlin/**/*.kt"
---
# Backend Rules
- Controller에는 비즈니스 로직을 두지 않는다.
- Service는 transaction boundary를 명확히 한다.
- Repository는 JPA query method 또는 QueryDSL을 우선 사용한다.
---
paths:
- "src/**/*.tsx"
- "src/**/*.ts"
---
# Frontend Rules
- API 호출은 `src/api/client.ts`를 사용한다.
- 컴포넌트는 가능한 한 presentational/container 구조로 분리한다.
- list page는 숫자 pagination보다 infinite scroll을 우선 검토한다.
이렇게 paths를 통해 특정 파일에서만 로드되게 하면, 백엔드 관련 파일을 읽거나 수정할 때 backend.md만 로드하기 때문에 노이즈와 컨텍스트 사용량이 줄어들어 더욱 효과적이다.
특정 파일이나 디렉터리에만 적용되야 한다면 rule을 만드는게 적합하다.
| 상황 | 위치 |
|---|---|
| 모든 세션에서 반드시 알아야 함 | CLAUDE.md |
| 특정 파일·디렉터리에만 적용 | .claude/rules/ |
| 가끔 쓰는 긴 체크리스트 | .claude/skills/ |
docs/ 긴 설명은 문서로 분리
docs는 claude가 항상 자동으로 읽는 곳이라기보다 필요할 때 읽게하는 참고 문서 저장소로 사용하자.
CLAUDE.md에서는 포인팅 정보만 추가하고 클로드가 확인하게끔 유도하는 것이다.
## Important Docs
-Architecture overview: `docs/architecture.md`
-Domain definitions: `docs/domain.md`
-API error format: `docs/api/error-format.md`
-ADRs: `docs/adr/`
-Incident runbooks: `docs/runbooks/`
docs/에는 어떤 내용을 추가하면 좋을까
| 문서 | 용도 |
|---|---|
docs/adr/*.md |
중요한 기술 결정 기록 |
docs/architecture.md |
시스템 구조, 모듈 관계, 데이터 흐름 |
docs/domain.md |
핵심 도메인 개념, 용어, 상태 전이 |
docs/api/*.md |
API endpoint, request/response, error format |
docs/data-model.md |
DB 테이블, 엔티티 관계, 제약 조건 |
docs/security.md |
인증, 권한, 보안 정책 |
docs/runbooks/*.md |
장애 대응, 배포, 롤백 절차 |
# Architecture
## Domain Model
Account
-조직 단위
-여러 Subscription을 가질 수 있음
Subscription
-Account의 현재 요금제 상태
-active, trialing, past_due, canceled 상태를 가짐
Invoice
-특정 billing period에 대한 청구 문서
PaymentAttempt
-결제 시도 기록
-외부 PG 응답을 저장함
## Important Flows
### Subscription renewal
1.Scheduler가 갱신 대상 subscription을 조회
2.Invoice 생성
3.PaymentAttempt 생성
4.PG 결제 요청
5.성공 시 invoice paid 처리
6.실패 시 subscription past_due 처리
아키텍처 문서를 CLAUDE.md에 전부 몰아 넣으면 모든 세션에서 토큰을 소모한다. 대신 CLAUDE.md에는 상세 아키텍처는 docs/architecture.md 참조로 포인팅을 한다면 필요한 작업에서 claude가 알아서 해당 파일을 읽는다.
# ADR-0001: Use PostgreSQL as Primary Database
## Status
Accepted
## Context
구독, 결제, 송장 데이터는 강한 정합성이 필요하다.
## Decision
Primary database로 PostgreSQL을 사용한다.
## Consequences
-transaction 기반 결제 상태 변경이 가능하다.
-relational constraint를 적극 활용한다.
-analytics workload는 별도 warehouse로 분리할 수 있다.
7. Permission & Safety: Claude 가 어디까지 하게 할 것인가
Claude가 읽기, 파일 수정, 쉘 명령과 같은 행위를 어디까지 허용하고 차단할지 정해야 한다. 예를 들어 rm -rf, git push —force 등과 같은 위험한 명령어는 시스템적으로 차단할 수 있어야 한다.
.claude/settings.json
settings.json 에서는 다음 역할을 수행할 수 있다.
| 설정 종류 | 예시 |
|---|---|
| 권한 | 특정 명령 허용/차단 |
| hooks | 파일 수정 후 lint 실행 |
| 환경 변수 | telemetry, provider 관련 변수 |
| plugin | 팀 공통 plugin 활성화 |
| MCP 관련 승인 | 프로젝트 MCP 서버 승인 |
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(npm test)",
"Bash(npm run lint)",
"Bash(git status)",
"Bash(git diff *)",
...
],
"ask": [
"Bash(npm install *)",
"Bash(docker compose *)",
"Bash(git commit *)",
"Bash(git merge *)",
...
],
"deny": [
"Bash(git push *)",
"Bash(git push --force *)",
"Bash(curl *)",
"Bash(wget *)",
"Read(./.env.*)",
"Read(./secrets/**)",
...
]
}
}
위 예시처럼, 실행 권한처럼 “어떤 명령 실행을 막아야하고 어떤 명령은 허용해도 되는가”에 대한 정보를 적을 수 있다.
8. Verification Engineering: 에이전트가 스스로 검증하게 만들기
scripts/verify.sh 구성
#!/usr/bin/env bash
set -euo pipefail
./gradlew test
./gradlew ktlintCheck
./gradlew detekt
./gradlew build
위 스크립트를 CLAUDE.md에 연결하는 것을 잊지 말자.
## Verification
Before completing any coding task:
1. Run `./scripts/verify.sh`.
2. If it fails, inspect the output and fix the root cause.
3. Re-run `./scripts/verify.sh` after fixing.
4. If you cannot fix it, report:
- the exact command that failed,
- the relevant error output,
- the suspected root cause,
- what you changed before the failure.
5. Do not claim completion unless verification has passed or the failure is explicitly documented.
검증 루프: 실패 → 로그 해석 → 수정 → 재검증
Verification Engineering의 핵심은 단순 실행이 아니라, 실패 → 로그 해석 → 수정 → 재검증 루프이다.
기존의 우리가 하던 방식:
- Claude가 코드 수정
- 코드가 그럴듯해 보임
- “완료했습니다”라고 보고
- 사용자가 직접 실행
- 빌드 실패
Verification Engineering 도입 후:
- Claude가 코드 수정
- ./scripts/verify.sh 실행
- typecheck 실패
- 실패 로그 확인
- 원인 수정
- ./scripts/verify.sh 재실행
- 통과 후 완료 보고
완료의 정의가 전처럼 모호하지 않고, 증거 기반의 신뢰성 높은 완료 보고를 받을 수 있다.
검증 스크립트 예시: scripts/verify.sh
#!/usr/bin/env bash
set -euo pipefail
echo "=== Running verification ==="
# 1. Type check
echo "→ Type checking..."
npx tsc --noEmit
# 2. Lint
echo "→ Linting..."
npx eslint src/ --max-warnings 0
# 3. Format check
echo "→ Format check..."
npx prettier --check src/
# 4. Tests
echo "→ Running tests..."
npm test
# 5. Build
echo "→ Building..."
npm run build
echo "=== All checks passed ==="
Verification Engineering 의 핵심은 단순 실행이 아니라, 실패 → 로그 해석 → 수정 → 재검증의 자동화된 루프입니다.
기존 방식 (하네스 전):
- Claude 가 코드 수정
- 코드가 그럴듯해 보임
- “완료했습니다”라고 보고
- 사용자가 직접 실행
- 빌드 실패 ← 여기서 발견
Verification Engineering 도입 후 (하네스 후):
- Claude 가 코드 수정
./scripts/verify.sh실행 ← 자동tsc실패 ← 자동- 실패 로그 읽음 ← 자동
src/services/user.ts:42:14 - error TS2322: Type 'string' is not assignable to type 'number'.- 원인 파악:
userId변수 타입 오류 - 수정 ← 자동
./scripts/verify.sh재실행 ← 자동- 통과 ← 자동
- 완료 보고
완료의 정의가 명확해집니다:
- 이전: “코드 작성 완료”
- 이후: “
verify.sh통과 + quality gate marker + 요약 보고”
Hook 으로 자동화하면 Claude 는 검증 없이 “완료”라고 말할 수 없습니다.
Hook 으로 자동화된 검증 루프
PostToolUse hook 으로 파일을 수정할 때마다 자동으로 검증이 실행되게 할 수 있습니다:
{
"hooks": {
"PostToolUse": {
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-quality-gate.sh"
}
]
}
}
}
이렇게 하면 Claude 가 코드를 수정할 때마다:
- 자동으로 formatter 실행
- 하네스 도메인 검증 실행
- 검증 통과 시 quality gate marker 생성
- 검증 실패 시 Claude 에게 실패 이유 전달 → 수정 유도
결론: Verification Engineering 은 단순히 verify.sh 를 실행하는 것이 아니라,
Hook 을 통해 Claude 가 검증 없이 완료라고 말할 수 없는 환경을 만드는 것입니다.
9. Skills: 반복 작업을 명령화하자
스킬은 에이전트에게 반복 업무 절차를 재사용 가능한 작업 단위로 묶어둔 md 파일이다.
예를 들어, 반복되는 업무 절차 → skill로 분리하면 좋다.
---
name: review
description: Review code changes for correctness, maintainability, security, tests, and verification readiness. Use when the user asks for a code review, PR review, risk review, or change review.
---
## Task
Review the current changes.
## Steps
1. Inspect the changed files.
2. Identify correctness risks.
3. Check test coverage.
4. Check security and data handling risks.
5. Check whether `./scripts/verify.sh` should be run.
6. Return findings grouped by severity.
## Output format
### Critical
- ...
### Major
- ...
### Minor
- ...
### Suggested tests
- ...
### Verification
- State whether verification was run or should be run.
중요한 점은 frontmatter의 description 이다. Claude는 description을 보고 해당 Skill을 자동으로 쓸지 판단한다. 따라서 “무엇을 하는지”뿐 아니라 “언제 사용해야 하는지”를 같이 적어야 된다. Claude Code 문서에서도 description은 Skill 적용 판단에 쓰이며, name, description, disable-model-invocation, allowed-tools, paths 같은 frontmatter 필드를 지원한다.
Reference Skill: 배경 지식, 규칙, 도메인 컨벤션을 제공하는 Skill
---
name: api-conventions
description: API design conventions for this project. Use when designing, reviewing, or modifying API endpoints, request DTOs, response DTOs, error formats, or pagination behavior.
user-invocable: false
---
## API conventions
When modifying API endpoints:
1.Use resource-based REST paths.
2.Return errors using `ApiErrorResponse`.
3.Validate request DTOs at the boundary.
4.Do not expose internal domain exceptions directly.
5.Keep response DTOs stable unless the task explicitly requests a breaking change.
## Related references
-For error response examples, read `references/errors.md`.
-For pagination conventions, read `references/pagination.md`.
user-invocable: false는 사용자가 /api-conventions로 직접 실행할 필요는 없지만, Claude가 관련 상황에서 참고해야 하는 배경 Skill에 적합합니다. Claude Code 문서에서도 user-invocable: false는 사용자 메뉴에서는 숨기되 Claude가 관련 시 사용할 수 있는 배경 지식용 Skill에 적합하다고 설명합니다.
Reference Skill vs Task Skill
| 구분 | Reference Skill | Task Skill |
|---|---|---|
| 용도 | 배경 지식, 규칙, 도메인 컨벤션 제공 | 구체적 작업 절차 수행 |
| 사용 방법 | Claude 가 관련 작업 시 자동으로 참고 | 사용자가 /name 으로 직접 실행 가능 |
| frontmatter | user-invocable: false |
user-invocable: true (기본값) |
| 예시 | api-conventions, naming-rules |
review, write-tests, migration |
| 적합한 내용 | “우리 프로젝트는 이런 식으로 짠다” | “이 작업을 할 때 이 순서로 진행해” |
선택 가이드:
- Reference Skill — 프로젝트 전체에 적용되는 규칙, 컨벤션, 배경 지식. 사용자가 직접 실행할 필요가 없으며 Claude 가 관련 작업을 할 때 참고하도록 두는 것.
- Task Skill — 구체적인 작업 절차. 사용자가
/skill-name으로 직접 호출할 수 있어야 하며, Claude 가 관련 상황에서 자동으로 위임할 수 있는 것.
Task Skill: 구체적인 작업 절차를 수행하게 하는 Skill
---
name: write-tests
description: Write or update tests for changed behavior. Use when adding tests, improving coverage, fixing regressions, or validating new functionality.
---
## Task
Write tests for the relevant behavior change.
## Steps
1.Identify the behavior being changed.
2.Locate existing test patterns.
3.Add the smallest useful tests.
4.Prefer unit tests for pure logic.
5.Add integration tests when API, database, queue, or external boundary behavior changes.
6.Run the relevant test command.
7.Report what was tested and what remains untested.
## Rules
-Do not create superficial tests that only assert implementation details.
-Follow existing fixture and factory patterns.
-If the codebase has no test pattern for this area, propose one before adding broad new structure.
## Verification
After adding tests, run one of:
-`./scripts/verify-fast.sh`
-`./scripts/verify.sh`
-the nearest package-specific test command
Report the exact command and result.
Task Skill은 절차, 체크리스트, 출력 형식이 명확해야 한다.
CLAUDE.md에는 Skill 사용 원칙만 짧게 두자
Skill 목록 전체를 길게 설명하는 것보다, Skill 사용 원칙만 짧게 두는게 좋다.
## Skills
Use project skills for repeatable workflows.
-Use `/review` for code or PR review.
-Use `/write-tests` when adding or updating tests.
-Use `/debug-incident` when investigating logs, failures, or incidents.
-Use `/migration` for database, API, schema, or framework migrations.
-Use `/summarize-changes` when preparing commit or PR summaries.
-Use `/release` only when explicitly asked to prepare a release.
Keep general project rules in `CLAUDE.md`.
Keep workflow-specific procedures in `.claude/skills/<skill-name>/SKILL.md`.
10. Hooks: 반드시 실행되어야 하는 자동화
Hook이란 무엇인가
- Claude Code LifeCycle 중 특정 시점에 실행되는 Shell command
- 프롬프트 지침보다 강한 자동화 규칙
Hook은 보통 repo 안의 .claude/settings.json에 둔다. 이 파일은 프로젝트 단위로 공유 가능하다. 개인 전용 설정은 ~/.claude/settings.json, 로컬 전용 설정은 .claude/settings.local.json에 둔다.
- 예시 설정
{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-harness-files.sh" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-quality-gate.sh" }, { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-tool-use.sh" } ] } ], "Notification": [ { "matcher": "permission_prompt|idle_prompt", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/notify.sh" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/stop-log.sh" } ] } ] } }
Hook이 적합한 경우
| 상황 | 적합 여부 |
|---|---|
| 파일 수정 후 formatter 실행 | 적합 |
.env 수정 차단 |
적합 |
| lint after edit | 적합 |
| 세션 종료 시 로그 저장 | 적합 |
| Slack 알림 전송 | 적합 |
| 테스트 실패 원인 추론 | 부적합 |
| PR 리뷰 관점 분석 | 부적합 |
.claude/hooks/ 디렉터리 구조
.claude/
└── hooks/
├── protect-harness-files.sh # PreToolUse: 보호 파일 수정 차단
├── post-edit-quality-gate.sh # PostToolUse: 편집 후 품질 검증
├── audit-tool-use.sh # PostToolUse: 도구 사용 감사 로그
├── notify.sh # Notification: 알림 전송
└── stop-log.sh # Stop: 세션 종료 로그
protect-harness-files.sh — 보호 파일 수정 차단
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# 하네스 엔지니어링 보호 패턴
PROTECTED_PATTERNS=(
"/.env"
"/.env."
"/data/connectors/master.csv"
"/data/wire-specs/released/"
"/manufacturing/released/"
"/bom/released/"
"/plm/export/"
)
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
cat <<JSON
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Protected harness engineering file:$FILE_PATH. Create a change request or edit a staging file instead."
}
}
JSON
exit 0
fi
done
exit 0
post-edit-quality-gate.sh — 편집 후 품질 검증
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
exit 0
fi
# 포맷팅
case "$FILE_PATH" in
*.json) npx prettier --write "$FILE_PATH" 2>/dev/null || true ;;
*.yaml|*.yml|*.md) npx prettier --write "$FILE_PATH" 2>/dev/null || true ;;
*.py) python -m black "$FILE_PATH" 2>/dev/null || true ;;
*.ts|*.tsx) npx prettier --write "$FILE_PATH" 2>/dev/null || true ;;
esac
# 하네스 도메인 검증 (harness-lint 가 없으면 스킵)
if command -v harness-lint >/dev/null 2>&1; then
if !harness-lint "$FILE_PATH" > /tmp/harness-lint.out 2>&1; then
REASON=$(sed 's/"/\\"/g' /tmp/harness-lint.out)
cat <<JSON
{
"decision": "block",
"reason": "Harness lint failed after editing$FILE_PATH:\\n$REASON"
}
JSON
exit 0
fi
fi
# 성공 마커
mkdir -p "$CLAUDE_PROJECT_DIR/.claude/audit"
touch "$CLAUDE_PROJECT_DIR/.claude/audit/last-quality-ok"
exit 0
audit-tool-use.sh — 도구 사용 감사 로그
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
mkdir -p "$CLAUDE_PROJECT_DIR/.claude/audit"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIMESTAMP |$TOOL |$FILE_PATH" >> "$CLAUDE_PROJECT_DIR/.claude/audit/tool-use.log"
exit 0
stop-log.sh — 세션 종료 로그
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(cat)
ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
if [ "$ACTIVE" = "true" ]; then
exit 0
fi
if [ ! -f "$CLAUDE_PROJECT_DIR/.claude/audit/last-quality-ok" ]; then
cat <<JSON
{
"decision": "block",
"reason": "Quality gate not passed. Run post-edit quality checks before stopping."
}
JSON
exit 0
fi
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
LOG_FILE="$CLAUDE_PROJECT_DIR/.claude/audit/session-end.log"
echo "$TIMESTAMP | session ended | quality gate: OK" >> "$LOG_FILE"
exit 0
PreToolUse: 실행 전에 막기
Claude가 도구를 실행하기 전에 실행된다.
- 예시:
- 특정 파일 수정 차단
- bash 도구 사용 시, block 명령어 검사
- 예시 설정
#!/bin/bash set -euo pipefail INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') PROTECTED_PATTERNS=( "/.env" "/.env." "/data/connectors/master.csv" "/data/wire-specs/released/" "/manufacturing/released/" "/bom/released/" "/plm/export/" ) for pattern in "${PROTECTED_PATTERNS[@]}"; do if [[ "$FILE_PATH" == *"$pattern"* ]]; then cat <<JSON { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Protected harness engineering file blocked:$FILE_PATH. Create a change request or edit a staging file instead." } } JSON exit 0 fi done exit 0 - 특정 파일들을 수정하려하면 차단시키는 쉘 스크립트다.
PostToolUse: 실행 후 검증하기
Claude가 파일을 수정한 뒤 자동으로 실행
주의할 점은, 같은 event에 여러 hook handler를 넣으면 병렬 실행되기 때문에 format 후 lint 처럼 순서가 중요한 작업은 하나의 script안에서 순차 실행하는게 안전하다.
- 예시:
- lint
- test
- schema validation
- 예시 설정 (format on edit + lint after edit)
#!/bin/bash set -euo pipefail INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then exit 0 fi case "$FILE_PATH" in *.json) npx prettier --write "$FILE_PATH" ;; *.yaml|*.yml|*.md|*.ts|*.tsx) npx prettier --write "$FILE_PATH" ;; *.py) python -m black "$FILE_PATH" ;; esac # 하네스 도메인 lint 예시: # - connector_id 존재 여부 # - cavity 중복 여부 # - wire gauge 허용 범위 # - splice rule 위반 # - released BOM 참조 위반 if command -v harness-lint >/dev/null 2>&1; then if !harness-lint "$FILE_PATH" > /tmp/harness-lint.out 2>&1; then REASON=$(cat /tmp/harness-lint.out | sed 's/"/\\"/g') cat <<JSON { "decision": "block", "reason": "Harness lint failed after editing$FILE_PATH. Fix the violations before continuing.\\n$REASON" } JSON exit 0 fi fi exit 0 PostToolUse에서decision: block을 반환하면 Claude에게 전달되고 피드백을 확인하고 수정을 시도할 수 있다.
Notification: 필요한 순간 알리기
Claude가 사용자 입력이나 승인을 기다릴 때 알림을 보냄
- 예시:
- permission request 알림
- idle 상태 알림
- Slack / Desktop Notification 구성 가능
- 예시 설정
#!/bin/bash set -euo pipefail INPUT=$(cat) TYPE=$(echo "$INPUT" | jq -r '.notification_type // "unknown"') MESSAGE=$(echo "$INPUT" | jq -r '.message // "Claude Code notification"') # macOS desktop notification if command -v osascript >/dev/null 2>&1; then osascript -e "display notification\"$MESSAGE\" with title\"Claude Code:$TYPE\"" fi # Slack webhook 예시: SLACK_WEBHOOK_URL은 로컬 환경변수로만 관리 if [ -n "${SLACK_WEBHOOK_URL:-}" ]; then curl -sS -X POST \ -H 'Content-Type: application/json' \ --data "{\"text\":\"Claude Code [$TYPE]:$MESSAGE\"}" \ "$SLACK_WEBHOOK_URL" >/dev/null fi exit 0 - Notification Hook은 PostToolUse와 같이 차단이나 수정용이 아니라, 알림이나 외부 서비스 전달 같은 용으로 쓰인다.
Stop: 작업 종료 시 처리하기
Claude가 응답을 끝내기 전에 실행함
- 예시:
- 작업 로그 저장
- 세션 요약 저장
- 품질 게이트 미통과 시 종료 차단
- 예시 설정 (종료 조건 검수)
#!/bin/bash set -euo pipefail INPUT=$(cat) ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false') # 무한 루프 방지 if [ "$ACTIVE" = "true" ]; then exit 0 fi if [ ! -f "$CLAUDE_PROJECT_DIR/.claude/audit/last-quality-ok" ]; then cat <<JSON { "decision": "block", "reason": "Quality gate marker is missing. Run the post-edit harness lint and summarize the result before stopping." } JSON exit 0 fi exit 0 - Claude가 “완료했습니다”라고 말했지만 품질 게이트 marker가 없으면 종료를 막을 수 있다.
Stophook에서도decision: block+reason을 반환해 Claude가 계속 작업하도록 할 수 있다.
11. MCP: 외부 시스템까지 포함
MCP는 Claude가 외부 시스템을 읽고, 경우에 따라 작업까지 수행하게 해주는 연결 규격이다. MCP를 통해 이슈 트래커, Postgresql, Slack, Github 같은 외부 도구의 정보를 직접 읽고 작업할 수 있다.
MCP를 사용하면 다음과 같이 바뀐다.
1. Jira 이슈를 브라우저에서 연다
2. 내용을 복사한다
3. Claude Code에 붙여넣는다
4. 관련 GitHub PR이나 Sentry 로그도 다시 복사한다
5. Claude에게 구현을 요청한다
Claude Code에게 요청:
"Jira ENG-4521을 읽고, 관련 Sentry 에러를 확인한 뒤,
repo에서 수정하고 GitHub PR 초안을 만들어줘."
간단한 예시: Github + Sentry + DB
프로덕션에서 로그인 실패 에러가 발생했을 때, MCP가 있다면 다음과 같이 요청하면 된다.
"Sentry에서 최근 AUTH-500 에러를 확인하고,
관련 stack trace를 바탕으로 auth-service에서 원인을 찾아줘.
DB는 schema만 확인하고 실제 user data는 조회하지 마."
이렇게 되면 Claude가 Sentry → repo → DB schema를 연결해서 추론할 수 있다는 점이다. MCP가 없을 때는 직접 Sentry가서 에러 복사한다음 Claude에게 붙여넣기하고 DB Schema 복사해서 붙여넣기 하고.. 이런 짓을 안해도 된다.
MCP 로 작업할 때 Claude 의 단계별 행동
MCP 가 없었을 때:
1. 사용자가 Sentry 접속 → 에러 복사
2. GitHub 접속 → 관련 코드 복사
3. DB Schema 복사
4. Claude 에게 붙여넣기
5. Claude 분석 → 해결책 제안
MCP 가 있을 때 (Claude 가 직접 수행):
단계 1 — Sentry MCP 로 에러 조회
Claude: "Sentry 에서 최근 AUTH-500 에러 5 건 조회"
→ MCP(sentry) 호출
→ Sentry API 로 에러 로그 조회
→ stack trace, 발생 빈도, 영향 받은 사용자 수 수집
단계 2 — repo 에서 관련 코드 검색
Claude: "auth-service/src/auth.ts 에서 AUTH-500 관련 코드 확인"
→ Read(src/auth.ts) 호출
→ 에러 발생 지점 식별
→ 관련 함수 호출 체인 추적
단계 3 — DB Schema 확인 (데이터는 조회하지 않음)
Claude: "user_sessions 테이블 schema 확인"
→ MCP(db-schema) 호출
→ 테이블 구조, 인덱스, 제약 조건 확인
→ 실제 user data 는 조회하지 않음 (read-only)
단계 4 — 원인 분석
Sentry 로그: "session expired" 에러가 3 배 증가
auth.ts: 세션 만료 체크 로직이 오후 3 시에만 실행
DB schema: user_sessions 에 last_active_at 인덱스 없음
→ 원인: 세션 만료 체크가 실시간이 아니라 배치로 실행되어,
만료된 세션으로 계속 로그인 시도 발생
단계 5 — 해결책 제안 + PR 생성
Claude: "해결책 제안"
1. 세션 만료 체크를 실시간으로 변경
2. user_sessions.last_active_at 에 인덱스 추가
3. GitHub PR 생성
→ MCP(github-pr) 호출 → 브랜치 생성, 커밋, PR 생성
전체 소요:
- MCP 없을 때: 15-20 분 (수동 복사/붙여넣기)
- MCP 있을 때: 2-3 분 (자동 조회 → 분석 → PR)
중요: 각 단계에서 Claude 는 MCP 서버의 권한 범위 내에서만 작업합니다. db-schema MCP 는 read-only 이므로 실제 user data 를 조회할 수 없습니다.
가장 중요한 권한 분리!
MCP는 우리에게 편리성을 제공하지만 권한을 제대로 분리하지 못하면 치명적인 보안 위험이 있다.
예를 들어 github token 권한을 github-read MCP(issue, pr 읽기 권한), github-pr MCP(branch/pr 생성, commit push 권한), github-admin MCP(merge, release 권한) 이런식으로 쪼개서 사용하는 것도 방법이다.
그리고 하네스(settings.json, hook 등)에서 권한은 다음과 같이 이중으로 제한하면 더욱 안전하다.
- 읽기 작업 → 자동 허용
- PR 생성 → 조건부 허용
- merge/release → 명시 승인 필요
- repo 설정 변경 → 금지 또는 별도 break-glass
MCP 권한 분리: 실제 설정 예시
.mcp.json — 권한 분리된 MCP 서버 정의
{
"mcpServers": {
"github-read": {
"type": "http",
"url": "https://mcp.company.com/github",
"headers": {
"Authorization": "Bearer ${GITHUB_READ_TOKEN}"
},
"description": "Read-only: issues, PRs, code browsing"
},
"github-pr": {
"type": "http",
"url": "https://mcp.company.com/github",
"headers": {
"Authorization": "Bearer ${GITHUB_PR_TOKEN}"
},
"description": "Branch creation, PR creation, commit push"
},
"db-schema": {
"command": "node",
"args": ["./tools/mcp/db-schema-server.js"],
"env": {
"DATABASE_URL": "${READONLY_SCHEMA_DATABASE_URL}"
},
"description": "Read-only schema inspection"
},
"sentry": {
"type": "http",
"url": "https://mcp.company.com/sentry",
"headers": {
"Authorization": "Bearer ${SENTRY_TOKEN}"
},
"description": "Error log inspection"
}
}
}
.claude/settings.json — MCP 연동 권한 제어
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "ask",
"allow": [
"Bash(npm test)",
"Bash(npm run lint)",
"Bash(git status)",
"Bash(git diff *)",
"MCP(github-read)",
"MCP(db-schema)",
"MCP(sentry)"
],
"ask": [
"MCP(github-pr)",
"Bash(git commit *)",
"Bash(git push *)",
"Bash(npm install *)"
],
"deny": [
"MCP(github-admin)",
"Bash(git push --force *)",
"Bash(curl *)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
}
}
권한 분리 원칙:
| MCP 서버 | 권한 | 허용 작업 |
|---|---|---|
github-read |
자동 허용 | 이슈/PR 조회, 코드 검색 |
db-schema |
자동 허용 | 스키마 조회 (데이터는 조회 불가) |
sentry |
자동 허용 | 에러 로그 조회 |
github-pr |
조건부 승인 | 브랜치 생성, PR 생성, commit push |
github-admin |
금지 | merge, release, repo 설정 변경 |
/context 명령어로 컨텍스트 점검
각 Skill 과 MCP 서버는 세션 시작 시 자동으로 컨텍스트에 로드됩니다. 사용하지 않는 것들이 계속 로드되어 있으면:
- 토큰 낭비 — 매 메시지마다 불필요한 컨텍스트 전송
- 응답 속도 저하 — 컨텍스트가 길수록 처리 시간 증가
- 모델 집중도 분산 — 관련 없는 정보가 노이즈가 됨
현재 로드 중인 컨텍스트 확인:
/context
출력 예시:
Active context:
Rules: 3 (backend.md, frontend.md, testing.md)
Skills: 5 (review, write-tests, migration, api-conventions, debug)
MCP Servers: 4 (github-read, db-schema, sentry, github-pr)
Total tokens: ~18,500
Disabled:
Skills: 2 (release, security-reviewer)
MCP Servers: 1 (github-admin)
사용하지 않는 Skill 비활성화:
/context disable skill release
사용하지 않는 MCP 서버 비활성화:
/context disable mcp github-admin
다시 활성화:
/context enable skill release
/context enable mcp github-admin
정리 주기:
- 새 프로젝트 시작 시: 불필요한 Skill/MCP 즉시 비활성화
- 주 1 회:
/context로 컨텍스트 사용량 점검 - 기능 변경 시: 관련 없는 Reference Skill 은
user-invocable: false로 전환
.mcp.json
프로젝트 단위 MCP 설정 파일이다. 중요한 점은 직접 secret 값을 넣지 말고, 환경 변수를 사용하는 것이다.
{
"mcpServers": {
"github-read": {
"type": "http",
"url": "https://mcp.company.com/github-read",
"headers": {
"Authorization": "Bearer${GITHUB_READ_TOKEN}"
}
},
"db-schema": {
"command": "node",
"args": ["./tools/mcp/db-schema-server.js"],
"env": {
"DATABASE_URL": "${READONLY_SCHEMA_DATABASE_URL}"
}
}
}
}
12. Subagents: context 를 분리해서 전문 작업자 만들기
| 구분 | 메인 대화 | subagent |
|---|---|---|
| 역할 | 목표 설정, 의사결정, 최종 구현 방향 | 탐색, 리뷰, 로그 분석, 테스트 작성 |
| context | 깨끗하게 유지 | 대량 파일·로그·검색 결과 처리 |
| 결과물 | 최종 판단, 구현 지시, 승인 | 요약, 발견사항, 권고안 |
| 적합한 작업 | 설계 결정, 요구사항 정리, 최종 변경 | code review, test failure 분석, security scan |
| 위험 | context 오염, 장기 대화의 집중력 저하 | 너무 넓은 권한 부여 시 불필요한 변경 |
Claude Code의 subagent는 메인 대화와 분리된 context window에서 동작한다. 메인 context에서는 감독 관리를 수행하고 subagent를 통해 검색 결과, 로그, 파일 내용처럼 메인 context를 오염시킬 수 있는 대량 정보를 별도 컨텍스트에서 처리하는 방식으로 사용하면 기존 context 오염을 방지하고 더 효율적인 작업을 할 수 있다.
Custom subagent를 만드는 이유
Claude에서도 Explore, Plan 등과 같은 기본 subagent가 있다. 하지만 우리 프로젝트에 적합하고 필요한 서브에이전트들은 우리가 직접 만드는게 좋다.
예를 들어, 코드 리뷰할 때 다음과 같이 매번 프롬프트를 작성한다고 했을 때:
Review this diff for correctness, missing tests, security risks,
unnecessary scope, and compatibility with our test harness conventions.
위 규칙을 다음 subagent md로 저장하면 Claude가 description을 통해 subagent로 위임하여 처리한다.
.claude/agents/code-reviewer.md예시--- name: code-reviewer description: Reviews code changes for correctness, missing tests, security risks, excessive scope, and harness compatibility. Use proactively after code changes. tools: Read, Grep, Glob, Bash model: inherit --- You are a senior code reviewer focused on correctness, maintainability, and test harness safety. When invoked: 1. Inspect the current git diff. 2. Identify changed files and related tests. 3. Review only the relevant scope. 4. Do not modify files. Review checklist: - Correctness regressions - Missing or weak tests - Security risks - Excessive scope creep - Hidden coupling with test harnesses - Mock/stub misuse - Flaky test risk - Backward compatibility - Error handling - Observability and diagnosability Return results in this format: ## Critical Issues that must be fixed before merge. ## Warnings Issues that should be fixed soon. ## Suggestions Optional improvements. ## Missing tests Specific tests that should be added. ## Final recommendation Approve, approve with changes, or block.- 여기서 중요한 점은 tools에 Edit 권한을 주지 않고 검토자 역할로 제한하였다.
서브 에이전트로 보내면 좋을 작업들:
- 로그 분석
- 코드베이스 탐색
- 테스트 실패 원인 조사
- diff review
- security review
- coverage gap 분석
좋은 사용 프롬포트 예시:
Use the code-reviewer subagent to review this diff for:
- correctness
- missing tests
- security risks
- excessive scope
- harness compatibility
Return only actionable findings grouped by severity.
Subagent 없을 때 vs 있을 때
Subagent 없을 때:
- 메인 대화에서 git log 읽음
- 관련 파일 20 개 읽음
- 테스트 실패 로그 500 줄 읽음
- → 메인 context 가 5 만 토큰으로 포화
- → Claude 집중력 저하, 중요한 디테일 놓침
Subagent 있을 때:
- 메인 대화: “test failure 분석해줘” 지시
- code-analyzer subagent 에 위임
- subagent 가 500 줄 로그 + 20 개 파일 분석
- subagent 가 “원인은 X, 제안은 Y” 요약 반환
- 메인 context 는 깨끗하게 유지
subagent 위임 방법
Claude Code(메인 에이전트) 가 Agent 도구로 subagent 를 호출합니다.
위임 흐름:
사용자: "이 PR 리뷰해줘"
Claude Code(메인 에이전트):
→ Agent(code-reviewer) 호출
프롬프트: "Current git diff 를 correctness, missing tests,
security risk, excessive scope 관점에서 리뷰해줘."
← code-reviewer subagent 가 분석 완료하고 반환
Claude Code(메인 에이전트):
← subagent findings 수신
→ 사용자에게 findings 전달
실제 위임 프롬프트 예시:
Use the code-reviewer subagent to review the current git diff.
Focus on:
- correctness regressions
- missing or weak tests
- security risks
- excessive scope creep
- harness compatibility
Return only actionable findings grouped by severity.
이게 메인 에이전트가 subagent 에게 보내는 실제 프롬프트입니다.
subagent 결과물 예시
code-reviewer subagent 의 실제 반환 예시:
## Critical
- [src/auth.ts:42] `user.password` 를 plain text 로 로그에 출력
→ `logger.debug('user login', { userId })` 로 수정해야 함
## Warnings
- [src/auth.ts:89] `refreshToken` 만료 체크가 1 분 오차 있음
→ `Date.now() + 60_000` 대신 `token.expiry - Date.now() < 0` 사용 권장
## Missing tests
- `AuthController.refresh()` 의 만료 토큰 경로를 테스트하는 케이스 없음
- `AuthService.login()` 의 rate limiting 테스트 없음
## Final recommendation
Approve with changes — Critical 1 건 수정 후 merge 가능.
Skill, MCP는 Context를 먹는다
/context 명령어를 통해 현재 불필요하게 Context를 먹고 있는 Skill, MCP가 있는지 점검하고 사용하지 않는것들은 주기적으로 점검해서 정리하자.
개발자라는 직업은 계속 이동중이다.
“AI 시대의 개발자는
'코드를 많이 치는 사람'에서 ’에이전트가 잘 일하도록레일·규칙·검증·운영체계를 설계하는 사람(하네스 엔지니어)’으로 무게중심이 이동 중이다.” — OpenAI
- CLAUDE.md/AGENTS.md 및 docs 지속적 업데이트
- Hooks 구현
- 검증 루프 설계 실습
- AI가 잘 따라올 수 있는 아키텍처 유지
- 비즈니스 요구사항이 추가/변경될 때마다 프로젝트 구조 발전
- 오래되거나 사용하지 않는 규칙 및 문서 제거 - 가비지 컬렉션
하네스 가비지 컬렉션: 사용하지 않는 규칙과 문서 정리
하네스 구성 요소는 시간이 지날수록 불필요한 것이 쌓입니다. 새 기능이 추가되면서 오래된 규칙이 무효해지고, docs 에는 한 번도 읽히지 않는 문서가 쌓입니다.
정리 주기 (분기별 권장):
1. .claude/rules/ 정리
paths패턴이 더 이상 매칭되지 않는 규칙 삭제- 여러 규칙이 중복되는 내용 통합
- 실제 위반 사례가 한 번도 보고되지 않은 경미한 규칙 비활성화
2. .claude/skills/ 정리
/context
user-invocable: false인 Reference Skill 중 관련 도메인에서 한 번도 언급되지 않은 것 삭제- 6 개월 이상 실행되지 않은 Task Skill 비활성화 (
/context disable skill <name>)
3. .claude/agents/ 정리
- custom subagent 중 실제로 위임된 적이 없는 것 삭제
tools권한이 과도하게 부여된 agent 는 권한 축소
4. docs/ 정리
- 1 년 이상 접근 기록이 없는 문서 아카이브 (다른 곳으로 이동)
- ADR 중 대안으로 선택되지 않은 결정 기록은
docs/adr/archive/로 이동 CLAUDE.md에서 포인팅만 하고 실제로 존재하지 않는 문서 링크 제거
5. .mcp.json 정리
/context
- 비활성화된 MCP 서버 삭제
- 더 이상 연결되지 않는 외부 서비스 MCP 서버 제거
정리 원칙:
“하네스의 모든 구성 요소는 ’모델이 혼자 못하는 것’에 대한 가정을 인코딩한다. 모델이 좋아지면 가정을 재검증해야 한다.” — Anthropic
정리는 단순한 정리 작업이 아니라, 모델 능력 향상에 따른 하네스 단순화의 일환입니다.