본문 바로가기
C.W.K.
Stream
Lesson 01 of 05 · published

권한 모드는 반대편에 누가 있는지로 골라

~14 min · permissions, permission-mode, safety

Level 0Observer
0 XP0/64 lessons0/13 achievements
0/150 XP to next level150 XP to go0% complete

모드가 자동 실행 범위를 바꿔

permission_mode='default'는 부수 효과가 있는 도구를 사용자에게 묻고, acceptEdits는 Write와 Edit를 자동 승인하되 Bash는 계속 물어. bypassPermissions는 모든 문을 열며, plan은 실행 없이 계획만 만들게 해. dontAsk는 아무것도 묻지 않고, 미리 승인 안 된 건 거부해. 목록은 SDK와 함께 늘어나(새 릴리스는 auto도 받아). 그러니 설치한 버전의 PermissionMode를 직접 읽어.

사람이 어디서 검토하는지 먼저 봐

개발자가 키보드 앞에서 매 요청을 보는 흐름에는 파일 편집을 빠르게 하는 acceptEdits가 잘 맞을 수 있어. 서버에서 무인으로 돌지만 네 UI로 누군가 답한다면 자체 권한 처리기를 둔 default가 맞고, 답할 사람이 아예 없다면 짧은 allowed_tools와 dontAsk를 써서 멈춰 서는 대신 거부하게 해. bypassPermissions는 다른 경계에서 이미 검토된 신뢰 가능한 CI 실행기 정도로 제한해.

도구별 판단이 필요하면 처리기를 만들어

콜백은 도구 이름, 도구 입력, ToolPermissionContext를 받아 PermissionResultAllow나 PermissionResultDeny를 돌려줘. 원래라면 물어봤을 호출에만 불려. allowed_tools로 미리 승인한 도구는 여기까지 오지도 않고, echo나 ls처럼 CLI가 이미 읽기 전용으로 보는 셸 명령도 안 와. 처리기를 시험할 땐 뭔가를 쓰는 명령으로 해. cwkPippa는 지금 이 콜백을 등록하지 않으니까, 사람이 보는 UI가 반대편에 있을 때 쓰는 패턴으로 받아. 권한 정책과 승인 화면이 같은 흐름을 가리켜야 해.

원칙: 권한 정책은 보안이면서 사용자 경험이야. 실제로 승인할 사람이 있는 자리에 맞춰.

Code

컨텍스트로 모드 선택·python
from claude_agent_sdk import ClaudeAgentOptions

# 개발자와 붙어서 일할 때: 편집은 조용히 받고, 셸은 물어.
dev_options = ClaudeAgentOptions(
    cwd="/Users/me/repo",
    permission_mode="acceptEdits",
)

# 어딘가 사람이 있는 서버 작업자: 모든 질문을 네 UI로 보내.
server_options = ClaudeAgentOptions(
    cwd="/srv/jobs",
    permission_mode="default",
    can_use_tool=permission_handler,  # 다음 블록의 네 함수
)

# 무인이고 엄격하게: 아무것도 묻지 않고, 미리 승인 안 된 건 전부 거부.
batch_options = ClaudeAgentOptions(
    cwd="/srv/jobs",
    permission_mode="dontAsk",
    allowed_tools=["Read", "Grep"],
)

# 격리 컨테이너의 신뢰 CI: 우회하되, 대신 존재하는 도구를 줄여.
ci_options = ClaudeAgentOptions(
    cwd="/workspace",
    permission_mode="bypassPermissions",
    tools=["Read", "Edit", "Bash"],  # 이 실행이 가진 기본 도구는 이것뿐
)

# 리허설용 계획 전용 모드.
plan_options = ClaudeAgentOptions(
    cwd="/srv",
    permission_mode="plan",
)
Custom permission handler·python
from claude_agent_sdk import (
    ClaudeAgentOptions,
    PermissionResultAllow,
    PermissionResultDeny,
    ToolPermissionContext,
)

DEMANDS_REVIEW = {"Bash", "Write"}

async def permission_handler(tool_name: str, tool_input: dict, context: ToolPermissionContext):
    if tool_name not in DEMANDS_REVIEW:
        return PermissionResultAllow()
    # 요청을 네 UI로 넘겨. 사용자가 승인이나 거부를 눌러.
    decision = await ask_user_in_ui(tool_name, tool_input)
    if decision == "approve":
        return PermissionResultAllow()
    return PermissionResultDeny(message="User denied via UI")

options = ClaudeAgentOptions(
    cwd="/srv",
    permission_mode="default",
    can_use_tool=permission_handler,  # allowed_tools에 있는 도구에는 아예 안 불려
)

External links

Exercise

Agent SDK 호출 하나의 permission_mode를 확인하고 그 선택이 맞는 실행자 사실을 한 가지 써. 복사해 둔 bypassPermissions라면 고쳐.
Hint
실행 시점에 “해도 되나?”에 답할 사람이 누구인지 보고 모드를 정해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.