Claude Code Tools Deep Dive #2 — EnterPlanMode: 왜 빈 스키마(Empty Schema)가 설계상의 선택인가
요약
Claude Code의 핵심 도구인 EnterPlanMode의 설계 원리와 기능을 심층 분석합니다. 이 도구는 Claude를 읽기 전용 탐색 및 솔루션 설계 모드로 전환하여 AI와 사용자 간의 정렬을 강화합니다.
핵심 포인트
- EnterPlanMode는 Claude를 계획 중심의 워크플로우로 전환함
- 읽기 전용 탐색을 강제하여 의도치 않은 코드 수정을 방지함
- 사용자의 명시적 승인을 통해 AI와 작업 방향을 정렬함
- 추적 가능한 문서화된 계획 산출물을 생성함
이 글은 저의 Claude Code Tools Deep Dive 시리즈의 두 번째 포스트입니다. 이전 포스트에서는 사용자가 구체적인 옵션 중에서 선택할 수 있게 해주는 구조화된 도구인 AskUserQuestion을 살펴보았습니다. 이번에는 그 형제 격인 EnterPlanMode를 살펴보고자 합니다.
이 포스트를 읽기 전에, Claude Code의 도구 메커니즘이 어떻게 작동하는지에 대한 시리즈 서문을 읽어보는 것이 도움이 될 수 있습니다. 이 글은 거기서 소개된 것과 동일한 4계층 프레임워크(four-layer framework)를 따릅니다.
EnterPlanMode
AskUserQuestion과 마찬가지로, EnterPlanMode는 거의 매일 마주치게 될 수도 있는 도구입니다. 하지만 그 설계는 훨씬 더 무겁습니다. 단순히 질문을 던지는 것이 아니라, Claude를 완전히 다른 운영 모드로 전환시킵니다.
기능
EnterPlanMode는 Claude Code에 내장된 **계획 모드(planning mode)로의 진입점(entry point)**입니다. 그 역할은 단순하지만 강력합니다. Claude를 기본값인 "쓰면서 생각하기(think while writing)" 워크플로우에서, **읽기 전용 탐색(read-only exploration) 및 솔루션 설계(solution design)**를 중심으로 구축된 계획 워크플로우로 이동시키는 것입니다. Claude는 사용자가 계획을 명시적으로 승인한 후에야 구현 단계로 돌아옵니다.
이 도구가 해결하는 핵심 문제는 **AI와 사용자 간의 정렬(alignment)**입니다:
- 작업이 잘못된 방향으로 흐르는 것을 방지 — Claude는 단 하나의 파일도 수정하기 전에 접근 방식에 대해 정렬(align)합니다.
- 읽기 전용 탐색 강제 — 계획 모드가 활성화되면 Edit, Write, NotebookEdit 기능이 비활성화됩니다. Claude는 탐색하는 동안 몰래 변경 사항을 만들 수 없습니다.
- 명시적인 의사결정 경계 생성 — 사용자는 풀 리퀘스트(pull request)를 확인한 후에야 잘못된 방향을 발견하는 대신, 완성된 제안에 대해 승인, 거절 또는 수정을 요청할 수 있습니다.
- 추적 가능한 계획 산출물 생성 — 계획 모드는 채팅 기록 속으로 사라져 버리는 한 단락의 글이 아니라, 참조하고 수정할 수 있는 문서화된 계획을 생성합니다.
구체적인 예시
시나리오 (Scenario): 사용자가 Claude에게 다음과 같이 말합니다. "이 인증 모듈을 리팩터링하고 JWT를 세션 쿠키 (session cookies)로 교체해줘."
요청 자체는 명확해 보이지만, 실제로는 로그인 경로 (login routes), 토큰 생성 미들웨어 (token-generation middleware), 프론트엔드 저장소 (frontend storage), 세션 만료 정책 (session-expiration policy), 데이터베이스 스키마 (database schema) 결정, 그리고 기존 API 소비자들을 위한 하위 호환성 (backward compatibility)까지 아우르는 작업입니다. 이는 다중 파일, 다중 결정, 의존성이 높은 (dependency-heavy) 변경 사항입니다.
안티 패턴 (The Anti-Pattern): EnterPlanMode 없이 작업하기
계획의 경계 (planning boundary)가 없다면, Claude는 가용한 컨텍스트 (context)로부터 접근 방식을 추론하여 즉시 편집을 시작해야 합니다:
auth/middleware.ts를 열어 세션 쿠키를 읽도록 전환합니다.auth/routes.ts를 열어 JWT 발급을 제거하고req.session으로 교체합니다.frontend/api.ts를 열어Authorization헤더 로직을 제거합니다.models/user.ts를 열어sessionId필드를 추가합니다.- 리팩터링 중간에, 다른 세 개의 서비스가 동일한 API에 대해 JWT로 인증하고 있다는 사실을 발견합니다.
사용자는 변경 사항 (diff)을 보고 이렇게 말합니다: "나는 웹 앱에만 세션을 적용하고 싶었던 거야. 백엔드 서비스들은 여전히 JWT가 필요해. 왜 API 전체의 인증 방식을 바꿔버린 거지?"
여러 가지 문제가 발생했습니다:
- 방향성 오류가 5단계나 늦게 드러났습니다 — 이미 4개의 파일이 변경되었으므로 롤백 (rollback)이 고통스럽습니다.
- 결정 경계 (decision boundary)가 불분명했습니다 — "모든 인증을 교체할 것인가, 아니면 웹 흐름만 교체할 것인가?"는 결정적인 분기점이었지만, Claude는 묻지 않고 추측했습니다.
- 사용자는 전체 그림을 전혀 보지 못했습니다 — 사용자는 쌓여있는 변경 사항 (diffs) 뭉치를 전달받았고, 의도된 설계를 역공학 (reverse-engineer)해야 했습니다.
- 중요한 부작용 (side effects)이 전혀 드러나지 않았습니다 — 시스템이 세션 테이블을 생성해야 할까요? 세션 상태를 메모리, Redis, 또는 데이터베이스 중 어디에 두어야 할까요? Claude가 이러한 질문들을 고려했을 수는 있지만, 이를 명시적인 제안으로 만들지는 않았습니다.
- 롤백 비용이 비쌉니다 — 모든 편집은 토큰과 어텐션 (attention)을 소비합니다. 구현 내용을 폐기하는 것은 이 두 가지를 모두 낭비하는 것입니다.
핵심적인 문제점: "쓰면서 생각하기 (think while writing)" 방식은 접근 방식이 안정화되기 전에 Claude가 디프 (diff)를 생성하게 만들며, 사용자는 마지막 단계가 될 때까지 전체 설계를 확인할 수 없습니다.
EnterPlanMode가 이를 해결하는 방법
Claude는 먼저 플랜 모드 (plan mode)에 진입하고 싶다고 선언하며 사용자의 승인을 요청합니다. 이 전환 과정 자체가 하나의 상호작용적인 확인 (interactive confirmation)입니다. 사용자가 거절하면 Claude는 기본 모드에 머뭅니다.
1단계: 읽기 전용 탐색 (Read-Only Exploration) 진입
Claude의 도구 세트 (toolset)가 좁아집니다:
- ✅ 사용 가능: Read, Glob, Grep, Agent, AskUserQuestion, ExitPlanMode
- ❌ 비활성화: Edit, Write, NotebookEdit
Claude는 물리적으로 프로젝트 파일을 수정할 수 없습니다. 모든 탐색 작업은 읽기 전용 (read-only)입니다.
2단계: 현재 시스템 이해
- Grep을 사용하여 모든 JWT 참조를 찾아 세 개의 내부 서비스를 발견합니다.
- Read를 사용하여
auth/middleware.ts에 있는 현재 검증 로직을 조사합니다. - Glob을 사용하여 인증 관련 테스트를 찾아냅니다.
- Agent를 사용하여 프로젝트에 이미 세션 스토어 (session-store) 관례가 있는지 조사하도록 범용 서브에이전트 (subagent)를 할당합니다.
3단계: AskUserQuestion으로 중요한 분기점 명확화
예를 들어:
- JWT를 웹 앱에만 교체할 것인가, 아니면 모든 곳에 적용할 것인가?
- 세션을 메모리, Redis, 또는 데이터베이스에 저장할 것인가?
이는 이전 포스트에서 논의했던 명확화 패턴 (clarification pattern)과 정확히 일치합니다. AskUserQuestion과 EnterPlanMode는 자연스러운 파트너입니다.
4단계: 계획 작성
Claude는 범위 (scope), 영향받는 파일, 마이그레이션 단계, 리스크, 그리고 롤백 전략 (rollback strategy)을 포함한 완전한 제안서를 플랜 파일 (plan file)에 작성합니다. 이것은 일시적인 채팅 메시지가 아니라, 수정 가능하고 참조 가능한 산출물 (artifact)입니다.
5단계: ExitPlanMode로 승인 요청
사용자는 완성된 계획을 확인하고 다음 단계를 선택합니다:
- ✅ 승인 (Approve) → Claude가 구현 모드 (implementation mode)로 돌아가 계획을 실행합니다.
- ✏️ 변경 요청 (Request changes) → Claude가 피드백을 사용하여 계획을 수정합니다.
- ❌ 거절 (Reject) → Claude가 방향을 전환합니다.
승인 전에는 단 하나의 프로젝트 파일도 수정되지 않습니다. 사용자의 토큰, 시간, 그리고 주의력이 잘못된 접근 방식을 구현하는 데 낭비되지 않습니다.
Side-by-Side Comparison (측면 비교)
| 안티 패턴(Anti-pattern)의 고통 | EnterPlanMode의 해결책 |
|---|---|
| 5단계나 늦게 발견된 방향성 오류 | ExitPlanMode 승인 전에는 프로젝트 파일을 변경할 수 없음 |
| ... |
사용 시점
이 도구의 공식 설명에는 흥미로운 규칙이 포함되어 있습니다: 사소하지 않은 구현 작업(non-trivial implementation tasks)은 기본적으로 계획(planning) 단계로 넘어가야 합니다. 이는 의도적으로 보수적인 편향(bias)을 둔 것입니다.
Plan Mode가 필요한 7가지 상황
- 새로운 기능 구현 — 아주 작은 기능이라도 결정 사항이 숨어 있습니다: 코드가 어디에 위치해야 하는지, 버튼이 무엇을 해야 하는지, 그리고 에러는 어떻게 처리해야 하는지 등입니다.
- 여러 가지 합리적인 접근 방식이 존재할 때 — "캐싱 추가"는 Redis, 메모리, 또는 파일 방식을 의미할 수 있으며, "실시간 업데이트"는 WebSockets, SSE, 또는 폴링(polling)을 의미할 수 있습니다. 선택 그 자체가 설계 작업입니다.
- 기존 동작을 변경할 때 — "로그인 흐름 업데이트"는 모호합니다. 코드를 건드리기 전에 변경 사항을 정의하십시오.
- 아키텍처 결정(Architectural decisions)을 내릴 때 — 패턴, 의존성(dependencies), 그리고 데이터 흐름(data-flow)의 방향이 합의되어야 합니다.
- 두 개 또는 세 개 이상의 파일에 걸친 변경 — 영향 범위가 충분히 커서 더 이상 디프(diff)만으로는 전체 설계를 전달할 수 없습니다.
- 불분명한 요구사항 — "앱을 더 빠르게 만들기"는 프로파일링(profiling)과 최적화 우선순위에 대한 논의가 선행되어야 합니다.
- 사용자의 선호도에 의해 구현 방식이 결정될 때 — 접근 방식을 명확히 하기 위해 AskUserQuestion이 필요하다면, 이를 개발하기 위해 EnterPlanMode가 필요할 가능성이 높습니다.
사용하지 않아도 되는 4가지 상황
- 한 줄짜리 수정 (A one-line fix) — 오타를 수정하거나 명백한 off-by-one 에러를 바로잡는 경우.
- 명확하게 지정된 단일 함수 추가 — 직접 구현하십시오. 번거로운 절차를 거칠 필요가 없습니다.
- 사용자가 이미 정밀하고 상세한 지침을 제공한 경우 — 사용자가 이미 계획을 세웠으므로, 이를 반복하는 것은 마찰(friction)만 가중시킵니다.
- 순수 연구 또는 탐색 — 구현 작업이 뒤따르지 않는 경우에는 탐색 에이전트(explore agent)와 함께 에이전트 도구(Agent tool)를 사용하십시오.
원문 설명 중 특히 시사하는 바가 큰 문구가 있습니다: "계획하는 방향으로 실수하라 (err on the side of planning)." 불확실할 때는 먼저 계획하십시오. 기본 설정 자체가 설계자들의 선호도를 드러냅니다: 속도보다 정렬 (alignment)을 우선시하는 편향입니다.
기술 설계 (Technical Design)
1. 명명 (Naming)
EnterPlanMode
AskUserQuestion은 네 가지 설계 계층 전체에 걸쳐 신호를 전달합니다. 반면 EnterPlanMode는 이를 매우 다르게 분산합니다: 이름 자체가 스키마(schema)가 수행했을 법한 역할을 수행합니다.
Enter는 데이터를 가져오거나 일회성 동작을 수행하는 것이 아니라, 특정 상태로 진입함을 암시하는 동사입니다.PlanMode는 해당 상태의 이름을 나타내며,ExitPlanMode와 자연스러운 쌍을 이룹니다.
반사실적인 설계인 SetMode(mode: "plan")를 가정해 봅시다. 모델은 이를 단순히 속성을 설정하는 것으로 해석하여 가볍게 모드를 전환할 수도 있습니다. 현재의 이름은 **의례적인 상태 전이 (ceremonial state transition)**를 인코딩합니다: 진입(entering)이 명시적이며, 퇴장(exiting) 또한 명시적입니다. 이 방식의 의미론(semantics)은 매개변수화된 SetMode보다 훨씬 강력합니다.
이것이 바로 스키마가 비어 있어도 되는 이유입니다. 이름이 이미 의미를 고정했으므로, 스키마가 이를 보완할 필요가 없습니다.
2. 도구 수준 설명 (Tool-Level Description)
EnterPlanMode의 설명은 네 가지 질문을 중심으로 구성됩니다: 언제 사용하는가, 언제 사용하지 않는가, 인접한 도구들과 어떻게 작업을 나누는가, 그리고 런타임(runtime)에 어떤 일이 발생하는가.
보수적인 시작 편향 (A Conservative Opening Bias)
구현 작업이 단순하지 않다면, EnterPlanMode 사용을 선호하십시오.
이 한 문장이 Claude의 동작을 재구성합니다. 불확실할 때는 즉각적으로 행동하는 대신 계획을 세웁니다. 이 도구는 기본 설정을 주의(caution) 쪽으로 이동시키며 시작됩니다.
7가지 유스케이스(Use Cases)를 위한 정량화된 임계값(Quantified Thresholds)
"이 도구를 언제 사용할 것인가(When to Use This Tool)\
협업 에티켓으로서의 계획 (Planning as Collaboration Etiquette)
사용자는 자신의 코드베이스에 중대한 변경이 이루어지기 전에 상담을 받는 것을 선호합니다.
이 문장은 Claude의 **사회적 직관 (Social Intuition)**을 훈련시킵니다. 계획(Planning)은 단순히 효율성을 위한 메커니즘이 아닙니다. 이는 코드베이스에 대한 사용자의 소유권을 존중하는 행위입니다. 이러한 프레임워크는 Claude가 상담을 방해가 아닌, 훌륭한 협업의 과정으로 취급하도록 유도합니다.
3. 필드 수준 설명 (Field-Level Descriptions)
없음.
EnterPlanMode에는 입력 필드가 없습니다. 스키마(Schema)가 빈 객체 {}이므로, 이 계층은 존재하지 않습니다. 모든 행동 신호는 도구 수준의 설명(Tool-level description)으로 상향 이동합니다.
4. 스키마 유효성 검사 규칙 (Schema Validation Rules)
없음.
input_schema는 비어 있습니다: 필드, 타입, 제약 조건이 모두 없습니다. 도구를 호출하는 행위 자체가 상태를 변경하려는 의도이며, 전달할 데이터가 없습니다.
그러한 부재(Absence) 자체가 하나의 설계 신호입니다: 권한은 파라미터 계층이 아닌, 도구 및 런타임(Runtime) 계층에서 강제됩니다. Claude는 개별 권한을 요청하거나 대상 모드를 지정할 필요가 없습니다. Claude가 EnterPlanMode를 호출하면, 런타임은 자동으로 다음과 같이 동작합니다:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기