바이브코딩 실전 플레이북
Claude Code로 베어메탈 프로비저닝 시스템을 만들며 배운 것들
기반 프로젝트: 베어메탈 프로비저닝 시스템 (프로젝트명·일부 API 규격은 각색)
참고: 마켓컬리 Vibe Coding with Claude Code
배경 — 왜 시스템 엔지니어가 바이브코딩을 했나
시스템 엔지니어라고 코딩을 안 하는 건 아니다. 다만 필요한 툴을 직접 개발할 때, 웹 프론트엔드나 어드민 기능을 만드는 데 약하다. 그래서 보통은 CLI 위주로 짜거나, UI가 필요한 부분은 젠킨스 같은 도구로 대체한다.
문제는 그 결과물을 제3자에게 쓰게 할 때다. 매번 사용법을 설명해줘야 하거나, 직관적이고 보기 좋은 웹 인터페이스가 없어서 늘 아쉬웠다. 그렇다고 이런 어드민 화면 하나 만들겠다고 서비스 프론트엔드 UXD 엔지니어를 섭외해달라는 건 현실적으로 말이 안 되는 일이었다.
이런 상황에서 바이브코딩이 등장하면서 개발 진입 장벽이 크게 낮아졌다. 그래서 직접 바이브코딩으로 기존 도구를 리팩터링하면서 겪은 시행착오를 공유한다.
예제로 다루는 시스템
이 글의 예제는 시스템 엔지니어 영역의 베어메탈 프로비저닝 시스템이다. 데이터센터에 PXE 네트워크를 통해 서버 OS를 자동으로 설치(프로비저닝)하고, 서비스가 종료된 서버의 OS를 회수·삭제하고 자원을 반납하는 과정을, 사내 자산 DB(CMDB)와 연동해 자동화하는 시스템이다. 예전에 CLI + 젠킨스 방식으로 만들었던 것을, 바이브코딩으로 "전문 프로비저닝 툴"답게 다시 개발하면서 겪은 이야기다.
이게 왜 자동화가 필요한가
대규모 서비스를 하는 데이터 센터에서는 서버 OS 설치는 하루에 수십 건에서 수백 건까지도 발생한다. 그때마다 일일이 USB를 꽂고 한 대당 30~40분씩 붙잡고 있으면(게다가 세부 설정까지 수작업 하면 더 오래 걸린다.), 서비스 리드 타임을 도저히 따라갈 수 없다. 수십 ~ 수백 대를 20~30분 만에 OS 프로비저닝하고 기본 애플리케이션까지 구성해 곧바로 서비스에 투입하는 시스템이 필요한 이유다.
그런데 서버를 안전하게 서비스에 투입하려면 생각보다 많은 과정을 거쳐야 한다.
- OS 하드닝 — 회사 보안 정책에 맞춘 강화 작업. 패스워드·계정 정책, 불필요한 애플리케이션·계정 삭제, 보안 패치, 취약점 패치, 감시 체계, 형상 관리 등
- OS 표준화 — 커널 튜닝, 서버 하드웨어에 맞는 드라이버 구성, 사내 Repo 연결, 모니터링 에이전트(메트릭·하드웨어 모니터링) 구성 등
- IP 및 본딩 자동화 — 서비스 VLAN 구성, 네트워크 본딩 자동 구성 등 기본 네트워크 설정
- 그 외에도 일반인은 짐작하기 어려울 만큼 과정이 복잡하다
단순히 "OS 깔고 끝"이 아니다. 하루에도 수백 대씩 일어나는 OS 설치·회수·자원 정리를 전부 자동화하는 것 — 이게 이 시스템 엔지니어 하는일 중에 일부다.
바이브코딩이란
Andrej Karpathy가 2025년 소개한 개념. "자연어로 의도만 전달하면 에이전트가 코드를 만든다."
원래 정의는 극단적이다 — diff도 안 읽고 Accept All. 실무에서는 그렇게 하면 안 된다. LLM이 주도하고, 개발자가 방향을 감독하는 협업 모델이 맞다.
핵심은 이거다: LLM은 패턴을 잘 인식하고 코드를 잘 생성하지만, 긴 정보를 추적하거나 스스로 상태를 관리하는 데 약하다. 이 약점을 시스템으로 보완하는 것이 바이브코딩 전략의 전부다.
💡 이 글에 나오는 용어 정리 (비전문가용)
- 베어메탈 프로비저닝: 텅 빈 물리 서버에 운영체제(OS)와 기본 설정을 자동으로 깔아 "바로 쓸 수 있는 상태"로 만드는 작업.
- CMDB (Configuration Management Database): 회사가 보유한 서버·네트워크 장비 같은 IT 자산 정보(호스트명, IP, 설치 위치, 사양 등)를 모아둔 "자산 대장" 데이터베이스.
- MAAS (Metal as a Service): 물리 서버에 OS를 원격으로 자동 설치해주는 오픈소스 도구.
- Vault: 비밀번호·인증키 같은 민감 정보를 안전하게 보관·발급하는 저장소.
1. 설계 — "적당한 디테일"의 기술
내가 한 실수
프로젝트를 시작할 때 프롬포트 지시에 참고를 위해 PRD_template.md 란 파일을 만들어 모든 것을 설계했다. DB 스키마, API 엔드포인트, 화면 목록, 에러 케이스까지. 결과는? 설계만 하다가 지쳐서 중단했고, 실제 구현에서는 설계를 벗어나는 경우가 더 많았다.
배운 것
큰 방향 + TODO 전략이 훨씬 낫다.
## 4. DB 스키마 [DONE + TODO]
-- 유저 테이블 → [DONE]
-- 작업 이력 테이블 → [DONE]
-- 6개월 보관: 배치 삭제 or 파티셔닝 전략 [TODO]
PRD에서 실제로 이렇게 했다. 확정된 것만 [DONE], 나머지는 [TODO]로 남겨뒀다. 구현하면서 [TODO]를 하나씩 채웠고, 처음 설계에 없던 것들(IP 관리, 네트워크 서비스)도 자연스럽게 추가됐다.
설계에 없는 TODO 는 단위를 나눠서 코드를 구현 하기전 하나씩 자연어로 대화 해가면서 하나 하나 디테일을 채워 나가면 된다. Claude Code가 도움을 많이 줄 것이다.
실전 원칙
❌ 처음부터 완벽한 스펙 작성 → 설계 피로, 구현 이탈
✅ 큰 흐름만 확정 → 나머지는 TODO → 하나씩 구현하며 채워나감
설계 문서에 담을 것:
- 핵심 플로우 (프론트 입력 → CMDB 조회 → MAAS API → 폴링 → 알림)
- 기술 스택 (바꾸기 어렵기 때문)
- 외부 연동 시스템 목록 (CMDB, MAAS, Vault, 알림)
- 디렉토리 구조 (대략)
설계 문서에 담지 말 것 (처음엔):
- 모든 API 엔드포인트 명세
- 세부 에러 케이스
- UI 컴포넌트 목록
- 성능 요구사항 숫자
2. 컨텍스트 관리 — 오염을 막는 법
LLM의 "Lost in the Middle" 문제
긴 대화에서 중간 정보는 희석된다. 처음(초두 효과)과 끝(최신 효과)은 강하게 반영되지만, 중간에 넣은 지시사항은 어텐션이 약해진다. 개발 중 이런 패턴을 자주 봤다:
- 초반에 "MAAS API v2 사용" 지시 → 30턴 후 v1 패턴으로 코드 작성
- "Tailwind만 쓰고 인라인 스타일 금지" → 후반부에 style 속성 슬그머니 등장
해결책 1: 기능 단위로 잘게 쪼개기
❌ "프로비저닝 전체 기능 만들어줘"
✅
1턴: 프로비저닝 폼 UI만 (hostname 입력, OS 선택)
2턴: 폼 제출 시 CMDB API 호출해서 서버 정보 조회
3턴: MAAS API로 프로비저닝 요청 전송
4턴: 작업 상태 폴링 로직
5턴: 완료 시 슬랙 알림 발송
각 턴마다 확인하고 넘어간다. 이 방식의 핵심은 오류 누적 방지다. 1턴에서 잘못 이해한 것이 2턴에 영향을 미치기 전에 잡는다.
해결책 2: /compact — 컨텍스트 정리
작업 중간에 /compact를 치면 대화를 요약해서 컨텍스트를 비운다. 사용 시점:
- 하나의 기능 완성 후 다음 기능으로 넘어갈 때
- 대화가 10턴 이상 길어졌을 때
- 응답이 느려지기 시작할 때
중요: compact 전에 핵심 결정사항을 CLAUDE.md나 별도 파일에 저장해놔야 한다. compact하면 "왜 이렇게 설계했는지"가 사라진다.
해결책 3: 완전히 새로운 기능은 새 세션에서
프론트엔드와 백엔드를 같은 세션에서 같이 개발하다가 컨텍스트가 섞이는 경험을 했다. 백엔드 API 얘기를 하다가 갑자기 React 컴포넌트 얘기로 넘어가면 에이전트가 두 맥락을 동시에 들고 있어 집중력이 떨어진다.
✅ 백엔드 provision.py 완성 → git commit → 새 세션에서 프론트엔드 시작
해결책 4: Plan 모드 — 실행 전 검증
Shift+Tab으로 Plan 모드 진입. 에이전트가 코드를 건드리기 전에 무엇을 할지 계획서를 먼저 쓴다.
> MAAS API 연동 추가해줘
[Plan 모드]
1. services/maas.py에 MAAS API 클라이언트 클래스 추가
2. routers/provision.py에 /provision 엔드포인트 추가
3. CMDB에서 받은 MAC 주소를 MAAS 형식으로 변환하는 유틸 추가
계획서에서 의도와 다른 부분을 잡아낼 수 있다. 특히 여러 외부 API가 얽힌 작업에서 유효하다.
3. 하네스 구성 — 서브에이전트로 나누기
하네스 구조
.claude/agents/ 에 5개 에이전트를 뒀다:
agents/
├── architect.md — 전체 설계, 기술 결정
├── backend-dev.md — FastAPI, Python, DB
├── frontend-dev.md — React, Tailwind, Vite
├── devops-engineer.md — 배포, nginx, 환경변수
└── qa-engineer.md — 테스트, 검증
각 에이전트가 자기 도메인에만 집중한다. 백엔드 에이전트는 Tailwind 얘기 안 한다. 프론트엔드 에이전트는 FastAPI 라우터 설계에 끼어들지 않는다.
왜 하네스인가
에이전트가 "MAAS API 연동 + React UI + nginx 설정 + 알림 발송"을 한 번에 하면 각각의 품질이 낮아진다. 사람도 마찬가지다. 한 사람이 동시에 여러 영역에 집중하면 퀄리티가 분산된다.
서브에이전트 장점:
- 각자 작은 컨텍스트에 집중 → Lost in the Middle 문제 축소
- 전문성 집중 → 도메인별 품질 향상
- 병렬 실행 가능 → 속도
skills/ — 반복 작업 자동화
skills/
├── fullstack-webapp/ — 메인 오케스트레이터
├── api-security-checklist/ — API 보안 검사
├── component-patterns/ — UI 컴포넌트 패턴
└── provisioning-api-clients/ — MAAS/CMDB 클라이언트 패턴
provisioning-api-clients 스킬이 특히 유용했다. MAAS API 호출 패턴이 복잡한데 (토큰 인증, 재시도 로직, 상태 폴링), 이걸 스킬로 만들어놓으면 새로운 MAAS 엔드포인트 추가할 때마다 처음부터 설명할 필요가 없다.
✅ "MAAS API로 릴리즈 호출 추가해줘" → 스킬이 패턴 자동 적용
❌ 매번 "MAAS는 Token 인증이고, 응답이 비동기라 폴링이 필요하고..."
4. 도메인 지식 — 이게 핵심이다
시스템 엔지니어의 강점
백엔드 설계에서 나는 명확한 지시를 줄 수 있었다. MAAS 아키텍처, IPMI 동작 방식, CMDB 데이터 구조, 네트워크 프로비저닝 플로우를 알고 있었기 때문이다.
# 이런 수준의 지시가 가능했다:
"MAAS API /machines/{system_id}/op-deploy 호출 시
distro_series와 hwe_kernel 파라미터를 함께 보내야 하고,
응답의 status_name이 'Deploying'으로 바뀌면 폴링 시작,
'Deployed' 되면 완료야"
도메인 지식 없이 "OS 설치해줘"만 했다면 에이전트가 추측으로 코드를 짰을 것이고, 그 추측은 틀렸을 것이다.
내 약점: 프론트엔드 UX
솔직히 말하면, 프론트엔드 UI 부분에서 고생했다. "프로비저닝 상태를 보기 좋게 보여줘"가 내가 줄 수 있는 최선이었고, 에이전트는 나름 만들었지만 내가 원하는 것과 달랐다.
해결책으로 쓴 것: 레퍼런스 스크린샷
잘 만들어진 사이트의 스크린샷을 캡처해서 붙여넣고, "이런 스타일로 만들어줘"라고 했다. 말로 설명하는 것보다 훨씬 정확했다.
✅ [스크린샷 첨부] "이 Vercel 대시보드처럼 상태 카드 레이아웃으로"
❌ "깔끔하고 현대적인 느낌으로 상태를 보여줘"
더 나은 방법 (지금 안다면):
UX 용어를 알면 더 정확하게 지시할 수 있다:
- "Status Badge" - 색깔 있는 상태 표시
- "Skeleton Loading" - 로딩 중 회색 플레이스홀더
- "Toast Notification" - 화면 우상단 알림
- "Infinite Scroll vs Pagination" - 무한스크롤 vs 페이지네이션
- "Optimistic Update" - 서버 응답 전에 UI 먼저 업데이트
이 용어들로 지시하면 에이전트가 오해 없이 정확히 구현한다.
외부 API 연동 시 핵심
CMDB, MAAS, Vault API 연동에서 이것이 가장 중요했다:
구체적인 API 규격을 직접 제공하라
# 나쁜 지시:
"장비 등록 정보 가져와"
# 좋은 지시 (아래는 설명용으로 각색한 REST 예시):
"Inventory API: GET /sample/v2/assets/{asset_code}
헤더: X-Api-Key: {api_key}
응답: {asset_code, network_profile, boot_mode, location_group, owner_team}
이 값을 설치 요청 DTO에 매핑해서 배포 API로 넘겨줘"
위 엔드포인트·필드는 설명을 위해 임의로 각색한 예시다. 실제 사내 CMDB 규격은 공개하지 않는다. 핵심은 "에이전트가 추측하지 않도록 요청·응답 형태를 명시해서 준다"는 점이다.
모호한 지시는 에이전트의 추측을 유발한다. 추측은 대부분 틀린다.
구버전 코드를 참고 소스로 활용
프로젝트에 /old 디렉토리가 있다. 젠킨스 기반 구버전 코드인데, MAAS API 호출 방식이 이미 구현돼 있었다. 에이전트에게 이렇게 지시했다:
"/old/ 아래 젠킨스(Groovy) 코드에서 MAAS API 호출 부분 참고해서
Python으로 재구현해줘. 특히 op-deploy와 op-release 파트"
결과가 훨씬 정확했다. 구체적인 참고 위치를 알려주는 것이 핵심이다.
5. Extended Thinking — "왜"가 필요할 때
일반 모드 vs Extended Thinking
일반 모드: 질문 → 바로 답변
Extended Thinking: 질문 → [여러 접근 탐색 → 자기 검증] → 답변
Tab 키로 활성화한다. 레벨이 있다:
think < think hard < think harder < ultrathink
레벨이 높을수록 thinking budget(내부 추론 토큰)이 늘어난다. 복잡할수록 높은 레벨이 유효하지만, 단순 작업에 ultrathink를 쓰면 느리고 낭비다.
효과적인 경우: "왜"가 필요한 작업
✅ MAAS 폴링 로직이 간헐적으로 실패하는 이유 추적
✅ CMDB API 응답이 특정 서버에서만 타임아웃 나는 원인 분석
✅ FastAPI와 nginx 사이 502 에러 발생 경로 추론
✅ 비동기 job 상태가 가끔 stuck되는 레이스 컨디션 추적
✅ 아키텍처 결정 (SQLite → PostgreSQL 마이그레이션 필요한지 트레이드오프)
이런 상황들이 있었다. 일반 모드로는 "코드 다시 확인해봐"를 반복했는데, Extended Thinking을 쓰면 에이전트가 여러 가설을 스스로 세우고 검증하면서 원인을 좁혀갔다.
효과 없는 경우: "무엇을"만 명확한 작업
❌ 단순 CRUD 엔드포인트 추가
❌ UI 컴포넌트 레이아웃 잡기
❌ 환경변수 추가
❌ 이미 패턴이 명확한 보일러플레이트
이런 작업에 Extended Thinking을 쓰면 답이 늦어질 뿐 품질 차이가 없다.
실전 판단 기준
"왜 이렇게 해야 하는지"를 에이전트가 추론해야 하면 → Extended Thinking
"이렇게 해" 지시가 명확하면 → 일반 모드
6. 프롬프트 전략
숫자로 명확하게
❌ "너무 많이 실패하면 잠금"
✅ "로그인 5회 실패 시 30분 잠금"
❌ "빠르게 응답해야 해"
✅ "MAAS API 응답 10초 초과 시 타임아웃 처리"
부정문보다 긍정문
❌ "복잡하게 만들지 마"
✅ "Tailwind 유틸리티 클래스만 사용, 커스텀 CSS 없음"
❌ "Redux 쓰지 마"
✅ "상태 관리는 Zustand로"
이유: 명시적 지시("Redux 금지")와 학습 데이터에 내재된 prior("Redux가 React 상태관리 표준")가 경쟁한다. 대화가 짧을 때는 명시적 지시가 이기지만, 대화가 길어질수록 학습 패턴이 우세해진다. 긍정문("Zustand 써")은 학습 데이터에도 Zustand 사용 패턴을 직접 활성화하므로 더 안정적이다.
경계 조건을 명시하라
❌ "프로비저닝 요청 처리해줘"
✅ "프로비저닝 요청:
- 이미 Running 상태면 에러 반환
- CMDB에 없는 hostname이면 에러 반환
- MAAS에 등록 안 된 서버면 에러 반환
- 정상이면 provision 태스크 시작 후 job_id 반환"
경계 조건이 없으면 에이전트가 Happy Path만 구현한다.
Todo로 체크리스트 관리
여러 파일을 수정해야 할 때:
"MAAS API 모듈에 rate limiting 추가해야 해.
먼저 수정할 파일 목록을 Todo로 만들어줘"
→ Claude가 Todo 생성:
□ services/maas.py
□ services/cmdb.py
□ routers/provision.py
□ core/config.py (설정값 추가)
이 방식으로 Lost in the Middle 문제를 우회한다. 체크리스트가 있으면 어디까지 했는지 명확하다.
7. CLAUDE.md — 기억을 시스템으로
대화가 길어지면 초반 지시는 컨텍스트 중간에 묻혀 어텐션이 희석된다. CLAUDE.md는 매 턴마다 시스템 수준에서 자동 로드되므로 이 문제를 우회한다. 세션이 바뀌어도, compact해도 항상 살아있다.
CLAUDE.md 실제 구조
# 프로비저닝 시스템 하네스
**목표:** FastAPI + React 기반 베어메탈 OS 프로비저닝 웹앱을
에이전트 팀이 협업하여 개발한다.
**트리거:** 기능 개발 요청 시 fullstack-webapp 스킬을 사용한다.
여기서 더 발전시킬 것들
개발하면서 반복적으로 설명해야 했던 것들 — 이것들을 CLAUDE.md에 넣어야 했다:
## 외부 API 원칙
- MAAS API: /api/2.0/ 기준, OAuth 1.0 헤더 인증
- CMDB: Bearer 토큰, 응답 캐시 60초
- Vault: AppRole 인증, IPMI 패스워드 조회 전용
## 코딩 규칙
- 금액 없음 (이 프로젝트), 모든 상태값은 Enum으로
- 비동기 작업은 반드시 job_id 반환 후 폴링 구조
- 에러 응답: {"detail": "메시지"} 형식 통일
## 디렉토리 원칙
- services/ : 외부 API 클라이언트만
- routers/ : FastAPI 엔드포인트만, 비즈니스 로직 없음
- models/ : DB 스키마와 Pydantic 모델
이런 내용이 CLAUDE.md에 있었다면 같은 설명을 반복하지 않았을 것이다.
8. 실전 워크플로우
새 기능 시작할 때
1. CLAUDE.md 확인 (관련 규칙 있는지)
2. Plan 모드로 접근 방법 확인 (Shift+Tab)
3. 계획 승인 후 첫 번째 작은 단위만 구현
4. 결과 확인
5. 다음 단위로 이동
기능 완료 후
1. 동작 확인 (직접 실행해서)
2. git commit (의미있는 단위로)
3. /compact (컨텍스트 정리)
4. 중요한 결정사항 CLAUDE.md에 추가
5. 메모리 저장 (claude memory 커맨드)
외부 API 연동할 때
1. API 문서 또는 실제 응답 예시 준비
2. 구버전 구현 코드 있으면 위치 파악
3. 에이전트에게 규격 + 참고 위치 함께 제공
4. 구현 후 실제 API 호출로 검증
막힐 때
- 에이전트가 계속 틀린 방향으로 가면 → 새 세션 시작
- "왜 이게 안 되지?" 싶을 때 → Extended Thinking (Tab키)
- 여러 파일을 건드려야 할 때 → Todo 먼저 만들게 하기
- UI가 의도와 다를 때 → 레퍼런스 스크린샷 첨부
9. 핵심 원칙 요약
| 문제 | 원인 | 해결책 |
|---|---|---|
| 설계만 하다 지침 | 과도한 사전 설계 | 큰 방향 + TODO 전략 |
| 중간 지시 누락 | Lost in the Middle (어텐션 희석) | 잘게 쪼개기 + Todo 체크리스트 |
| 컨벤션이 후반에 무너짐 | 학습 데이터 prior가 우세해짐 | CLAUDE.md + 긍정문 지시 |
| 엉뚱한 방향 구현 | 모호한 지시 | Plan 모드 + 구체적 스펙 |
| 원인 모를 버그 | 추론이 필요한 복잡한 문제 | Extended Thinking (Tab키, 레벨 조절) |
| API 연동 실패 | 도메인 지식 부재 | 규격 직접 제공 + 구버전 코드 참조 |
| UI 의도 불일치 | UX 용어 부재 | 레퍼런스 스크린샷 + UX 용어 학습 |
| 같은 실수 반복 | 일회성 피드백 | 스킬로 자동화 |
한 줄 요약
작게 나누고, 구체적으로 지시하고, 잊어버리기 전에 CLAUDE.md에 저장하라.
부록: LLM의 한계와 우리의 역할
LLM은 패턴 인식과 코드 생성을 잘한다. 하지만:
- 긴 정보를 추적하지 못한다 → 우리가 시스템(CLAUDE.md, Todo, compact)으로 보완
- 도메인 지식이 없다 → 우리가 규격과 예시로 주입
- 모호함을 추측으로 채운다 → 우리가 구체적으로 명시
- 실행 결과를 스스로 검증하지 않는다 → 우리가 직접 실행해서 확인
바이브코딩은 "에이전트가 다 해준다"가 아니다. 에이전트가 잘 할 수 있도록 환경을 만드는 것이 개발자의 역할이다. 도메인 전문가로서 방향을 잡고, 에이전트가 그 방향대로 속도를 내게 하는 것.
시스템 엔지니어로서 인프라 도메인 지식은 강점이다. 프론트엔드 UX 지식은 투자할 영역이다. 그 차이가 결과물의 품질 차이로 바로 나타난다.
'IT > AX' 카테고리의 다른 글
| IoT 코딩도 잘하는 Fable 형님 — ESP32 원격 전원 켜기 트러블슈팅 후기 (1) | 2026.07.05 |
|---|---|
| [Codex 입문 6/6] Automations·Subagents·Hooks - 안전한 Codex 하네스 (0) | 2026.06.13 |
| [Codex 입문 5/6] Skills·MCP·Plugins - Codex를 내 도구로 확장하기 (0) | 2026.06.13 |
| [Codex 입문 4/6] AGENTS.md와 Memories - Codex가 내 프로젝트를 기억하는 법 (0) | 2026.06.13 |
| [Codex 입문 3/6] Plan과 Goal로 일 맡기기 - 좋은 프롬프트와 검증 (0) | 2026.06.13 |