컨텍스트 엔지니어링을 넘은 하네스 엔지니어링 시대에 맞추어 Claude를 적극적으로 활용하고 있다. 이에 시행착오를 거쳐가면서 팀에서 사용 가능한 범용 Agent를 만들었고, 이를 통해 현재도 굉장히 빠르고 정확하게 개발을 하고 있다. Claude를 사용할 때 가장 중요한 것은 토큰을 적게 사용하면서 AI가 효율적으로 코드를 짤 수 있도록 하는 것인데, 어떻게 만들었는지 공유하고자 한다.
직접 생성한 팀의 Java 백엔드 개발 자동화 플러그인은 1)Java 프로젝트에서 Claude Code로 티켓 분석 및 요구사항 구체화 → 아키텍처 설계 → 코드 분석 및 생성 → 테스트 및 커버리지 자동 검증 → 코드 리뷰 → MR 까지 자동 처리하거나, 2)신규 프로젝트를 초기화하는 기능을 가지고 있다.
작업 project 루트 폴더 하위에 docs/domain-knowledge/ 폴더를 생성하고 도메인 지식을 담은 Markdown 파일을 구성하면, 에이전트가 이를 바탕으로 작업을 수행한다. 이렇게 파일을 미리 만들어두는 이유는 아래에서 나올 토큰 절약 방법 중 하나인 lazy-loading 기법을 위해서이다.
01-project-structure.md02-domain-model.md03-api-design.md04-database.md05-configuration.md06-conventions.md
cse-agent/
├── agents/ ← 서브 에이전트 (sonnet)
│ ├── codebase-explorer.md ← 코드 탐색 (컨텍스트 격리)
│ └── pr-writer.md ← 리뷰 + MR 생성 (컨텍스트 격리)
├── skills/ ← 스킬 (슬래시 커맨드)
│ ├── dev-pipeline/ ← 전체 파이프라인 오케스트레이션
│ ├── init-project/ ← 신규 프로젝트 초기화
│ ├── analyze-ticket/ ← 티켓 분석
│ ├── triage/ ← 복잡도 판정
│ ├── explore-codebase/ ← 코드 탐색
│ ├── design-code/ ← 구현 설계
│ ├── generate-code/ ← 코드 생성
│ ├── db-migration/ ← Flyway 마이그레이션
│ ├── write-tests/ ← 테스트 생성
│ ├── pr-review/ ← 자체 리뷰
│ ├── write-pr/ ← MR 생성
│ └── start/ ← 로컬 환경 세팅
└── rules/ ← 프로젝트 규칙
├── branch-strategy.md ← Git 브랜치 전략
├── coding-convention.md ← 코딩 컨벤션
└── verification.md ← 검증 규칙

플러그인은 Claude Code에서 제공하는 확장 기능으로, 한 번 만들어두면 팀 전체가 공유해서 사용할 수 있다. 설치 명령어 하나로 동일한 자동화 파이프라인을 팀원 누구나 바로 쓸 수 있게 된다.
다만 도메인 컨텍스트는 프로젝트마다 다르기 때문에, CLAUDE.md나 docs/ 폴더는 각자 정의해야 한다. 그래서 공통으로 재사용할 수 있는 부분은 template/ 폴더에 모아두고, 각자 복사해서 자기 프로젝트에 맞게 커스텀해서 쓸 수 있도록 해놨다.
참고로 아래와 같은 문서들을 AI가 자동으로 생성하고 또 이를 참고하며 작업이 이루어진다.

/dev-pipeline — 티켓 → MR 자동화PRD/아키텍처 문서가 아니더라도 티켓 텍스트 하나로도 end-to-end 개발 파이프라인을 실행할 수 있도록 구현했다.
/dev-pipeline
비즈톡 API를 활용한 알림톡 발송 방식을 DB INSERT에서 API 직접 호출로 전환해주세요.
BiztalkApiClient 구현하고, 실패 시 SMS fallback 처리, 발송 이력 DB 저장도 필요합니다.
파이프라인 흐름:
티켓 텍스트 or 프로젝트 문서(PRD, 아키텍처 등)
│
▼
┌────────────────┐
│ analyze-ticket │
│ │ 문서 - 명확하지 않은 요구사항은 사용자 질문 루프로 구체화
│ │ 텍스트 - 단순 질문 VS 코드 작업 판별
│ │ 코드 작업인 경우 티켓 → 기술 스펙 변환
│ │ ⤷ ticket.md 생성
└────────┬───────┘
▼
┌────────────────┐
│ triage │ 5가지 조건으로 복잡도 판정
│ │ ⤷ light / full 모드 결정
└────────┬───────┘
│
├─── light ─────────────────────┐
│ (explore 스킵, design 간소화) │
│ │
│ full │
▼ ▼
┌────────────────┐ ┌────────────────┐
│ explore-codebase│ │ design-code │ ticket.md → 간소화 설계
│ ← sonnet 서브 │ │ │ ⤷ design.md + tasks/00-*.md
│ ⤷ exploration.md│ └────────┬───────┘
└────────┬───────┘ │
▼ │
┌────────────────┐ │
│ design-code │ ticket.md + │
│ │ exploration.md → │
│ │ 전체 구현 설계 및 사용자 피드백 루프
│ │ tasks 폴더에 단계별 태스크로 나누어 순차/병렬 실행
│ ⤷ design.md │
│ ⤷ tasks/*.md │ │
└────────┬───────┘ │
│ │
├───────────────────────────────┘
▼
┌────────────────┐
│ generate-code │ tasks/*.md 기반 코드 생성
│ │ ⤷ Java 소스 파일 + 태스크별 자동 git commit
│ │ ⤷ generated.json (생성 파일 목록)
└────────┬───────┘
▼
┌────────────────┐
│ db-migration │ Entity 변경 감지 시 자동 실행
│ │ ⤷ Flyway SQL 마이그레이션 파일
└────────┬───────┘
▼
┌────────────────┐
│ write-tests │ generated.json + design.md 기반
│ │ ⤷ JUnit5 테스트 (커버리지 70%+ 달성 루프)
└────────┬───────┘
▼
┌────────────────┐
│ code-review & │
│ write-pr │ ← sonnet 서브에이전트
│ │ 자체 리뷰 체크리스트 검증 → MR 생성
└────────┬───────┘
▼
MR URL
산출물 흐름 요약:
ticket.md → exploration.md → design.md + tasks/*.md → generated.json → 테스트 → MR
(스펙) (코드 분석) (설계 + 태스크) (생성 파일 목록)
각 단계는 이전 단계의 산출물만 읽고, 불필요해진 산출물은 다시 읽지 않아 토큰을 절약한다.
메인 에이전트(opus)가 모든 단계를 직접 수행하면 컨텍스트 윈도우가 빠르게 소진된다. 코드 탐색과 MR 생성처럼 대량의 파일을 읽어야 하는 단계는 sonnet 서브 에이전트에 위임하여 메인의 컨텍스트를 보존한다.
| 에이전트 | 모델 | 역할 | 왜 분리? |
|---|---|---|---|
codebase-explorer | sonnet | 코드 탐색 → exploration.md | 수십 개 파일을 읽어야 하는 탐색 작업 격리 |
pr-writer | sonnet | 자체 리뷰 + MR 생성 | 전체 diff 분석을 메인 컨텍스트 밖에서 처리 |
서브 에이전트 실패 시 메인이 직접 실행하여 fallback한다.
모든 티켓을 동일한 무게로 처리하지 않는다. triage 단계에서 5가지 조건(파일 수, 패턴 재사용, DB 변경, 의존성, 레이어 수)을 평가하여 light/full 모드를 자동 결정한다.
| Light 모드 | Full 모드 | |
|---|---|---|
| 대상 | CRUD, 단순 FIX 등 | 신규 기능, 복잡한 변경 |
| explore-codebase | 스킵 | sonnet 서브에이전트 실행 |
| design-code | 간소화 | 전체 설계 + 피드백 루프 |
| 효과 | 시간 및 토큰 절약 | 정확도 우선 |
파이프라인 전체가 아닌, 필요한 단계만 개별 실행할 수 있다.
| 스킬 | 명령 | 설명 |
|---|---|---|
| analyze-ticket | /analyze-ticket | 티켓이나 텍스트를 바탕으로 요구사항 파일인 ticket.md 생성 |
| triage | /triage | 요구사항 복잡도 판정 (light / full) |
| explore-codebase | /explore-codebase | 프로젝트 코드 탐색 후 exploration.md 생성 |
| design-code | /design-code | 아키텍처 설계도인 design.md 파일과 실제 구현 상세 설계가 있는 tasks/*.md 생성 |
| generate-code | /generate-code | 코드 탐색 결과를 바탕으로 코드 생성, 태스크 별로 자동 커밋 |
| db-migration | /db-migration | Entity 변경이 발생하면 Flyway SQL 생성 |
| write-tests | /write-tests | JUnit5 테스트와 커버리지 70% 이상 될때까지 반복 |
| pr-review | /pr-review | 자체 리뷰 체크리스트 검증 |
| write-pr | /write-pr | 커밋 내역에 대한 MR 설명과 MR 자동 생성 |
스킬을 이렇게 잘게 쪼갠 데는 이유가 있다.
특히 코드 탐색(explore-codebase)과 설계(design-code)를 분리한 것이 핵심이다. 두 작업은 성격 자체가 다른데, 탐색은 Grep/Glob/Read로 기존 코드를 파악하는 입력 중심 작업이고, 설계는 design.md와 tasks/를 만들어내는 출력 중심 작업이다. 이 둘을 한 스킬에 묶으면 길이가 길어져서 AI가 중간 지시를 흘리기 쉽고 탐색 결과를 재활용하기도 어려워지므로, 분리해두면 탐색 결과(exploration.md)는 그대로 두고 설계만 다시 실행할 수 있어 훨씬 유연하다.
| 규칙 | 핵심 내용 |
|---|---|
| branch-strategy | 보호 브랜치 규칙, feature/hotfix 브랜치 생성 절차 |
| coding-convention | 기존 코드 스타일 준수, 외부 API는 @Transactional 밖, 개인정보 마스킹 |
| verification | 증거 없이 완료 주장 금지, 테스트 통과 결과 필수 |
Rules 폴더가 필요한 이유는, AI에게 코드를 맡겼을 때 가장 자주 발생하는 문제가 기술적인 오류가 아니라 팀 규칙을 모르고 어기는 것이기 때문이다. 예를 들어 외부 API 호출을 트랜잭션 안에 넣거나, 개인정보를 로그에 그대로 출력하는 식의 실수들이 존재하는데 이런 규칙들은 코드베이스만 봐서는 파악하기 어렵고 그렇다고 매번 프롬프트에 일일이 적어주기도 번거롭다.
Rules 폴더에 명시적으로 정의해두면 Claude가 작업할 때마다 자동으로 참조하여, 따로 지시하지 않아도 팀 컨벤션에 맞는 코드를 생성한다.
에이전트로 개발을 하며 느낀점은, 너무 많은 컨텍스트와 지시 사항들을 써놓을 경우 AI가 내가 지시해놓은 규칙을 따르지 않는다는 것이다. 예를 들어 자동으로 테스트 커버리지를 돌리며 70% 이상 넘을 때 까지 테스트들을 추가해야 하는데 그냥 넘어가버렸다.
이렇게 정보는 다 알고 있으나 엉뚱한 짓을 하는 경우가 종종 있는데, 이를 위해서 필요한 것이 바로 컨텍스트 엔지니어링을 넘은 '하네스 엔지니어링'이다. 단순히 에이전트가 규칙을 어겼을 때 프롬프트/스킬에 규칙을 추가하지 않고 마구를 씌우는 것처럼 AI를 통제하고 훈련시킬 수 있는 장비, 즉 그 규칙을 어겼을 때 실패하도록 시스템을 바꿔 강제해야 하는 것이다.
☁️ 하네스 엔지니어링 기둥 종류
1. 컨텍스트 파일 배치 및 규칙 정의
2. Hook을 이용해 규칙을 시스템에 내장: 자동으로 막고, 실패했을 경우 자동으로 고치며 교정을 해나가는 루프를 돈다.
3. 지속적 피드백 루프 : 기존 코드에 나쁜 패턴이 있으면 그대로 따라하게 되므로, 주기적으로 자동으로 청소되게 하는 시스템이 필요하다. (ex)코딩 규칙 위반 감지 / 중복 코드 리팩토링 PR 자동 생성 / 미사용 코드 자동 제거)
이렇게 시스템적으로 강제하면 한번 실수한 것에 대해서 두번 다시 같은 실수를 하지 않도록, 시간이 지날수록 견고한 시스템이 만들어지게 된다. 이 부분은 현재 계속해서 테스트를 하며 보완해나가고 있다.
JPA를 써본 사람이라면 lazy loading과 eager loading의 차이를 잘 알 것이다. Claude에서도 정확히 같은 개념이 적용된다. CLAUDE.md나 .claude 내부의 내용은 모든 요청마다 기본으로 읽힌다. 즉, 여기에 내용이 길어질수록 실제 작업과 무관한 내용까지 매 턴마다 컨텍스트를 차지하며 토큰을 낭비하게 된다.
이를 해결하는 방법은 생각보다 단순하다. 관련 문서를 최대한 잘게 쪼개어 별도의 Markdown 파일로 분리해두고, CLAUDE.md나 Skill 에는 파일 목록과 간단한 설명만 적어두는 것이다. 그러면 AI가 요청 내용과 관련된 문서만 '필요할 때' 직접 읽어오도록 유도할 수 있다.
예를 들어 CLAUDE.md에 아래와 같이 작성해두면,
## 도메인 지식
필요한 경우 아래 문서를 참조하세요.
- docs/domain-knowledge/01-project-structure.md — 프로젝트 구조
- docs/domain-knowledge/03-api-design.md — API 설계 원칙
- docs/domain-knowledge/05-database.md — DB 스키마 및 쿼리 규칙
Claude는 DB 관련 작업이 들어왔을 때만 05-database.md를 읽고, API 작업이 들어왔을 때만 03-api-design.md를 읽는다. 모든 문서를 처음부터 통째로 올리는 것보다 훨씬 효율적이다.
Claude의 컨텍스트 윈도우는 대화가 길어질수록 점점 채워진다. 이때 문제가 되는 것은 단순히 토큰 비용만이 아니라, 컨텍스트가 가득 찰수록 Claude의 집중도와 정확도가 함께 떨어진다는 점이다.
따라서 메인 에이전트가 '기억하고 있을 필요가 없는' 작업은 과감하게 서브 에이전트에 위임하는 것이 중요하다. 이 플러그인에서는 두 가지 단계를 서브 에이전트로 분리했다.
codebase-explorer): 수십 개의 파일을 열어 읽어야 하는 탐색 작업. 결과만 exploration.md로 요약해서 메인에 돌려준다.pr-writer): 전체 diff를 읽고 리뷰 체크리스트를 검증하는 작업. 완료 후 MR URL만 반환한다.이렇게 하면 메인 에이전트는 '무엇을 만들지'에만 집중할 수 있고, 파일을 대량으로 읽는 지저분한 작업은 서브 에이전트가 맡아서 격리된 컨텍스트에서 처리한다. 서브 에이전트가 실패하면 메인이 직접 실행하는 fallback도 구현해두었다.
단순히 코드를 생성하고 끝내는 것이 아니라 생성한 결과물을 스스로 검증하고 기준을 충족할 때까지 반복하도록 설계하는 자가 피드백 루프를 만들었다.
예를 들어write-tests 단계에서는 테스트를 생성한 뒤 실제로 실행해서 커버리지를 측정하고, 70%에 미치지 못하면 부족한 부분을 스스로 파악해서 테스트를 보완하는 루프를 돌고 있다. 사람이 "커버리지가 부족하니 더 써줘"라고 피드백을 주지 않아도 되는 것이다. design-code 단계에서도 설계안을 작성한 뒤 스스로 도메인 지식 문서와 비교해 누락된 요구사항이나 설계상의 허점을 검토하는 피드백 루프를 포함시켰다.
즉 명확한 완료 기준을 정의해서 이"테스트를 작성해라"가 아니라 "커버리지 70%를 달성할 때까지 테스트를 작성해라"처럼, AI가 스스로 완료 여부를 판단할 수 있는 기준을 함께 제공했다.
스킬 파일 안에서 코드베이스를 탐색하는 단계를 작성할 때, 그냥 "관련 파일을 찾아봐"라고만 적으면 Claude가 bash로 find나 ls를 실행하거나 엉뚱한 방법을 쓰는 경우가 있다. 그보다 스킬 지시문 안에 Grep, Glob, Read 도구를 명시적으로 지정해주는 것이 훨씬 안정적이다.
## 코드 탐색
1. Glob으로 `src/main/**/*.java` 패턴에 해당하는 파일 목록을 가져온다
2. Grep으로 티켓에 언급된 클래스명을 검색하여 관련 파일을 좁힌다
3. Read로 후보 파일들을 읽고 구조를 파악한다
도구를 명시하면 Claude가 일관되게 같은 방식으로 탐색하고, 의도치 않은 bash 명령 실행도 방지할 수 있다.
정말 모든 것이 너무 빠르게 변하고 있다. 매일 Claude 관련 새로운 기능이 업데이트되고, 사람이 따라가기 힘든 속도로 새로운 버전들이 나오고 있다. sub-agent가 나온 지 얼마 되지도 않아 Agent-teams가 나왔고, 머지않아 AGI나 완전 자율 SaaS 형태의 무언가가 나오지 않을까 싶기도 하다.
단순히 코딩하는 것뿐만 아니라 프로덕트를 만들어내고 문제를 해결하는 것을 좋아하는 나로서는 여전히 재미를 느끼고 있기는 하지만 점점 불안해지는 것도 사실이다.
그럼에도 아직까지는 AI가 있어도 오더를 내리는 사람의 퀄리티에 따라 결과물의 퀄리티도 달라진다. 무엇을 만들어야 하는지 또 왜 만들어야 하는지를 정의하는 능력은 여전히 사람의 영역이다. 그리고 AI가 틀린 것을 알아채는 능력, 즉 생성된 코드나 설계의 허점을 판별하는 눈도 아직은 깊은 도메인 이해 없이는 갖추기 어렵다.
그래서 나는 아직 AI 도입 전과 똑같이 개발 공부를 열심히 하고 싶다. AI를 잘 쓰는 것과 개발을 잘 이해하는 것은 서로 대체재가 아니라 보완재라고 생각하기 때문이다. AI를 지휘하는 사람이 되려면, 결국 잘 지휘할 줄 아는 사람이 되어야 하지 않을까?
참고 자료
https://www.youtube.com/watch?v=vxEvo2BLM6A&t=1418s
https://www.youtube.com/watch?v=6gvnDSAcZww&t=196s