AI 코딩 에이전트에 가드레일 치는 법 — 두 번 데이고 배운 하네스 엔지니어링
“글 하나만 올려줘”라고 했더니 대기열에 있던 글이 전부 발행됐다. 또 한 번은 백업도 안 하고 시킨 걸 그대로 실행해서 데이터가 통째로 날아갔다. AI 코딩 에이전트를 진짜로 굴려보면, 문제는 “얼마나 똑똑하냐”가 아니라 “얼마나 사고를 치느냐”다. 그래서 나는 모델을 구슬리는 대신, 모델이 일하는 판(하네스) 을 다시 짜기 시작했다.
두 번의 사고
블로그 자동화 시스템을 에이전트로 굴린다. 글을 쓰고, 검증하고, 발행하고, 키워드를 분석하는 걸 사람 대신 AI한테 맡기는 구조다. 처음엔 신났다. 그러다 두 번 크게 데였다.
첫 번째. 발행을 잠깐 멈춰둔 상태였다. 대기열(큐)에 글이 여러 개 쌓여 있었고, 나는 그중 딱 하나만 올리고 싶었다. “이 글 하나 push 해줘.” 결과는 — 큐에 있던 게 전부 발행됐다. 하나만 가리켰는데 에이전트는 “발행”이라는 동작을 큐 전체에 적용해버린 거다.
두 번째. 어떤 작업을 시켰는데, 원래라면 백업부터 뜨고 실행했어야 하는 일이었다. 나는 당연히 그럴 줄 알았다. 에이전트는 그냥 곧장 실행했고, 데이터가 다 지워졌다. “되돌릴 수 없는 일은 한 번 더 확인한다”는 건 사람한테나 당연한 거였다. 판에 그게 안 박혀 있으면 에이전트한테는 당연한 게 아니다.
두 번 다 모델이 멍청해서 난 사고가 아니다. 내가 판을 안 깔아놓고 강력한 도구를 풀어놨기 때문이다.
”하네스”가 뭔데
모델 자체는 텍스트를 받아 텍스트를 뱉는 엔진일 뿐이다. 그런데 코딩 에이전트는 파일을 읽고, 명령을 실행하고, 글을 발행하고, 데이터를 지운다. 이걸 가능하게 하는 바깥 틀 전체가 하네스(harness)다. 마구(馬具)에서 온 말 — 말(엔진)에 안장·고삐를 씌워 일을 시키는 장치다.
대부분은 이 틀을 기본값 그대로 두고 채팅창에만 매달린다. 하네스 엔지니어링은 이 판 자체를 내 작업에 맞게 다시 짜는 일이다. 그리고 위의 두 사고를 겪고 나면, 그 일의 절반은 “능력 추가”가 아니라 “가드레일 설치” 라는 걸 알게 된다.
프롬프트를 잘 쓰는 게 말에게 더 잘 말하는 법 이라면, 하네스 엔지니어링은 말이 절벽으로 안 달리게 울타리를 치는 법 이다.
1. 위험한 규칙은 대화가 아니라 구조로 박는다
큐 전체가 발행된 사고 뒤, 나는 매번 “큐는 건드리지 마”라고 당부하는 짓을 그만뒀다. 사람은 까먹고, 에이전트는 그 당부가 든 대화가 맥락 창 밖으로 밀려나면 잊는다.
대신 프로젝트 지침 파일(매 세션 자동으로 읽히는 규칙 문서) 맨 위에 절대 규칙으로 박았다. 요지는 이렇다.
대기열의 발행 대기 글은 절대 건드리지 않는다. 자동 발행은 정해진 스크립트가 매일 정해진 시간에 알아서 처리한다. 사용자가 “이 글 올려줘”라고 명시적으로 지시하기 전에는 발행·이동·삭제 어떤 조작도 하지 않는다. 목록 확인은 되지만, 실제 발행은 명시적 지시 후에만.
이 파일(CLAUDE.md)은 프로젝트 루트에 두면 매 세션 자동으로 읽힌다. 위쪽 디렉터리로 거슬러 올라가며 다 모아 읽고, 개인용은 ~/.claude/CLAUDE.md에 둔다. 그래서 한 번 박아두면 매번 당부할 필요가 없다.
# CLAUDE.md (프로젝트 루트)
## ⚠️ 절대 규칙 — 발행 큐
- 대기열의 발행 대기 글은 절대 건드리지 않는다.
- 자동 발행은 정해진 스크립트가 매일 알아서 처리한다.
- 사용자가 "이 글 올려줘"라고 명시적으로 지시하기 전엔
발행·이동·삭제 어떤 조작도 하지 않는다.
단, 솔직히 말하면 이건 ‘강제’가 아니라 ‘맥락’이다. 매 세션 읽히니 까먹진 않지만, 작정하고(혹은 헷갈려서) 어기는 것까지 코드 수준에서 막아주진 않는다. “큐 건드리지 마”는 결국 부탁이다. 부탁으로 충분한 규칙은 여기에, 부탁으로 안 되는 위험한 동작은 다음 장의 강제 장치로 내린다.
2. 되돌릴 수 없는 일에는 울타리를 친다
데이터가 날아간 사고의 교훈은 더 단순했다. 에이전트한테 “알아서 조심하겠지”는 없다. 그리고 앞 장에서 봤듯, CLAUDE.md에 “조심해”라고 적는 건 부탁이지 강제가 아니다. 되돌릴 수 없는 동작은 코드로 막아야 한다. Claude Code엔 그걸 위한 두 장치가 있다.
① 권한 규칙 — 위험한 동작에 빗장.
.claude/settings.json에 무엇을 그냥 두고, 무엇을 묻고, 무엇을 막을지 선언한다.
{
"permissions": {
"deny": ["Bash(rm -rf *)"],
"ask": ["Bash(git push *)"]
}
}
deny는 아예 차단, ask는 실행 전 무조건 사람한테 물음. (평가 순서가 deny → ask → allow라, 막을 건 확실히 막힌다.) “git push”에 ask를 걸어두면 — 큐 전체가 발행되던 그 사고처럼 무를 수 없는 동작이 나가기 전에, 무엇이 올라가는지 확인할 틈이 생긴다.
② PreToolUse 훅 — 실행 직전에 가로채기. 권한 규칙보다 똑똑하게, 명령 내용을 보고 조건부로 막을 수 있다. “백업 없이 삭제”를 막는 가드가 이거다.
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": ".claude/guard.sh" }] }
]
}
}
#!/bin/bash
cmd=$(jq -r '.tool_input.command') # 훅은 stdin으로 JSON을 받는다
if [[ "$cmd" == *"rm -rf"* ]]; then
echo "백업부터 떠라. 차단됨." >&2
exit 2 # exit 2 = 이 동작 차단
fi
핵심은 exit 2. 0이면 통과, 2면 그 도구 호출이 실제로 막히고 stderr에 적은 이유가 에이전트한테 피드백으로 전달된다. CLAUDE.md의 ‘부탁’과 달리, 이건 에이전트가 못 어긴다 — 실행 자체가 차단되니까. 실제로 내 작업 폴더엔 *.bak_날짜 백업이 굴러다니는데, 지금은 손으로 뜨는 습관이다. 위 훅은 그걸 자동 강제로 끌어올리는 방법이다.
요는, 모델한테 신중함을 부탁하는 게 아니라 판이 신중함을 강제하게 만드는 거다. 사람의 주의력은 새지만, exit 2는 안 샌다.
3. 큰 일은 붙들지 말고 쪼개서 풀어놓는다
가드레일을 깔고 나면, 이제 판을 적극적으로 활용할 차례다. 큰 작업을 채팅 하나로 붙들면 금세 막힌다 — 파일을 수십 개 읽고 로그를 뒤지다 보면 정작 중요한 지시가 맥락 창 밖으로 밀려나고, 앞에서 정한 걸 뒤에서 잊는다.
그래서 큰 일은 서브에이전트(본 채팅이 띄우는 별도의 일손)에게 떼어 맡긴다. 예를 들어 “코드 전체에서 이 패턴 다 찾아줘” 같은 건 본 채팅이 직접 뒤지지 않고, 탐색 전용 에이전트가 자기 창에서 파일을 잔뜩 읽고 결론만 돌려준다. 본 채팅의 맥락은 파일 더미로 더럽혀지지 않는다.
서브에이전트는 .claude/agents/ 아래 마크다운 한 장으로 정의한다 — 위쪽은 설정(이름·역할·쓸 도구), 아래 본문이 그 에이전트의 시스템 프롬프트다.
---
name: explorer
description: 코드베이스 탐색 전용. 파일을 뒤져 결론만 보고한다.
tools: Read, Grep, Glob
model: inherit
---
너는 탐색 전용이다. 파일을 읽고 핵심만 요약해 돌려준다.
수정(Write·Edit)은 하지 않는다.
tools에 읽기 도구만 줬으니 이 친구는 애초에 파일을 고칠 수 없다 — §2의 가드레일이 에이전트 단위로도 걸리는 셈이다. 부를 땐 “explorer로 ~ 찾아줘”처럼 지목하거나, 설명을 보고 알아서 위임되게 둔다.
실은 이 글을 쓰는 중에도 그랬다. “여러 작업을 한 화면에서 보는 기능이 진짜 있나?”가 막혔을 때, 내 기억으로 답하면 글에 거짓이 박힌다. 그래서 확인 전용 에이전트를 따로 띄워 그것만 파게 시키고, 나는 그동안 다른 걸 계속했다. 잠시 뒤 걔가 정확한 답을 정리해서 돌아왔다.
장점은 셋이다 — 맥락 격리(각자 자기 창에서 일하니 본 작업이 안 터짐), 병렬화(독립적인 일은 동시에), 역할 분리(탐색용·설계용·실행용을 나눠 시킴).
4. 풀어놨으면 한 화면에서 관제한다
작업을 여러 개 백그라운드로 던지면 새 문제가 생긴다 — 지금 누가 뭘 하는지가 안 보인다.
그래서 쓰는 게 작업들을 한 화면에 모아 보는 관제 화면이다. 거기서 보이는 것:
- 답을 기다리며 멈춘 것 (내 입력이 필요한 작업)
- 돌고 있는 것
- 끝난 것

작업자 한 명한테 붙어 어깨너머로 보는 게 아니라, 관제실에서 여러 작업을 동시에 내려다보는 모드다. 일을 쪼개 푸는 순간부터, 시키는 능력보다 관제하는 능력이 중요해진다.
5. 단, 이게 과한 경우
정직하게. 이 방식이 항상 옳은 건 아니다.
- 작은 일엔 손해다. 한 줄 고치는 데 판 깔고 에이전트 쪼개는 건 배보다 배꼽이다.
- 판 까는 것 자체가 비용이다. 규칙 다듬고 절차 만드는 데 시간이 든다. 한 번 쓰고 말 일엔 안 맞는다.
- 단, 가드레일만은 예외다. 발행·삭제처럼 무를 수 없는 동작이 끼면, 작업이 크든 작든 울타리는 친다. 사고는 작은 작업에서도 난다.
기준은 단순하다. 또 할 일인가? 한 창에 안 들어갈 만큼 큰가? 무르지 못할 동작이 끼는가? 마지막 질문은 규모와 무관하게 항상 “그렇다”면 울타리부터 친다.
정리
AI 코딩 에이전트를 잘 쓰는 건 더 좋은 프롬프트를 쓰는 일이 아니다. 모델이 일하는 판을 설계하는 일이고, 그 절반은 가드레일이다.
- 한 번 데인 규칙은 입이 아니라 구조에 박는다
- 되돌릴 수 없는 일엔 울타리를 친다 (백업·확인·권한)
- 큰 일은 서브에이전트로 쪼개 푼다
- 풀어놨으면 한 화면에서 관제한다
- 작은 일엔 안 깔지만, 무를 수 없는 동작엔 규모 불문 울타리
나는 두 번 데이고 나서야 이걸 배웠다. 강력한 도구일수록, 시키는 사람이 아니라 판을 까는 사람이 되어야 한다.
(블로그 자동화 시스템을 직접 만들어 굴리면서 정리한 실전 기록입니다.)