IDE → CLI 전환 가이드 · EDITION 01

커맨드라인 에이전트
와 대화하는 법.

Cursor, Windsurf, VS Code 의 인라인 채팅에서 Claude Code 같은 CLI 에이전트로 넘어갈 때 필요한 것은 새 단축키가 아니라 새 사고방식이다. 이 문서는 프롬프트·컨텍스트·하네스 엔지니어링을 난이도 순으로 정리한 실전 로드맵이다.

난이도 단계
기초 하네스
수록 방법론
22 가지
대상 독자
IDE 에이전트 졸업생
읽는 시간
대략 25
서문 · The Mental Shift

먼저, 사고방식을 뒤집는다.

IDE 에이전트는 당신의 커서 위치, 선택된 코드, 열린 탭으로부터 의도를 추론해준다. CLI 에이전트는 그러지 않는다. 당신이 명시한 것당신이 깔아둔 컨텍스트만이 전부다. 이 제약이 오히려 에이전트를 더 예측 가능하고, 더 강력하고, 더 자동화 가능하게 만든다.

IDE 기반 에이전트

암묵적 · 시각 주도

  • 커서 위치, 선택 영역, 열린 파일이 자동으로 컨텍스트에 포함
  • 짧은 턴, 한두 줄 수정 중심
  • 사람이 루프를 돌린다 — 클릭, 수락, 거절
  • 자동화 어렵다 — GUI 종속
  • 세션 간 기억은 IDE 가 관리
CLI 기반 에이전트

명시적 · 의도 주도

  • 컨텍스트는 당신이 @파일, CLAUDE.md, stdin 으로 주입
  • 길고 자율적인 다중 턴, 계획·실행·검증까지
  • 에이전트가 루프를 돌린다 — 당신은 제약을 설계
  • 파이프·스크립트·CI 에 자연스럽게 결합
  • 기억은 파일 시스템과 당신의 규약이 관리
핵심 한 문장. IDE에서는 에이전트를 조작했지만, CLI에서는 에이전트에게 환경을 설계해서 건네준다. 이 문서의 모든 방법론은 그 "환경"을 어떻게 깎아낼지에 관한 이야기다.
개념 지도 · Three Pillars

세 개의 엔지니어링, 세 가지 레버.

에이전트의 결과물은 세 레버가 함께 결정한다. 대부분의 학습은 왼쪽(프롬프트)에서 시작해 오른쪽(하네스)로 이동한다. 난이도 순서이기도 하고, 영향력 순서이기도 하다.

I
Prompt Engineering

당신이 말하는 것

한 번의 요청에서 무엇을, 어떻게, 어떤 형식으로 달라고 할지 설계한다. 역할, 제약, 출력 스키마, 예시, 부정적 지시. 가장 눈에 보이지만 가장 얕은 레버.

II
Context Engineering

모델이 알고 있는 것

요청 시점에 모델의 컨텍스트 윈도우에 무엇이 들어가 있는지 설계한다. CLAUDE.md, 파일 참조, 검색 결과, 규약 문서, 대화 기억. 프롬프트보다 훨씬 크게 작동한다.

III
Harness Engineering

루프가 움직이는 방식

에이전트가 도구를 고르고, 실행하고, 관찰하고, 재시도하는 전체 루프를 설계한다. 훅, 서브에이전트, 헤드리스 모드, 평가 파이프라인. 자동화의 끝.

01
● LEVEL 01 · 기초 FOUNDATIONS

IDE 습관에서 한 발짝 떨어지기.

여기 있는 다섯 가지만 익혀도 CLI 에이전트의 80%는 먹고 들어간다. 모두 "에이전트에게 필요한 정보를 어떻게 명시적으로 줄 것인가"에 대한 이야기다.

01

의도를 서술하라, 단계를 명령하지 말고.

IDE에서는 "이 줄 고쳐줘"가 통했다. 컨텍스트를 눈으로 보고 있었으니까. CLI에서는 왜 고치는지, 어떤 상태가 되어야 성공인지를 써줘야 한다. 에이전트가 스스로 단계를 분해할 여지를 주는 것이 훨씬 더 나은 결과를 낸다.

같은 문장에 "목표 + 성공 기준 + 비허용 사항"을 포함하면, 모델은 중간 단계를 더 안정적으로 계획한다.
Before / After한 줄짜리 지시
✗ IDE 습관
chat prompt
> 이 함수 최적화해줘
✓ CLI 전환
chat prompt
> 목표: parse_pointcloud() 의 p95 지연을 현재 820ms → 200ms 이하로.
> 제약: 외부 의존 추가 금지, 기존 공개 시그니처 유지.
> 성공 판정: tests/bench_parse.py 의 bench_p95 가 통과.
> 먼저: 어디를 바꿀지 계획만 말해줘. 코드는 승인 후에.
02

프로젝트의 첫 번째 기억, CLAUDE.md.

IDE에서는 에이전트가 열린 파일·워크스페이스 설정을 읽었다. CLI에서는 CLAUDE.md (또는 프로젝트 루트의 규약 파일)가 그 역할을 한다. 세션 시작 시 자동으로 주입되는 "프로젝트의 상수"이다.

여기에 담아야 하는 것은 매 세션마다 다시 설명해야 피곤한 사실들이다: 기술 스택, 디렉토리 규약, 테스트 실행법, 커밋 스타일, 하지 말아야 할 것.

매 대화의 첫 5분을 아낀다. 그리고 에이전트의 "추측"을 "사실"로 바꾼다.
CLAUDE.md프로젝트 루트
markdown
# CVP — Computer Vision Pipeline Builder

## Stack
- Frontend: React 19 + Vite + Tailwind v4 + shadcn
- Backend: FastAPI (Python 3.12) + Supabase + pgmq
- Infra: Cloudflare Workers, k3s + MetalLB

## 규약
- 커밋은 Conventional Commits (feat:, fix:, chore:, docs:)
- 코드 주석은 영문 + 한글 병기
- 파이썬은 ruff + mypy --strict 통과 필수
- 새 엔드포인트 추가 시 tests/api/ 에 반드시 E2E 테스트

## 실행
- dev: `pnpm dev` (프론트), `uv run fastapi dev` (백)
- 테스트: `uv run pytest -x -q`
- 타입체크: `uv run mypy src/`

## 하지 말 것
- src/legacy/ 디렉토리 수정 금지 (별도 PR 로만)
- 프로덕션 마이그레이션 자동 적용 금지
03

파일을 정확히 가리켜라.

IDE에서는 열려있는 탭이 자동으로 컨텍스트였다. CLI에서는 @ 참조를 통해 명시한다. "이 프로젝트 좀 봐줘" 대신 @src/api/welding.py @CLAUDE.md @tests/api/test_welding.py. 이 차이가 정확도의 80%다.

추상적 지시 + 정확한 파일 세 개가, 장황한 설명 + 파일 없음보다 언제나 낫다.
@ 파일 참조정확성의 지렛대
session
# 모호한 요청
> 인증 로직 버그 좀 찾아줘

# 명시적 요청 — 범위가 좁아 환각이 줄어든다
> @src/auth/middleware.py @src/auth/jwt.py @tests/auth/
> 이 세 파일만 봐. 만료된 토큰이 401이 아니라 500을 반환하는
> 경로가 있다. 어디서 예외가 잘못 잡히고 있는지 찾아서 수정 계획만 제시.

# 디렉토리 전체도 가능
> @docs/rfc/ 를 읽고 가장 최근 RFC 의 결정사항을 3줄 요약.
04

슬래시 명령어로 반복을 줄여라.

에이전트 세션의 상태를 제어하는 내장 명령들이 있다. /clear 로 컨텍스트 리셋, /compact 로 기존 대화 압축, /init 으로 프로젝트 분석하여 CLAUDE.md 초안 생성, /model 로 모델 스위칭. 이것만 알아도 컨텍스트 낭비가 급감한다.

긴 세션은 비용과 혼란의 원인. 명령어 몇 개로 "상태 위생"을 유지한다.
세션 제어빈번한 4가지
slash commands
/init        # 프로젝트 구조 분석 → CLAUDE.md 초안 생성
/clear       # 컨텍스트 완전 초기화 (새 주제 시작 시)
/compact     # 기존 대화를 요약본으로 압축 (긴 세션 구제)
/model       # 모델 전환 (빠른 탐색 ↔ 깊은 추론)

# 습관:
#  · 새 작업 주제 = /clear 로 시작
#  · 한 PR 끝나면 = /compact 로 정리
#  · 버그 사냥에는 = 추론 강한 모델로 /model 전환
05

출력 형식을 요구하라.

"설명해줘" 대신 "3단계 diff + 근거 한 문장씩"을 요구한다. JSON, 표, bullet, diff, 리포트 — 어느 형식이든 선언하면 모델은 구조를 잡는다. 대신 자유롭게 흐르지 않는다.

형식 지시는 프롬프팅 중에서 가장 ROI 가 높다. 출력이 산만할 이유를 제거한다.
출력 스키마 강제형식이 곧 정확도
prompt
> @src/models/ptv3.py 를 읽고 다음 표로 답해.
>
> | 함수 | 책임 | 입력 shape | 출력 shape | 비용 추정 |
> |------|------|------------|------------|-----------|
>
> 비용 추정은 O(N), O(N log N), O(N²) 중 하나로만.
> 확신 없으면 "?" 로 표기. 추측 금지.
> 표 밖에는 한 문장도 쓰지 마.
02
● LEVEL 02 · 중급 INTERMEDIATE

컨텍스트를 의식적으로 조립하기.

이제 에이전트의 입력이 결과의 대부분을 결정한다는 사실을 체감한다. 여기부터는 "프롬프트"에서 "컨텍스트"로 무게중심이 이동한다.

컨텍스트 윈도우는 예산이다.

FIG. 02 · 토큰은 무료가 아니다
SYSTEM CLAUDE.MD ATTACHED FILES · @refs CONVERSATION HISTORY TOOL OUTPUTS FREE 고정 프로젝트 규약 참조 소스 누적 대화 도구 결과 여유 1. 오래된 대화가 가장 큰 낭비다 — 주기적으로 /compact. 2. 큰 파일 통째로 첨부하지 말고, 필요한 함수 범위만 @file:L20-L80. 3. 도구 출력이 길면 요약 후 재주입. 원본은 파일로. 4. 오른쪽 "여유"가 항상 20% 이상 남도록 운영.
06

Plan → Execute, 두 턴으로 쪼개라.

에이전트에게 한 번에 "계획하고, 구현하고, 테스트 붙여"라고 하면 중간에 길을 잃는다. 먼저 계획만 요구하고, 검토한 뒤 그 계획을 실행하게 한다. 이 두 턴 분할이 버그의 절반을 예방한다.

사람이 리뷰하는 지점이 명확해지고, 에이전트의 "몽상"을 조기에 차단한다.
2-turn pattern계획 → 검토 → 실행
session
# Turn 1 — 계획만 요청
> @src/api/welding.py/inspect 엔드포인트 추가 필요.
> 코드 쓰지 말고, 아래 형식의 계획만 제시:
>   1) 변경할 파일 목록
>   2) 새 pydantic 모델 스키마
>   3) 추가할 pytest 목록
>   4) 모르는 것 / 가정 / 확인 필요 사항

# ... 에이전트 답변 확인, 잘못된 가정 수정 ...

# Turn 2 — 승인된 계획으로 실행
> 좋다. 3) 의 테스트 목록에서 두 번째만 빼고 그대로 구현해.
> 변경 후 `uv run pytest tests/api/ -x` 까지 돌려서 결과 보고.
07

예시가 설명보다 강하다 — Few-shot.

"Conventional Commits 스타일로 커밋 메시지 써줘"보다, 커밋 메시지 예시 3개를 붙여주는 것이 훨씬 정확하다. 스타일, 톤, 경계 케이스는 예시를 통해 전달되는 것이 빠르다. 특히 당신의 팀만의 관습이 있을 때.

모델은 일반 스타일은 알지만 당신 팀의 관습은 모른다. 예시로 주입하라.
Few-shot by example팀 스타일 주입
prompt
> 아래 diff 에 대한 PR 제목과 본문을 작성해.
> 우리 팀 스타일 예시 3개:
>
> [예시 1]
> 제목: feat(api): add /inspect endpoint for LVS scan results
> 본문:
>   · what: POST /inspect 신설. scanCONTROL 3D 포인트클라우드 수신.
>   · why: 프런트에서 실시간 결함 판정 트리거 필요.
>   · how: pgmq 로 비동기 enqueue, PTv3 워커가 consume.
>   · test: tests/api/test_inspect.py (happy + 3 edge cases)
>
> [예시 2] ... (생략)
> [예시 3] ... (생략)
>
> 이제 실제 diff:
> @.git/diff.patch
08

반복되는 작업을 커스텀 명령어로 굳혀라.

.claude/commands/ (또는 에이전트별 동등 디렉토리) 에 마크다운을 두면, 프로젝트 전용 슬래시 명령이 된다. "PR 리뷰해줘", "마이그레이션 스크립트 짜줘", "이 함수 테스트 추가해줘" — 자주 쓰는 프롬프트는 전부 여기로 옮긴다.

프롬프트도 코드다. 재사용하고, 버전관리하고, 팀원과 공유한다.
.claude/commands/review.md프로젝트 슬래시 명령
markdown
---
description: 현재 브랜치 diff 를 우리 팀 체크리스트로 PR 리뷰
---

# PR 리뷰

현재 브랜치와 main 의 diff 를 아래 순서로 검토해.

## 1) 정확성
- 비즈니스 로직에 edge case 누락?
- null / empty / 경계값 처리?
- 동시성 이슈 (race, deadlock, TOCTOU)?

## 2) 우리 팀 규약
- ruff / mypy --strict 통과?
- 주석 영/한 병기?
- 새 public API 에 docstring 있음?

## 3) 테스트
- 변경된 라인에 대한 테스트가 존재하는가?
- 없다면 추가해야 할 테스트 목록만 제시 (구현 X)

## 출력
각 섹션마다 🔴 / 🟡 / 🟢 로 상태 표기,
🔴 에만 구체적 줄번호를 명시.
usage
> /review      # 한 단어로 전체 리뷰 루틴이 돈다
09

역할과 부정적 지시를 함께 써라.

"시니어 리뷰어 역할"만으로는 약하다. 여기에 하지 말아야 할 것들을 붙여야 모델의 기본 습관이 눌린다. "칭찬하지 말 것", "확신 없으면 '?'로 표시할 것", "코드 수정 없이 지적만 할 것".

모델의 기본 톤(친절, 균형, 요약) 을 적극적으로 차단해야 실전에 쓰기 좋아진다.
Role + negative constraints모델 기본값 눌러두기
prompt
> 역할: 15년차 시스템 엔지니어, 3D 포인트클라우드 딥러닝 리뷰어.
> 목표: @src/models/ptv3.py 의 추론 경로 코드 리뷰.
>
> 하지 말 것:
>   · 칭찬, 요약, 결론 문단
>   · "좋은 코드입니다" 류의 서문
>   · 코드 수정 제안 (지적만)
>   · 파일 밖 일반론
>
> 할 것:
>   · 지적 사항만, 줄번호 + 한 문장씩
>   · 확신도 표기: (확실) / (추정) / (모름)
>   · 최대 10개, 중요도 내림차순
10

컨텍스트는 피라미드로 쌓아라.

큰 파일 통째로 붙이지 말고, 레벨별로 쌓는다. (1) 프로젝트 개요 1문단 → (2) 해당 모듈 README → (3) 관련 파일 3~5개 → (4) 구체 함수. 모델이 "어디서 왔는지" 를 알면 추론이 훨씬 안정적이다.

동일한 토큰 수라도 구조에 따라 추론 품질이 다르다. 맥락은 계층으로 쌓아라.
Context Pyramid넓게 → 좁게
prompt
> [LEVEL 1 — 프로젝트 맥락]
> CVP 는 컴퓨터비전용 no-code 파이프라인 빌더. 사용자는
> 노드를 드래그해서 파이프라인을 만들고, 서버가 Python 으로
> 컴파일해 실행한다.
>
> [LEVEL 2 — 관련 모듈]
> @src/compiler/README.md
>
> [LEVEL 3 — 연관 파일]
> @src/compiler/graph.py
> @src/compiler/emit.py
> @tests/compiler/test_emit.py
>
> [LEVEL 4 — 구체 질문]
> graph.py 의 topological_sort() 가 사이클에서 무한 루프에 빠진다.
> 재현 케이스는 test_emit::test_cycle_detection. 원인 분석 후
> 수정 계획을 Level 1~3 의 규약에 맞게 제시.
11

에이전트에게 스스로 검증시켜라.

코드 변경 후 "테스트 돌려보고 결과 보고", "타입체크 통과할 때까지 수정"을 지시한다. CLI 에이전트는 셸을 직접 쓸 수 있다. IDE와 달리 결과를 관찰하고 스스로 루프 돌리는 것이 기본값이 될 수 있다.

"자기 피드백 루프"가 켜지는 순간, 에이전트는 조수에서 동료로 격상된다.
Self-verifying loop"테스트 통과할 때까지"
prompt
> @src/api/welding.py 에 /inspect 를 위 계획대로 구현.
>
> 워크플로우:
>   1. 코드 작성
>   2. `uv run pytest tests/api/test_inspect.py -x -q` 실행
>   3. 실패 시 원인 분석 → 수정 → 2. 로 복귀
>   4. `uv run mypy src/api/welding.py` 통과 확인
>   5. 통과 시 변경 요약 + diff 제출
>
> 중단 조건:
>   · 같은 에러가 3회 반복되면 중단하고 나에게 의견 요청
>   · 스키마 변경이 필요하면 먼저 확인 후 진행
03
● LEVEL 03 · 고급 ADVANCED

에이전트를 시스템으로 다루기.

여기부터는 "대화"가 아니라 "프로세스"를 설계한다. 여러 에이전트, 여러 컨텍스트 소스, 여러 저장소를 오케스트레이션한다.

Agentic loop 의 해부도.

FIG. 03 · Think → Plan → Act → Observe
Think reasoning Plan tool choice Act exec tool Observe tool result Verify self-check strategy call stdout/exit pass? re-think 하네스 엔지니어링은 이 루프의 모든 간선을 제어하는 일이다 — 어떤 도구를 허용할지, 어떤 결과를 재주입할지, 어떻게 멈출지.
12

CLAUDE.md 를 계층으로 쌓아라.

한 프로젝트 안에서도 모듈마다 규약이 다르다. 프런트엔드와 인프라의 커밋 스타일, 테스트 전략이 같을 수 없다. CLAUDE.md 는 디렉토리 계층으로 중첩 적용된다 — 루트, 모듈, 하위 디렉토리 순으로 쌓아 올린다.

규약은 "있는 곳"에 두어야 한다. 글로벌 한 장에 모두 몰면 어차피 지켜지지 않는다.
hierarchical CLAUDE.md디렉토리별 상속
tree
~/.claude/CLAUDE.md              # 전역 (개인 선호)
cvp/
├── CLAUDE.md                   # 프로젝트 공통
├── frontend/
│   └── CLAUDE.md               # React/Vite 전용
├── backend/
│   ├── CLAUDE.md               # FastAPI 전용
│   └── migrations/
│       └── CLAUDE.md           # "절대 자동 적용 금지"
└── infra/
    └── CLAUDE.md               # k3s / helm 규약

# 에이전트는 작업 중인 경로에 따라
# 바깥 → 안쪽 순서로 CLAUDE.md 를 모두 읽는다.
# 더 안쪽이 바깥쪽을 덮어쓸 수 있다.
13

Subagent 로 작업을 분할하라.

메인 에이전트 하나가 모든 걸 하면 컨텍스트가 오염된다. "리뷰어", "테스트 작성자", "문서 작성자" 같은 전용 서브에이전트를 정의하면, 각자 깨끗한 컨텍스트에서 일한다. 메인은 오케스트레이터 역할만.

컨텍스트 오염을 막는 가장 강력한 수단. 각 서브에이전트는 자기 역할만 안다.
.claude/agents/test-writer.md전용 서브에이전트
markdown
---
name: test-writer
description: 구현이 끝난 함수에 대해 pytest 를 생성한다
tools: Read, Write, Bash(pytest:*)
---

너는 오직 pytest 작성만 담당한다.

## 규칙
1. 대상 함수의 구현은 수정하지 않는다
2. 테스트는 AAA (Arrange-Act-Assert) 패턴
3. happy path 1개 + edge cases 최소 3개
4. 픽스처는 conftest.py 에 있는 것만 재사용
5. 생성 후 `uv run pytest <new_file> -x` 로 확인

## 보고 형식
- 생성된 테스트 파일 경로
- 커버한 시나리오 bullet
- 통과 / 실패 요약
main agent
> 방금 만든 parse_pointcloud() 에 대해
> test-writer 서브에이전트 호출해서 테스트 생성.
14

MCP 로 도메인 지식을 주입하라.

Model Context Protocol 서버는 에이전트가 쓸 수 있는 "도구와 데이터의 표준 플러그인" 이다. Supabase, GitHub, Jira, 사내 위키, 커스텀 DB — 이 모든 것을 에이전트의 손에 쥐어줄 수 있다. 한 번 설정하면 프롬프트가 짧아진다.

프롬프트에 "이 API 는 이렇게 쓴다"를 설명하는 대신, 에이전트가 직접 호출하게 만든다.
.mcp.json프로젝트 MCP 연결
json
{
  "mcpServers": {
    "supabase": {
      "command": "npx",
      "args": ["-y", "@supabase/mcp-server", "--project-ref=xxxx"],
      "env": { "SUPABASE_ACCESS_TOKEN": "${SB_TOKEN}" }
    },
    "unwiki": {
      "command": "python",
      "args": ["-m", "unwiki_mcp"],
      "env": { "UNWIKI_URL": "https://unwiki.net" }
    },
    "playwright": {
      "command": "npx",
      "args": ["-y", "@playwright/mcp"]
    }
  }
}
usage
> 내 unwiki 에서 "PTv3 semantic segmentation" 문서 찾고,
> 거기 언급된 하이퍼파라미터 기준으로
> @configs/ptv3.yaml 을 비교 검토해.
15

Git worktree 로 병렬 작업을 돌려라.

IDE에서는 한 브랜치만 작업했다. CLI 에이전트에서는 worktree 로 복수 브랜치에 복수 에이전트를 동시에 붙일 수 있다. "이 PR 리뷰 에이전트"와 "저 기능 구현 에이전트"가 서로의 파일을 건드리지 않고 나란히 달린다.

에이전트의 최대 병목은 "사람이 한 번에 볼 수 있는 양"이다. 공간을 분리하면 시간이 압축된다.
git worktree 패턴브랜치 = 워크스페이스
bash
# 메인 저장소는 건드리지 않고, 별도 디렉토리에 브랜치를 체크아웃
git worktree add ../cvp-feature-inspect -b feature/inspect
git worktree add ../cvp-bugfix-ptv3    -b bugfix/ptv3-cycle
git worktree add ../cvp-refactor-api   -b refactor/api-v2

# 각 디렉토리에서 각각의 에이전트 세션 실행
cd ../cvp-feature-inspect  && claude
cd ../cvp-bugfix-ptv3     && claude
cd ../cvp-refactor-api    && claude

# 끝나면 정리
git worktree remove ../cvp-feature-inspect
실전 팁. tmux 나 zellij 에 worktree 별 창을 배치하면 한 화면에서 3~4개 에이전트를 모니터링할 수 있다. 각자에게 다른 CLAUDE.md 를 줘서 역할을 다르게 만드는 것도 가능하다.
16

긴 작업은 아티팩트로 중간 저장해라.

리팩토링, 마이그레이션 같은 긴 작업은 한 세션에 다 안 들어간다. 에이전트에게 PLAN.md, PROGRESS.md, NOTES.md 같은 파일을 만들어 작업 상태를 저장하게 한다. 다음 세션은 그 파일을 먼저 읽는다. 상태는 파일이다.

에이전트의 "기억"은 당신의 파일 시스템에 위임할 수 있다. 휘발성 대화에 의존하지 마라.
artifact-driven work상태 = 파일
prompt
> SQLAlchemy 1.4 → 2.0 마이그레이션을 시작한다.
>
> 아티팩트 규칙:
>   · docs/migrations/sa2/PLAN.md   - 전체 계획, 단계별 체크박스
>   · docs/migrations/sa2/PROGRESS.md - 매 단계 완료 시 append
>   · docs/migrations/sa2/NOTES.md   - 발견한 이슈, 결정 이유
>
> 이번 세션 목표:
>   1. PLAN.md 초안 작성 (파일 수준 체크리스트)
>   2. 단계 1만 수행, PROGRESS.md 업데이트
>   3. 다음 세션에서 재개할 수 있도록 "다음 할 일" 섹션 끝에 추가
>
> 다음 세션 시작 프롬프트는 단순히:
>   "@docs/migrations/sa2/ 를 읽고 이어서 진행"
17

평가 프롬프트로 모델을 채점시켜라.

에이전트가 만든 결과를, 다른 에이전트(또는 같은 에이전트 다른 세션)가 채점한다. 코드 리뷰, 테스트 커버리지, 문서 품질 — "판단" 역할의 프롬프트를 따로 만들면 휴먼 리뷰 전에 한 단계 거른다.

LLM 을 자기 자신의 QA 로 쓴다. 완벽하지 않지만 놀랄 만큼 버그를 잡는다.
LLM-as-judge에이전트 A → 에이전트 B 가 채점
markdown
# .claude/commands/grade.md
---
description: 최근 변경에 대한 엄격한 채점
---

# 채점 기준 (각 0-5)

| 항목 | 0 | 3 | 5 |
|------|---|---|---|
| 정확성 | 동작하지 않음 | 해피패스만 동작 | 에지케이스 포함 |
| 안정성 | 타입 에러 | 경고만 | mypy strict 통과 |
| 테스트 | 없음 | 행복경로만 | 실패경로 포함 |
| 가독성 | 이해 불가 | 평균 | 6개월 뒤 본인도 이해 |
| 우리 규약 | 위반 | 부분 준수 | 완전 준수 |

# 출력
총점 / 25 와 3점 미만 항목의 구체 근거를 제시.
4점 이상은 언급하지 않는다 (잡음 제거).
코드 수정은 하지 않는다.
04
● LEVEL 04 · 하네스 HARNESS ENGINEERING

에이전트를 라이브러리처럼 다루기.

이 단계는 "에이전트에게 말한다"가 아니라 "에이전트를 호출하는 시스템을 만든다" 이다. CI 파이프라인, 배치, 커스텀 루프 — 사람이 사라지고 코드가 남는다.

하네스의 여섯 겹.

FIG. 04 · 프롬프트는 맨 안쪽일 뿐
L6 · 운영 / 관측 (로그, 비용, 에러 알람) L5 · 오케스트레이션 (CI, cron, 큐, 이벤트 트리거) L4 · Hooks (pre/post tool, stop, notify) L3 · 도구 정의 · 권한 화이트리스트 L2 · 컨텍스트 주입 · CLAUDE.md · MCP L1 · 프롬프트 ops who triggers? deterministic gates capability knowledge intent
18

Headless 모드로 파이프에 꽂아라.

대화형 TUI 가 아니라, 한 번 실행하고 결과만 받는 모드 (claude -p "..." 같은 플래그) 가 있다. stdin 으로 컨텍스트를 넣고 stdout 으로 결과를 받으면, 에이전트는 그냥 또 하나의 유닉스 도구 가 된다.

셸 파이프에 꽂히는 순간, 에이전트는 스크립팅의 일급 시민이 된다.
Unix compositionstdin | agent | stdout
bash
# 1) 커밋 메시지 자동 생성 (git hook 에 끼우기 딱 좋음)
git diff --staged | claude -p "이 diff 에 대한 Conventional Commit 메시지 한 줄만."

# 2) 로그에서 에러 패턴 추출
kubectl logs -n prod welding-worker | tail -500 \
  | claude -p "반복되는 에러 3가지만 JSON 으로: [{pattern, count, first_seen}]."

# 3) 여러 파일 일괄 리뷰
for f in src/api/*.py; do
  echo "### $f"
  cat "$f" | claude -p "타입 힌트 누락만 줄번호로 나열. 본문 없음."
done > review.md
19

Hooks — 결정론적 제어 레이어.

에이전트의 매 도구 사용 전/후에 당신의 스크립트를 끼워 넣을 수 있다. 위험 명령 차단, 자동 포맷터 실행, 민감 파일 필터, 완료 알림 — 모델의 판단에 의존하지 않고 코드로 못박는 레이어. 하네스 엔지니어링의 심장.

"모델이 절대 이 짓은 안 하도록" 만드는 유일한 방법은 코드로 막는 것이다. 프롬프트로는 약속일 뿐.
.claude/settings.json · hooks이벤트 → 스크립트
json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": ".claude/hooks/deny-dangerous.sh"
          // rm -rf, drop database, force push 등을 탐지하여 exit 1
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "uv run ruff format && uv run ruff check --fix"
        }]
      }
    ],
    "Stop": [
      {
        "hooks": [{
          "type": "command",
          "command": "notify-send 'Claude 작업 완료' || true"
        }]
      }
    ]
  }
}
20

도구를 화이트리스트로 좁혀라.

권한은 줄 수 있는 만큼만 준다. 리뷰 에이전트에게 rm 을 줄 이유가 없다. 각 서브에이전트/커스텀 명령마다 사용 가능한 도구 집합을 명시하면, 사고 반경이 수학적으로 제한된다.

가장 저렴한 보안 레이어. 그리고 가장 자주 잊혀지는 레이어.
agent tools whitelistcapability scoping
markdown
# .claude/agents/doc-writer.md
---
name: doc-writer
description: 코드에서 문서만 생성 — 절대 코드 수정 안 함
tools:
  - Read
  - Write(docs/**)              # docs 아래만 쓰기 가능
  - Bash(mkdocs:*)              # mkdocs 명령만
  # Edit, WebFetch, 다른 Bash 는 차단됨
---

너는 문서 작성만 한다. 코드 파일을 수정하려고 하면 거부하고,
대신 docs/rfc/ 에 "제안 RFC" 로 남긴다.
설계 원칙. 서브에이전트 정의서마다 "이 역할에 꼭 필요한 최소 도구"를 적는다. 추가가 필요해지면 그때 명시적으로 넓힌다. 기본은 deny.
21

CI 에 에이전트를 상주시켜라.

GitHub Actions 에서 PR 이 열릴 때마다 에이전트가 돌아 리뷰 코멘트를 남기게 한다. 이슈에 특정 라벨이 붙으면 초안 PR 을 연다. 에이전트는 이제 팀의 또 하나의 역할 이다. 이 단계부터는 에이전트를 "서비스"로 취급한다.

에이전트가 사람의 시간이 아니라 기계의 시간에 맞춰 일하기 시작한다.
.github/workflows/review.ymlPR 자동 리뷰
yaml
name: AI Review
on: { pull_request: { types: [opened, synchronize] } }

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }

      - name: Install Claude Code
        run: npm i -g @anthropic-ai/claude-code

      - name: Run review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          git diff origin/main...HEAD > /tmp/diff.patch

          claude -p "아래 diff 를 .claude/commands/review.md
          기준으로 평가. 🔴 항목만 JSON 배열로:
          [{file, line, severity, reason}].
          
          $(cat /tmp/diff.patch)" > /tmp/review.json

      - name: Post as PR comments
        run: node .github/scripts/post-review.js /tmp/review.json
22

자기만의 에이전트 루프를 짜라.

최종 단계. Anthropic SDK (또는 동등한 것) 를 써서 직접 agentic loop 을 구현한다. 도구 정의, 도구 라우팅, 종료 조건, 재시도 정책, 비용 한도 — 전부 당신 코드다. 이 시점엔 CLI 에이전트가 아니라 당신 제품의 일부다.

완전히 통제하고 싶을 때. 도메인 특화 에이전트, 사내 툴, 프로덕션 기능에 내장할 때.
minimal agent loop (Python)도구 · 관찰 · 종료조건
python
from anthropic import Anthropic
import json, subprocess

client = Anthropic()

# 1) 도구 스펙 — 모델에게 사용 가능한 능력을 알려준다
# 1) Tool specs — declare capabilities to the model
TOOLS = [{
    "name": "run_pytest",
    "description": "pytest 를 주어진 경로로 실행하고 요약을 반환",
    "input_schema": {"type": "object",
        "properties": {"path": {"type": "string"}},
        "required": ["path"]}
}, {
    "name": "read_file",
    "description": "파일을 읽어서 내용 반환 (max 2000 lines)",
    "input_schema": {"type": "object",
        "properties": {"path": {"type": "string"}},
        "required": ["path"]}
}]

def execute_tool(name, args):
    # 도구 실제 실행 — 여기서 권한, 로깅, 타임아웃을 건다
    # Actual tool execution — permission, logging, timeout here
    if name == "run_pytest":
        r = subprocess.run(["uv", "run", "pytest", args["path"],
                            "-x", "-q"], capture_output=True, text=True, timeout=120)
        return f"exit={r.returncode}\n{r.stdout[-2000:]}"
    if name == "read_file":
        with open(args["path"]) as f:
            return "".join(f.readlines()[:2000])

def run(task: str, max_steps: int = 15):
    messages = [{"role": "user", "content": task}]
    for step in range(max_steps):                   # 종료조건: 스텝 한도
        resp = client.messages.create(
            model="claude-opus-4-7",
            max_tokens=4096,
            tools=TOOLS,
            messages=messages,
        )
        messages.append({"role": "assistant", "content": resp.content})

        if resp.stop_reason == "end_turn":            # 종료조건: 모델 완료
            return resp

        # 도구 호출 처리
        tool_results = []
        for block in resp.content:
            if block.type == "tool_use":
                out = execute_tool(block.name, block.input)
                tool_results.append({"type": "tool_result",
                                     "tool_use_id": block.id,
                                     "content": out})
        messages.append({"role": "user", "content": tool_results})

    raise RuntimeError("max_steps exceeded")   # 종료조건: 안전장치
여기서부터는 진짜 엔지니어링이다. 프롬프트, 컨텍스트 적재 방식, 도구 명세, 재시도 정책, 종료 조건, 비용 한도, 로그, 관측, 회귀 평가 — 전부 코드로 담긴다. 이쯤 되면 "AI 어떻게 쓰는지"가 아니라 "내 시스템의 일부를 어떻게 LLM 으로 구현했는지" 의 문제가 된다.
빠른 참조 · Cheat Sheet

한 페이지로 다시.

난이도별 핵심만 뽑았다. 새 프로젝트를 시작할 때 이 리스트를 체크리스트로 써라.

01 · 기초
  1. 의도 + 성공 기준 + 제약을 한 덩어리로 쓴다
  2. CLAUDE.md 로 프로젝트 상수 고정
  3. @파일 로 정확히 범위 지정
  4. /clear /compact /init /model 습관화
  5. 출력 형식을 항상 지시 (표, JSON, diff)
02 · 중급
  1. Plan 턴과 Execute 턴을 분리
  2. Few-shot: 설명 대신 예시 3개
  3. .claude/commands/ 로 반복 프롬프트 자산화
  4. 역할 + 부정적 지시를 함께
  5. 컨텍스트를 피라미드로 쌓기
  6. "테스트 통과할 때까지" 자가 검증 루프
03 · 고급
  1. 계층적 CLAUDE.md (모듈별)
  2. 서브에이전트로 역할 분리
  3. MCP 로 도메인 데이터 주입
  4. git worktree 로 병렬 에이전트
  5. 긴 작업은 PLAN.md / PROGRESS.md
  6. LLM-as-judge 로 내부 QA
04 · 하네스
  1. claude -p 헤드리스 파이프 합성
  2. Hooks 로 결정론적 가드 (pre/post/stop)
  3. 도구 화이트리스트로 권한 최소화
  4. CI 에 PR 리뷰 에이전트 상주
  5. SDK 로 자체 에이전트 루프 구현
  6. 로그·비용·실패율을 관측 대시보드로

결국 환경
설계하는 일이다.

IDE 에이전트는 커서 옆의 도구 였다. CLI 에이전트는 동료다 — 당신이 건네주는 환경만큼 일한다. 프롬프트가 목소리라면, 컨텍스트는 기억이고, 하네스는 몸이다. 셋 모두를 깎아낼 때, 에이전트는 비로소 당신의 시스템이 된다.