claude-code/docs/ko/level-2-systems/command-system.md
JuYoung Jeong 3358348196 docs: add comprehensive Korean source code analysis (19 documents, 6,926 lines)
Add complete Korean-language technical documentation analyzing Claude Code CLI
internals, organized in a leveled guide structure (Level 1-3 + Appendix).

Level 1 (입문): architecture overview, request lifecycle, key concepts
Level 2 (시스템): QueryEngine, Tool system, Command system, Permission system,
  Agent coordinator, UI/Ink components
Level 3 (심화): MCP/LSP integration, IDE bridge, Plugin/Skill system,
  Context compression, OAuth/Auth, Telemetry
Appendix: Korean-English glossary, file map, design patterns

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 19:39:03 +09:00

20 KiB

커맨드 시스템: 슬래시 커맨드 분석

1. 개요

커맨드 시스템은 사용자가 /commit, /mcp, /review 처럼 슬래시(/)로 시작하는 명령어를 입력할 때 이를 해석하고 실행하는 계층이다. 단순한 UI 단축키가 아니라 Claude Code의 모든 사용자 대면 기능을 조율하는 중앙 디스패처 역할을 수행한다.

역할 요약:

  • 등록: 내장(built-in) 커맨드, 스킬(skill) 디렉터리, 플러그인, MCP 서버, 워크플로 스크립트를 단일 커맨드 풀로 통합
  • 필터링: 인증 공급자 가용성(availability), feature flag(bun:bundlefeature()), 환경 변수 조건을 거쳐 현재 세션에서 사용 가능한 커맨드 목록을 결정
  • 실행: 커맨드 타입(prompt / local / local-jsx)에 따라 서로 다른 실행 경로로 위임
  • 캐시 관리: lodash-es/memoize를 사용하여 디스크 I/O가 수반되는 동적 로딩을 메모이제이션

핵심 파일:

파일 역할
src/commands.ts 레지스트리, 필터링, 공개 API 전체
src/types/command.ts Command 타입 계층 정의
src/commands/*/index.ts 개별 커맨드 구현체 (100개 이상)

2. 아키텍처 다이어그램

graph TD
    User["사용자 입력\n(/command args)"] --> Resolver["findCommand()\n이름·별칭(alias) 탐색"]
    Resolver --> Avail["meetsAvailabilityRequirement()\n인증 공급자 확인"]
    Avail --> Enabled["isCommandEnabled()\nfeature flag / isEnabled()"]
    Enabled --> Dispatch{커맨드 타입}

    Dispatch -- "type: 'prompt'" --> Prompt["getPromptForCommand()\n프롬프트 확장 → LLM 전달"]
    Dispatch -- "type: 'local'" --> Local["load() → call()\n동기적 로컬 실행"]
    Dispatch -- "type: 'local-jsx'" --> JSX["load() → call()\nInk JSX 렌더링"]

    subgraph "loadAllCommands() — memoized by cwd"
        Bundled["getBundledSkills()"]
        BuiltinPlugin["getBuiltinPluginSkillCommands()"]
        SkillDir["getSkillDirCommands(cwd)"]
        Workflow["getWorkflowCommands(cwd)"]
        PluginCmd["getPluginCommands()"]
        PluginSkill["getPluginSkills()"]
        COMMANDS["COMMANDS()\n내장 커맨드 배열"]
    end

    Bundled --> Pool["커맨드 풀\n(우선순위 순 병합)"]
    BuiltinPlugin --> Pool
    SkillDir --> Pool
    Workflow --> Pool
    PluginCmd --> Pool
    PluginSkill --> Pool
    COMMANDS --> Pool

    Pool --> Dynamic["getDynamicSkills()\n파일 작업 중 발견된 스킬"]
    Dynamic --> getCommands["getCommands(cwd)\n최종 필터링된 커맨드 목록"]
    getCommands --> Resolver

    subgraph "조건부 로딩 (feature flag)"
        F1["feature('PROACTIVE') → proactive"]
        F2["feature('KAIROS') → brief, assistant"]
        F3["feature('BRIDGE_MODE') → bridge"]
        F4["feature('VOICE_MODE') → voice"]
        F5["feature('WORKFLOW_SCRIPTS') → workflows"]
        F6["USER_TYPE=ant → agentsPlatform"]
    end

    F1 & F2 & F3 & F4 & F5 & F6 --> COMMANDS

3. Command 타입 분석

src/types/command.ts에 정의된 타입 계층은 모든 커맨드가 공유하는 CommandBase와 실행 방식을 결정하는 세 가지 유니언 멤버로 구성된다.

3.1 CommandBase — 공통 메타데이터

type CommandBase = {
  name: string                          // 슬래시 뒤에 오는 식별자 (/name)
  description: string                   // 자동완성·도움말에 표시되는 설명
  aliases?: string[]                    // 대체 이름 (예: config의 'settings')
  availability?: CommandAvailability[]  // 'claude-ai' | 'console' (인증 게이팅)
  isEnabled?: () => boolean             // feature flag / 환경 조건
  isHidden?: boolean                    // 자동완성 목록에서 숨김
  argumentHint?: string                 // 인수 힌트 (회색 미리보기 텍스트)
  whenToUse?: string                    // 모델 호출 시나리오 설명 (스킬 전용)
  disableModelInvocation?: boolean      // 모델이 직접 호출하지 못하도록 차단
  loadedFrom?: 'commands_DEPRECATED' | 'skills' | 'plugin' | 'managed' | 'bundled' | 'mcp'
  source: SettingSource | 'builtin' | 'mcp' | 'plugin' | 'bundled'
  kind?: 'workflow'                     // 워크플로 배지 표시
  immediate?: boolean                   // 큐를 우회하여 즉시 실행
  isSensitive?: boolean                 // 인수를 대화 히스토리에서 삭제
}

3.2 세 가지 실행 타입

타입 설명 실행 방식 대표 예시
prompt 프롬프트 템플릿을 LLM에 전달 getPromptForCommand() → ContentBlockParam[] → 모델 쿼리 /commit, /review, /security-review
local 순수 로컬 함수 실행 load()call()LocalCommandResult /compact, /cost, /clear
local-jsx Ink 기반 인터랙티브 UI 렌더링 load()call()React.ReactNode /mcp, /config, /session, /plan

PromptCommand 추가 필드

type PromptCommand = {
  progressMessage: string        // 실행 중 표시할 메시지
  contentLength: number          // 토큰 추정용 콘텐츠 길이 (동적이면 0)
  allowedTools?: string[]        // 이 커맨드 실행 중 허용되는 도구 목록
  model?: string                 // 특정 모델 지정 (없으면 세션 기본값 사용)
  context?: 'inline' | 'fork'   // 'fork': 별도 서브에이전트로 실행
  agent?: string                 // fork 컨텍스트에서 사용할 에이전트 타입
  paths?: string[]               // 이 glob 패턴에 해당하는 파일 접근 후에만 표시
  hooks?: HooksSettings          // 스킬 호출 시 등록할 훅
}

LocalCommand 추가 필드

type LocalCommand = {
  supportsNonInteractive: boolean  // CI/비대화형 모드 지원 여부
  load: () => Promise<LocalCommandModule>
}

LocalJSXCommand 추가 필드

type LocalJSXCommand = {
  load: () => Promise<LocalJSXCommandModule>
  // load()는 항상 지연 임포트(dynamic import)로 구현
  // → 무거운 UI 의존성을 커맨드 호출 시점까지 번들에서 분리
}

4. 커맨드 레지스트리

4.1 직접 import (정적 로딩)

commands.ts 상단에서 약 55개 커맨드를 ES 모듈 정적 임포트로 등록한다. 이 커맨드들은 번들 시점에 포함되며 런타임 조건 없이 항상 사용 가능하다.

import commit from './commands/commit.js'
import compact from './commands/compact/index.js'
import mcp from './commands/mcp/index.js'
// ... (약 55개)

각 커맨드 파일(예: src/commands/mcp/index.ts)은 커맨드 객체를 정의하고 무거운 구현체는 load: () => import('./mcp.js') 형태로 지연 임포트한다. 결과적으로 메타데이터는 즉시, 실제 로직은 필요 시 로드된다.

4.2 조건부 require (feature flag 게이팅)

Bun 번들러의 feature() 함수와 CommonJS require()를 조합하여 특정 기능이 활성화된 경우에만 커맨드를 포함시킨다. feature()는 빌드 시 데드 코드 제거(dead code elimination)를 가능하게 한다.

// 단일 플래그
const voiceCommand = feature('VOICE_MODE')
  ? require('./commands/voice/index.js').default
  : null

// 복합 플래그 (OR)
const proactive = feature('PROACTIVE') || feature('KAIROS')
  ? require('./commands/proactive.js').default
  : null

// 복합 플래그 (AND)
const remoteControlServerCommand =
  feature('DAEMON') && feature('BRIDGE_MODE')
    ? require('./commands/remoteControlServer/index.js').default
    : null

null이 된 커맨드는 스프레드 연산자(...(voiceCommand ? [voiceCommand] : []))로 COMMANDS() 배열에서 자동 제외된다.

4.3 사용자 타입 게이팅

USER_TYPE === 'ant'인 경우에만 INTERNAL_ONLY_COMMANDSCOMMANDS()에 포함된다. 이 배열에는 backfillSessions, bughunter, commit, goodClaude, autofixPr 등 Anthropic 내부 개발자 전용 커맨드 약 20개가 포함된다.

...(process.env.USER_TYPE === 'ant' && !process.env.IS_DEMO
  ? INTERNAL_ONLY_COMMANDS
  : []),

4.4 가용성(Availability) 게이팅

CommandAvailability 타입으로 인증 공급자별 접근을 제한한다.

대상
'claude-ai' claude.ai OAuth 구독자 (Pro/Max/Team/Enterprise)
'console' Anthropic Console API 키 사용자 (api.anthropic.com 직접 접근)

meetsAvailabilityRequirement()는 매 getCommands() 호출 시 재평가된다(메모이제이션 없음). /login 이후 인증 상태가 변경되어도 즉시 반영된다.

4.5 동적 로딩 소스 우선순위

loadAllCommands()는 다음 순서로 커맨드를 병합한다:

bundledSkills → builtinPluginSkills → skillDirCommands
  → workflowCommands → pluginCommands → pluginSkills → COMMANDS()

나중에 추가된 커맨드가 이름 충돌 시 덮어쓰지 않도록 중복 제거는 getCommands()의 Set 기반 필터링으로 처리된다.

4.6 지연 로딩 특례: /insights

113KB에 달하는 insights.ts 모듈은 정적 임포트 없이 commands.ts 내부에서 직접 인라인 prompt 타입 커맨드로 정의되어 있다.

const usageReport: Command = {
  type: 'prompt',
  name: 'insights',
  // ...
  async getPromptForCommand(args, context) {
    const real = (await import('./commands/insights.js')).default
    return real.getPromptForCommand(args, context)
  },
}

이 패턴은 getPromptForCommand() 호출 시점에만 무거운 모듈을 로드하는 지연 심(lazy shim)이다.


5. 커맨드 실행 흐름

5.1 커맨드 탐색

function findCommand(commandName: string, commands: Command[]): Command | undefined {
  return commands.find(
    _ =>
      _.name === commandName ||
      getCommandName(_) === commandName ||  // userFacingName() 우선
      _.aliases?.includes(commandName),
  )
}

getCommandName()cmd.userFacingName?.()을 먼저 시도하여 플러그인이 접두사를 제거한 이름을 표시할 수 있도록 한다. 탐색 실패 시 getCommand()가 사용 가능한 모든 커맨드 이름을 나열한 ReferenceError를 던진다.

5.2 prompt 타입 실행 흐름

사용자 입력 /commit
  → findCommand('commit') → commit 커맨드 객체
  → getPromptForCommand(args, context) 호출
      → executeShellCommandsInPrompt() 로 !`git status` 등 셸 명령 미리 실행
      → ContentBlockParam[] 반환
  → 반환된 프롬프트가 현재 대화에 삽입되어 LLM에 전달
  → LLM이 allowedTools 범위 내에서 도구 호출 수행

allowedTools 필드는 해당 커맨드 실행 중에 사용 가능한 도구를 제한한다. /commit의 경우 ['Bash(git add:*)', 'Bash(git status:*)', 'Bash(git commit:*)']로 git 관련 작업만 허용한다.

5.3 local 타입 실행 흐름

사용자 입력 /compact [instructions]
  → findCommand('compact') → compact 커맨드 객체
  → compact.load() → import('./compact.js') (지연 임포트)
  → module.call(args, context) 호출
  → LocalCommandResult 반환
      → { type: 'text', value: string }
      → { type: 'compact', compactionResult, displayText? }
      → { type: 'skip' }

supportsNonInteractive: true인 경우 --print 플래그 등 비대화형 모드에서도 실행 가능하다.

5.4 local-jsx 타입 실행 흐름

사용자 입력 /mcp enable server-name
  → findCommand('mcp') → mcp 커맨드 객체
  → immediate: true → 큐 대기 없이 즉시 실행
  → mcp.load() → import('./mcp.js') (지연 임포트)
  → module.call(onDone, context, args) 호출
  → React.ReactNode 반환 → Ink 렌더러가 터미널에 출력
  → 사용자 인터랙션 완료 후 onDone() 호출
      → display: 'skip' | 'system' | 'user'
      → shouldQuery: true → 완료 후 LLM에 메시지 전달

5.5 캐시 무효화

함수 용도
clearCommandMemoizationCaches() 커맨드 목록 캐시만 클리어 (스킬 캐시 유지)
clearCommandsCache() 전체 캐시 클리어 (플러그인, 스킬 포함)

동적 스킬이 추가되면 clearCommandMemoizationCaches()를 호출하여 loadAllCommandsgetSkillToolCommands의 memoize 캐시를 무효화한다. skillSearch/localSearch.ts의 스킬 인덱스는 별도 메모이제이션 계층이므로 clearSkillIndexCache?.() 호출이 추가로 필요하다.


6. 주요 커맨드 카테고리

6.1 Git / 코드 관리

커맨드 타입 설명
/commit prompt git add/status/commit을 LLM이 수행
/commit-push-pr prompt commit + push + PR 생성 원스텝
/review prompt gh pr 기반 PR 코드 리뷰
/ultrareview local-jsx 원격 bughunter 경로를 통한 심층 리뷰
/security-review prompt 보안 취약점 집중 리뷰
/diff local-jsx 현재 변경 사항 시각화
/branch local-jsx 브랜치 관리
/autofix-pr prompt PR 자동 수정 (내부 전용)

6.2 컨텍스트 / 메모리 관리

커맨드 타입 설명
/compact local 대화 히스토리 압축, 요약 보존
/context local-jsx 컨텍스트 창 관리
/memory local-jsx 프로젝트/사용자 메모리 편집
/clear local 대화 초기화
/summary local 대화 요약 생성
/rewind local-jsx 이전 대화 상태로 복귀
/files local 추적 중인 파일 목록

6.3 설정 / 환경

커맨드 타입 설명
/config (= /settings) local-jsx 설정 패널 열기
/model local-jsx 사용 모델 변경
/theme local-jsx 터미널 테마 변경
/vim local Vim 모드 토글
/keybindings local-jsx 키 바인딩 관리
/effort local-jsx 모델 사고 노력(effort) 조정
/output-style local-jsx 출력 스타일 변경
/sandbox-toggle local-jsx 샌드박스 모드 토글
/env local-jsx 환경 변수 관리
/remote-env local-jsx 원격 환경 변수 관리

6.4 MCP / 플러그인 / 스킬

커맨드 타입 설명
/mcp local-jsx MCP 서버 활성화/비활성화
/plugin local-jsx 플러그인 관리
/reload-plugins local 플러그인 캐시 재로드
/skills local-jsx 사용 가능한 스킬 목록 조회
/hooks local-jsx 훅 설정 관리
/permissions local-jsx 도구 권한 관리

6.5 세션 / 이력 관리

커맨드 타입 설명
/session (= /remote) local-jsx 원격 세션 URL/QR 코드 표시
/resume local-jsx 이전 세션 재개
/tasks local-jsx 백그라운드 태스크 관리
/agents local-jsx 에이전트 목록 조회
/export local-jsx 대화 내보내기
/tag local-jsx 세션 태그 관리

6.6 AI 기능

커맨드 타입 설명
/plan local-jsx 플랜 모드 활성화/세션 플랜 조회
/thinkback local-jsx 사고 과정 재검토
/thinkback-play local-jsx 사고 재생
/fast local-jsx 빠른 응답 모드
/passes local-jsx 멀티 패스 실행 설정
/advisor prompt 코드 개선 조언
/bughunter local-jsx 버그 탐색 (내부 전용)

6.7 설치 / 셋업

커맨드 타입 설명
/init prompt 프로젝트 CLAUDE.md 초기화
/doctor local-jsx 설치 상태 진단
/ide local-jsx IDE 익스텐션 설치
/terminal-setup local-jsx 터미널 환경 설정
/install-github-app local-jsx GitHub 앱 설치
/install-slack-app local-jsx Slack 앱 설치
/upgrade local-jsx Claude Code 업그레이드
/desktop local-jsx 데스크탑 앱 설정
/mobile local-jsx 모바일 QR 코드
/chrome local-jsx Chrome 익스텐션 설정

6.8 인증 / 요금

커맨드 타입 설명
/login local-jsx 인증 (3P 서비스 비사용 시만 표시)
/logout local 로그아웃
/cost local 세션 비용 조회
/usage local-jsx 사용량 정보
/extra-usage local-jsx 추가 사용량 구매
/rate-limit-options local-jsx 요금 한도 설정
/insights prompt 세션 분석 리포트 (지연 로드)

6.9 유틸리티 / 기타

커맨드 타입 설명
/help local-jsx 도움말
/exit local 종료
/status local-jsx 시스템 상태
/statusline local 상태 표시줄 토글
/copy local 마지막 메시지 복사
/feedback local-jsx 피드백 전송
/color local-jsx 에이전트 색상 변경
/stickers local-jsx 스티커
/btw local-jsx 빠른 노트
/rename local-jsx 세션 이름 변경
/stats local-jsx 통계 조회
/release-notes local-jsx 변경 이력
/privacy-settings local-jsx 개인정보 설정
/add-dir local-jsx 작업 디렉터리 추가

7. 주요 설계 결정

7.1 타입 유니언 방식의 실행 다형성

커맨드 실행은 상속 계층이 아닌 구조적 타입 유니언(prompt | local | local-jsx)으로 구현된다. 각 타입은 서로 다른 함수 시그니처(getPromptForCommand / call)를 가지며, 호출 측에서 cmd.type 판별식으로 분기한다. 이 방식은 타입 안전성을 유지하면서도 새로운 실행 타입을 추가할 때 기존 커맨드를 수정하지 않아도 된다는 장점이 있다.

7.2 메모이제이션과 신선도의 균형

loadAllCommands(cwd)lodash-es/memoize로 메모이제이션되어 디스크 I/O 비용을 절감한다. 반면 meetsAvailabilityRequirement()는 의도적으로 메모이제이션하지 않아 /login 이후 인증 상태 변경이 즉시 반영된다. 캐시 계층(memoize) 위에 신선한 필터링 계층을 두는 이중 구조가 핵심이다.

7.3 bun:bundle feature()를 활용한 데드 코드 제거

feature('VOICE_MODE') 같은 호출은 Bun 번들러가 빌드 시 평가하여 비활성 브랜치를 번들에서 완전히 제거한다. 외부 배포본에서 INTERNAL_ONLY_COMMANDS에 해당하는 코드가 포함되지 않는 것도 같은 원리다. /* eslint-disable @typescript-eslint/no-require-imports */ 주석과 함께 CommonJS require()를 사용하는 이유가 여기에 있다: ES 모듈 정적 임포트는 번들러가 조건부 제거를 적용할 수 없기 때문이다.

7.4 원격 모드와 브리지 모드의 이중 안전 목록

REMOTE_SAFE_COMMANDS(18개)와 BRIDGE_SAFE_COMMANDS(6개)는 두 가지 다른 원격 실행 컨텍스트를 각각 제어한다. REMOTE_SAFE_COMMANDS는 CCR 초기화 전 TUI 사전 필터링에 사용되고, BRIDGE_SAFE_COMMANDS는 iOS/웹 클라이언트에서 들어오는 슬래시 커맨드의 안전 실행에 사용된다. local-jsx 타입은 Ink UI를 렌더링하므로 브리지에서 원천 차단된다(isBridgeSafeCommand()).

7.5 스킬과 커맨드의 통합 레지스트리

스킬(skill)은 type: 'prompt'인 커맨드의 하위 집합으로, loadedFrom 필드('skills', 'bundled', 'plugin')와 disableModelInvocation 유무로 구분된다. getSkillToolCommands()는 모델이 직접 호출할 수 있는 커맨드를, getSlashCommandToolSkills()는 슬래시 커맨드 형태로 사용자가 호출하는 스킬을 필터링한다. 이 통합 구조 덕분에 동일한 커맨드 객체가 자동완성 UI와 모델 SkillTool 양쪽에서 재사용된다.

7.6 formatDescriptionWithSource()의 UI/모델 분리

커맨드 설명은 사용자 대면 UI(자동완성, 도움말)와 모델 대면 프롬프트(SkillTool)에서 다르게 표시된다. UI에서는 formatDescriptionWithSource()가 출처 주석((plugin), (bundled), (workflow))을 추가하여 사용자가 커맨드 출처를 인식할 수 있게 한다. 모델 프롬프트에서는 cmd.description을 직접 사용하여 불필요한 메타 정보 없이 깔끔한 설명을 전달한다.


Navigation