
Claude Code의 허가 프롬프트를 안전망을 유지하며 줄이는 방법 — 재석(在席)과 무인(無人) 상황에 따른 최적해는 다르다
요약
Claude Code 사용 시 작업 흐름을 방해하는 허가 프롬프트를 효율적으로 관리하는 방법을 제안합니다. 사용자의 재석(In-person) 및 무인(Unattended) 상황에 따라 최적의 설정 전략이 달라짐을 설명합니다.
핵심 포인트
- 재석 상황에서는 프롬프트 빈도를 줄이고 즉시 응답하는 auto 모드가 적합합니다.
- 무인 상황에서는 프롬프트 자체를 생성하지 않는 dontAsk 모드가 권장됩니다.
- 안전망 유지를 위해 hook, deny, sandbox 등 공통 토대 설정을 선행해야 합니다.
- 상황별 최적해는 프롬프트를 사람에게 보여줄지, 거부할지에 따라 결정됩니다.
AI 코딩 에이전트 (본고는 Claude Code)에게 작업을 맡기고 싶은데, python -c나 rm을 할 때마다 허가 프롬프트가 나타나 흐름이 끊긴다. 귀찮다고 Bash(*)로 넓게 허가하면, 이번에는 안전망 자체가 사라진다——이 딜레마는 대개 하나의 질문을 모호하게 둔 채 설정을 만지기 때문에서 발생한다.
그 질문은 바로 "당신은 그 자리에 있는가 (재석, 在席), 없는가 (무인, 無人)"이다.
목표는 공통적이다. 불필요한 허가 프롬프트를 없애 효율적으로 작업하되, 안전망은 제거하지 않는다. 하지만 최적해는 재석과 무인 상황에서 다르다. 재석 중이라면 "줄이고, 남은 것은 즉시 응답한다". 무인 중이라면 "애초에 내보내지 않는다 (대답할 사람이 없으니까)". 본고는 이 두 가지를 정면으로 구분하고, 양쪽 모두에 공통되는 토대 → 재석 → 무인 순으로 정리한다.
전제: 본고는 Claude Code의 settings.json (permissions/sandbox/hooks를 작성)을 편집할 수 있고, PreToolUse hook (도구 실행 전에 실행되는 외부 스크립트)을 설치할 수 있는 로컬 개인 이용을 상정한다.
검증 환경: 동작은 2026년 6월·macOS CLI (v2.1.x)에서 확인한 것이다. 허가 관련 사양은 버전에 따라 달라지므로, claude --version으로 자신의 버전을 확인하고 마지막에는 자신의 환경에서 직접 확인하기 바란다. : 연구 프리뷰 단계이므로 버전 및 플랜에 따라 이용 가능 여부가 달라진다 (사용할 수 없는 경우 후술할 sandbox auto-allow + scoped allow 조합이 대안이다). auto mode sandbox 활성화 여부는 settings.json의 sandbox.enabled (기본값 on)로 확인한다. 설정 key의 정석: 구체적인 key는 공식 permissions doc / sandbox doc을 기준으로 한다.
유일한 분기점: 재석인가, 무인인가
허가 프롬프트 설계는 이 한 축에 따라 최적해가 갈린다. 같은 목표 (불필요한 프롬프트를 없애는 것)라도, 사람이 대답할 수 있는지에 따라 수단이 반대가 된다.
| 구분 | 재석 (사람이 루프 안에 있음) | 무인 (사람이 없음) |
|---|---|---|
| 예시 | 대화 작업 · /rc로 원격 대응 | 야간 배치 · 정기 처리 |
| 프롬프트 처리 | 줄인다 → 남은 것은 즉시 응답 | 없앤다 (내보내지 않음) |
| 최적 mode | auto | dontAsk |
| 위험 조작 | 프롬프트 → 사람이 판단 (remote는 알림 → mobile) | 자동 deny + 에이전트가 스스로 수정 |
| 안전망 | 사람 (즉시 응답) + 공통 토대 | 공통 토대 (사람을 대신함) |
포인트는, 재석인가 무인인가에 따라 변하는 것은 "남은 프롬프트를 사람에게 보여줄 것인가 거부할 것인가"뿐이라는 점이다. 토대인 안전망 (평가 순서 · sandbox · 비밀 보호 · hook · deny)은 양쪽 모두에 공통된다. 따라서 먼저 "공통 토대"를 한 번만 설명하고, 그 위에서 재석/무인의 차이를 서술한다.
/rc (원격 대응)는 재석의 변종이다. 사람은 루프 안에 있어 대답하지만, 터미널 앞에 있지 않기 때문에 각 프롬프트가 mobile로의 중단이 된다. 따라서 재석 중에서도 "프롬프트 빈도를 더욱 낮추고 싶다"는 압박이 강한 위치에 있다.
공통 토대 — 재석이든 무인이든 동일한 부분
재석/무인 어느 쪽에서도 유효한 토대를 먼저 정리한다. 여기가 제대로 작동하면, 재석에서 줄이는 것이나 무인에서 없애는 것이나 동일한 부품으로 실현할 수 있다.
① 평가 순서: hook → deny → ask → allow → mode
명령어는 고정된 순서로 평가된다. 상세도(Specificity)는 순서를 바꾸지 않는다 (더 구체적인 allow가 있더라도 ask가 있다면 패배한다 · 공식 doc 명시).
| 순서 | 판정 | 결과 |
|---|---|---|
| 1 | PreToolUse hook | exit 2로 즉시 차단 (rule 평가보다 앞선 최후의 보루) |
| 2 | deny 규칙 | 일치 시 거부 (최우선 · 스코프를 넘나듦) |
| 3 | ask 규칙 | 일치 시 확인 프롬프트 (allow보다 우선) |
| 4 | allow 규칙 | 일치 시 자동 실행 |
| 5 | (모두 불일치) | ← 재석/무인의 분기점 defaultMode 의존 |
마지막 행이 분기점이다. 어떤 규칙에도 해당하지 않는 명령어를, **재석은 auto...
가 「분류기에서 안전하면 자동, 위험하면 확인」, 무인은 dontAsk가 「거부」**로 기울어집니다. deny
/ask
/allow
/hook의 토대는 같으며, 5행의 기본값(default)만 mode에 따라 달라집니다 —— 이것이 「재석/무인에 따라 변하는 것은 기본값뿐이다」의 실체입니다.
흔히 하는 실수 주의: 평가 순서는 공식 doc에 따라
deny → ask → allow 순입니다.
ask가 allow보다 우선합니다 (일치하는 ask가 있다면, 범위가 넓은 allow가 있더라도 프롬프트가 나타납니다). 「deny → allow → ask」는 틀린 순서입니다.
② 상자 (sandbox) — 양 모드의 토대
sandbox는 OS 레벨에서 Bash의 쓰기 대상 및 통신 대상을 격리합니다 (macOS=Seatbelt / Linux=bubblewrap). autoAllowBashIfSandboxed: true (기본값)라면, 상자 안에 수용되는 Bash는 프롬프트 없이 실행됩니다. 재석 모드에서는 프롬프트를 「줄이는」 주력 수단이며, 무인 모드에서는 「상자가 경계를 보장하므로 자동 실행해도 된다」는 근거가 됩니다.
경계를 결정하는 것은 cwd입니다 (이 부분이 설계의 핵심입니다):
sandbox의 쓰기 가능 경계 =
실행 시의 작업 디렉토리 (cwd) 및 그 하위 디렉토리 + allowWrite로 명시된 경로 + 세션 tmp. 동일한 명령어라도 cwd가 바뀌면 허용 여부가 반전됩니다.
저는 이 경계를 두 번이나 착각했습니다. 「어떤 명령어가 거부되는가」를 관찰하며 당초 「명령어의 종류에 따라 결정된다」고 결론 내렸으나, 그것은 오류였습니다. 원인은 (1) echo / python -c "print(...)"와 같은 부작용(side-effect)이 없는 명령어로 검증했던 것 (아무것도 쓰지 않으므로 경계에 닿지 않아 항상 통과함), (2) cwd=home에서 검증했던 것 (home 전체가 경계 내에 있어 폭넓게 통과함)의 두 가지 착각 때문이었습니다. 경계를 확인하려면, 실제로 쓰는 1줄의 명령어로, 실제 환경과 동일한 cwd에서 수행하십시오 (touch <cwd 하위>/_t는 통과하지만, touch <cwd 외부>/_t는 무인 모드에서 거부됩니다).
③ 비밀은 이중으로 보호한다
sandbox를 on으로 설정하는 것만으로는 비밀을 지킬 수 없습니다. sandbox가 가두는 것은 Bash뿐이며, Read/Edit 도구나 MCP를 통한 전송은 상자 밖에 있습니다. 게다가 기본 read 설정에서는 .env나 ~/.aws/credentials가 에이전트에게 그대로 노출됩니다 (공식 doc에 명시됨). 따라서:
permissions.deny에Read(.env)/Read(**/.env)/Read(~/.ssh/**)(도구를 통한 읽기 차단)sandbox.filesystem.denyRead에~/.ssh/~/.aws(Bash를 통한 읽기 차단)
이와 같은 이중 구조를 갖춰야 비로소 차단할 수 있습니다 (한쪽만으로는 유출됩니다).
④ hook과 deny를 「벽」으로 만든다
최후의 보루 또한 양 모드 공통입니다.
- PreToolUse hook (exit 2): 평가 순위 최상위. 막고 싶은 작업 (main 브랜치로의 직접 push 등)을 의도 기반으로 차단하는 최후의 보루 —— 단, 래퍼(wrapper)를 벗겨내면 우회될 수 있습니다.
env FOO=bar git push와 같이env/timeout/nohup/xargs를 앞에 붙이면 선두 토큰이 어긋나 그대로 통과해 버립니다 (저의 guard가 실제로 이 방식으로 뚫렸었으며, 재점검을 통해 막았습니다). 판단을 내리기 전에 래퍼 명령어,VAR=val, 옵션 등을 건너뛰고 본체 명령어를 추출해야 합니다. 구현의 골자는 「무인 자율 편」과 공식 hooks doc에 있습니다. deny규칙: 전송로 (curl/wget) · 이력 파괴 (git push --force/reset --hard) · 불가역적 공개 (npm publish
/deploy 계열을 최우선으로 거부합니다. -
치명적인 삼각지대(lethal trifecta)를 하나 제거한다(설계 관점): '기밀 접근 / 의심스러운 입력 / 외부 전송 경로'의 3가지 조건이 갖춰지면 injection에 무방비 상태가 됩니다 (Simon Willison). Meta의 Rule of Two도 유사합니다 (권한은 최대 2개). Read(.env)
deny로 기밀을, network deny로 전송 경로를 제거하여, 세 가지 모두 갖추지 못하는 설계를 합니다.
상주(在席) — 프롬프트를 '줄이는 것'(당신이 있을 때)
사람이 있다면 목표는 '멈추지 않는 것'입니다. 안전한 것은 자동으로 실행하고, 위험한 것만 확인을 남겨 즉시 응답합니다. 상주 설정은 3단계입니다:
어떤 규칙에도 해당하지 않는 명령어를 백그라운드 분류기가 안전성 검사하여 자동 실행하고, 위험하다고 판단된 것(deploy / 대량 삭제 / 권한 부여 등)만 확인에 올립니다. auto
mode를 기본값으로 합니다. deny
그리고 '중요한 파괴 작업만 요청하는(ask)' 기능을 남기므로 '멈추지 않지만 위험한 것만 확인'이 됩니다. 저는 상주 시 auto
을 기본값으로 사용하며, 프롬프트 때문에 작업이 멈추지 않는 차이는 실제 운영에서 명확합니다 (사용 가능 여부는 버전/플랜에 따라 다름 - 참고 참조). -
sandbox auto-allow로 대부분 자동화한다. python -c
이나 uv run은 '위험하니까 매번 확인'이 아니라 '상자 안에 가둬 자유롭게 실행'됩니다. 내용물이 무엇이든 쓰기 위치나 통신 위치를 OS가 제한하기 때문에, 루틴한 프롬프트의 대부분이 사라집니다. -
남은 것은 범위(scoped)로 좁힌다. 광범위하게 허용하지 않고 좁게 허용합니다. 임의 스크립트는 Bash(python3 ./scripts/<실제 파일명>.py *)
처럼 named-script + 해당 경로만 allow로 설정합니다. 반대로 '상주 시에도 확인하고 싶은 위험 작업'은 ask
에 넣습니다 (예: Bash(git push origin main))——평가 순서에서 allow보다 우선되므로 확실하게 확인을 받을 수 있습니다.
/rc remote의 경우: 상주하지만 mobile로 응답하기 때문에, 각 프롬프트가 중단됩니다. 할 일은 1~3과 동일하며, 프롬프트 빈도를 더욱 낮추는 방향(auto + sandbox auto-allow를 두껍게)으로 가져가서, 정말 판단이 필요한 것만 알림이 오는 상태를 만듭니다.
상주에 대한 심층 분석은 별도 글로: allow/deny의 인자 제약 allow 우회, env-runner(devbox run / docker exec 등)의 허점, 복합 명령어의 서브 커맨드별 대조, built-in read-only set——상주에서 허용을 엄격하게 다듬는 자세한 내용은 'Claude Code 상주편'에 있습니다. 본 글은 방침이며, 저곳이 상세 참고 자료입니다.
무인(無人) — 프롬프트를 '없애는 것'(당신이 없을 때)
야간 배치나 주기적 처리는 ask
(확인 프롬프트)에 답변할 사람이 없습니다. 순진한 해결책인 --dangerously-skip-permissions는 안전망 자체를 해제하는 위험한 수단입니다 (→ 마지막 절). 핵심은 dontAsk mode입니다. 무인의 설정도 3단계입니다:
'원래 프롬프트가 나오는 상황을 defaultMode
을 dontAsk
로 변경합니다. 거부(deny)로 변환하는 것입니다. 다만 allow 규칙이나 sandbox에서 허용된 것은 평소대로 실행됩니다. 즉, '안전하고 허용됨 → 실행 / 그 외 → 프롬프트가 아닌 즉시 deny (아무도 기다리지 않음 = 멈추지 않음)'입니다. deny
/hook의 안전망은 살아있다 -
(escape hatch=상자를 우회하여 non-sandbox로 실행하는 탈출구,를 막는 Strict sandbox). sandbox.allowUnsandboxedCommands: false
을 추가하여 무인은 사람이 최종 판단할 수 없기 때문에, 상자를 벗어나는 탈출구까지 막아 '상자 = 최종 경계'를 철저히 합니다(상주 시에는 기반 + 사람으로 충분하므로 필수적이지 않습니다). -
network를 narrow로 + git 외 데이터의 백업을 별도로 운영한다. 전송 대상을 좁히고 (github.com 등 광역은 domain fronting의 표적이 될 수 있음), Sheets/DB처럼 git으로 되돌릴 수 없는 데이터는 일일 백업합니다 (자세한 내용은 무인 자율편).
deny되면, 에이전트가 올바른 방식으로 수정한다
dontAsk의 핵심은 바로 이 지점입니다. deny는 사람을 멈추게 하지 않고 에이전트에게 즉시 반환되므로, 에이전트는 허가되는 방식으로 다시 작성하여 계속 진행할 수 있습니다. ... | python3 -c "…"가 거부되면 jq를 사용하고, 복잡한 heredoc은 파일에 작성하여 실행합니다. 사람의 승인을 단 한 번도 거치지 않고 진행됩니다. "AI가 주의할 것이다"라는 믿을 수 없는 약속을, 결정론적인 (확률에 의존하지 않고 규칙으로 확실하게 판정하는) 거부 + 자기 수정 (Self-correction) 루프로 대체하는 발상입니다 (수정할 수 없을 때는 retry 상한선에서 중단하여 "미완성 + 나중에 리뷰" 상태로 착지합니다).
실제로 이 동작은 격리된 dontAsk 세션에서 확인했습니다. curl (deny 대상)을 실행하게 하면, 확인 절차 없이 즉시 거부되며, 에이전트는 멈추지 않고 "네트워크가 필요하다면 WebFetch로 가져올 수 있습니다"라며 대안을 제시했습니다.
무인 상황의 심층 분석은 별도 기사로: 이 이후의 내용——위협을 6가지 유형으로 나누어 무엇에 무엇이 필요한지에 대한 지도, hook/sandbox의 허점과 다층 방어, prevention을 뚫고 나온 파괴에 대비하는 backup——는 「Claude Code 무인 자율편」에서 심도 있게 다루고 있습니다. 본고는 재석(在席) 상황과의 대비를 통해 무인 상황을 위치시키는 것까지를 담당합니다.
해서는 안 될 일: bypassPermissions
프롬프트를 없애는 가장 빠른 방법은 --dangerously-skip-permissions (= bypassPermissions 모드)이지만, 이는 프롬프트를 일괄 스킵하여 대부분을 자동 승인하는 설계입니다 (명시적인 ask 규칙과 rm -rf / 등의 circuit breaker만 남습니다). 공식 문서에서 격리된 container/VM 전용이라고 명시했듯이, 이는 "프롬프트를 선택해서 줄이는" 것이 아니라 "프롬프트 층 자체를 제거하고 환경 측면(상자)을 유일한 방벽으로 만드는" 설계이므로, 로컬 운영에는 적합하지 않습니다. "프롬프트를 줄이면서" 동시에 "안전망을 유지하는" 정석은 재석=auto / 무인=dontAsk이며, bypass가 아닙니다.
요약: 재석 버전 / 무인 버전의 settings
판단 기준은 우선 "재석인가 무인인가"입니다. 토대 (deny / sandbox / 비밀의 이중 구조 / hook)는 공통이며, defaultMode와 무인용 몇 줄만 달라집니다. 아래는 최소 예시이며, deny는 프로젝트 요구 사항에 맞춰 추가하십시오 (저의 실제 환경은 deny 17건입니다).
{
"permissions": {
"defaultMode": "auto", // 재석: 분류기로 줄이고 위험한 것만 확인
...
무인 버전은 permissions와 hooks를 그대로 둔 채, defaultMode를 바꾸고, sandbox에 2줄을 추가하며, backup을 별도로 운용합니다:
"sandbox": {
"enabled": true, "autoAllowBashIfSandboxed": true,
"allowUnsandboxedCommands": false, // ← 추가: escape hatch를 차단 (Strict)
...
허가 프롬프트를 줄이는 것은 단순히 편하기 위해서만이 아닙니다. approval fatigue (승인 피로) 실측에 따르면 사람은 허가 프롬프트의 약 93%를 정밀하게 검토하지 않고 승인합니다. 즉, 너무 많이 내보내는 것은 안전망을 공동화(空洞化)시킵니다. 따라서 critical한 것만 사람에게 묻고, low-risk는 기제(mechanism)를 통해 통과시키는 것이 효율과 안전을 모두 잡는 해답입니다.
설정 전 체크리스트
설정을 건드리기 전에, 먼저 다음 순서로 결정하십시오.
- 재석인가 무인인가 — 대답할 사람이 있는가. /rc는 재석 측입니다.
- 재석이라면 —
auto, 무인이라면dontAsk.skip-permissions(bypass)는 격리 환경 전용이며, 로컬에서는 사용하지 않습니다. - 토대는 양쪽 모두 공통: 평가 순서 (deny → ask → allow) ·
.env의 이중 차단 · sandbox auto-allow · hook (wrapper 제거 필수) - git으로 되돌릴 수 없는 데이터 (Sheets/DB)에는 backup — 무인이라면 필수 (→ 무인 자율편 참조)
「허가 프롬프트(permission prompt)를 줄이는 것」의 최적해는 하나가 아닙니다. 재석(在席) 시에는 줄여서 즉시 응답하고, 무인(無人) 시에는 내보내지 않고 스스로 수정하게 합니다. 토대의 안전망은 어느 경우에도 제거하지 않는 것——그것이 바로 「효율과 안전을 양립하는 것」입니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기