에이전트 가드레일

읽기만 하지 말고, 오늘 필요한 부분 하나만 골라 바로 써보세요.

이 글의 순서 5개
  1. 권한 규칙 문법
  2. 우선순위와 스코프 — 누구의 규칙이 이기는가
  3. hooks — 라이프사이클에 강제 장치 끼우기
  4. 조직 거버넌스 — managed settings로 고정
  5. 격리와 번들 — 서브에이전트·plugins

Claude Code 실무 가이드에서 권한 모드 순환과 bypassPermissions 경고를 봤다면, 이 문서는 그 권한을 설계하고, 에이전트의 행동을 강제하고, 조직 차원에서 고정하는 방법을 다룹니다. 개인 설정으로는 끌 수 없는 가드레일을 팀·조직 단위로 세우려는 개발자가 대상입니다. 에이전트 운영 원칙과 그 '왜'는 여기서 다시 정의하지 않습니다 — 에이전트 개념에 정본이 있습니다. 이 문서는 "어떻게 통제하고, 어떻게 강제하는가"만 봅니다. 이어지는 다섯 절은 권한 규칙 문법, 충돌 시 우선순위와 스코프, hooks로 라이프사이클 강제, managed settings로 조직 고정, 그리고 격리 워커·번들 순서로 갑니다.


권한 규칙 문법

권한 규칙은 "도구 + 범위"를 패턴으로 적어 무엇을 허용(allow)·질문(ask)·차단(deny)할지 정의합니다. 규칙은 세 가지 형태를 가집니다.

형태의미
Tool도구 전체WebFetch
Tool(specifier)도구 + 세부 범위Bash(npm run *)
Tool(param:value)입력 파라미터별 (deny/ask만)WebFetch(domain:example.com)

도구별로 specifier 문법이 다릅니다. Bash는 와일드카드를 쓰되 경계가 단어 단위입니다 — Bash(npm run *)npm run으로 시작하는 명령을 매칭합니다( *는 word-boundary). Read·Edit는 gitignore 스타일 경로를 받습니다 — 프로젝트 상대 경로 Read(/src), 홈 기준 Read(~/notes), 절대 경로 Read(//etc/hosts). WebFetch는 도메인으로 WebFetch(domain:example.com)·WebFetch(domain:*.example.com). MCP 서버는 mcp__server(서버 전체)·mcp__server__*·mcp__server__tool(개별 도구). 서브에이전트는 Agent(Explore)·Agent(name)로 지정합니다.

규칙은 .claude/settings.json의 권한 블록에 deny·ask·allow로 나눠 적습니다. 아래는 저장소에서 반복되는 검증 작업은 통과시키고, 배포·게시·외부 전송·민감 파일 접근은 차단하거나 확인을 받는 예시입니다.

{
  "permissions": {
    "deny":  ["Bash(rm -rf *)", "WebFetch", "Read(/secrets/**)", "mcp__github__*"],
    "ask":   ["Bash(git push *)", "Bash(npm publish *)"],
    "allow": ["Bash(npm run *)", "Read(/src)", "Edit(/src)"]
  }
}

현재 세션에서 어떤 규칙이 어느 설정 파일에서 왔는지는 Claude Code 안에서 /permissions로 출처까지 확인합니다. MCP 서버 설정·.env·.mcp.json에는 토큰·키가 섞이기 쉽습니다. 무엇을 입력해도 되는지(자사 소스코드 포함)는 권한 문법이 아니라 입력 정책의 문제이므로 안전에서 다룹니다. 다음은 이 규칙들이 충돌할 때 누가 이기는지입니다.


우선순위와 스코프 — 누구의 규칙이 이기는가

같은 동작에 여러 규칙이 걸리면 결과는 두 축으로 결정됩니다. 결론부터: 종류는 deny > ask > allow, 스코프는 강한 쪽이 약한 쪽을 덮습니다.

먼저 종류. deny 규칙은 스코프·구체성과 무관하게 이깁니다(deny-first) — 같은 동작에 더 구체적인 allow가 있어도 차단됩니다. "허용 목록에 있으니 되겠지"는 통하지 않습니다.

다음으로 스코프. 설정은 아래 우선순위(높음 → 낮음)로 병합됩니다.

스코프위치비고
Managed settings서버/OS 정책·MDM최상단·override 불가
명령행 인자세션 실행 시 전달해당 세션 한정
Local project.claude/settings.local.json개인용(비버전)
Shared project.claude/settings.json팀 공유(VCS 커밋)
User~/.claude/settings.json내 모든 저장소
권한 규칙 충돌 결정 — deny 규칙이 하나라도 있으면 스코프·구체성 무관하게 차단(deny-first), 없으면 가장 높은 스코프의 ask/allow 적용. 스코프 우선순위 Managed → 명령행 → Local → Shared → User.

두 축을 합치면 핵심은 하나입니다 — deny는 스코프를 가로질러 이깁니다. managed settings의 deny가 걸려 있으면 user 설정에서 같은 동작을 allow로 풀어도 차단됩니다. 그래서 팀 저장소의 .claude/settings.json에 deny로 박은 위험 명령은 개인 설정으로 되돌릴 수 없습니다. 어떤 규칙이 어느 스코프에서 적용 중인지는 세션에서 /permissions로 확인합니다. 다음 절의 hooks는 이 권한 규칙보다도 앞에서 동작할 수 있습니다.

/permissions와 settings.json 대조 — 오른쪽 /permissions는 적용 중인 allow·ask·deny 규칙을 보여주지만 출처 파일명은 표시하지 않으므로, 왼쪽 settings.json(규칙이 정의된 곳)과 나란히 두고 충돌을 디버그함.

hooks — 라이프사이클에 강제 장치 끼우기

hooks는 권한 규칙과 별개로, 특정 라이프사이클 시점에 스크립트를 강제로 실행해 동작을 검사하거나 차단하는 메커니즘입니다. 권한 규칙이 "무엇을 허용할지"를 정의한다면, hook은 "그 시점에 무조건 이 검사를 돌려라"를 강제합니다.

대표 이벤트로는 SessionStart, PreToolUse(도구 실행 , 차단 가능), PostToolUse(실행 후), PermissionRequest(권한 prompt 시), Stop(턴 종료) 등 다수가 있습니다. 이벤트 종류는 버전마다 추가되므로 총수를 단정하지 않습니다 — 필요한 이벤트는 매번 레퍼런스에서 확인하세요. 각 hook은 matcher로 어떤 도구에 걸지 매칭합니다.

hooks 라이프사이클 — SessionStart → PreToolUse hook(권한 평가보다 먼저, 차단 가능) → 권한 규칙 평가 → 도구 실행 → PostToolUse → Stop. 종료코드 exit 0 통과·exit 2 차단·stdout JSON decision.

가장 흔한 형태인 command hook은 종료 코드로 결과를 전달합니다.

출력의미
exit 0통과 (결정 없음)
exit 2차단 — stderr 내용이 Claude에게 피드백으로 전달됨
stdout JSONdecision으로 제어 (예: PermissionRequest hook이 "behavior":"allow"로 prompt 대신 자동 응답)

단, PreToolUse에서 exit 0은 "승인"이 아니라 정상 권한 흐름이 그대로 이어진다는 뜻입니다. 강제력의 핵심은 순서입니다. PreToolUse hook은 권한 규칙보다 먼저 돌고, 도구 실행 전에 차단할 수 있습니다. hook의 deny는 allow 규칙도 덮습니다(단 hook의 allow가 deny 규칙을 덮지는 못합니다 — deny는 여전히 이깁니다). 여러 hook의 결정이 충돌하면 가장 제한적인 쪽이 우선합니다(deny > defer > ask > allow). 예를 들어 커밋 전 린트를 강제하려면, PreToolUse hook을 걸고 검사 스크립트를 돌린 뒤 실패 시 차단합니다.

npm run lint || exit 2

hook 설정은 권한과 같은 자리에 둡니다 — ~/.claude/settings.json(전역)·.claude/settings.json(프로젝트)·.claude/settings.local.json(비버전)·managed settings·plugin. 아래는 Bash 도구 호출에 사전 검사를 거는 예시입니다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/check-bash.sh"
          }
        ]
      }
    ]
  }
}

권한 규칙과 hook의 정확한 선후·상호작용은 code.claude.com/docs/en/hooks 레퍼런스에서 재확인하세요. 다음은 이 규칙과 hook을 개인이 끌 수 없게 만드는 방법입니다.


조직 거버넌스 — managed settings로 고정

지금까지의 규칙과 hook은 팀 저장소에 커밋해 공유할 수 있지만, 개인이 자기 스코프에서 우회할 여지가 남습니다. 개인이 끌 수 없는 강제는 managed settings에서 옵니다. managed settings는 스코프 우선순위의 최상단이라 override되지 않으며, 여기에만 있는 전용 강제 필드로 무엇을 잠글지 정합니다.

필드효과
allowManagedPermissionRulesOnlymanaged 권한 규칙만 유효 — project/user 규칙은 적용 안 됨
disableBypassPermissionsModebypassPermissions 모드 자체를 차단
allowManagedHooksOnlymanaged/plugin이 강제한 hook만 실행
allowManagedMcpServersOnlymanaged allowlist에 있는 MCP 서버만 연결
strictPluginOnlyCustomizationskills·hooks 등의 커스터마이즈를 plugin/managed로만 제한

여기서도 deny-first가 스코프를 가로질러 적용됩니다 — managed deny와 user allow가 부딪치면 deny가 이깁니다. 이렇게 하면 "위험 명령 차단·bypass 금지·승인된 MCP 서버만"을 조직 정책으로 고정하고, 그 위에서 각 팀이 자기 규칙을 얹는 구조가 됩니다.

{
  "allowManagedPermissionRulesOnly": true,
  "allowManagedHooksOnly": true,
  "allowManagedMcpServersOnly": true,
  "permissions": {
    "disableBypassPermissionsMode": "disable",
    "deny": [
      "Read(/secrets/**)",
      "Bash(curl *)"
    ],
    "ask": [
      "Bash(git push *)",
      "Bash(npm publish *)"
    ],
    "allow": [
      "Bash(npm run *)"
    ]
  }
}

실제로 어떤 managed 설정을 적용하는지·어떤 사내 MCP 서버와 plugin을 허용하는지는 조직 계정·정책에 따라 다릅니다.

다음은 권한을 좁힌 격리 워커와, 이 모든 표준을 묶어 배포하는 단위입니다.


격리와 번들 — 서브에이전트·plugins

가드레일의 마지막 두 조각은 권한을 좁힌 워커로 격리하기그 표준을 팀에 배포하기입니다.

서브에이전트는 격리된 컨텍스트·자체 system prompt·도구 allowlist(toolspermissionMode를 가진 워커입니다. 정의는 .claude/agents/(프로젝트)·~/.claude/agents/(user)에 두며, YAML frontmatter(name·description·tools·model·permissionMode 등) + 마크다운 system prompt로 작성합니다. 가드레일 관점에서 핵심은 권한을 좁힌 워커로 격리한다는 점입니다 — 예를 들어 읽기 도구만 가진 탐색용 서브에이전트를 두면, 그 워커는 편집·셸을 애초에 못 합니다. 특정 서브에이전트는 Agent(name) 권한 규칙으로 deny할 수도 있습니다.

plugins는 skills·agents·hooks·MCP 서버를 묶어 마켓플레이스로 배포하는 번들입니다. 가드레일 관점에서는 팀에 표준(hook·권한 규칙·서브에이전트)을 배포하는 단위로 보면 됩니다 — 한 번 묶어 두면 팀원이 같은 강제 장치를 일괄로 받습니다.

한 가지 혼동 정리: Claude Code의 skills(.claude/skills/SKILL.md)는 비개발자용 Claude Skills같은 Agent Skills 표준의 개발자/CLI 표면입니다 — 별개 기능이 아니라 같은 표준의 다른 표면입니다.

그리고 bypassPermissions·--dangerously-skip-permissions 위험한지(승인 게이트 생략)는 에이전트 개념의 승인 게이트 정본을 보세요. bypass 모드에서도 명시적 ask 규칙과 파괴적 삭제(rm -rf /·~)는 여전히 prompt가 뜨고(circuit breaker), 관리자는 disableBypassPermissionsMode로 모드 자체를 막을 수 있습니다.

여기까지가 권한 설계 → 강제 → 조직 고정 → 격리의 흐름입니다. 더 깊이 가려면: 사내 서버를 붙이는 MCP 커넥터, 그 전 단계인 Claude Code 실무, 에이전트 3원칙과 승인 게이트의 '왜'는 에이전트 개념, 무엇을 입력해도 되는지는 안전, 출력을 사람이 검증하는 절차는 검증 워크플로, 용어 정의는 용어집에서 이어집니다.