GateGuard — 사실 강제 사전 실행 게이트
Claude가 편집 전에 조사하도록 강제하는 PreToolUse 훅입니다. '괜찮습니까?' 같은 자기 평가 대신 구체적인 사실을 요구합니다. 조사 활동 자체가 자기 평가가 제공하지 못한 인식을 만들어냅니다.
활성화 시점
- 파일 편집이 여러 모듈에 영향을 미치는 코드베이스 작업
- 특정 스키마나 날짜 형식을 가진 데이터 파일이 있는 프로젝트
- AI가 생성한 코드가 기존 패턴과 일치해야 하는 팀
- Claude가 조사 대신 추측하는 경향이 있는 모든 워크플로
핵심 개념
LLM의 자기 평가는 작동하지 않습니다. '정책을 위반했습니까?'라고 물으면 항상 '아니오'라는 답이 돌아옵니다. 이는 실험적으로 검증되었습니다.
하지만 '이 모듈을 임포트하는 모든 파일을 나열하라'고 요구하면 LLM은 Grep과 Read를 실행해야 합니다. 조사 활동 자체가 맥락을 형성하여 출력을 변화시킵니다.
3단계 게이트:
1. DENY — 첫 번째 Edit/Write/Bash 시도를 차단
2. FORCE — 모델이 정확히 어떤 사실을 수집해야 하는지 지시
3. ALLOW — 사실이 제시된 후 재시도 허용
세 단계를 모두 구현한 경쟁자는 없습니다. 대부분은 차단에서 멈춥니다.
증거
동일한 작업을 수행하는 두 개의 독립적인 A/B 테스트, 동일한 에이전트:
| 작업 | 게이트 있음 | 게이트 없음 | 차이 |
|---|---|---|---|
| 분석 모듈 | 8.0/10 | 6.5/10 | +1.5 |
| 웹훅 검증기 | 10.0/10 | 7.0/10 | +3.0 |
| 평균 | 9.0 | 6.75 | +2.25 |
두 에이전트 모두 실행되고 테스트를 통과하는 코드를 생성합니다. 차이는 설계 깊이에 있습니다.
게이트 유형
Edit / MultiEdit 게이트 (파일당 첫 번째 편집)
MultiEdit도 동일하게 처리됩니다. 배치의 각 파일은 개별적으로 게이트됩니다.
{file_path}을(를) 편집하기 전에 다음 사실을 제시하세요.
1. 이 파일을 임포트/require하는 모든 파일을 나열하세요 (트리 검색 — Glob/Grep, 또는 Bash를 통해 find/grep)
2. 이 변경으로 영향을 받는 공개 함수/클래스를 나열하세요
3. 이 파일이 데이터 파일을 읽거나 쓰는 경우, 필드명, 구조 및 날짜 형식을 보여주세요
(원시 프로덕션 데이터 대신 수정된 값 또는 합성 값 사용)
4. 사용자의 현재 지시사항을 그대로 인용하세요
Write 게이트 (첫 번째 새 파일 생성)
{file_path}을(를) 생성하기 전에 다음 사실을 제시하세요.
1. 이 새 파일을 호출할 파일과 라인을 지정하세요
2. 동일한 용도를 제공하는 기존 파일이 없는지 확인하세요 (트리 검색 — Glob/Grep, 또는 Bash를 통해 find/grep)
3. 이 파일이 데이터 파일을 읽거나 쓰는 경우, 필드명, 구조 및 날짜 형식을 보여주세요
(원시 프로덕션 데이터 대신 수정된 값 또는 합성 값 사용)
4. 사용자의 현재 지시사항을 그대로 인용하세요
파괴적 Bash 게이트 (모든 파괴적 명령)
다음에서 트리거: rm -rf, git reset --hard, git push --force, drop table 등
1. 이 명령이 수정하거나 삭제할 모든 파일/데이터를 나열하세요
2. 한 줄 롤백 절차를 작성하세요
3. 사용자의 현재 지시사항을 그대로 인용하세요
일상적 Bash 게이트 (세션당 한 번)
1. 현재 사용자 요청을 한 문장으로 요약
2. 이 특정 명령이 검증하거나 생성하는 내용
병렬 배치 및 부분 적용
최초 접촉 게이트는 각 도구 호출을 독립적으로 평가합니다. 아직 접촉하지 않은 파일에 대한 여러 편집이 하나의 병렬 배치로 전송되면, 첫 번째 호출이 거부되고 해당 파일이 검사됨으로 표시되어 해당 배치의 나머지 형제 편집은 적용됩니다. 롤백은 없습니다. 파일은 거부된 편집 없이 형제 편집만 담은 상태가 될 수 있습니다.
거부 메시지는 파일을 명시하고 배치 형제가 이미 적용되었을 수 있음을 경고합니다. 문자 그대로 처리하세요.
- 아직 접촉하지 않은 파일에 대한 종속 편집은 병렬 배치가 아닌 순차적으로 전송하세요. 정의와 첫 번째 사용, 임포트와 호출 지점은 동일한 배치에 포함되어서는 안 됩니다.
- 최초 접촉 거부 후 사실을 제시하고, 거부된 편집을 재시도한 후 배치의 다른 내용을 기반으로 작업하기 전에 파일을 다시 읽으세요.
배치 전체 잠금은 불가능합니다. 훅은 도구 호출을 한 번에 하나씩만 보므로 게이트는 어떤 호출이 함께 도착했는지 알 수 없습니다.
빠른 시작
옵션 A: ECC 훅 사용 (설치 불필요)
scripts/hooks/gateguard-fact-force.js 훅이 이 플러그인에 포함되어 있습니다. hooks.json을 통해 활성화하세요.
GateGuard가 설정 또는 복구 작업을 차단하는 경우, 세션을 ECC_GATEGUARD=off로 시작하세요. 훅 수준 제어를 위해 GateGuard 훅 ID와 함께 ECC_DISABLED_HOOKS를 계속 사용하세요.
긴 세션에서는 처음 GATEGUARD_FACT_FORCE_FULL_DENIALS(기본값 3)개의 사실 강제 거부만 전체 4가지 사실 블록을 출력하고, 이후 거부는 거부 순서만 포함하는 한 줄로 축소되어 거의 동일한 블록이 컨텍스트 윈도우에 누적되어 모델 반복 루프를 증폭하는 것을 방지합니다(#2142). 사실을 제시한 후 동일한 파일이나 명령을 재시도하면 게이트가 다시 트리거되지 않습니다.
세분화된 제어
ECC_GATEGUARD=off(또는 GATEGUARD_DISABLED=1)는 게이트를 완전히 끕니다. 이 표의 변수는 그렇지 않습니다. 각각 하나의 동작을 좁히는 반면, 중요한 파괴적 Bash 검사는 계속 실행됩니다.
| 변수 | 기본값 | 효과 |
|---|---|---|
GATEGUARD_BASH_ROUTINE_DISABLED | 설정 안 됨 (게이트 켜짐) | 일상적 Bash 게이트만 비활성화합니다. 파괴적 Bash 게이트(rm -rf, git reset --hard, drop table, dd if=, …)는 영향을 받지 않습니다. |
GATEGUARD_EXEMPT_GLOBS | 설정 안 됨 (면제 없음) | 쉼표로 구분된 글로브; 일치하는 Edit/Write/MultiEdit 대상은 최초 접촉 사실 강제를 건너니다. 임포트 가치가 낮은 트리(테스트, 생성된 아티팩트, 스크래치 디렉토리)에 사용됩니다. |
GATEGUARD_FACT_FORCE_FULL_DENIALS | 3 | 전체 4가지 사실 블록을 출력하는 거부 횟수입니다. 이후 거부는 한 줄로 축소됩니다. 0은 첫 번째 거부부터 축소합니다. |
GATEGUARD_BASH_EXTRA_DESTRUCTIVE | 설정 안 됨 | 정규식 소스 형태의 추가 파괴적 명령 패턴으로, 내장 집합에 추가됩니다. 잘못된 형식의 정규식은 설정되지 않은 것으로 처리(내장 패턴은 여전히 적용)되고 stderr에 한 번 기록됩니다. |
GATEGUARD_STATE_DIR | ~/.gateguard | 세션별 게이트 상태가 저장되는 위치입니다. 상태를 유지할 수 없으면 게이트는 루프 대신 작업을 허용하고 경고에 이 변수를 명시합니다. |
GATEGUARD_BASH_ROUTINE_DISABLED는 1, true, on, enabled, enable 또는 yes(대소문자 및 공백 무시)를 허용합니다. 다른 값은 게이트를 켠 상태로 둡니다.
게이트 완전히 끄기
| 변수 | 효과 |
|---|---|
ECC_GATEGUARD=off | 세션에 대해 GateGuard를 비활성화합니다. 0, false, off, disabled 또는 disable을 허용합니다. |
GATEGUARD_DISABLED=1 | 동일한 효과. 1만 인식합니다. 위의 철자는 여기에 적용되지 않습니다. |
훅 수준 제어를 위해 GateGuard 훅 ID와 함께 ECC_DISABLED_HOOKS를 계속 사용하세요.
GATEGUARD_EXEMPT_GLOBS에 대한 글로브 의미
패턴은 프로젝트 기준 전체 대상 경로와 일치합니다. 프로젝트 루트는 CLAUDE_PROJECT_DIR이며, 훅 페이로드의 cwd, 그 다음 훅 프로세스 작업 디렉토리로 폴백됩니다. 상대 글로브는 해당 루트 외부의 대상을 절대 면제하지 않습니다. 명시적 절대 글로브는 전체 절대 대상 경로와 일치하며 의도적으로 프로젝트 외부 경로를 면제할 수 있습니다.
패턴과 경로 모두 / 구분자를 사용하고 소문자로 일치합니다. *는 세그먼트 내에서 일치하고, **는 세그먼트를 가로질러 일치하며, ?는 구분자가 아닌 문자 하나와 일치합니다. **/는 디렉토리 0개를 포함하므로 **/tests/**는 tests/foo.js와도 일치합니다. 잘못된 형식의 패턴은 면제를 부여하지 않고 삭제됩니다.
2.2.1부터 services/**는 프로젝트의 루트 services 트리만 포함하고, *.md는 루트 Markdown 파일만 포함합니다. 프로젝트 내 모든 Markdown 파일에는 **/*.md를 사용하세요. 기존의 앵커되지 않은 면제는 조정이 필요할 수 있습니다.
{
"env": {
"GATEGUARD_BASH_ROUTINE_DISABLED": "1",
"GATEGUARD_EXEMPT_GLOBS": "**/tests/**,tests/**,**/*.test.*,**/docs/**,**/dist/**"
}
}
옵션 B: 구성이 포함된 전체 패키지
pip install gateguard-ai
gateguard init
이렇게 하면 프로젝트별 구성(사용자 정의 메시지, 무시 경로, 게이트 토글)을 위한 .gateguard.yml이 추가됩니다.
안티 패턴
- 자기 평가를 대신 사용하지 마세요. '괜찮습니까?'는 항상 '예'라는 답을 얻습니다. 이는 실험적으로 검증되었습니다.
- 데이터 스키마 검사를 건너뛰지 마세요. 두 A/B 테스트 에이전트 모두 실제 데이터가
%Y/%m/%d %H:%M을 사용하는데 ISO-8601 날짜를 가정했습니다. 데이터 구조를 확인(수정된 값 사용)하면 이러한 전체 버그 유형을 방지할 수 있습니다. - 모든 단일 Bash 명령을 게이트하지 마세요. 일상적 Bash 게이트는 세션당 한 번만 수행됩니다. 파괴적 Bash 게이트는 매번 수행됩니다. 이 균형은 속도 저하를 피하면서 실제 위험을 포착합니다.
모범 사례
- 게이트가 자연스럽게 작동하도록 하세요. 게이트 질문에 미리 답변하지 마세요. 조사 활동 자체가 품질을 향상시킵니다.
- 도메인에 맞게 게이트 메시지를 사용자 정의하세요. 프로젝트에 특정 규칙이 있는 경우 게이트 프롬프트에 추가하세요.
.gateguard.yml을 사용하여.venv/,node_modules/,.git/과 같은 경로를 무시하세요.
관련 스킬
safety-guard— 런타임 안전 검사 (보완적이며 중복되지 않음)code-reviewer— 사후 편집 검토 (GateGuard는 사전 편집 조사)