Files
AX-Copilot/docs/claude-docs.html

692 lines
183 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Claude Code 문서 아카이브</title>
<meta
name="description"
content="폴더 안의 Markdown 문서를 보기 좋은 단일 HTML 문서로 묶은 아카이브입니다."
/>
<style>
:root {
--bg: #f6f1e8;
--bg-deep: #efe4d3;
--paper: rgba(255, 251, 246, 0.86);
--paper-strong: rgba(255, 255, 255, 0.94);
--line: rgba(99, 70, 42, 0.12);
--line-strong: rgba(99, 70, 42, 0.22);
--text: #2f241b;
--muted: #685b4e;
--accent: #b85f2f;
--accent-strong: #8a431f;
--accent-soft: rgba(184, 95, 47, 0.12);
--teal: #215f66;
--shadow: 0 24px 70px rgba(71, 45, 24, 0.12);
--radius-xl: 34px;
--radius-lg: 26px;
--radius-md: 18px;
--max-width: 1180px;
--font-sans: "Pretendard", "SUIT", "Apple SD Gothic Neo", "Noto Sans KR", sans-serif;
--font-display: "MaruBuri", "Nanum Myeongjo", serif;
color-scheme: light;
scroll-behavior: smooth;
}
* {
box-sizing: border-box;
}
html {
scroll-padding-top: 110px;
}
body {
margin: 0;
color: var(--text);
font-family: var(--font-sans);
background:
radial-gradient(circle at top left, rgba(33, 95, 102, 0.16), transparent 30%),
radial-gradient(circle at top right, rgba(184, 95, 47, 0.18), transparent 34%),
linear-gradient(180deg, #fbf7f1 0%, var(--bg) 45%, var(--bg-deep) 100%);
min-height: 100vh;
}
a {
color: var(--accent-strong);
}
.page {
width: min(calc(100% - 32px), var(--max-width));
margin: 0 auto;
padding: 24px 0 96px;
}
.hero {
position: relative;
overflow: hidden;
padding: 38px;
border: 1px solid var(--line);
border-radius: var(--radius-xl);
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 246, 237, 0.76)),
var(--paper-strong);
box-shadow: var(--shadow);
backdrop-filter: blur(16px);
}
.hero::before,
.hero::after {
content: "";
position: absolute;
border-radius: 999px;
pointer-events: none;
filter: blur(8px);
}
.hero::before {
top: -90px;
right: -50px;
width: 260px;
height: 260px;
background: radial-gradient(circle, rgba(33, 95, 102, 0.2), transparent 66%);
}
.hero::after {
bottom: -120px;
left: -80px;
width: 320px;
height: 320px;
background: radial-gradient(circle, rgba(184, 95, 47, 0.16), transparent 68%);
}
.hero-kicker {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
border: 1px solid rgba(33, 95, 102, 0.16);
border-radius: 999px;
background: rgba(255, 255, 255, 0.72);
color: var(--teal);
font-size: 13px;
font-weight: 800;
letter-spacing: 0.03em;
}
.hero h1 {
margin: 18px 0 12px;
font-family: var(--font-display);
font-size: clamp(2.5rem, 5vw, 4.7rem);
line-height: 1.04;
letter-spacing: -0.04em;
}
.hero p {
max-width: 760px;
margin: 0;
color: var(--muted);
font-size: 1.06rem;
line-height: 1.78;
}
.hero-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
gap: 14px;
margin-top: 28px;
}
.stat {
padding: 18px 18px 16px;
border: 1px solid var(--line);
border-radius: var(--radius-md);
background: rgba(255, 255, 255, 0.7);
}
.stat strong {
display: block;
margin-bottom: 4px;
font-size: 1.45rem;
}
.stat span {
color: var(--muted);
font-size: 0.94rem;
}
.toc {
position: relative;
margin: 24px 0 28px;
padding: 20px;
border: 1px solid var(--line);
border-radius: 30px;
background: rgba(255, 249, 242, 0.8);
box-shadow: 0 12px 34px rgba(71, 45, 24, 0.08);
backdrop-filter: blur(12px);
}
.toc-head {
display: flex;
align-items: end;
justify-content: space-between;
gap: 16px;
margin-bottom: 16px;
}
.toc-head h2 {
margin: 0;
font-size: 1.05rem;
letter-spacing: 0.02em;
}
.toc-head p {
margin: 6px 0 0;
color: var(--muted);
font-size: 0.94rem;
}
.toc-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
gap: 12px;
}
.toc-link,
.back-link,
.floating-toc {
border: 1px solid transparent;
text-decoration: none;
transition:
transform 160ms ease,
border-color 160ms ease,
background 160ms ease,
box-shadow 160ms ease,
opacity 160ms ease;
}
.toc-link {
display: flex;
flex-direction: column;
gap: 6px;
min-height: 74px;
padding: 14px 15px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.88);
color: var(--text);
border-color: rgba(99, 70, 42, 0.08);
box-shadow: 0 10px 24px rgba(71, 45, 24, 0.06);
}
.toc-link:hover,
.back-link:hover,
.floating-toc:hover {
transform: translateY(-2px);
border-color: rgba(184, 95, 47, 0.28);
box-shadow: 0 16px 30px rgba(71, 45, 24, 0.12);
}
.toc-link strong {
font-size: 0.82rem;
color: var(--teal);
letter-spacing: 0.05em;
text-transform: uppercase;
}
.toc-link span {
line-height: 1.4;
font-weight: 800;
}
.toc-link.active {
background: linear-gradient(135deg, rgba(184, 95, 47, 0.15), rgba(33, 95, 102, 0.14));
border-color: rgba(184, 95, 47, 0.24);
}
.sections {
display: grid;
gap: 24px;
}
.doc-section {
position: relative;
overflow: hidden;
padding: 30px;
border: 1px solid var(--line);
border-radius: var(--radius-lg);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(255, 249, 243, 0.82)),
var(--paper);
box-shadow: var(--shadow);
}
.doc-section::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1px;
background: linear-gradient(90deg, rgba(33, 95, 102, 0.3), rgba(184, 95, 47, 0.3), transparent);
}
.section-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
margin-bottom: 22px;
}
.section-badge {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
border-radius: 999px;
border: 1px solid var(--line);
background: rgba(255, 255, 255, 0.78);
color: var(--muted);
font-size: 0.92rem;
font-weight: 700;
}
.section-badge strong {
color: var(--accent-strong);
font-size: 0.84rem;
letter-spacing: 0.04em;
}
.back-link {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 14px;
border-radius: 999px;
border-color: rgba(99, 70, 42, 0.12);
background: rgba(255, 255, 255, 0.82);
color: var(--accent-strong);
font-weight: 800;
white-space: nowrap;
}
.doc-body {
line-height: 1.84;
font-size: 1rem;
}
.doc-body > :first-child {
margin-top: 0;
}
.doc-body h1,
.doc-body h2,
.doc-body h3,
.doc-body h4 {
margin: 1.8em 0 0.55em;
color: var(--text);
line-height: 1.26;
}
.doc-body h1 {
font-size: 2rem;
}
.doc-body h2 {
font-size: 1.5rem;
padding-bottom: 0.28em;
border-bottom: 1px solid rgba(99, 70, 42, 0.14);
}
.doc-body h3 {
font-size: 1.18rem;
}
.doc-body p,
.doc-body li,
.doc-body blockquote {
color: #3c3128;
}
.doc-body ul,
.doc-body ol {
padding-left: 1.35rem;
}
.doc-body blockquote {
margin: 18px 0;
padding: 14px 18px;
border-left: 4px solid rgba(33, 95, 102, 0.42);
border-radius: 0 16px 16px 0;
background: rgba(33, 95, 102, 0.07);
}
.doc-body code {
padding: 0.14em 0.38em;
border-radius: 0.45em;
background: rgba(184, 95, 47, 0.1);
font-family: "JetBrains Mono", "Fira Code", Consolas, monospace;
font-size: 0.94em;
}
.doc-body pre {
overflow-x: auto;
padding: 16px 18px;
border-radius: 18px;
background: #261b16;
color: #f6eadf;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.doc-body pre code {
padding: 0;
background: transparent;
color: inherit;
}
.doc-body table {
width: 100%;
margin: 20px 0;
border-collapse: collapse;
overflow: hidden;
border-radius: 18px;
background: rgba(255, 255, 255, 0.92);
box-shadow: inset 0 0 0 1px rgba(99, 70, 42, 0.12);
}
.doc-body th,
.doc-body td {
padding: 12px 14px;
border-bottom: 1px solid rgba(99, 70, 42, 0.08);
text-align: left;
vertical-align: top;
}
.doc-body th {
background: rgba(184, 95, 47, 0.08);
font-weight: 800;
}
.doc-body hr {
margin: 28px 0;
border: 0;
border-top: 1px dashed rgba(99, 70, 42, 0.24);
}
.doc-body img {
max-width: 100%;
border-radius: 18px;
box-shadow: 0 18px 38px rgba(71, 45, 24, 0.12);
}
.floating-toc {
position: fixed;
top: auto;
right: max(16px, calc((100vw - var(--max-width)) / 2 - 90px));
bottom: 28px;
z-index: 30;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 76px;
padding: 14px 16px;
border-radius: 999px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(255, 245, 237, 0.94));
border-color: rgba(99, 70, 42, 0.14);
color: var(--accent-strong);
font-weight: 900;
box-shadow: 0 18px 38px rgba(71, 45, 24, 0.14);
transform: translateY(12px);
opacity: 0;
pointer-events: none;
}
.floating-toc.visible {
opacity: 1;
pointer-events: auto;
transform: translateY(0);
}
@media (max-width: 900px) {
.floating-toc {
top: auto;
right: 16px;
bottom: 16px;
transform: translateY(12px);
}
.floating-toc.visible {
transform: translateY(0);
}
}
@media (max-width: 720px) {
.page {
width: min(calc(100% - 20px), var(--max-width));
padding-top: 12px;
}
.hero,
.doc-section {
padding: 22px;
}
.toc {
padding: 14px;
}
.toc-grid {
grid-template-columns: 1fr;
}
.section-top,
.toc-head {
flex-direction: column;
align-items: flex-start;
}
}
</style>
</head>
<body>
<div class="page">
<header id="top" class="hero">
<span class="hero-kicker">Single File Docs</span>
<h1>Claude Code 문서 아카이브</h1>
<p>
이 폴더의 Markdown 문서를 한 페이지 HTML로 묶었습니다. 상단 목차에서 원하는 문서로 바로 이동할 수 있고,
문서를 읽는 동안 오른쪽의 떠다니는 버튼으로 언제든 목차로 빠르게 돌아올 수 있습니다.
</p>
<div class="hero-stats">
<div class="stat">
<strong>21</strong>
<span>문서 섹션</span>
</div>
<div class="stat">
<strong>9,450</strong>
<span>대략적인 단어 수</span>
</div>
<div class="stat">
<strong>2026년 4월 1일</strong>
<span>생성 날짜</span>
</div>
</div>
</header>
<nav id="toc" class="toc" aria-labelledby="toc-title">
<div class="toc-head">
<div>
<h2 id="toc-title">목차</h2>
<p>카드를 누르면 해당 문서 섹션으로 바로 이동합니다.</p>
</div>
</div>
<div id="toc-grid" class="toc-grid"></div>
</nav>
<main id="sections" class="sections"></main>
</div>
<a id="floating-toc" class="floating-toc" href="#toc" aria-label="목차로 이동">목차로</a>
<script>/**
* marked v15.0.12 - a markdown parser
* Copyright (c) 2011-2025, Christopher Jeffrey. (MIT Licensed)
* https://github.com/markedjs/marked
*/
/**
* DO NOT EDIT THIS FILE
* The code in this file is generated from files in ./src/
*/
(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("marked",f)}else {g["marked"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports};
"use strict";var H=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var Te=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var ye=(l,e)=>{for(var t in e)H(l,t,{get:e[t],enumerable:!0})},Re=(l,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Te(e))!we.call(l,s)&&s!==t&&H(l,s,{get:()=>e[s],enumerable:!(n=be(e,s))||n.enumerable});return l};var Se=l=>Re(H({},"__esModule",{value:!0}),l);var kt={};ye(kt,{Hooks:()=>L,Lexer:()=>x,Marked:()=>E,Parser:()=>b,Renderer:()=>$,TextRenderer:()=>_,Tokenizer:()=>S,defaults:()=>w,getDefaults:()=>z,lexer:()=>ht,marked:()=>k,options:()=>it,parse:()=>pt,parseInline:()=>ct,parser:()=>ut,setOptions:()=>ot,use:()=>lt,walkTokens:()=>at});module.exports=Se(kt);function z(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var w=z();function N(l){w=l}var I={exec:()=>null};function h(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,i)=>{let r=typeof i=="string"?i:i.source;return r=r.replace(m.caret,"$1"),t=t.replace(s,r),n},getRegex:()=>new RegExp(t,e)};return n}var m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}#`),htmlBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}<(?:[a-z].*>|!--)`,"i")},$e=/^(?:[ \t]*(?:\n|$))+/,_e=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,Le=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,O=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ze=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,F=/(?:[*+-]|\d{1,9}[.)])/,ie=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,oe=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Me=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Q=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Pe=/^[^\n]+/,U=/(?!\s*\])(?:\\.|[^\[\]\\])+/,Ae=h(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",U).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Ee=h(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,F).getRegex(),v="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",K=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,Ce=h("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",K).replace("tag",v).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),le=h(Q).replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Ie=h(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",le).getRegex(),X={blockquote:Ie,code:_e,def:Ae,fences:Le,heading:ze,hr:O,html:Ce,lheading:oe,list:Ee,newline:$e,paragraph:le,table:I,text:Pe},re=h("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Oe={...X,lheading:Me,table:re,paragraph:h(Q).replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",re).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex()},Be={...X,html:h(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",K).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:I,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:h(Q).replace("hr",O).replace("heading",` *#{1,6} *[^
]`).replace("lheading",oe).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},qe=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,ve=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,ae=/^( {2,}|\\)\n(?!\s*$)/,De=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,D=/[\p{P}\p{S}]/u,W=/[\s\p{P}\p{S}]/u,ce=/[^\s\p{P}\p{S}]/u,Ze=h(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,W).getRegex(),pe=/(?!~)[\p{P}\p{S}]/u,Ge=/(?!~)[\s\p{P}\p{S}]/u,He=/(?:[^\s\p{P}\p{S}]|~)/u,Ne=/\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g,ue=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,je=h(ue,"u").replace(/punct/g,D).getRegex(),Fe=h(ue,"u").replace(/punct/g,pe).getRegex(),he="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Qe=h(he,"gu").replace(/notPunctSpace/g,ce).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Ue=h(he,"gu").replace(/notPunctSpace/g,He).replace(/punctSpace/g,Ge).replace(/punct/g,pe).getRegex(),Ke=h("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ce).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Xe=h(/\\(punct)/,"gu").replace(/punct/g,D).getRegex(),We=h(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Je=h(K).replace("(?:-->|$)","-->").getRegex(),Ve=h("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",Je).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),q=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ye=h(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label",q).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ke=h(/^!?\[(label)\]\[(ref)\]/).replace("label",q).replace("ref",U).getRegex(),ge=h(/^!?\[(ref)\](?:\[\])?/).replace("ref",U).getRegex(),et=h("reflink|nolink(?!\\()","g").replace("reflink",ke).replace("nolink",ge).getRegex(),J={_backpedal:I,anyPunctuation:Xe,autolink:We,blockSkip:Ne,br:ae,code:ve,del:I,emStrongLDelim:je,emStrongRDelimAst:Qe,emStrongRDelimUnd:Ke,escape:qe,link:Ye,nolink:ge,punctuation:Ze,reflink:ke,reflinkSearch:et,tag:Ve,text:De,url:I},tt={...J,link:h(/^!?\[(label)\]\((.*?)\)/).replace("label",q).getRegex(),reflink:h(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",q).getRegex()},j={...J,emStrongRDelimAst:Ue,emStrongLDelim:Fe,url:h(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/},nt={...j,br:h(ae).replace("{2,}","*").getRegex(),text:h(j.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},B={normal:X,gfm:Oe,pedantic:Be},P={normal:J,gfm:j,breaks:nt,pedantic:tt};var st={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},fe=l=>st[l];function R(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,fe)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,fe);return l}function V(l){try{l=encodeURI(l).replace(m.percentDecode,"%")}catch{return null}return l}function Y(l,e){let t=l.replace(m.findPipe,(i,r,o)=>{let a=!1,c=r;for(;--c>=0&&o[c]==="\\";)a=!a;return a?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,"|");return n}function A(l,e,t){let n=l.length;if(n===0)return"";let s=0;for(;s<n;){let i=l.charAt(n-s-1);if(i===e&&!t)s++;else if(i!==e&&t)s++;else break}return l.slice(0,n-s)}function de(l,e){if(l.indexOf(e[1])===-1)return-1;let t=0;for(let n=0;n<l.length;n++)if(l[n]==="\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function me(l,e,t,n,s){let i=e.href,r=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=!0;let a={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:i,title:r,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,a}function rt(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
`).map(i=>{let r=i.match(t.other.beginningSpace);if(r===null)return i;let[o]=r;return o.length>=s.length?i.slice(s.length):i}).join(`
`)}var S=class{options;rules;lexer;constructor(e){this.options=e||w}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=t[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?n:A(n,`
`)}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=rt(n,t[3]||"",this.rules);return{type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=A(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:A(t[0],`
`)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=A(t[0],`
`).split(`
`),s="",i="",r=[];for(;n.length>0;){let o=!1,a=[],c;for(c=0;c<n.length;c++)if(this.rules.other.blockquoteStart.test(n[c]))a.push(n[c]),o=!0;else if(!o)a.push(n[c]);else break;n=n.slice(c);let p=a.join(`
`),u=p.replace(this.rules.other.blockquoteSetextReplace,`
$1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}
${p}`:p,i=i?`${i}
${u}`:u;let d=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(u,r,!0),this.lexer.state.top=d,n.length===0)break;let g=r.at(-1);if(g?.type==="code")break;if(g?.type==="blockquote"){let T=g,f=T.raw+`
`+n.join(`
`),y=this.blockquote(f);r[r.length-1]=y,s=s.substring(0,s.length-T.raw.length)+y.raw,i=i.substring(0,i.length-T.text.length)+y.text;break}else if(g?.type==="list"){let T=g,f=T.raw+`
`+n.join(`
`),y=this.list(f);r[r.length-1]=y,s=s.substring(0,s.length-g.raw.length)+y.raw,i=i.substring(0,i.length-T.raw.length)+y.raw,n=f.substring(r.at(-1).raw.length).split(`
`);continue}}return{type:"blockquote",raw:s,tokens:r,text:i}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,i={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let r=this.rules.other.listItemRegex(n),o=!1;for(;e;){let c=!1,p="",u="";if(!(t=r.exec(e))||this.rules.block.hr.test(e))break;p=t[0],e=e.substring(p.length);let d=t[2].split(`
`,1)[0].replace(this.rules.other.listReplaceTabs,Z=>" ".repeat(3*Z.length)),g=e.split(`
`,1)[0],T=!d.trim(),f=0;if(this.options.pedantic?(f=2,u=d.trimStart()):T?f=t[1].length+1:(f=t[2].search(this.rules.other.nonSpaceChar),f=f>4?1:f,u=d.slice(f),f+=t[1].length),T&&this.rules.other.blankLine.test(g)&&(p+=g+`
`,e=e.substring(g.length+1),c=!0),!c){let Z=this.rules.other.nextBulletRegex(f),te=this.rules.other.hrRegex(f),ne=this.rules.other.fencesBeginRegex(f),se=this.rules.other.headingBeginRegex(f),xe=this.rules.other.htmlBeginRegex(f);for(;e;){let G=e.split(`
`,1)[0],C;if(g=G,this.options.pedantic?(g=g.replace(this.rules.other.listReplaceNesting," "),C=g):C=g.replace(this.rules.other.tabCharGlobal," "),ne.test(g)||se.test(g)||xe.test(g)||Z.test(g)||te.test(g))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!g.trim())u+=`
`+C.slice(f);else{if(T||d.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||ne.test(d)||se.test(d)||te.test(d))break;u+=`
`+g}!T&&!g.trim()&&(T=!0),p+=G+`
`,e=e.substring(G.length+1),d=C.slice(f)}}i.loose||(o?i.loose=!0:this.rules.other.doubleBlankLine.test(p)&&(o=!0));let y=null,ee;this.options.gfm&&(y=this.rules.other.listIsTask.exec(u),y&&(ee=y[0]!=="[ ] ",u=u.replace(this.rules.other.listReplaceTask,""))),i.items.push({type:"list_item",raw:p,task:!!y,checked:ee,loose:!1,text:u,tokens:[]}),i.raw+=p}let a=i.items.at(-1);if(a)a.raw=a.raw.trimEnd(),a.text=a.text.trimEnd();else return;i.raw=i.raw.trimEnd();for(let c=0;c<i.items.length;c++)if(this.lexer.state.top=!1,i.items[c].tokens=this.lexer.blockTokens(i.items[c].text,[]),!i.loose){let p=i.items[c].tokens.filter(d=>d.type==="space"),u=p.length>0&&p.some(d=>this.rules.other.anyLine.test(d.raw));i.loose=u}if(i.loose)for(let c=0;c<i.items.length;c++)i.items[c].loose=!0;return i}}html(e){let t=this.rules.block.html.exec(e);if(t)return{type:"html",block:!0,raw:t[0],pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:t[0]}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",i=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:n,raw:t[0],href:s,title:i}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=Y(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),i=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(`
`):[],r={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?r.align.push("right"):this.rules.other.tableAlignCenter.test(o)?r.align.push("center"):this.rules.other.tableAlignLeft.test(o)?r.align.push("left"):r.align.push(null);for(let o=0;o<n.length;o++)r.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:!0,align:r.align[o]});for(let o of i)r.rows.push(Y(o,r.header.length).map((a,c)=>({text:a,tokens:this.lexer.inline(a),header:!1,align:r.align[c]})));return r}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:t[2].charAt(0)==="="?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===`
`?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let r=A(n.slice(0,-1),"\\");if((n.length-r.length)%2===0)return}else{let r=de(t[2],"()");if(r===-2)return;if(r>-1){let a=(t[0].indexOf("!")===0?5:4)+t[1].length+r;t[2]=t[2].substring(0,r),t[0]=t[0].substring(0,a).trim(),t[3]=""}}let s=t[2],i="";if(this.options.pedantic){let r=this.rules.other.pedanticHrefTitle.exec(s);r&&(s=r[1],i=r[3])}else i=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),me(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:i&&i.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),i=t[s.toLowerCase()];if(!i){let r=n[0].charAt(0);return{type:"text",raw:r,text:r}}return me(n,i,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||s[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){let r=[...s[0]].length-1,o,a,c=r,p=0,u=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(u.lastIndex=0,t=t.slice(-1*e.length+r);(s=u.exec(t))!=null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(a=[...o].length,s[3]||s[4]){c+=a;continue}else if((s[5]||s[6])&&r%3&&!((r+a)%3)){p+=a;continue}if(c-=a,c>0)continue;a=Math.min(a,a+c+p);let d=[...s[0]][0].length,g=e.slice(0,r+s.index+d+a);if(Math.min(r,a)%2){let f=g.slice(1,-1);return{type:"em",raw:g,text:f,tokens:this.lexer.inlineTokens(f)}}let T=g.slice(2,-2);return{type:"strong",raw:g,text:T,tokens:this.lexer.inlineTokens(T)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),i=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&i&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){let t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else{let i;do i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(i!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0]}return{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;tokenizer;inlineQueue;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||w,this.options.tokenizer=this.options.tokenizer||new S,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let t={other:m,block:B.normal,inline:P.normal};this.options.pedantic?(t.block=B.pedantic,t.inline=P.pedantic):this.options.gfm&&(t.block=B.gfm,this.options.breaks?t.inline=P.breaks:t.inline=P.gfm),this.tokenizer.rules=t}static get rules(){return{block:B,inline:P}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
`),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let n=this.inlineQueue[t];this.inlineTokens(n.src,n.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=!1){for(this.options.pedantic&&(e=e.replace(m.tabCharGlobal," ").replace(m.spaceLine,""));e;){let s;if(this.options.extensions?.block?.some(r=>(s=r.call({lexer:this},e,t))?(e=e.substring(s.raw.length),t.push(s),!0):!1))continue;if(s=this.tokenizer.space(e)){e=e.substring(s.raw.length);let r=t.at(-1);s.raw.length===1&&r!==void 0?r.raw+=`
`:t.push(s);continue}if(s=this.tokenizer.code(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="paragraph"||r?.type==="text"?(r.raw+=`
`+s.raw,r.text+=`
`+s.text,this.inlineQueue.at(-1).src=r.text):t.push(s);continue}if(s=this.tokenizer.fences(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.heading(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.hr(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.blockquote(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.list(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.html(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.def(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="paragraph"||r?.type==="text"?(r.raw+=`
`+s.raw,r.text+=`
`+s.raw,this.inlineQueue.at(-1).src=r.text):this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title});continue}if(s=this.tokenizer.table(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.lheading(e)){e=e.substring(s.raw.length),t.push(s);continue}let i=e;if(this.options.extensions?.startBlock){let r=1/0,o=e.slice(1),a;this.options.extensions.startBlock.forEach(c=>{a=c.call({lexer:this},o),typeof a=="number"&&a>=0&&(r=Math.min(r,a))}),r<1/0&&r>=0&&(i=e.substring(0,r+1))}if(this.state.top&&(s=this.tokenizer.paragraph(i))){let r=t.at(-1);n&&r?.type==="paragraph"?(r.raw+=`
`+s.raw,r.text+=`
`+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=r.text):t.push(s),n=i.length!==e.length,e=e.substring(s.raw.length);continue}if(s=this.tokenizer.text(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="text"?(r.raw+=`
`+s.raw,r.text+=`
`+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=r.text):t.push(s);continue}if(e){let r="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(r);break}else throw new Error(r)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,s=null;if(this.tokens.links){let o=Object.keys(this.tokens.links);if(o.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!=null;)o.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!=null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!=null;)n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);let i=!1,r="";for(;e;){i||(r=""),i=!1;let o;if(this.options.extensions?.inline?.some(c=>(o=c.call({lexer:this},e,t))?(e=e.substring(o.raw.length),t.push(o),!0):!1))continue;if(o=this.tokenizer.escape(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.tag(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.link(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(o.raw.length);let c=t.at(-1);o.type==="text"&&c?.type==="text"?(c.raw+=o.raw,c.text+=o.text):t.push(o);continue}if(o=this.tokenizer.emStrong(e,n,r)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.codespan(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.br(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.del(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.autolink(e)){e=e.substring(o.raw.length),t.push(o);continue}if(!this.state.inLink&&(o=this.tokenizer.url(e))){e=e.substring(o.raw.length),t.push(o);continue}let a=e;if(this.options.extensions?.startInline){let c=1/0,p=e.slice(1),u;this.options.extensions.startInline.forEach(d=>{u=d.call({lexer:this},p),typeof u=="number"&&u>=0&&(c=Math.min(c,u))}),c<1/0&&c>=0&&(a=e.substring(0,c+1))}if(o=this.tokenizer.inlineText(a)){e=e.substring(o.raw.length),o.raw.slice(-1)!=="_"&&(r=o.raw.slice(-1)),i=!0;let c=t.at(-1);c?.type==="text"?(c.raw+=o.raw,c.text+=o.text):t.push(o);continue}if(e){let c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}else throw new Error(c)}}return t}};var $=class{options;parser;constructor(e){this.options=e||w}space(e){return""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],i=e.replace(m.endingNewline,"")+`
`;return s?'<pre><code class="language-'+R(s)+'">'+(n?i:R(i,!0))+`</code></pre>
`:"<pre><code>"+(n?i:R(i,!0))+`</code></pre>
`}blockquote({tokens:e}){return`<blockquote>
${this.parser.parse(e)}</blockquote>
`}html({text:e}){return e}heading({tokens:e,depth:t}){return`<h${t}>${this.parser.parseInline(e)}</h${t}>
`}hr(e){return`<hr>
`}list(e){let t=e.ordered,n=e.start,s="";for(let o=0;o<e.items.length;o++){let a=e.items[o];s+=this.listitem(a)}let i=t?"ol":"ul",r=t&&n!==1?' start="'+n+'"':"";return"<"+i+r+`>
`+s+"</"+i+`>
`}listitem(e){let t="";if(e.task){let n=this.checkbox({checked:!!e.checked});e.loose?e.tokens[0]?.type==="paragraph"?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&e.tokens[0].tokens[0].type==="text"&&(e.tokens[0].tokens[0].text=n+" "+R(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=!0)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:!0}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`<li>${t}</li>
`}checkbox({checked:e}){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph({tokens:e}){return`<p>${this.parser.parseInline(e)}</p>
`}table(e){let t="",n="";for(let i=0;i<e.header.length;i++)n+=this.tablecell(e.header[i]);t+=this.tablerow({text:n});let s="";for(let i=0;i<e.rows.length;i++){let r=e.rows[i];n="";for(let o=0;o<r.length;o++)n+=this.tablecell(r[o]);s+=this.tablerow({text:n})}return s&&(s=`<tbody>${s}</tbody>`),`<table>
<thead>
`+t+`</thead>
`+s+`</table>
`}tablerow({text:e}){return`<tr>
${e}</tr>
`}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}>
`}strong({tokens:e}){return`<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return`<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return`<code>${R(e,!0)}</code>`}br(e){return"<br>"}del({tokens:e}){return`<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),i=V(e);if(i===null)return s;e=i;let r='<a href="'+e+'"';return t&&(r+=' title="'+R(t)+'"'),r+=">"+s+"</a>",r}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let i=V(e);if(i===null)return R(n);e=i;let r=`<img src="${e}" alt="${n}"`;return t&&(r+=` title="${R(t)}"`),r+=">",r}text(e){return"tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:R(e.text)}};var _=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return""+e}image({text:e}){return""+e}br(){return""}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||w,this.options.renderer=this.options.renderer||new $,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new _}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e,t=!0){let n="";for(let s=0;s<e.length;s++){let i=e[s];if(this.options.extensions?.renderers?.[i.type]){let o=i,a=this.options.extensions.renderers[o.type].call({parser:this},o);if(a!==!1||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(o.type)){n+=a||"";continue}}let r=i;switch(r.type){case"space":{n+=this.renderer.space(r);continue}case"hr":{n+=this.renderer.hr(r);continue}case"heading":{n+=this.renderer.heading(r);continue}case"code":{n+=this.renderer.code(r);continue}case"table":{n+=this.renderer.table(r);continue}case"blockquote":{n+=this.renderer.blockquote(r);continue}case"list":{n+=this.renderer.list(r);continue}case"html":{n+=this.renderer.html(r);continue}case"paragraph":{n+=this.renderer.paragraph(r);continue}case"text":{let o=r,a=this.renderer.text(o);for(;s+1<e.length&&e[s+1].type==="text";)o=e[++s],a+=`
`+this.renderer.text(o);t?n+=this.renderer.paragraph({type:"paragraph",raw:a,text:a,tokens:[{type:"text",raw:a,text:a,escaped:!0}]}):n+=a;continue}default:{let o='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}parseInline(e,t=this.renderer){let n="";for(let s=0;s<e.length;s++){let i=e[s];if(this.options.extensions?.renderers?.[i.type]){let o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==!1||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(i.type)){n+=o||"";continue}}let r=i;switch(r.type){case"escape":{n+=t.text(r);break}case"html":{n+=t.html(r);break}case"link":{n+=t.link(r);break}case"image":{n+=t.image(r);break}case"strong":{n+=t.strong(r);break}case"em":{n+=t.em(r);break}case"codespan":{n+=t.codespan(r);break}case"br":{n+=t.br(r);break}case"del":{n+=t.del(r);break}case"text":{n+=t.text(r);break}default:{let o='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var L=class{options;block;constructor(e){this.options=e||w}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}provideLexer(){return this.block?x.lex:x.lexInline}provideParser(){return this.block?b.parse:b.parseInline}};var E=class{defaults=z();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=b;Renderer=$;TextRenderer=_;Lexer=x;Tokenizer=S;Hooks=L;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case"table":{let i=s;for(let r of i.header)n=n.concat(this.walkTokens(r.tokens,t));for(let r of i.rows)for(let o of r)n=n.concat(this.walkTokens(o.tokens,t));break}case"list":{let i=s;n=n.concat(this.walkTokens(i.items,t));break}default:{let i=s;this.defaults.extensions?.childTokens?.[i.type]?this.defaults.extensions.childTokens[i.type].forEach(r=>{let o=i[r].flat(1/0);n=n.concat(this.walkTokens(o,t))}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)))}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let r=t.renderers[i.name];r?t.renderers[i.name]=function(...o){let a=i.renderer.apply(this,o);return a===!1&&(a=r.apply(this,o)),a}:t.renderers[i.name]=i.renderer}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let r=t[i.level];r?r.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]))}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens)}),s.extensions=t),n.renderer){let i=this.defaults.renderer||new $(this.defaults);for(let r in n.renderer){if(!(r in i))throw new Error(`renderer '${r}' does not exist`);if(["options","parser"].includes(r))continue;let o=r,a=n.renderer[o],c=i[o];i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u||""}}s.renderer=i}if(n.tokenizer){let i=this.defaults.tokenizer||new S(this.defaults);for(let r in n.tokenizer){if(!(r in i))throw new Error(`tokenizer '${r}' does not exist`);if(["options","rules","lexer"].includes(r))continue;let o=r,a=n.tokenizer[o],c=i[o];i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u}}s.tokenizer=i}if(n.hooks){let i=this.defaults.hooks||new L;for(let r in n.hooks){if(!(r in i))throw new Error(`hook '${r}' does not exist`);if(["options","block"].includes(r))continue;let o=r,a=n.hooks[o],c=i[o];L.passThroughHooks.has(r)?i[o]=p=>{if(this.defaults.async)return Promise.resolve(a.call(i,p)).then(d=>c.call(i,d));let u=a.call(i,p);return c.call(i,u)}:i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u}}s.hooks=i}if(n.walkTokens){let i=this.defaults.walkTokens,r=n.walkTokens;s.walkTokens=function(o){let a=[];return a.push(r.call(this,o)),i&&(a=a.concat(i.call(this,o))),a}}this.defaults={...this.defaults,...s}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return(n,s)=>{let i={...s},r={...this.defaults,...i},o=this.onError(!!r.silent,!!r.async);if(this.defaults.async===!0&&i.async===!1)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);let a=r.hooks?r.hooks.provideLexer():e?x.lex:x.lexInline,c=r.hooks?r.hooks.provideParser():e?b.parse:b.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(n):n).then(p=>a(p,r)).then(p=>r.hooks?r.hooks.processAllTokens(p):p).then(p=>r.walkTokens?Promise.all(this.walkTokens(p,r.walkTokens)).then(()=>p):p).then(p=>c(p,r)).then(p=>r.hooks?r.hooks.postprocess(p):p).catch(o);try{r.hooks&&(n=r.hooks.preprocess(n));let p=a(n,r);r.hooks&&(p=r.hooks.processAllTokens(p)),r.walkTokens&&this.walkTokens(p,r.walkTokens);let u=c(p,r);return r.hooks&&(u=r.hooks.postprocess(u)),u}catch(p){return o(p)}}}onError(e,t){return n=>{if(n.message+=`
Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error occurred:</p><pre>"+R(n.message+"",!0)+"</pre>";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var M=new E;function k(l,e){return M.parse(l,e)}k.options=k.setOptions=function(l){return M.setOptions(l),k.defaults=M.defaults,N(k.defaults),k};k.getDefaults=z;k.defaults=w;k.use=function(...l){return M.use(...l),k.defaults=M.defaults,N(k.defaults),k};k.walkTokens=function(l,e){return M.walkTokens(l,e)};k.parseInline=M.parseInline;k.Parser=b;k.parser=b.parse;k.Renderer=$;k.TextRenderer=_;k.Lexer=x;k.lexer=x.lex;k.Tokenizer=S;k.Hooks=L;k.parse=k;var it=k.options,ot=k.setOptions,lt=k.use,at=k.walkTokens,ct=k.parseInline,pt=k,ut=b.parse,ht=x.lex;
if(__exports != exports)module.exports = exports;return module.exports}));
</script>
<script>
const sections = [{"index":1,"id":"section-01-readme","fileName":"README.md","title":"Claude Code Docs (KO/EN)","markdown":"# Claude Code Docs (KO/EN)\n\n> 2026년 3월, Claude Code의 npm 소스맵을 통해 내부 TypeScript 소스코드가 유출되는 사건이 발생했습니다. \n> 이 레포는 그 과정에서 공개된 내부 구조 분석 문서를 한국어로 번역·정리한 아카이브입니다.\n\n---\n\n## 배경\n\n2026년 3월 31일, Claude Code npm 패키지에 포함된 `.map` 파일이 Anthropic의 내부 R2 버킷에 있는 unobfuscated TypeScript 소스 zip을 가리키고 있음이 발견되었습니다. 이를 통해 약 1,900개 파일, 512,000줄 규모의 Claude Code 원본 소스가 외부에 노출되었습니다.\n\n유출된 소스를 분석한 커뮤니티([@VineeTagarwaL](https://github.com/VineeTagarwaL-code))는 내부 아키텍처를 문서화하여 Mintlify 사이트로 공개했습니다. 이 레포는 해당 문서를 한국어로 번역한 것입니다.\n\n---\n\n## 주요 발견 사항\n\n유출 소스 분석을 통해 드러난 Claude Code의 실제 아키텍처:\n\n- **런타임**: Bun + React/Ink (터미널 UI 렌더링)\n- **에이전틱 루프**: `query.ts`가 구동하는 연속 루프 — 도구 호출 → 권한 확인 → 결과 수집 → 반복\n- **컨텍스트 조립**: `context.ts`의 `getSystemContext()` / `getUserContext()`가 git 상태, CLAUDE.md, 현재 날짜를 조립\n- **도구 시스템**: ~40개 내장 도구 (`BashTool`, `FileEditTool`, `AgentTool` 등)\n- **멀티에이전트**: `coordinator/`에서 팀 레벨 병렬 오케스트레이션\n- **스킬 시스템**: `.claude/skills/`의 마크다운 파일 기반 온디맨드 기능\n- **피처 플래그**: Bun 빌드타임 dead code elimination (`PROACTIVE`, `KAIROS`, `BRIDGE_MODE`, `DAEMON` 등)\n\n---\n\n## 구조\n\n```\n/ (root) — 한국어 번역본 (21개)\nen/ — 영어 원본 (26개)\n concepts/\n configuration/\n guides/\n reference/\n commands/\n sdk/\n tools/\n```\n\n---\n\n## 출처\n\n- 원본 문서: https://vineetagarwal-code-claude-code.mintlify.app\n- 관련 레포: https://github.com/instructkr/claw-code\n- 최초 발견: [@Fried_rice (Chaofan Shou)](https://x.com/shouc001) — npm 소스맵 경유 R2 버킷 접근\n\n---\n\n> 이 레포는 공개된 분석 문서의 번역 아카이브입니다. Anthropic의 독점 소스코드를 포함하지 않습니다.\n"},{"index":2,"id":"section-02-01-소개","fileName":"01_소개.md","title":"소개","markdown":"# 소개\n\n> Claude Code는 터미널에서 실행되는 AI 코딩 에이전트로, 전체 코드베이스에 걸쳐 코드를 읽고, 편집하고, 실행합니다.\n\nClaude Code는 Claude를 기반으로 만들어진 터미널 기반 AI 에이전트입니다. 파일 시스템, 셸, 도구에 직접 접근할 수 있어서, 자연어로 작업을 설명하면 Claude가 처음부터 끝까지 구현을 처리합니다 — 복사&붙여넣기 없이, 컨텍스트 전환 없이.\n\n## Claude Code가 할 수 있는 일\n\n- **파일 읽기 및 편집** — 소스 파일을 읽고, 새 내용을 작성하고, 정밀하게 편집합니다. 변경 사항을 적용하기 전에 diff를 보여줘서 사용자가 통제권을 유지합니다.\n- **셸 커맨드 실행** — 테스트, 빌드 스크립트, git 작업 등 모든 셸 커맨드를 실행합니다. 설정 가능한 권한 제어로 안전성을 보장합니다.\n- **코드베이스 검색** — glob 패턴으로 파일을 찾고, 정규식으로 내용을 검색하며, 모든 파일을 수동으로 읽지 않아도 대규모 코드베이스를 탐색합니다.\n- **웹에서 정보 가져오기** — 문서를 가져오거나, API 스펙을 읽거나, 웹을 검색합니다 — 모두 터미널 세션에서 벗어나지 않고.\n- **서브에이전트 생성** — 복잡한 작업을 병렬 워크스트림으로 분리합니다. Claude가 여러 에이전트를 스폰하고 조율해서 문제의 각 부분을 동시에 처리합니다.\n- **MCP 서버 연결** — 데이터베이스, API, 내부 도구 등을 위한 Model Context Protocol 서버로 Claude의 역량을 확장합니다.\n\n## 권한 시스템\n\nClaude Code의 모든 도구 사용은 권한 확인을 거칩니다. 사용자가 Claude에게 얼마나 많은 자율성을 줄지 제어합니다.\n\n| 모드 | 동작 |\n|------|------|\n| `default` | 셸 커맨드 실행 및 편집 전에 Claude가 확인을 요청합니다. 각 작업을 승인하거나 거부할 수 있습니다. |\n| `acceptEdits` | 파일 편집이 자동으로 적용됩니다. 셸 커맨드는 여전히 승인이 필요합니다. |\n| `plan` | Claude가 계획을 만들고 어떤 작업도 실행하기 전에 승인을 요청합니다. 큰 변경 사항이 발생하기 전에 검토하기 좋습니다. |\n| `bypassPermissions` | 모든 작업이 프롬프트 없이 실행됩니다. 샌드박스 환경의 자동화 파이프라인 전용 — 대화형 사용에는 적합하지 않습니다. |\n\n> ⚠️ `bypassPermissions` 모드는 모든 확인 프롬프트를 비활성화합니다. Claude가 작업 범위 외부의 시스템에 영향을 줄 수 없는 격리된 환경(Docker 컨테이너, CI 샌드박스)에서만 사용하세요.\n\n시작 시 `--permission-mode` 플래그로 설정하거나, 세션 중 `/permissions`로 변경하세요:\n\n```bash\nclaude --permission-mode acceptEdits\n```\n\n## CLAUDE.md 메모리 시스템\n\nClaude Code는 매 세션 시작 시 저장소의 `CLAUDE.md` 파일을 읽습니다. 이 파일을 통해 프로젝트별 지식 — 빌드 커맨드, 코딩 컨벤션, 아키텍처 노트, 필요한 환경 변수 등 — 을 인코딩할 수 있어서, Claude가 매번 처음부터 다시 발견할 필요가 없습니다.\n\n세 가지 범위:\n\n- **프로젝트** (`CLAUDE.md` — 저장소 루트) — 팀 전체가 공유, 소스 컨트롤에 커밋\n- **개인** (`CLAUDE.local.md` — 저장소 루트) — 이 프로젝트에 대한 개인 설정, gitignore됨\n- **서브디렉토리** (서브디렉토리 안의 `CLAUDE.md`) — Claude가 해당 디렉토리에서 작업할 때 자동으로 로드됨. 별개의 모듈이 있는 모노레포에 유용\n\nClaude Code 세션 안에서 `/init`을 실행하면 프로젝트의 `CLAUDE.md`가 자동으로 생성됩니다.\n\n> 💡 `CLAUDE.md`는 간결하게 유지하세요. 모든 줄이 이 테스트를 통과해야 합니다: \"이것을 제거하면 Claude가 실수를 할까?\" 그렇지 않다면 삭제하세요.\n\n## 인증\n\nClaude Code는 두 가지 방식으로 인증합니다:\n\n1. **OAuth (권장)** — `claude.ai`에서 Anthropic 계정으로 로그인. 처음 `claude`를 실행하면 브라우저 프롬프트가 나타납니다.\n2. **API 키** — `ANTHROPIC_API_KEY` 환경 변수를 설정. CI 파이프라인과 비대화형 세션에 유용합니다.\n"},{"index":3,"id":"section-03-02-빠른시작","fileName":"02_빠른시작.md","title":"빠른 시작","markdown":"# 빠른 시작\n\n> Claude Code를 설치하고, 인증하고, 5분 안에 첫 번째 코딩 작업을 완료하세요.\n\n## 사전 요구사항\n\n- Node.js 18 이상\n- npm\n\nNode.js 버전 확인:\n\n```bash\nnode --version\n```\n\nNode.js를 설치하거나 업그레이드해야 한다면 [nodejs.org](https://nodejs.org)에서 다운로드하세요.\n\n---\n\n## 1단계: Claude Code 설치\n\nnpm으로 전역 설치:\n\n```bash\nnpm install -g @anthropic-ai/claude-code\n```\n\n설치 확인:\n\n```bash\nclaude --version\n```\n\n---\n\n## 2단계: 인증\n\n아무 디렉토리에서나 `claude`를 실행해 최초 설정을 시작:\n\n```bash\nclaude\n```\n\n처음 실행하면, Claude Code가 브라우저를 열고 Anthropic 계정으로 로그인하는 과정을 안내합니다. 완료하면 자격 증명이 안전하게 저장되어 이후 세션에서 재사용됩니다.\n\n**대안으로**, OAuth를 사용하지 않으려면 API 키를 직접 설정하세요:\n\n```bash\nexport ANTHROPIC_API_KEY=sk-ant-...\n```\n\n> 📝 `ANTHROPIC_API_KEY` 환경 변수가 설정되어 있으면 API 키가 우선합니다. 대화형 사용에는 OAuth가 권장됩니다 — 토큰 갱신을 자동으로 처리합니다.\n\n---\n\n## 3단계: 프로젝트로 이동\n\nClaude Code는 현재 디렉토리 내에서 작동합니다. 작업하려는 프로젝트로 이동하세요:\n\n```bash\ncd my-project\n```\n\n---\n\n## 4단계: 대화형 세션 시작\n\n`claude`를 실행해 대화형 세션을 열기:\n\n```bash\nclaude\n```\n\n자연어로 작업을 입력할 수 있는 프롬프트가 나타납니다. Claude가 프로젝트 파일을 읽고, 커맨드를 실행하고, 지시에 따라 변경 사항을 만듭니다.\n\n**첫 번째로 시도할 예제 작업들:**\n\n```\n> 이 코드베이스의 구조를 설명해줘\n> 회원가입 폼에 입력 검증 추가해줘\n> UserService 클래스에 대한 테스트 작성해줘\n> 에러를 잡고 무시하는 곳을 모두 찾아줘\n```\n\nClaude는 권한이 필요한 변경 사항을 만들기 전에 계획을 보여줍니다. 각 단계에서 승인하거나, 거부하거나, 다른 접근 방식을 요청할 수 있습니다.\n\n---\n\n## 5단계: CLAUDE.md 파일 초기화\n\n세션 안에서 `/init`을 실행해 프로젝트의 `CLAUDE.md` 파일을 생성:\n\n```\n/init\n```\n\nClaude가 저장소를 분석하여 — 매니페스트 파일, 기존 문서, 코드 구조를 읽어 — 코드베이스에서 효과적으로 작업하는 데 필요한 커맨드와 컨텍스트를 담은 `CLAUDE.md`를 생성합니다. 커밋하기 전에 생성된 파일을 검토하고 편집하세요.\n\n> 💡 `CLAUDE.md`는 매 세션 시작 시 로드됩니다. 비표준 빌드 커맨드, 테스트 특이사항, 팀 고유의 코딩 컨벤션 등을 기록하기 가장 좋은 곳입니다.\n\n---\n\n## 비대화형 커맨드 실행\n\n`-p` 플래그를 사용해 단일 작업을 실행하고 결과를 출력합니다 — 대화형 세션에 들어가지 않고. 스크립팅이나 일회성 쿼리에 유용합니다:\n\n```bash\nclaude -p \"이 코드베이스를 설명해줘\"\nclaude -p \"src/ 안의 모든 TODO 주석과 파일을 나열해줘\"\nclaude -p \"src/ 안의 미사용 export를 확인해줘\"\n```\n\n---\n\n## 핵심 슬래시 커맨드\n\n대화형 세션 안에서 가장 유용한 슬래시 커맨드들:\n\n| 커맨드 | 설명 |\n|--------|------|\n| `/help` | 사용 가능한 커맨드와 키보드 단축키 표시 |\n| `/init` | 현재 프로젝트의 `CLAUDE.md` 생성 또는 업데이트 |\n| `/memory` | 메모리 파일(`CLAUDE.md`, `CLAUDE.local.md`) 보기 및 편집 |\n| `/permissions` | 현재 권한 모드 보기 또는 변경 |\n| `/mcp` | 연결된 MCP 서버 관리 |\n| `/clear` | 현재 대화 컨텍스트 지우기 |\n| `/exit` | 세션 종료 |\n"},{"index":4,"id":"section-04-03-설치","fileName":"03_설치.md","title":"설치","markdown":"# 설치\n\n> macOS, Linux, Windows(WSL 경유)에 Claude Code를 설치합니다. Node.js 18 이상이 필요합니다.\n\n## 요구사항\n\n- **Node.js 18 이상** — Claude Code는 시작 시 Node.js 버전을 확인하고, 18 미만이면 오류와 함께 종료합니다.\n- **npm** — Node.js에 포함되어 있습니다.\n\n현재 버전 확인:\n\n```bash\nnode --version\nnpm --version\n```\n\n---\n\n## Claude Code 설치\n\nnpm으로 전역 설치:\n\n```bash\nnpm install -g @anthropic-ai/claude-code\n```\n\n설치 후 동작 확인:\n\n```bash\nclaude --version\n```\n\n---\n\n## 플랫폼별 안내\n\n### macOS\n\nmacOS에서는 npm 전역 설치가 기본적으로 작동합니다. `npm install -g` 실행 시 권한 오류가 발생하면 두 가지 옵션이 있습니다:\n\n**옵션 A: npm 권한 수정 (권장)**\n\n홈 폴더의 디렉토리를 사용하도록 npm을 설정:\n\n```bash\nmkdir -p ~/.npm-global\nnpm config set prefix ~/.npm-global\n```\n\n셸 프로파일(`~/.zshrc` 또는 `~/.bash_profile`)에 다음 추가:\n\n```bash\nexport PATH=~/.npm-global/bin:$PATH\n```\n\n프로파일 다시 로드 후 설치:\n\n```bash\nsource ~/.zshrc\nnpm install -g @anthropic-ai/claude-code\n```\n\n**옵션 B: Node 버전 관리자 사용**\n\n[nvm](https://github.com/nvm-sh/nvm) 또는 [fnm](https://github.com/Schniz/fnm) 같은 도구는 홈 디렉토리에 Node.js를 설치해서 전역 권한 문제를 완전히 피할 수 있습니다:\n\n```bash\n# nvm 사용\nnvm install --lts\nnvm use --lts\nnpm install -g @anthropic-ai/claude-code\n```\n\n### Linux\n\n대부분의 Linux 배포판에서 `npm install -g`는 `sudo` 또는 npm prefix 수정이 필요합니다. `sudo` 사용은 나중에 권한 문제를 일으킬 수 있으므로 권장하지 않습니다.\n\n**권장: Node 버전 관리자 사용**\n\n```bash\n# nvm 설치\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash\n\n# 셸 다시 로드 후 Node.js 설치\nnvm install --lts\nnvm use --lts\n\n# Claude Code 설치\nnpm install -g @anthropic-ai/claude-code\n```\n\n**대안: npm 전역 prefix 수정**\n\n```bash\nmkdir -p ~/.npm-global\nnpm config set prefix ~/.npm-global\necho 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc\nsource ~/.bashrc\nnpm install -g @anthropic-ai/claude-code\n```\n\n### Windows (WSL)\n\nClaude Code는 Windows Subsystem for Linux(WSL)를 통해 Windows에서 실행됩니다. 커맨드 프롬프트나 PowerShell에서 직접 실행하는 것은 지원되지 않습니다.\n\n**1단계: WSL 설치**\n\n관리자 권한으로 PowerShell 열고 실행:\n\n```powershell\nwsl --install\n```\n\n메시지가 나타나면 재시작. 기본적으로 Ubuntu와 함께 WSL 2가 설치됩니다.\n\n**2단계: WSL 터미널 열기**\n\n시작 메뉴에서 Ubuntu를 실행하거나, PowerShell에서 `wsl`을 실행합니다.\n\n**3단계: WSL 안에 Node.js 설치**\n\n```bash\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash\nsource ~/.bashrc\nnvm install --lts\nnvm use --lts\n```\n\n**4단계: Claude Code 설치**\n\n```bash\nnpm install -g @anthropic-ai/claude-code\n```\n\n> 📝 항상 WSL 터미널 안에서 `claude`를 실행하세요 — Windows CMD나 PowerShell에서 실행하지 마세요. 프로젝트 파일은 WSL 파일시스템(`~/projects/` 등) 안에 있어야 최상의 성능을 발휘합니다. `/mnt/c/...`를 통한 Windows 파일 접근은 가능하지만 느립니다.\n\n---\n\n## 업데이트\n\n최신 버전으로 업데이트:\n\n```bash\nnpm update -g @anthropic-ai/claude-code\n```\n\n또는 Claude Code 내장 업데이트 커맨드 사용:\n\n```bash\nclaude update\n```\n\n현재 버전 확인:\n\n```bash\nclaude --version\n```\n\n---\n\n## 제거\n\nClaude Code 제거:\n\n```bash\nnpm uninstall -g @anthropic-ai/claude-code\n```\n\n`claude` 바이너리가 제거됩니다. `~/.claude/`의 설정 파일은 자동으로 제거되지 않습니다. 삭제하려면:\n\n```bash\nrm -rf ~/.claude\n```\n\n---\n\n## 문제 해결\n\n### 설치 후 `claude` 커맨드를 찾을 수 없음\n\nnpm 전역 bin 디렉토리가 `PATH`에 없는 경우입니다.\n\nnpm이 전역 바이너리를 설치하는 위치 확인:\n\n```bash\nnpm config get prefix\n```\n\n해당 경로의 `bin` 서브디렉토리를 `PATH`에 추가해야 합니다. 예를 들어 출력이 `/home/you/.npm-global`이면:\n\n```bash\nexport PATH=/home/you/.npm-global/bin:$PATH\n```\n\n셸을 다시 로드(`source ~/.zshrc` 또는 새 터미널 열기) 후 다시 시도하세요.\n\n### Node.js 버전이 18 미만\n\nClaude Code는 Node.js 18 이상이 필요합니다. 시작 시 이 오류가 보이면:\n\n```\nError: Claude Code requires Node.js version 18 or higher.\n```\n\n버전 관리자를 사용해 Node.js를 업그레이드하세요:\n\n```bash\n# nvm\nnvm install --lts\nnvm use --lts\n\n# fnm\nfnm install --lts\nfnm use --lts\n```\n\n### npm install -g 시 권한 거부\n\n`sudo npm install -g`를 사용하지 마세요 — root 소유 파일이 남아 추가 문제를 일으킬 수 있습니다. 대신 npm prefix를 사용자 쓰기 가능 디렉토리로 수정하세요:\n\n```bash\nmkdir -p ~/.npm-global\nnpm config set prefix ~/.npm-global\nexport PATH=~/.npm-global/bin:$PATH\nnpm install -g @anthropic-ai/claude-code\n```\n\n### 첫 실행 시 인증 실패\n\n브라우저 기반 OAuth 흐름이 실패하거나 브라우저를 사용할 수 없는 경우, 환경 변수로 API 키를 직접 설정하세요:\n\n```bash\nexport ANTHROPIC_API_KEY=sk-ant-...\nclaude\n```\n\n셸 프로파일에 추가하면 영구적으로 설정됩니다. API 키는 [Anthropic Console](https://console.anthropic.com)에서 발급받을 수 있습니다.\n\n### Docker 또는 CI 환경에서 실행\n\n비대화형 환경에서는 환경 변수로 인증하세요:\n\n```bash\nexport ANTHROPIC_API_KEY=sk-ant-...\n```\n\n비대화형으로 실행하려면 `-p` 플래그 사용:\n\n```bash\nclaude -p \"테스트 스위트를 실행하고 실패를 보고해줘\"\n```\n\n샌드박스 컨테이너에서 권한 프롬프트 없이 Claude Code를 작동시켜야 한다면 `--dangerously-skip-permissions` 플래그를 사용하세요. 이 플래그는 Claude Code의 샌드박스 안전 검사를 통과한 환경(인터넷 접근 없음, 컨테이너 외부에서 root로 실행하지 않음)에서만 작동합니다.\n"},{"index":5,"id":"section-05-04-작동원리","fileName":"04_작동원리.md","title":"작동 원리","markdown":"# 작동 원리\n\n> 에이전틱 루프, 컨텍스트 로딩, 도구 실행 모델, 대화 생명주기에 대한 내부 동작 설명.\n\nClaude Code는 터미널 기반 코딩 에이전트로, 연속적인 에이전틱 루프를 실행합니다. 요청을 읽고, 무엇을 해야 할지 추론하고, 도구를 호출하고, 결과를 관찰하고, 작업이 완료되거나 입력이 필요할 때까지 이를 반복합니다.\n\n## 에이전틱 루프\n\n모든 상호작용은 동일한 기본 사이클을 따릅니다:\n\n1. **사용자가 메시지를 보냄** — 터미널에서 메시지를 입력하거나(대화형 모드), `--print` / stdin을 통해 전달합니다(비대화형/헤드리스 모드). 메시지는 대화 기록에 추가됩니다.\n\n2. **컨텍스트 조립** — 모델을 호출하기 전에, Claude Code가 시스템 프롬프트를 조립합니다: 현재 날짜, git 상태(브랜치, 최근 커밋, 워킹트리 상태), 로드된 CLAUDE.md 메모리 파일들, 사용 가능한 도구 목록. 이 컨텍스트는 대화당 한 번 구성되고 메모이제이션됩니다.\n\n3. **Claude가 추론하고 도구를 선택** — 조립된 대화가 Anthropic API로 전송됩니다. 모델이 작업에 대해 추론하고 하나 이상의 `tool_use` 블록을 출력합니다 — 각각 도구 이름과 구조화된 JSON 입력을 지정합니다.\n\n4. **권한 확인** — 각 도구 호출을 실행하기 전에, Claude Code가 현재 권한 모드와 허용/차단 규칙을 평가합니다. 모드에 따라 자동 승인하거나, 확인을 요청하거나, 호출을 완전히 차단합니다.\n\n5. **도구가 실행되고 결과를 반환** — 승인된 도구 호출이 실행됩니다. 결과(파일 내용, 명령어 출력, 검색 결과)는 `tool_result` 블록으로 대화에 추가됩니다.\n\n6. **루프 계속** — 모델이 도구 결과를 받아 더 많은 도구를 호출하거나 최종 텍스트 응답을 생성합니다. 모델 턴에 도구 호출이 더 이상 없을 때까지 루프가 반복됩니다.\n\n> 📝 루프는 전적으로 터미널 프로세스 안에서 실행됩니다. 원격 실행 서버가 없습니다 — 도구가 명시적으로 전송하지 않는 한(`WebFetch`, `WebSearch`, 또는 MCP 서버 등), 파일, 셸, 자격 증명이 사용자의 머신을 벗어나지 않습니다.\n\n## 컨텍스트 로딩\n\n각 대화 시작 시, Claude Code가 모든 API 호출에 앞에 추가되는 두 개의 컨텍스트 블록을 구성합니다:\n\n**시스템 컨텍스트** (`context.ts`의 `getSystemContext()`로 조립):\n- **Git 상태** — 현재 브랜치, 기본/메인 브랜치, git 사용자명, `git status --short` 출력(2,000자 초과 시 자름), `git log --oneline`의 마지막 5개 커밋\n- **캐시 무효화 주입** — 디버깅 중 서버 측 프롬프트 캐시를 무효화하기 위해 내부적으로 사용되는 임시 문자열\n\n**사용자 컨텍스트** (`context.ts`의 `getUserContext()`로 조립):\n- **CLAUDE.md 메모리** — 4단계 계층(managed → user → project → local)에서 발견된 모든 메모리 파일\n- **현재 날짜** — 모델이 항상 날짜를 알 수 있도록 `Today's date is YYYY-MM-DD`로 주입\n\n두 컨텍스트 블록은 `lodash/memoize`를 사용해 대화 기간 동안 **메모이제이션**됩니다.\n\n## 도구 실행 모델\n\nClaude Code는 기본적으로 도구 호출을 자율적으로 실행하지 않습니다. 각 도구는 `checkPermissions` 메서드를 가지며, 그 결과가 다음 동작을 결정합니다:\n\n| 권한 결과 | 동작 |\n|-----------|------|\n| `allow` | 도구가 즉시 실행되고 결과가 대화에 추가됩니다 |\n| `ask` | Claude Code가 일시 중지하고 확인 다이얼로그를 렌더링합니다 |\n| `deny` | 도구 호출이 거부되고 Claude가 오류 결과를 받습니다 |\n\n안전하고 읽기 전용인 도구 호출(`Read`, `Glob`, `Grep` 등)은 일반적으로 모든 모드에서 자동 승인됩니다.\n\n## 대화형 vs 비대화형(작업) 모드\n\n**대화형(REPL) 모드** — 기본 경험. Claude Code가 React/Ink를 사용해 라이브 터미널 UI를 렌더링합니다. 에이전트가 작업하는 동안 스트리밍 출력, 도구 사용 확인, 스피너 애니메이션을 볼 수 있습니다. 메시지는 종료할 때까지 세션 전반에 걸쳐 유지됩니다.\n\n**비대화형/프린트 모드** — `--print`로 활성화하거나 stdin을 파이핑합니다. UI가 렌더링되지 않습니다. 출력이 stdout에 기록되어 스크립트나 CI 파이프라인에서 캡처할 수 있습니다. 일회성 자동화 작업에 유용합니다.\n\n### 서브에이전트 (Task 도구)\n\nClaude가 `Task` 도구(`AgentTool`)를 통해 서브에이전트를 스폰할 수 있습니다. 각 서브에이전트는 격리된 대화와 선택적으로 제한된 도구 집합을 가진 자체 중첩된 에이전틱 루프를 실행합니다. 서브에이전트는 로컬(인프로세스) 또는 원격 컴퓨팅에서 실행될 수 있습니다. 서브에이전트가 완료되면 결과가 부모 에이전트로 반환됩니다.\n\n## 대화 저장 및 재개\n\n대화는 디스크의 JSON 트랜스크립트 파일로 저장됩니다(기본적으로 `~/.claude/`에). 각 대화에는 고유한 세션 ID가 있습니다. `--resume <session-id>`로 이전 대화를 재개하거나, `--resume`만으로 목록에서 선택할 수 있습니다.\n\n대화가 재개될 때:\n- 전체 메시지 기록이 디스크에서 로드됩니다\n- 메모리 파일이 다시 발견되어 대화 최초 시작 시와 다를 수 있습니다\n- 권한 모드가 세션에 유지되지 않는 한 설정된 기본값으로 재설정됩니다\n\n> 💡 긴 대화는 주기적으로 **컴팩트**됩니다 — 가장 오래된 메시지가 요약되어 컨텍스트 윈도우를 관리 가능하게 유지합니다. 원본 트랜스크립트 전체는 항상 디스크에 보존됩니다; 컴팩트는 API에 전송되는 내용에만 영향을 줍니다.\n\n## 쿼리 엔진\n\n내부적으로, 에이전틱 루프의 각 \"턴\"은 **쿼리** — `query.ts`에 대한 호출로, 현재 메시지 목록을 Anthropic API에 전송하고 응답을 스트리밍합니다 — 에 의해 구동됩니다. 쿼리 엔진이 처리하는 것들:\n\n- 실시간으로 터미널에 토큰 출력 스트리밍\n- `tool_use` 블록을 적절한 도구 핸들러에 디스패치\n- 턴당 토큰 및 도구 호출 예산 적용\n- 도구 결과 수집 및 다음 모델 호출 전 추가\n- 컨텍스트 윈도우가 꽉 찰 때 컴팩트 트리거\n\n각 도구에는 `maxResultSizeChars` 속성이 있습니다. 결과가 이 한계를 초과하면 내용이 임시 파일로 저장되고 모델이 파일 경로와 함께 미리보기를 받아, 대용량 출력으로 인한 컨텍스트 윈도우 오버플로우를 방지합니다.\n"},{"index":6,"id":"section-06-05-메모리와컨텍스트","fileName":"05_메모리와컨텍스트.md","title":"메모리와 컨텍스트 (CLAUDE.md)","markdown":"# 메모리와 컨텍스트 (CLAUDE.md)\n\n> Claude Code가 CLAUDE.md 메모리 파일을 어떻게 발견하고, 로드하고, 우선순위를 결정하는지 설명합니다.\n\nClaude Code는 일반 마크다운 파일 기반의 계층적 메모리 시스템을 지원합니다. 파일 시스템의 여러 레벨에 있는 `CLAUDE.md` 파일에 지시사항을 작성해서 Claude의 동작을 전역적으로, 프로젝트별로, 또는 사용자별로 커스터마이징할 수 있습니다.\n\n## 4단계 메모리 계층\n\n메모리 파일은 다음 순서로 로드됩니다(낮은 우선순위 → 높은 우선순위). **나중에** 로드된 파일이 우선합니다. 컨텍스트 윈도우에서 나중에 나타나는 지시사항에 모델이 더 주의를 기울이기 때문입니다.\n\n**1단계: Managed 메모리 (최저 우선순위)**\n- 경로: `/etc/claude-code/CLAUDE.md`\n- 관리자 또는 배포 도구가 설정한 시스템 전체 지시사항. 머신의 모든 사용자에게 적용됩니다.\n\n**2단계: User 메모리**\n- 경로: `~/.claude/CLAUDE.md` 및 `~/.claude/rules/*.md`\n- 모든 프로젝트에 적용되는 개인 전역 지시사항. 선호하는 코드 스타일, 기본 언어, git 사용자명 등 개인 설정에 적합합니다. 이 파일은 어떤 저장소에도 커밋되지 않습니다.\n\n**3단계: Project 메모리**\n- 경로(CWD까지 각 상위 디렉토리에서 확인): `CLAUDE.md`, `.claude/CLAUDE.md`, `.claude/rules/*.md`\n- 팀 전체가 공유하는 코드베이스에 커밋된 지시사항. 프로젝트 컨벤션, 아키텍처 노트, 테스트 커맨드에 이상적입니다.\n\n**4단계: Local 메모리 (최고 우선순위)**\n- 경로: `CLAUDE.local.md` (각 상위 디렉토리에서 확인)\n- `.gitignore`에 추가해야 하는 개인 프로젝트별 재정의. 로컬 환경 경로, 개인 디버깅 노트 등에 사용합니다.\n\n> 📝 현재 작업 디렉토리에 더 가까운 파일이 **나중에** 로드되어 **더 높은 우선순위**를 가집니다. 프로젝트 루트의 `CLAUDE.md`가 상위 디렉토리의 것보다 우선합니다.\n\n## 파일 발견 알고리즘\n\nClaude Code 시작 시, 현재 작업 디렉토리에서 **파일시스템 루트까지** 올라가며 각 레벨의 메모리 파일을 수집합니다. 발견 순서는 낮은 우선순위 파일이 먼저 조립된 컨텍스트에 나타나도록 보장합니다:\n\n1. Managed 파일이 먼저 로드됩니다\n2. User 파일이 다음으로 로드됩니다\n3. Project 및 Local 파일은 **루트에서 CWD로 내려가며** 반복됩니다 — 상위 디렉토리가 하위 디렉토리보다 먼저 옵니다\n\n> 📝 발견된 파일 목록은 대화 기간 동안 메모이제이션됩니다. `/memory`를 실행해 메모리 에디터를 열고 강제 리로드하거나, 세션을 재시작해 Claude Code 외부에서 만들어진 변경 사항을 반영합니다.\n\n## `@include` 지시어\n\n메모리 파일은 `@` 표기법으로 다른 파일을 참조할 수 있습니다. 참조된 파일은 포함하는 파일 이전에 별도 항목으로 컨텍스트에 삽입됩니다.\n\n```markdown\n# My project CLAUDE.md\n\n@./docs/architecture.md\n@./docs/conventions/typescript.md\n\n커밋 전에 항상 `bun test`를 실행하세요.\n```\n\n| 구문 | 해석 |\n|------|------|\n| `@filename` | 포함하는 파일 디렉토리 기준 상대 경로 |\n| `@./relative/path` | 명시적 상대 경로 |\n| `@~/home/path` | 사용자 홈 디렉토리 기준 경로 |\n| `@/absolute/path` | 절대 경로 |\n\n**규칙:**\n- 코드 블록 및 인라인 코드 안의 `@include`는 무시됩니다\n- 순환 참조는 감지되어 건너뜁니다\n- 존재하지 않는 파일은 조용히 무시됩니다\n- 최대 include 깊이는 **5단계**입니다\n- 텍스트 기반 파일 형식만 포함됩니다(`.md`, `.ts`, `.py`, `.json` 등). 이미지와 PDF 같은 바이너리 파일은 건너뜁니다\n\n## `.claude/rules/*.md` — 세분화된 규칙 파일\n\n모든 것을 하나의 큰 `CLAUDE.md`에 넣는 대신, `.claude/rules/` 안의 여러 마크다운 파일로 지시사항을 나눌 수 있습니다:\n\n```\nmy-project/\n├── CLAUDE.md\n└── .claude/\n └── rules/\n ├── testing.md\n ├── typescript-style.md\n └── git-workflow.md\n```\n\n모든 `.md` 파일은 자동으로 로드됩니다. 규칙 파일은 **경로 범위 프론트매터**도 지원합니다:\n\n```markdown\n---\npaths:\n - \"src/api/**\"\n - \"src/services/**\"\n---\n\n항상 의존성 주입을 사용하세요. 구체적인 구현을 직접 import하지 마세요.\n```\n\n`paths`가 설정되면, 규칙 파일은 Claude가 해당 glob 패턴과 일치하는 파일을 작업할 때만 컨텍스트에 주입됩니다. 대규모 프로젝트에서 컨텍스트를 간결하게 유지합니다.\n\n## 최대 파일 크기\n\n단일 메모리 파일의 권장 최대 크기는 **40,000자**입니다. 이 한계를 초과하는 파일은 플래그 처리되고, Claude가 전체 내용을 읽지 못할 수 있습니다. 메모리 파일은 집중적이고 간결하게 유지하세요.\n\n## 메모리가 Claude 동작에 미치는 영향\n\n메모리 파일이 로드되면, 다음과 같은 프리픽스가 붙은 단일 컨텍스트 블록으로 조립됩니다:\n\n> *\"Codebase and user instructions are shown below. Be sure to adhere to these instructions. IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written.\"*\n\n즉, CLAUDE.md 파일의 지시사항이 Claude의 내장 기본값보다 우선합니다. 이를 활용해 프로젝트 컨벤션을 강제하거나, 특정 작업을 제한하거나, 도메인 지식을 주입할 수 있습니다.\n\n## 각 레벨 사용 지침\n\n| 레벨 | 용도 |\n|------|------|\n| **Managed 메모리** | 모든 사용자가 따라야 하는 조직 전체 정책, 보안 가이드라인 |\n| **User 메모리** (`~/.claude/CLAUDE.md`) | 모든 프로젝트에 걸쳐 적용되는 개인 선호도: 응답 언어, 커밋 메시지 스타일 |\n| **Project 메모리** (`CLAUDE.md`) | 팀과 공유하는 프로젝트 컨벤션: 테스트 실행 방법, 빌드 커맨드, 아키텍처 결정 |\n| **Local 메모리** (`CLAUDE.local.md`) | 특정 프로젝트의 개인 재정의: 로컬 환경 경로, 개인 디버깅 노트 |\n\n## `/memory` 커맨드\n\nClaude Code REPL 안에서 `/memory`를 실행해 메모리 파일 에디터를 엽니다. 현재 로드된 메모리 파일을 보여주고, 직접 편집하며, 저장 시 컨텍스트를 리로드합니다.\n\n> 💡 Claude에게 직접 물어볼 수도 있습니다: *\"CLAUDE.md에 항상 2칸 들여쓰기를 사용한다는 규칙을 추가해줘.\"* Claude가 적절한 메모리 파일을 찾아 지시사항을 작성합니다.\n\n## 메모리 로딩 비활성화\n\n| 방법 | 효과 |\n|------|------|\n| `CLAUDE_CODE_DISABLE_CLAUDE_MDS=1` | 모든 메모리 파일 로딩 완전 비활성화 |\n| `--bare` 플래그 | CWD 워크에서 메모리 파일 자동 발견 건너뜀 |\n| `claudeMdExcludes` 설정 | 건너뛸 메모리 파일 경로의 Glob 패턴 |\n"},{"index":7,"id":"section-07-06-권한시스템","fileName":"06_권한시스템.md","title":"권한 시스템","markdown":"# 권한 시스템\n\n> Claude Code가 어떤 작업을 자동으로 수행하고 어떤 작업에 명시적 승인이 필요한지 제어하는 방법.\n\nClaude Code는 로컬 머신에서 도구를 실행합니다 — 셸 커맨드 실행, 파일 편집, URL 가져오기. 권한 시스템은 Claude가 자동으로 수행하는 작업과 명시적 승인이 필요한 작업을 정밀하게 제어합니다.\n\n## 권한이 제어하는 것\n\n권한은 세 가지 작업 범주에 적용됩니다:\n\n- **파일 작업** — `Read`, `Edit`, `Write` 도구를 통한 로컬 파일시스템 읽기, 편집, 쓰기\n- **Bash 커맨드** — `Bash` 도구를 통한 셸 커맨드 실행(설치, 빌드, git 작업, 임의 스크립트 포함)\n- **MCP 도구 호출** — 연결된 MCP 서버가 노출한 도구(데이터베이스 쿼리, API 호출, 브라우저 자동화 등)\n\n## 권한 모드\n\n권한 모드는 특정 허용/차단 규칙과 일치하는 도구 호출이 없을 때의 기본 동작을 결정합니다. 모드를 한 번 설정하면 세션 전체에 적용됩니다.\n\n**`default` — 잠재적으로 위험한 작업에 확인 요청**\n표준 모드. 셸 커맨드 실행, 파일 편집, 네트워크 요청 등 부작용이 있을 수 있는 작업에 확인을 요청합니다. 파일 읽기, 검색 등 읽기 전용 작업은 자동 승인됩니다. 일상적인 사용에 권장됩니다.\n\n**`acceptEdits` — 파일 편집 자동 승인**\n`Edit`, `Write` 도구가 프롬프트 없이 자동 승인됩니다. Bash 커맨드는 여전히 확인이 필요합니다. Claude가 파일을 자유롭게 편집하도록 하되 셸 커맨드는 검토하고 싶을 때 유용합니다.\n\n**`plan` — 읽기 전용 계획 모드**\nClaude가 파일을 읽고, 코드베이스를 검색하고, 변경 사항에 대해 논의할 수 있지만 쓰기 또는 bash 작업을 실행할 수 없습니다. 모든 변경 도구 호출이 차단됩니다. Claude가 문제를 분석하고 변경 사항을 승인하기 전에 계획을 만들도록 할 때 사용하세요.\n\n**`bypassPermissions` — 모든 권한 검사 건너뛰기**\n모든 권한 검사가 비활성화됩니다. 모든 도구 호출이 확인 프롬프트 없이 즉시 실행됩니다.\n> ⚠️ 이 모드는 Claude가 수행할 작업을 미리 감사한 완전 스크립트화된 자동화 워크플로우 전용입니다. Claude가 예기치 않은 작업을 취할 수 있는 대화형 세션에서는 절대 사용하지 마세요.\n\n## 권한 모드 설정 방법\n\n**CLI 플래그:**\n```bash\nclaude --permission-mode acceptEdits\nclaude --permission-mode bypassPermissions\nclaude --permission-mode plan\n```\n\n**`/permissions` 커맨드 (세션 중):**\n```\n/permissions\n```\n재시작 없이 모드를 변경합니다.\n\n**settings.json:**\n```json\n{\n \"defaultMode\": \"acceptEdits\"\n}\n```\n유효한 값: `\"default\"`, `\"acceptEdits\"`, `\"bypassPermissions\"`, `\"plan\"`, `\"dontAsk\"`\n\n## 권한 규칙 (허용/차단 목록)\n\n전역 모드 외에도, 활성 모드에 관계없이 특정 도구 호출을 항상 허용하거나 항상 차단하는 세분화된 규칙을 만들 수 있습니다.\n\n규칙은 세 가지 구성 요소를 가집니다:\n\n| 필드 | 설명 |\n|------|------|\n| `toolName` | 규칙이 적용되는 도구 이름 (예: `\"Bash\"`, `\"Edit\"`, `\"mcp__myserver\"`) |\n| `ruleContent` | 도구 입력과 일치해야 하는 선택적 패턴 |\n| `behavior` | `\"allow\"`, `\"deny\"`, 또는 `\"ask\"` |\n\n규칙은 권한 모드보다 **먼저** 평가됩니다. 일치하는 규칙이 있으면 해당 동작이 즉시 적용됩니다.\n\n### 예시: 특정 git 커맨드 항상 허용\n\n```json\n{\n \"permissions\": {\n \"allow\": [\n \"Bash(git status)\",\n \"Bash(git diff *)\",\n \"Bash(git log *)\",\n \"Read(*)\"\n ],\n \"deny\": [\n \"Bash(rm -rf *)\",\n \"Bash(sudo *)\"\n ]\n }\n}\n```\n\n## Bash 권한 작동 방식\n\n**패턴 매칭:**\n- `git status` — 정확한 일치만\n- `git *` — 모든 `git` 서브커맨드와 일치\n- `npm run *` — 모든 `npm run` 스크립트와 일치\n- `*` — 모든 bash 커맨드와 일치 (극도의 주의 필요)\n\n**복합 커맨드:**\n`&&`, `||`, `;`, 파이프(`|`)로 연결된 복합 커맨드는 각 서브커맨드가 독립적으로 검사됩니다. 하나의 서브커맨드라도 차단되면 전체 복합 커맨드가 차단됩니다.\n\n**항상 차단/에스컬레이션되는 작업:**\n- 프로젝트 디렉토리 외부 경로로의 출력 리다이렉션(`>`, `>>`)\n- 워킹트리 외부로의 디렉토리 변경(`cd`)\n- `sed -i` 편집 인플레이스 커맨드(파일 수정 추적을 위해 특별 처리)\n- `.claude/` 또는 `.git/` 설정 디렉토리를 대상으로 하는 커맨드\n- 셸 설정 파일 수정(`.bashrc`, `.zshrc` 등)\n\n## MCP 도구 권한\n\nMCP 도구는 내장 도구와 동일한 규칙 시스템을 따릅니다:\n\n```json\n{\n \"permissions\": {\n \"deny\": [\n \"mcp__myserver\"\n ],\n \"allow\": [\n \"mcp__myserver__read_database\"\n ]\n }\n}\n```\n\n`mcp__servername`을 규칙으로 사용하면(특정 도구 이름 없이) 해당 서버의 모든 도구가 차단됩니다 — 모델이 보기 전에 도구 목록에서 필터링됩니다.\n\n## 보안 권장 사항\n\n- **`default` 모드**로 모든 대화형 세션을 시작하세요\n- 익숙하지 않은 코드베이스를 탐색하거나 큰 변경 사항을 설계할 때는 **`plan` 모드**를 사용하세요\n- Claude가 파일을 자유롭게 편집하도록 하되 셸 커맨드는 검토하려면 **`acceptEdits`**를 사용하세요\n- 광범위한 모드 에스컬레이션 대신 **세분화된 허용 규칙**을 선호하세요. `Bash(git *)`를 허용하는 것이 `bypassPermissions`로 전환하는 것보다 안전합니다\n- 친숙하지 않은 저장소를 클론할 때 `.claude/settings.json`을 검토하세요 — 권한 규칙이 미리 설정되어 있을 수 있습니다\n"},{"index":8,"id":"section-08-07-도구목록","fileName":"07_도구목록.md","title":"도구 목록","markdown":"# 도구 목록\n\n> Claude Code가 사용할 수 있는 모든 내장 도구 레퍼런스 — 파일 작업, 셸 실행, 웹 접근, 서브에이전트 생성 포함.\n\n## 파일 도구\n\n**Read — 파일 읽기**\n로컬 파일시스템에서 파일을 읽습니다. 기본적으로 최대 2,000줄 읽기. 대용량 파일의 타겟 읽기를 위한 `offset`과 `limit` 지원. `cat -n` 형식으로 줄 번호와 함께 내용 반환. 이미지(PNG, JPG 등), PDF(한 번에 최대 20페이지), Jupyter 노트북(`.ipynb`) 읽기도 지원. 읽기 전용, 항상 자동 승인.\n\n**Edit — 파일 편집**\n파일에서 정확한 문자열 교체를 수행합니다. 같은 대화에서 해당 파일을 먼저 `Read`해야 합니다. `old_string`을 `new_string`으로 교체 — 파일에서 유일하게 일치해야 합니다. 파일 전체에서 이름을 변경하려면 `replace_all: true` 사용. `old_string`이 두 번 이상 나타나면 실패합니다(replace_all이 설정되지 않은 경우).\n\n**Write — 파일 생성/덮어쓰기**\n새 파일을 만들거나 기존 파일을 완전히 덮어씁니다. 기존 파일은 같은 대화에서 먼저 `Read`가 필요합니다. 기존 파일 수정에는 `Edit`를 선호하세요 — `Write`는 전체 파일 내용을 전송하며 새 파일이나 전체 재작성에 더 적합합니다.\n\n**Glob — 파일 패턴 검색**\n이름 패턴으로 파일을 찾습니다. 어떤 코드베이스 크기에서도 작동하는 빠른 패턴 매칭. 수정 시간 기준으로 정렬된 매칭 파일 경로 반환. `**/*.ts`, `src/**/*.test.js`, `**/CLAUDE.md` 같은 패턴 지원. 읽기 전용, 항상 자동 승인.\n\n## 셸 도구\n\n**Bash — 셸 커맨드 실행**\n대화 내에서 지속되는 셸 세션에서 커맨드를 실행합니다. 도구 호출 간에 환경 변수와 작업 디렉토리 변경이 유지됩니다. `timeout` 파라미터 지원.\n\n주요 동작:\n- **복합 커맨드** (`&&`, `||`, `;`, `|`) — 파싱되어 각 서브커맨드가 독립적으로 권한 검사됨\n- **백그라운드 실행** — `run_in_background: true`를 전달해 블로킹 없이 장시간 실행 커맨드 실행\n- **출력 제한** — stdout/stderr이 도구 결과 크기 예산을 초과하면 미리보기와 파일 경로가 반환됨\n- **검색 커맨드** — 콘텐츠 검색에는 최적화된 권한과 접근을 가진 전용 `Grep` 도구를 선호하세요\n\n## 검색 도구\n\n**Grep — 파일 내용 검색**\n정규식을 사용해 파일 내용을 검색합니다. ripgrep 기반. 전체 regex 구문, 파일 타입 필터링(`*.ts`, `**/*.py`), 세 가지 출력 모드 지원:\n- `files_with_matches` (기본) — 파일 경로만 반환\n- `content` — 컨텍스트와 함께 매칭된 줄 반환\n- `count` — 파일당 매칭 수 반환\n\n`multiline: true`로 멀티라인 패턴 지원. 읽기 전용, 항상 자동 승인.\n\n**LS — 디렉토리 내용 나열**\n구조화된 형식으로 파일과 서브디렉토리를 반환합니다. 파일을 읽거나 편집하기 전에 프로젝트 구조를 탐색하는 데 유용합니다. 읽기 전용, 항상 자동 승인.\n\n## 웹 도구\n\n**WebFetch — URL 가져오기**\nURL에서 정보를 가져와 추출합니다. HTML을 마크다운으로 변환한 후 보조 모델을 통해 집중된 답변을 생성합니다.\n- HTTP URL은 자동으로 HTTPS로 업그레이드됨\n- 15분 자가 정리 캐시 포함\n- URL이 다른 호스트로 리다이렉트되면 후속 요청을 위한 리다이렉트 URL 반환\n- GitHub URL의 경우 `gh` CLI를 통한 Bash 사용 권장\n\n`default` 모드에서 승인 요청.\n\n**WebSearch — 웹 검색**\n웹을 검색하고 결과를 반환합니다. 제목, 스니펫, URL을 마크다운 링크로 형식화해서 반환. 모델의 훈련 컷오프 이후 정보에 접근하는 데 유용합니다. 응답 후 Claude가 자동으로 참조된 모든 URL을 나열하는 `Sources:` 섹션을 추가합니다. 현재 미국에서만 이용 가능. `default` 모드에서 승인 요청.\n\n## 에이전트 및 작업 도구\n\n**Task (Agent) — 서브에이전트 생성**\n별도의 컨텍스트에서 서브에이전트를 시작합니다. 서브에이전트는 자체 대화 기록, 도구 집합(선택적으로 제한됨)을 가지고 완료될 때까지 실행한 후 부모 에이전트에 결과를 반환합니다.\n\n서브에이전트 실행 방식:\n- **로컬** — 인프로세스, 부모의 파일시스템과 셸 공유\n- **원격** — 원격 에이전트 자격 기준이 충족될 때 별도 컴퓨팅에서 실행\n\n개방형 다단계 검색, 병렬 워크스트림, 또는 독립된 서브 문제를 격리된 에이전트에 위임할 때 사용하세요.\n\n**TodoWrite — 작업 목록 관리**\n구조화된 할 일 항목(`pending`, `in_progress`, `completed` 상태)을 터미널 UI의 영구 패널에 씁니다. Claude가 복잡한 다단계 작업의 진행 상황을 추적하는 데 도움이 됩니다. 3개 이상의 별개 단계가 있는 작업에 적극적으로 사용하세요.\n\n## MCP 도구\n\nMCP(Model Context Protocol) 서버가 Claude Code에 추가 도구를 노출할 수 있습니다. 연결된 도구는 내장 도구와 함께 도구 목록에 나타나며 동일한 권한 시스템을 따릅니다.\n\nMCP 도구 이름 형식:\n```\nmcp__<server-name>__<tool-name>\n```\n\n예: `mydb` 서버의 `query` 도구 → `mcp__mydb__query`\n\n일반적인 MCP 도구 범주:\n- 데이터베이스 쿼리 및 관리 도구\n- 브라우저 및 웹 자동화 도구\n- 클라우드 제공업체 API (AWS, GCP, Azure)\n- 이슈 트래커 통합 (GitHub, Linear, Jira)\n- 내부 회사 도구 및 API\n\n## 노트북 도구\n\n**NotebookEdit — Jupyter 노트북 편집**\n`.ipynb` 파일의 셀을 줄 단위 정밀도로 삽입, 교체, 삭제합니다. 노트북 읽기는 표준 `Read` 도구를 사용합니다(모든 셀과 출력 반환).\n\n## 도구 가용성\n\n모든 도구가 모든 컨텍스트에서 이용 가능한 것은 아닙니다:\n- `CLAUDE_CODE_SIMPLE=1` — `Bash`, `Read`, `Edit`만으로 제한\n- 권한 차단 규칙 — 규칙으로 포괄 차단된 도구는 모델이 보기 전에 목록에서 제거됨\n- `isEnabled()` 검사 — 각 도구는 환경 조건에 따라 자가 비활성화 가능\n- MCP 서버 연결 상태 — MCP 도구는 서버가 실행 중이고 연결된 경우에만 이용 가능\n\nREPL에서 `/tools` 커맨드로 활성 도구 집합을 확인할 수 있습니다.\n"},{"index":9,"id":"section-09-08-claude-md설정","fileName":"08_CLAUDE.md설정.md","title":"CLAUDE.md 설정","markdown":"# CLAUDE.md 설정\n\n> Claude에게 세션마다 자동으로 로드되는 지속적인 프로젝트별 지시사항을 주기 위한 CLAUDE.md 파일 작성 및 구성 방법.\n\n`CLAUDE.md` 파일로 Claude가 모든 세션 시작 시 로드하는 프로젝트 지식을 인코딩할 수 있습니다. 매번 프로젝트 컨벤션, 빌드 시스템, 아키텍처를 설명하는 대신, 한 번 작성하면 Claude가 자동으로 읽습니다.\n\n## CLAUDE.md에 들어가야 할 것\n\n빠진 경우 실수를 일으킬 지시사항을 작성하세요. 그 외에는 노이즈입니다.\n\n**포함할 것:**\n- 빌드, 테스트, lint 커맨드 (도구 이름만 아닌 정확한 호출)\n- 코드를 어떻게 작성하고 구성해야 하는지에 영향을 미치는 아키텍처 결정\n- 프로젝트 고유의 코딩 컨벤션 (네이밍 패턴, 파일 구조 규칙)\n- 환경 설정 요구사항 (필요한 env 변수, 예상 서비스)\n- Claude가 알아야 하는 일반적인 함정 또는 패턴\n- 모노레포 구조와 어떤 패키지가 어떤 책임을 가지는지\n\n**제외할 것:**\n- Claude가 이미 아는 것 (표준 TypeScript 구문, 일반 라이브러리 API)\n- 자명한 알림 (\"깔끔한 코드를 작성하세요\", \"주석을 추가하세요\")\n- 민감한 데이터 — API 키, 비밀번호, 토큰, 또는 어떤 시크릿도\n- 자주 변경되어 오래될 정보\n\n> 💡 테스트: \"이 줄을 제거하면 Claude가 이 코드베이스에서 실수를 할까?\" 그렇지 않다면 삭제하세요.\n\n## 파일 위치\n\nClaude는 현재 디렉토리에서 파일시스템 루트까지 올라가며 메모리 파일을 발견합니다. 현재 디렉토리에 더 가까운 파일이 더 높은 우선순위를 가집니다.\n\n| 파일 | 타입 | 용도 |\n|------|------|------|\n| `/etc/claude-code/CLAUDE.md` | Managed | 관리자가 설정한 모든 사용자의 시스템 전체 지시사항 |\n| `~/.claude/CLAUDE.md` | User | 모든 프로젝트에 적용되는 개인 전역 지시사항 |\n| `~/.claude/rules/*.md` | User | 모듈식 전역 규칙, 각 파일이 별도로 로드됨 |\n| `CLAUDE.md` (프로젝트 루트) | Project | 소스 컨트롤에 커밋된 팀 공유 지시사항 |\n| `.claude/CLAUDE.md` (프로젝트 루트) | Project | 팀 공유 프로젝트 지시사항의 대안 위치 |\n| `.claude/rules/*.md` (프로젝트 루트) | Project | 주제별로 구성된 모듈식 프로젝트 규칙 |\n| `CLAUDE.local.md` (프로젝트 루트) | Local | 커밋되지 않는 개인 프로젝트별 지시사항 |\n\n## 로딩 순서와 우선순위\n\n파일은 다음 순서로 로드됩니다. 모델이 컨텍스트에서 나중에 나타나는 내용에 더 주의를 기울이기 때문에, 나중에 로드된 파일이 더 높은 실효 우선순위를 가집니다.\n\n1. **Managed 메모리** — `/etc/claude-code/CLAUDE.md`와 `rules/*.md` — 항상 로드됨\n2. **User 메모리** — `~/.claude/CLAUDE.md`와 `rules/*.md` — 모든 프로젝트의 개인 전역 지시사항\n3. **Project 메모리 (루트에서 CWD까지)** — 파일시스템 루트에서 현재 디렉토리까지 각 디렉토리의 `CLAUDE.md`, `.claude/CLAUDE.md`, `.claude/rules/*.md`. CWD에 더 가까운 파일이 나중에 로드됨 (높은 우선순위)\n4. **Local 메모리** — 루트에서 CWD까지 각 디렉토리의 `CLAUDE.local.md`. 같은 순회 순서. 기본적으로 gitignore됨\n\n## @include 지시어\n\n메모리 파일은 `@` 표기법으로 다른 파일을 include할 수 있습니다:\n\n```markdown\n# CLAUDE.md\n\n@./docs/architecture.md\n@~/shared/style-guide.md\n@/etc/company-standards.md\n```\n\n| 구문 | 해석 |\n|------|------|\n| `@filename` | 현재 파일 디렉토리 기준 상대 경로 |\n| `@./relative/path` | 현재 파일 디렉토리 기준 명시적 상대 경로 |\n| `@~/path/in/home` | 홈 디렉토리 아래 경로 |\n| `@/absolute/path` | 절대 파일시스템 경로 |\n\n**동작:**\n- 비존재 파일은 조용히 무시됨\n- 순환 참조는 감지되고 방지됨\n- Include는 최대 5단계 깊이까지 중첩\n- 텍스트 파일 형식만 지원 — 이진 파일은 건너뜀\n- 코드 블록 안의 `@include`는 처리되지 않음\n\n## 프론트매터 경로 타겟팅\n\n`.claude/rules/`의 파일은 YAML 프론트매터로 어떤 파일 경로에 적용할지 제한할 수 있습니다:\n\n```markdown\n---\npaths:\n - \"src/api/**\"\n - \"*.graphql\"\n---\n\n# API 컨벤션\n\n모든 API 핸들러는 공유 `validate()` 헬퍼로 입력을 검증해야 합니다.\nGraphQL 리졸버는 직접 데이터베이스 쿼리를 수행하면 안 됩니다 — 데이터 레이어를 사용하세요.\n```\n\n프론트매터가 없는 규칙은 무조건 적용됩니다. `paths` 프론트매터가 있는 규칙은 Claude가 glob 패턴과 일치하는 파일을 작업할 때만 적용됩니다.\n\n## TypeScript 프로젝트용 CLAUDE.md 예시\n\n```markdown\n# Project: Payments API\n\n## 빌드 및 테스트\n\n- 빌드: `bun run build`\n- 테스트: `bun test` (Bun 내장 테스트 러너 사용 — Jest 사용하지 말 것)\n- Lint: `bun run lint` (biome, eslint 아님)\n- 타입 체크: `bun run typecheck`\n\n변경 사항을 완료하기 전에 항상 `bun run typecheck`를 실행하세요.\n\n## 아키텍처\n\n- `src/handlers/` — HTTP 핸들러, 라우트 그룹당 하나의 파일\n- `src/services/` — 비즈니스 로직, 직접 DB 접근 없음\n- `src/db/` — 데이터베이스 레이어 (Drizzle ORM); 모든 쿼리가 여기에 있음\n- `src/schemas/` — 핸들러 검증과 DB 타입 간에 공유되는 Zod 스키마\n\n핸들러는 서비스를 호출합니다. 서비스는 DB 레이어를 호출합니다. 레이어를 건너뛰지 마세요.\n\n## 컨벤션\n\n- 모든 입력 검증 스키마에 `z.object().strict()` 사용\n- 에러는 `Result<T, AppError>`로 전파 — 서비스 코드에서 절대 throw하지 말 것\n- 모든 금액 값은 센트 단위 정수\n- 타임스탬프는 Unix 초(number), Date 객체 아님\n\n## 환경\n\n필요한 env 변수: `DATABASE_URL`, `STRIPE_SECRET_KEY`, `JWT_SECRET`\n로컬 개발: `.env.example`을 `.env.local`로 복사하고 값 입력\n\n## 피해야 할 일반적인 실수\n\n- `new Date()`를 직접 사용하지 마세요 — `src/utils/time.ts`의 `getCurrentTimestamp()` 사용\n- `console.log` 추가하지 마세요 — `src/utils/logger.ts`의 `logger` 사용\n- Raw SQL 작성하지 마세요 — Drizzle 쿼리 빌더 사용\n```\n\n## /init으로 CLAUDE.md 생성\n\nClaude Code 세션에서 `/init`을 실행하면 프로젝트의 `CLAUDE.md`를 자동 생성합니다:\n\n```\n/init\n```\n\nClaude가 코드베이스를 분석하고 프로젝트와 가장 관련된 커맨드와 컨텍스트를 담은 파일을 생성합니다. 생성된 파일은 시작점입니다 — 검토하고, 진정으로 유용하지 않은 것은 제거하고, 코드에서 추론할 수 없는 프로젝트별 지식을 추가하세요.\n\n## /memory로 CLAUDE.md 편집\n\n`/memory`를 실행해 메모리 에디터를 열면 현재 로드된 모든 메모리 파일을 나열하고 세션 내에서 직접 편집할 수 있습니다:\n\n```\n/memory\n```\n\n변경 사항은 즉시 적용됩니다 — Claude가 업데이트된 파일을 리로드하고 새 지시사항을 현재 세션에 적용합니다.\n\n## 파일 제외\n\nClaude가 로드하지 않도록 할 CLAUDE.md 파일이 있다면(예: 벤더 의존성이나 생성된 코드에 있는 경우), 설정에 제외 패턴을 추가하세요:\n\n```json\n{\n \"claudeMdExcludes\": [\n \"/absolute/path/to/vendor/CLAUDE.md\",\n \"**/generated/**\",\n \"**/third-party/.claude/rules/**\"\n ]\n}\n```\n\n패턴은 picomatch를 사용해 절대 경로와 매칭됩니다. User, Project, Local 메모리 타입만 제외 가능합니다 — Managed(관리자) 파일은 항상 로드됩니다.\n"},{"index":10,"id":"section-10-09-환경변수","fileName":"09_환경변수.md","title":"환경 변수","markdown":"# 환경 변수\n\n> Claude Code가 인증, API 접근, 동작, 런타임 옵션을 설정하기 위해 읽는 환경 변수.\n\nClaude Code는 시작 시 환경 변수를 읽습니다. 설정 파일을 수정하지 않고 인증 설정, 커스텀 API 엔드포인트, 런타임 동작 튜닝, 활성 기능 제어가 가능합니다.\n\n## 인증\n\n| 변수 | 설명 |\n|------|------|\n| `ANTHROPIC_API_KEY` | Anthropic API 직접 인증용 API 키. 설정 시 OAuth 대신 이 키를 사용합니다. `export ANTHROPIC_API_KEY=\"sk-ant-...\"` |\n| `ANTHROPIC_AUTH_TOKEN` | 대안 인증 토큰. `ANTHROPIC_API_KEY`가 적용되지 않는 컨텍스트에서 사용합니다. |\n| `ANTHROPIC_BASE_URL` | Anthropic API 기본 URL 재정의. 프록시, 스테이징 환경, 호환 서드파티 엔드포인트를 가리킬 때 유용합니다. |\n| `CLAUDE_CODE_API_BASE_URL` | Claude Code 전용 API 기본 URL 재정의. 설정 시 `ANTHROPIC_BASE_URL`보다 우선합니다. |\n| `ANTHROPIC_BEDROCK_BASE_URL` | AWS Bedrock API 접근용 기본 URL. Bedrock 엔드포인트를 통해 라우팅할 때 설정합니다. |\n| `ANTHROPIC_VERTEX_PROJECT_ID` | Vertex AI 접근용 Google Cloud 프로젝트 ID. Google Cloud의 Vertex AI 플랫폼을 통해 Claude Code를 사용할 때 필요합니다. |\n| `CLAUDE_CODE_USE_BEDROCK` | `1` 또는 `true`로 설정해 AWS Bedrock을 API 공급자로 사용합니다. |\n| `CLAUDE_CODE_USE_FOUNDRY` | `1` 또는 `true`로 설정해 Anthropic Foundry를 API 공급자로 사용합니다. |\n| `CLAUDE_CODE_OAUTH_TOKEN` | OAuth 액세스 토큰을 직접 사용해 대화형 로그인 흐름을 우회합니다. 자동화 환경에 유용합니다. |\n\n## 설정 경로\n\n| 변수 | 기본값 | 설명 |\n|------|--------|------|\n| `CLAUDE_CONFIG_DIR` | `~/.claude` | Claude Code가 설정, 설정값, 트랜스크립트를 저장하는 디렉토리 재정의. `export CLAUDE_CONFIG_DIR=\"/opt/claude-config\"` |\n| `CLAUDE_CODE_MANAGED_SETTINGS_PATH` | - | Managed 설정 파일 경로 재정의. 기본 플랫폼 경로가 적절하지 않은 엔터프라이즈 환경에 유용합니다. |\n\n## 모델 선택\n\n| 변수 | 설명 |\n|------|------|\n| `ANTHROPIC_MODEL` | 사용할 기본 모델. 설정 파일의 `model` 설정과 명시적 `--model` 플래그에 의해 재정의됩니다. |\n| `CLAUDE_CODE_SUBAGENT_MODEL` | 메인 에이전트가 생성하는 서브에이전트 작업에 사용할 모델. 설정하지 않으면 서브에이전트는 메인 세션과 동일한 모델을 사용합니다. |\n| `CLAUDE_CODE_AUTO_MODE_MODEL` | 자동 모드에서 사용할 모델. 지정하지 않으면 메인 세션 모델을 기본으로 합니다. |\n\n## 동작 토글\n\n| 변수 | 설명 |\n|------|------|\n| `CLAUDE_CODE_REMOTE` | `1` 또는 `true`로 설정해 원격/컨테이너 모드 활성화. 비대화형 환경에 맞게 동작을 조정합니다 — API 타임아웃 연장(120s vs 300s), 대화형 프롬프트 억제, 출력 형식 조정. |\n| `CLAUDE_CODE_SIMPLE` | `1` 또는 `true`로 설정해(또는 `--bare` 전달) bare 모드로 실행. 훅, LSP 통합, 플러그인 동기화, 스킬 디렉토리 워크, 어트리뷰션, 백그라운드 프리페치, 키체인/자격증명 읽기를 모두 건너뜁니다. 경량 스크립트 사용에 유용합니다. |\n| `DISABLE_AUTO_COMPACT` | `1` 또는 `true`로 설정해 자동 컨텍스트 컴팩션 비활성화. 설정 시 모델의 컨텍스트 한계에 근접해도 대화 컨텍스트를 컴팩트하지 않습니다. |\n| `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS` | `1` 또는 `true`로 설정해 백그라운드 작업 실행 비활성화. |\n| `CLAUDE_CODE_DISABLE_THINKING` | `1` 또는 `true`로 설정해 모든 API 호출의 확장 thinking을 비활성화합니다. |\n| `CLAUDE_CODE_DISABLE_AUTO_MEMORY` | `1` 또는 `true`로 설정해 자동 메모리 비활성화. Claude가 자동 메모리 디렉토리를 읽거나 쓰지 않습니다. |\n| `CLAUDE_CODE_DISABLE_CLAUDE_MDS` | `1` 또는 `true`로 설정해 모든 `CLAUDE.md` 메모리 파일 로딩을 완전 비활성화합니다. |\n| `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | `1` 또는 `true`로 설정해 분석, 원격 측정, 기타 비필수 네트워크 요청을 억제합니다. |\n| `CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR` | `1` 또는 `true`로 설정해 각 Bash 커맨드 후 원래 프로젝트 루트로 작업 디렉토리를 재설정합니다. |\n\n## 리소스 제한\n\n| 변수 | 설명 |\n|------|------|\n| `CLAUDE_CODE_MAX_OUTPUT_TOKENS` | API 응답당 최대 출력 토큰 수 재정의. `export CLAUDE_CODE_MAX_OUTPUT_TOKENS=4096` |\n| `CLAUDE_CODE_MAX_CONTEXT_TOKENS` | 최대 컨텍스트 윈도우 크기 재정의. |\n| `BASH_MAX_OUTPUT_LENGTH` | Bash 커맨드 출력에서 캡처되는 최대 문자 수. `export BASH_MAX_OUTPUT_LENGTH=50000` |\n| `API_TIMEOUT_MS` | API 요청 타임아웃을 밀리초 단위로 재정의. 기본 300,000ms(5분), 원격 모드에서는 120,000ms(2분). `export API_TIMEOUT_MS=60000` |\n\n## 원격 측정 및 관찰 가능성\n\n| 변수 | 설명 |\n|------|------|\n| `CLAUDE_CODE_ENABLE_TELEMETRY` | `1` 또는 `true`로 설정해 트레이스, 메트릭, 로그의 OpenTelemetry 내보내기 활성화. 추가 OTEL 설정이 필요합니다. `export CLAUDE_CODE_ENABLE_TELEMETRY=1` |\n| `CLAUDE_CODE_JSONL_TRANSCRIPT` | Claude Code가 세션 JSONL 트랜스크립트를 쓸 파일 경로. `export CLAUDE_CODE_JSONL_TRANSCRIPT=\"/tmp/session.jsonl\"` |\n\n## Node.js 런타임\n\n| 변수 | 설명 |\n|------|------|\n| `NODE_OPTIONS` | 런타임에 전달되는 표준 Node.js 옵션. Claude Code는 `--max-old-space-size` 같은 플래그를 감지하기 위해 이것을 읽습니다. ⚠️ 코드 실행 플래그를 포함하는 값으로 설정하지 마세요. |\n\n## 호스트 플랫폼 재정의\n\n| 변수 | 설명 |\n|------|------|\n| `CLAUDE_CODE_HOST_PLATFORM` | 분석용 보고 호스트 플랫폼 재정의. `\"win32\"`, `\"darwin\"`, `\"linux\"` 허용. `export CLAUDE_CODE_HOST_PLATFORM=darwin` |\n\n## 클라우드 제공업체 리전 재정의\n\nVertex AI에서 모델별 리전 재정의를 지원합니다:\n\n| 모델 프리픽스 | 환경 변수 |\n|--------------|----------|\n| `claude-haiku-4-5` | `VERTEX_REGION_CLAUDE_HAIKU_4_5` |\n| `claude-3-5-sonnet` | `VERTEX_REGION_CLAUDE_3_5_SONNET` |\n| `claude-sonnet-4-6` | `VERTEX_REGION_CLAUDE_4_6_SONNET` |\n| `claude-opus-4` | `VERTEX_REGION_CLAUDE_4_0_OPUS` |\n\n기본 Vertex 리전은 `CLOUD_ML_REGION`으로 제어됩니다(기본값: `us-east5`).\n\n## AWS 자격 증명\n\nBedrock 접근을 위해 표준 AWS 자격 증명 환경 변수를 지원합니다:\n\n| 변수 | 설명 |\n|------|------|\n| `AWS_REGION` | Bedrock API 호출용 AWS 리전. `AWS_DEFAULT_REGION`으로 폴백, 없으면 `us-east-1` |\n| `AWS_DEFAULT_REGION` | `AWS_REGION`이 설정되지 않은 경우 폴백 AWS 리전 |\n\n## 모든 세션에 환경 변수 설정\n\n셸 프로파일 대신 설정 파일의 `env` 필드를 사용해 모든 Claude Code 세션에 적용되는 환경 변수를 설정할 수 있습니다:\n\n```json\n{\n \"env\": {\n \"DISABLE_AUTO_COMPACT\": \"1\",\n \"BASH_MAX_OUTPUT_LENGTH\": \"30000\"\n }\n}\n```\n"},{"index":11,"id":"section-11-10-설정파일","fileName":"10_설정파일.md","title":"설정 파일 (settings.json)","markdown":"# 설정 파일 (settings.json)\n\n> 사용자, 프로젝트, Managed 레벨의 JSON 설정 파일로 Claude Code 동작 설정.\n\nClaude Code는 여러 범위의 JSON 파일에서 설정을 읽습니다. 낮은 우선순위에서 높은 우선순위 순으로 병합됩니다.\n\n## 설정 파일 위치\n\n**전역(사용자):** `~/.claude/settings.json`\n모든 프로젝트에 걸쳐 실행하는 모든 Claude Code 세션에 적용됩니다. 선호 모델, 테마, 정리 정책 같은 개인 설정을 여기에 설정합니다.\n\n**프로젝트(공유):** `.claude/settings.json` (프로젝트 루트)\n소스 컨트롤에 체크인됩니다. 프로젝트 작업자 모두에게 적용되어야 하는 설정 — 권한 규칙, 훅 설정, MCP 서버, 환경 변수.\n\n**로컬(개인 프로젝트):** `.claude/settings.local.json` (프로젝트 루트)\n소스 컨트롤에 체크인되지 않습니다(자동으로 `.gitignore`에 추가됨). 특정 프로젝트 내의 개인 재정의.\n\n**Managed(엔터프라이즈):** 플랫폼별 시스템 경로\nMDM, 레지스트리(Windows), plist(macOS), 또는 Managed 설정 파일을 통해 관리자가 설정합니다. Managed 설정은 최고 우선순위를 가지며 사용자나 프로젝트가 재정의할 수 없습니다.\n\n## 설정 우선순위\n\n```\n플러그인 기본값 → 사용자 설정 → 프로젝트 설정 → 로컬 설정 → Managed(정책) 설정\n```\n\nManaged(정책) 설정은 항상 최종 우선순위를 가집니다.\n\n## 설정 열기\n\n세션 내에서 `/config`를 실행해 설정 UI를 엽니다. 각 범위의 현재 활성 설정을 찾아볼 수 있습니다. JSON 파일을 직접 편집할 수도 있습니다 — Claude Code가 파일 변경을 감지하면 자동으로 설정을 다시 로드합니다.\n\n## 설정 레퍼런스\n\n### `model`\n**타입:** `string` | **범위:** 모든 범위\n\nClaude Code가 사용하는 기본 모델 재정의. 설정된 공급자가 지원하는 모든 모델 ID 허용.\n\n```json\n{ \"model\": \"claude-opus-4-5\" }\n```\n\n### `permissions`\n**타입:** `object` | **범위:** 모든 범위\n\nClaude가 사용할 수 있는 도구와 모드를 제어합니다. 규칙 구문은 [권한 시스템](./06_권한시스템.md) 참조.\n\n| 필드 | 타입 | 설명 |\n|------|------|------|\n| `allow` | `string[]` | Claude가 확인 없이 수행할 수 있는 작업 규칙 |\n| `deny` | `string[]` | Claude가 항상 차단되는 작업 규칙 |\n| `ask` | `string[]` | 항상 확인을 요청하는 작업 규칙 |\n| `defaultMode` | `string` | 기본 권한 모드: `\"default\"`, `\"acceptEdits\"`, `\"plan\"`, `\"bypassPermissions\"` |\n| `disableBypassPermissionsMode` | `\"disable\"` | 사용자가 bypass permissions 모드에 들어가는 것을 방지 |\n| `additionalDirectories` | `string[]` | Claude가 접근할 수 있는 추가 디렉토리 |\n\n### `hooks`\n**타입:** `object` | **범위:** 모든 범위\n\n도구 실행 전후에 커스텀 셸 커맨드를 실행합니다. 지원 훅 이벤트: `PreToolUse`, `PostToolUse`, `Notification`, `UserPromptSubmit`, `SessionStart`, `SessionEnd`, `Stop`, `SubagentStop`, `PreCompact`, `PostCompact`.\n\n```json\n{\n \"hooks\": {\n \"PostToolUse\": [\n {\n \"matcher\": \"Write\",\n \"hooks\": [{ \"type\": \"command\", \"command\": \"prettier --write $CLAUDE_FILE_PATHS\" }]\n }\n ]\n }\n}\n```\n\n### `cleanupPeriodDays`\n**타입:** `integer` | **기본값:** `30` | **범위:** 모든 범위\n\n채팅 트랜스크립트 보관 일수. `0`으로 설정하면 세션 영속성이 완전히 비활성화됩니다.\n\n### `env`\n**타입:** `object` | **범위:** 모든 범위\n\n모든 Claude Code 세션에 주입할 환경 변수. 값은 문자열로 변환됩니다.\n\n```json\n{\n \"env\": {\n \"NODE_ENV\": \"development\",\n \"MY_API_URL\": \"https://api.example.com\"\n }\n}\n```\n\n### `availableModels`\n**타입:** `string[]` | **범위:** Managed만\n\n사용자가 선택 가능한 모델의 엔터프라이즈 허용 목록. 패밀리 별칭(`\"opus\"`는 모든 Opus 버전 허용), 버전 프리픽스, 또는 전체 모델 ID 허용.\n\n### `worktree`\n**타입:** `object` | **범위:** 모든 범위\n\n`--worktree` 플래그 동작 설정.\n\n| 필드 | 타입 | 설명 |\n|------|------|------|\n| `symlinkDirectories` | `string[]` | worktree에 메인 저장소에서 심링크할 디렉토리 (예: `\"node_modules\"`) |\n| `sparsePaths` | `string[]` | 대규모 모노레포에서 빠른 worktree를 위한 sparse 체크아웃 경로 |\n\n### `attribution`\n**타입:** `object` | **범위:** 모든 범위\n\nClaude가 커밋과 PR 설명에 추가하는 어트리뷰션 텍스트를 커스터마이징합니다.\n\n```json\n{\n \"attribution\": {\n \"commit\": \"Co-Authored-By: Claude <noreply@anthropic.com>\",\n \"pr\": \"\"\n }\n}\n```\n\n### `language`\nClaude 응답과 음성 받아쓰기에 선호되는 언어. `{ \"language\": \"korean\" }`\n\n### `alwaysThinkingEnabled`\n**기본값:** `true` — `false`로 설정해 확장 thinking 비활성화.\n\n### `effortLevel`\n`\"low\"` | `\"medium\"` | `\"high\"` — thinking 예산을 지원하는 모델의 effort 레벨.\n\n### `autoMemoryEnabled`\n**범위:** 사용자, 로컬 — 이 프로젝트의 자동 메모리 활성화 또는 비활성화.\n\n### `respectGitignore`\n**기본값:** `true` — 파일 피커가 `.gitignore` 파일을 존중할지 여부.\n\n### `defaultShell`\n`\"bash\"` | `\"powershell\"` — 입력 박스의 `!` 커맨드용 기본 셸.\n\n### `apiKeyHelper`\n**범위:** 사용자, Managed — API 키를 동적으로 검색하는 스크립트 경로. 스크립트는 stdout에 API 키만 출력하고 코드 0으로 종료해야 합니다.\n\n## Managed 설정 (엔터프라이즈)\n\n관리자는 플랫폼 네이티브 메커니즘을 통해 모든 사용자에게 설정을 배포할 수 있습니다.\n\n**macOS:** `/Library/Preferences/`에 plist 파일 배포 또는 MDM을 통해 `com.anthropic.claudecode` 타겟\n\n**Windows:** `HKLM\\Software\\Anthropic\\Claude Code` 레지스트리 키에 설정 작성\n\n**파일 기반:** Managed 설정 파일을 플랫폼별 managed 경로에 배치. 드롭인 설정 조각에는 `managed-settings.d/` 디렉토리 사용(알파벳 순으로 정렬 및 병합됨).\n\n### Managed 전용 잠금 설정\n\n| 설정 | 설명 |\n|------|------|\n| `allowManagedHooksOnly` | `true`로 설정 시 Managed 설정의 훅만 실행 |\n| `allowManagedPermissionRulesOnly` | `true`로 설정 시 Managed 설정의 권한 규칙만 존중 |\n| `allowManagedMcpServersOnly` | `true`로 설정 시 허용 MCP 서버 목록을 Managed 설정에서만 읽음 |\n| `strictPluginOnlyCustomization` | 특정 커스터마이징 표면을 플러그인 전용 소스로 잠금 |\n\n## JSON 스키마\n\n에디터 자동완성 및 유효성 검사를 위해 설정 파일에 `$schema` 추가:\n\n```json\n{\n \"$schema\": \"https://schemas.anthropic.com/claude-code/settings.json\"\n}\n```\n"},{"index":12,"id":"section-12-11-인증","fileName":"11_인증.md","title":"인증","markdown":"# 인증\n\n> Anthropic API, AWS Bedrock, GCP Vertex AI로 Claude Code 인증 설정 방법.\n\nClaude Code는 여러 인증 방식을 지원합니다. 방식은 API에 직접 접근하는지, 클라우드 제공업체를 통하는지, API 키 헬퍼 스크립트를 통하는지에 따라 다릅니다.\n\n## Claude.ai OAuth (기본)\n\nAPI 키가 설정되지 않은 상태에서 `claude`를 처음 실행하면, Claude Code가 claude.ai 계정으로 OAuth 흐름을 시작합니다.\n\n1. 터미널에서 실행: `claude`\n2. URL이 표시되면 브라우저에서 열어 claude.ai 계정으로 로그인하고 권한 부여\n3. 브라우저에서 인증 후 Claude Code가 자동으로 OAuth 토큰을 받아 저장합니다(macOS는 Keychain, 다른 플랫폼은 자격 증명 파일)\n\nOAuth 토큰은 만료 전에 자동으로 갱신됩니다. 명시적으로 로그아웃하거나 접근을 취소하지 않는 한 재인증이 필요하지 않습니다.\n\n## API 키\n\nOAuth 대신 Anthropic API 키로 인증할 수 있습니다.\n\n**환경 변수:**\n```bash\nexport ANTHROPIC_API_KEY=sk-ant-...\n```\n이 변수가 설정되면 Claude Code가 직접 사용하고 OAuth를 요청하지 않습니다.\n\n**설정 파일 apiKeyHelper:**\n```json\n{\n \"apiKeyHelper\": \"cat ~/.anthropic/api-key\"\n}\n```\nClaude Code가 이 커맨드를 실행해 자격 증명을 동적으로 가져옵니다. 결과는 5분 동안 캐시됩니다(`CLAUDE_CODE_API_KEY_HELPER_TTL_MS`로 설정 가능). 커맨드는 API 키만 stdout에 출력하고 코드 0으로 종료해야 합니다.\n\n> ⚠️ `ANTHROPIC_API_KEY`가 설정되거나 `apiKeyHelper`가 구성되면 OAuth 흐름이 비활성화됩니다.\n\n## AWS Bedrock\n\nAWS Bedrock을 통해 Claude를 사용하려면:\n\n```bash\n# 1. Bedrock 모드 활성화\nexport CLAUDE_CODE_USE_BEDROCK=1\n\n# 2. AWS 자격 증명 설정 (표준 AWS 자격 증명 체인)\n# - AWS 자격 증명 파일 (~/.aws/credentials)\n# - 환경 변수: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN\n# - IAM 역할(EC2 인스턴스 프로파일, ECS 태스크 역할 등)\n# - AWS SSO (aws sso login)\n\n# 3. 리전 설정 (선택사항)\nexport AWS_REGION=us-east-1\n```\n\n**자동 AWS 자격 증명 갱신:**\n세션이 만료될 경우(예: 단기 SSO 토큰) `awsAuthRefresh`를 설정해 자동으로 자격 증명을 갱신합니다:\n\n```json\n{\n \"awsAuthRefresh\": \"aws sso login --profile my-profile\"\n}\n```\n\n커맨드에서 자격 증명을 내보내려면 `awsCredentialExport`를 사용합니다:\n\n```json\n{\n \"awsCredentialExport\": \"aws sts assume-role --role-arn arn:aws:iam::123456789012:role/MyRole --role-session-name claude-code --query Credentials --output json\"\n}\n```\n\n## GCP Vertex AI\n\nGoogle Cloud Vertex AI를 통해 Claude를 사용하려면:\n\n```bash\n# 1. Vertex 모드 활성화\nexport CLAUDE_CODE_USE_VERTEX=1\n\n# 2. GCP 자격 증명 설정\n# - gcloud auth application-default login (대화형)\n# - GOOGLE_APPLICATION_CREDENTIALS를 통한 서비스 계정 키 파일\n# - 워크로드 아이덴티티(GKE용)\n\n# 3. 프로젝트 및 리전 설정 (선택사항)\nexport ANTHROPIC_VERTEX_PROJECT_ID=my-gcp-project\nexport CLOUD_ML_REGION=us-central1\n```\n\n**자동 GCP 자격 증명 갱신:**\n```json\n{\n \"gcpAuthRefresh\": \"gcloud auth application-default login\"\n}\n```\n\n## 계정 전환\n\n**다른 계정으로 로그인:**\n```\n/login\n```\n새 OAuth 흐름을 시작합니다. 저장된 토큰이 새 계정의 토큰으로 교체됩니다.\n\n**로그아웃:**\n```\n/logout\n```\n저장된 자격 증명을 제거합니다. 다음 실행 시 인증을 요청합니다.\n\n## 토큰 만료 및 갱신\n\nClaude Code가 조용히 토큰 갱신을 처리합니다:\n- 각 API 요청 전에 액세스 토큰 만료 여부 확인\n- 만료된 경우 저장된 갱신 토큰으로 잠금을 획득하고 갱신\n- 여러 동시 Claude Code 인스턴스는 잠금 파일을 통해 중복 갱신 방지\n- API에서 `401` 응답이 오면 즉시 강제 갱신\n\n## 인증 우선순위\n\n여러 인증 소스가 설정된 경우 이 순서로 해석됩니다:\n\n1. `ANTHROPIC_AUTH_TOKEN` 환경 변수\n2. `CLAUDE_CODE_OAUTH_TOKEN` 환경 변수\n3. 파일 디스크립터의 OAuth 토큰(관리형 배포용)\n4. 설정의 `apiKeyHelper`\n5. 저장된 claude.ai OAuth 토큰(Keychain 또는 자격 증명 파일)\n6. `ANTHROPIC_API_KEY` 환경 변수\n\n> 💡 CI 및 비대화형 환경에서는 `ANTHROPIC_API_KEY` 또는 `CLAUDE_CODE_OAUTH_TOKEN`을 사용하세요. 이것들은 대화형 흐름보다 먼저 확인됩니다.\n"},{"index":13,"id":"section-13-12-훅","fileName":"12_훅.md","title":"훅 (Hooks)","markdown":"# 훅 (Hooks)\n\n> Claude가 도구를 사용하거나 세션 마일스톤에 도달할 때 셸 커맨드, HTTP 요청, 프롬프트를 자동으로 실행합니다.\n\n훅은 Claude Code의 도구 라이프사이클에 자동화를 연결합니다. Claude가 파일을 읽거나, bash 커맨드를 실행하거나, 응답을 완료할 때 설정된 훅이 자동으로 실행됩니다. 코드 스타일 강제, 테스트 실행, 도구 사용 로깅, Claude가 할 수 있는 작업 제어에 훅을 사용하세요.\n\n## 훅 작동 방식\n\n훅은 특정 **이벤트**에 바인딩된 커맨드(셸 스크립트, HTTP 엔드포인트, LLM 프롬프트)입니다. 이벤트가 발생하면 Claude Code가 매칭된 모든 훅을 실행하고 종료 코드와 출력을 사용해 다음 동작을 결정합니다.\n\n각 훅의 입력은 무슨 일이 일어났는지 설명하는 JSON 객체입니다.\n\n**종료 코드 의미:**\n| 종료 코드 | 의미 |\n|----------|------|\n| `0` | 성공. stdout이 Claude에게 표시될 수 있음(이벤트별 다름) |\n| `2` | 차단 또는 주입. stderr를 Claude에게 표시하고(`PreToolUse`) 도구 호출 방지 |\n| 기타 | stderr를 사용자에게만 표시; 실행 계속 |\n\n## 훅 이벤트\n\n| 이벤트 | 설명 |\n|--------|------|\n| **PreToolUse** | 모든 도구 호출 직전에 발생. 도구 입력 검사, 승인/차단, 입력 수정 가능. 종료코드 `2` → 도구 호출 차단 |\n| **PostToolUse** | 모든 성공적인 도구 호출 후 발생. 도구 출력 관찰 또는 Claude가 처리할 컨텍스트 주입 가능 |\n| **PostToolUseFailure** | 도구 호출이 오류로 종료될 때 발생 |\n| **Stop** | Claude가 응답을 종료하기 직전에 발생. 종료코드 `2` → stderr를 Claude에게 표시하고 대화 계속 |\n| **SubagentStop** | 서브에이전트가 결론 내리기 직전에 발생 (`Stop`과 동일하지만 서브에이전트용) |\n| **SubagentStart** | 새 서브에이전트가 시작될 때 발생 |\n| **SessionStart** | 세션 시작, 재개, `/clear`, `/compact` 후에 발생 |\n| **UserPromptSubmit** | 사용자가 프롬프트를 제출할 때 발생. 종료코드 `2` → 프롬프트 차단 |\n| **PreCompact** | 컨텍스트 컴팩션 시작 직전에 발생. 종료코드 `2` → 컴팩션 차단 |\n| **PostCompact** | 컴팩션 완료 후 발생 |\n| **Setup** | 저장소 초기화(`init`) 및 주기적 유지보수(`maintenance`) 시 발생 |\n| **PermissionRequest** | 권한 다이얼로그가 표시될 때 발생. 프로그래밍 방식으로 승인/거부 가능 |\n| **PermissionDenied** | 도구 호출이 거부된 후 발생 |\n| **Notification** | 권한 프롬프트, 유휴 프롬프트, 인증 성공 등의 알림 시 발생 |\n| **CwdChanged** | 작업 디렉토리 변경 후 발생 |\n| **FileChanged** | 감시 중인 파일이 변경될 때 발생 |\n| **SessionEnd** | 세션이 종료될 때 발생 |\n| **ConfigChange** | 세션 중 설정 파일이 변경될 때 발생 |\n\n## 훅 설정\n\n세션 내에서 `/hooks`를 실행해 훅 설정 메뉴를 열 수 있습니다. 훅은 설정 파일의 `hooks` 필드에 저장됩니다:\n\n```json\n{\n \"hooks\": {\n \"PostToolUse\": [\n {\n \"matcher\": \"Write\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"prettier --write $CLAUDE_FILE_PATH\"\n }\n ]\n }\n ],\n \"Stop\": [\n {\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"echo 'Session complete' >> ~/.claude-log.txt\"\n }\n ]\n }\n ]\n }\n}\n```\n\n각 이벤트는 **매처 객체** 배열에 매핑됩니다:\n- `matcher` (선택사항) — 이벤트의 매칭 가능한 필드와 매칭되는 문자열 패턴\n- `hooks` — 매처가 일치할 때 실행할 훅 커맨드 배열\n\n빈 또는 없는 `matcher`는 해당 이벤트의 모든 입력과 일치합니다.\n\n## 훅 커맨드 타입\n\n**셸 커맨드 (`type: \"command\"`):**\n```json\n{\n \"type\": \"command\",\n \"command\": \"npm test\",\n \"timeout\": 60,\n \"shell\": \"bash\",\n \"async\": false\n}\n```\n\n필드:\n- `command` — 실행할 셸 커맨드 (필수)\n- `timeout` — 타임아웃(초)\n- `shell` — `\"bash\"` (기본) 또는 `\"powershell\"`\n- `async` — 백그라운드에서 실행 (출력 무시)\n- `once` — 한 번 실행 후 자동으로 훅 제거\n- `if` — 조건부로 훅 건너뛰기 위한 권한 규칙 구문\n- `statusMessage` — 훅 실행 중 스피너에 표시되는 커스텀 메시지\n\n**HTTP 요청 (`type: \"http\"`):**\n```json\n{\n \"type\": \"http\",\n \"url\": \"https://hooks.example.com/claude-event\",\n \"headers\": {\n \"Authorization\": \"Bearer $MY_TOKEN\"\n },\n \"allowedEnvVars\": [\"MY_TOKEN\"],\n \"timeout\": 10\n}\n```\n\nClaude Code가 훅 입력 JSON을 URL에 POST합니다.\n\n**LLM 프롬프트 (`type: \"prompt\"`):**\n```json\n{\n \"type\": \"prompt\",\n \"prompt\": \"이 bash 커맨드에 보안 문제가 있는지 확인하세요: $ARGUMENTS. 문제가 있으면 설명하고 코드 2로 종료하세요.\",\n \"model\": \"claude-haiku-4-5\",\n \"timeout\": 30\n}\n```\n\n**에이전트 훅 (`type: \"agent\"`):**\n```json\n{\n \"type\": \"agent\",\n \"prompt\": \"단위 테스트가 실행되고 통과했는지 확인하세요.\",\n \"timeout\": 60\n}\n```\n\n도구 접근 권한이 있는 짧은 에이전틱 루프로 실행됩니다. 파일을 읽거나 커맨드를 실행해야 하는 검증 작업에 유용합니다.\n\n## 훅 예시\n\n**파일 편집 후 자동 포맷:**\n```json\n{\n \"hooks\": {\n \"PostToolUse\": [\n {\n \"matcher\": \"Write\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"prettier --write \\\"$CLAUDE_FILE_PATH\\\" 2>/dev/null || true\"\n }\n ]\n }\n ]\n }\n}\n```\n\n**위험한 커맨드 차단:**\n```json\n{\n \"hooks\": {\n \"PreToolUse\": [\n {\n \"matcher\": \"Bash\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"if echo \\\"$CLAUDE_TOOL_INPUT\\\" | grep -q 'rm -rf'; then echo '차단: rm -rf는 허용되지 않습니다' >&2; exit 2; fi\"\n }\n ]\n }\n ]\n }\n}\n```\n\n**모든 도구 사용 로깅:**\n```json\n{\n \"hooks\": {\n \"PostToolUse\": [\n {\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"echo \\\"$(date -u +%Y-%m-%dT%H:%M:%SZ) $CLAUDE_TOOL_NAME\\\" >> ~/.claude-tool-log.txt\",\n \"async\": true\n }\n ]\n }\n ]\n }\n}\n```\n\n**디렉토리 변경 시 환경 변수 주입:**\n```json\n{\n \"hooks\": {\n \"CwdChanged\": [\n {\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"if [ -f .envrc ]; then grep '^export ' .envrc >> \\\"$CLAUDE_ENV_FILE\\\"; fi\"\n }\n ]\n }\n ]\n }\n}\n```\n\n## 훅 vs 스킬\n\n| 기능 | 훅 | 스킬 |\n|------|-----|------|\n| 실행 시점 | 도구 이벤트에 자동 | Claude나 사용자가 `/skill-name`으로 명시적 호출 |\n| 목적 | 부작용, 게이팅, 관찰 | 온디맨드 워크플로우와 기능 |\n| 설정 | 설정 JSON | `.claude/skills/`의 마크다운 파일 |\n\n자동으로 발생해야 하는 것(포맷팅, 로깅, 강제)에는 훅을 사용하고, 의도적으로 트리거하려는 반복 가능한 워크플로우에는 스킬을 사용하세요.\n"},{"index":14,"id":"section-14-13-mcp서버","fileName":"13_MCP서버.md","title":"MCP 서버","markdown":"# MCP 서버\n\n> Model Context Protocol 서버를 연결해 Claude Code의 기능을 데이터베이스, API, 커스텀 도구로 확장합니다.\n\nMCP(Model Context Protocol)는 Claude Code가 외부 데이터 소스와 서비스에 연결할 수 있게 하는 오픈 표준입니다. MCP 서버를 추가하면 Claude가 새 도구에 접근할 수 있습니다 — 예를 들어 데이터베이스 쿼리, Jira 티켓 읽기, Slack 워크스페이스 상호작용 등.\n\n## 서버 추가 방법\n\n**CLI를 통해:**\n```bash\n# 기본 추가\nclaude mcp add <이름> -- <커맨드> [인수...]\n\n# 예: filesystem MCP 서버 추가\nclaude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /tmp\n\n# 범위 지정\nclaude mcp add --scope project filesystem -- npx -y @modelcontextprotocol/server-filesystem /tmp\nclaude mcp add --scope user my-db -- npx -y @my-org/mcp-server-postgres\n```\n\n**`--mcp-config` 플래그:**\n```bash\nclaude --mcp-config ./my-mcp-config.json\n```\nCI 환경이나 설정 파일에 저장하지 않을 독립형 설정에 유용합니다.\n\n## 설정 파일 형식\n\n```json\n{\n \"mcpServers\": {\n \"filesystem\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/home/user/projects\"],\n \"env\": {\n \"NODE_ENV\": \"production\"\n }\n }\n }\n}\n```\n\n**HTTP 원격 서버:**\n```json\n{\n \"mcpServers\": {\n \"my-api\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.example.com/v1\",\n \"headers\": {\n \"Authorization\": \"Bearer $MY_API_TOKEN\"\n }\n }\n }\n}\n```\n\n**SSE (Server-Sent Events):**\n```json\n{\n \"mcpServers\": {\n \"events-server\": {\n \"type\": \"sse\",\n \"url\": \"https://mcp.example.com/sse\"\n }\n }\n}\n```\n\n`command`, `args`, `url`, `headers` 값은 `$VAR` 및 `${VAR}` 구문을 지원합니다. 참조 변수가 없으면 Claude Code가 경고를 로그하지만 연결을 시도합니다.\n\n## 설정 범위\n\n| 범위 | 위치 | 용도 |\n|------|------|------|\n| `project` | 현재 디렉토리의 `.mcp.json` | 팀 공유 서버 설정 |\n| `user` | `~/.claude.json` (전역 설정) | 모든 곳에서 이용 가능한 개인 서버 |\n| `local` | 현재 프로젝트의 `.claude/settings.local.json` | 개인 프로젝트별 재정의, VCS에 커밋되지 않음 |\n\n같은 서버 이름이 여러 범위에 나타나면 `local` > `project` > `user` 순으로 우선합니다.\n\n## 서버 관리\n\n**활성화/비활성화:**\n```\n/mcp enable <server-name>\n/mcp disable <server-name>\n/mcp enable all\n/mcp disable all\n```\n\n비활성화된 서버는 설정에 남아있지만 시작 시 연결되지 않습니다.\n\n**서버 재연결:**\n```\n/mcp reconnect <server-name>\n```\n\n**서버 상태 확인:**\n`/mcp`를 실행해 모든 설정된 서버와 현재 연결 상태를 확인합니다:\n- **connected** — 서버가 실행 중이고 준비됨\n- **pending** — 서버가 시작 중\n- **failed** — 서버 연결 실패(오류 메시지 확인)\n- **needs-auth** — OAuth 인증 필요\n- **disabled** — 설정되었지만 꺼짐\n\n## MCP 도구 호출 승인\n\nClaude Code는 MCP 도구를 호출하기 전에 권한 프롬프트를 표시합니다. 도구 이름과 입력 인수를 보여줍니다:\n- **한 번 허용** — 이 특정 호출 승인\n- **항상 허용** — 이 세션에서 이 도구의 모든 호출 승인\n- **거부** — 호출 차단; Claude가 오류를 받고 다른 접근을 시도\n\n> 📝 자동 모드(`--allowedTools`)에서 MCP 도구는 허용 도구 목록에 전체 이름(`mcp__<server-name>__<tool-name>` 형식)을 포함시켜 사전 승인할 수 있습니다.\n\n## 예시: filesystem 서버\n\n```bash\n# 1. 서버 추가\nclaude mcp add --scope project filesystem -- npx -y @modelcontextprotocol/server-filesystem /home/user/projects\n\n# 2. 연결 확인\n# /mcp 실행 → filesystem이 connected로 표시되는지 확인\n\n# 3. 사용\n# Claude가 이제 mcp__filesystem__read_file과 mcp__filesystem__write_file 도구로\n# /home/user/projects의 파일을 읽고 쓸 수 있음\n```\n\n## 예시: 데이터베이스 서버\n\n```json\n{\n \"mcpServers\": {\n \"postgres\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@modelcontextprotocol/server-postgres\"],\n \"env\": {\n \"POSTGRES_CONNECTION_STRING\": \"$DATABASE_URL\"\n }\n }\n }\n}\n```\n\nClaude Code 시작 전에 환경에서 `DATABASE_URL`을 설정하면 MCP 서버가 자동으로 받습니다.\n\n## 공식 MCP 레지스트리\n\n[modelcontextprotocol.io](https://modelcontextprotocol.io)에서 Anthropic과 커뮤니티가 관리하는 MCP 서버 레지스트리를 찾아볼 수 있습니다 — 데이터베이스, 생산성 도구, 클라우드 제공업체 등.\n\n## 문제 해결\n\n**서버가 'failed'로 표시됨:**\n- 커맨드가 존재하고 실행 가능한지 확인: `which npx`\n- 터미널에서 커맨드를 직접 실행해 오류 없이 시작되는지 확인\n- 필요한 환경 변수(API 키 등)가 설정되었는지 확인\n- `claude --debug`로 상세 연결 로그 확인\n\n**MCP 도구가 나타나지 않음:**\n연결되었지만 미인증 상태인 서버는 도구를 노출하지 않습니다. `/mcp`에서 **needs-auth** 상태를 확인하고 OAuth 흐름을 따르세요.\n\n**Windows: npx 실패:**\n```json\n{\n \"mcpServers\": {\n \"my-server\": {\n \"command\": \"cmd\",\n \"args\": [\"/c\", \"npx\", \"-y\", \"@my-org/mcp-server\"]\n }\n }\n}\n```\n"},{"index":15,"id":"section-15-14-멀티에이전트","fileName":"14_멀티에이전트.md","title":"멀티에이전트 워크플로우","markdown":"# 멀티에이전트 워크플로우\n\n> Claude가 서브에이전트를 스폰하고 조율해 복잡한 작업을 병렬화하는 방법.\n\nClaude Code는 서브에이전트 — 독립적으로 실행되어 병렬로 작업을 완료하는 별도의 Claude 인스턴스 — 를 스폰할 수 있습니다. 단일 대화에서 순차적으로 모든 것을 하는 대신, 동시에 실행하는 특화 에이전트로 분할해서 크고 다단계 작업을 처리할 수 있습니다.\n\n## 서브에이전트 작동 방식\n\nClaude가 `Agent` 도구를 사용하면, 자체 컨텍스트, 시스템 프롬프트, 도구 권한을 가진 새 Claude 인스턴스를 시작합니다. 부모 Claude는 에이전트가 완료될 때까지 기다리거나(또는 에이전트가 백그라운드에서 실행 중이면 다른 작업을 계속합니다), 그 후 에이전트의 결과를 단일 메시지로 받습니다.\n\n각 에이전트는:\n- 새 컨텍스트 윈도우로 시작 (fork가 아닌 한)\n- 에이전트 타입에 따라 특화된 시스템 프롬프트 적용\n- 자체 도구 권한 (에이전트 타입별로 설정 가능)\n- 추가 서브에이전트를 스폰 가능 (단, 중첩은 제한됨)\n\n## Agent 도구\n\nClaude가 `Agent` 도구를 사용해 서브에이전트를 스폰합니다. 이 도구를 직접 호출하는 것이 아니라 Claude가 필요할 때 결정합니다. 터미널에서 에이전트 스폰을 볼 수 있습니다 — 자체 진행 표시기와 함께 나타납니다.\n\n도구 파라미터:\n- `description` — 에이전트가 할 일의 3-5단어 요약 (UI에 표시)\n- `prompt` — 에이전트에 대한 전체 작업 설명\n- `subagent_type` — 사용할 특화 에이전트 타입 (선택사항; 기본값은 범용)\n- `run_in_background` — 비동기 실행 여부\n- `isolation` — `\"worktree\"`로 격리된 git worktree 제공\n\n## Claude가 서브에이전트를 사용하는 경우\n\n작업이 병렬 처리나 특화에 도움이 될 때 에이전트를 스폰합니다:\n- **독립적 병렬 작업** — 문서 업데이트와 동시에 테스트 작성\n- **특화 작업** — 보안 감사를 위한 코드 리뷰어 에이전트 사용\n- **장시간 실행 작업** — 다른 것을 작업하는 동안 백그라운드 리서치\n- **격리된 탐색** — 메인 컨텍스트를 오염시키지 않고 솔루션 탐색을 위해 자신을 포크\n\n## 멀티에이전트 워크플로우 요청\n\nClaude에게 명시적으로 여러 에이전트 사용을 요청할 수 있습니다:\n\n```\nlinter와 test suite를 병렬로 실행해줘.\n```\n\n```\n세 경쟁 라이브러리가 이 문제를 어떻게 처리하는지 별도의 에이전트로 조사한 후 결과를 요약해줘.\n```\n\n```\n보안 에이전트가 이 코드 변경의 보안 영향을 검토하는 동안 기능 구현을 계속해줘.\n```\n\n> 💡 Claude에게 에이전트를 \"병렬로\" 실행하도록 요청하면, 여러 Agent 도구 호출을 포함하는 단일 메시지를 전송해 모두 동시에 시작합니다.\n\n## 포그라운드 vs 백그라운드 에이전트\n\n기본적으로 에이전트는 **포그라운드**에서 실행됩니다 — Claude가 계속하기 전에 각 에이전트가 완료될 때까지 기다립니다. Claude가 결과를 계속 작업하는 데 필요한 경우 포그라운드 에이전트를 사용하세요.\n\n백그라운드 에이전트는 비동기로 실행됩니다. Claude가 시작하고 다른 작업을 계속합니다. 에이전트가 완료되면 알림을 받습니다.\n\n```\n다음 기능을 구현하는 동안 통합 테스트를 백그라운드에서 실행해줘.\n```\n\n> ⚠️ 실행 중인 백그라운드 에이전트의 출력 파일을 직접 확인하도록 Claude에게 요청하지 마세요. Claude는 자동으로 완료 알림을 받습니다.\n\n## 코디네이터 모드\n\n코디네이터 모드에서 Claude는 모든 구현 작업을 서브에이전트에 위임하고 계획, 라우팅, 종합에 집중합니다. 매우 큰 작업에 유용하며 서브에이전트가 실질적인 작업을 수행합니다.\n\n## 에이전트 메모리와 컨텍스트 격리\n\n각 서브에이전트는 **깨끗한 컨텍스트 윈도우**로 시작합니다. 부모 Claude가 에이전트 프롬프트에 전체 작업 설명과 관련 배경을 제공합니다 — 에이전트는 부모의 대화 기록을 자동으로 상속하지 않습니다.\n\n**영속 에이전트 메모리:**\n일부 에이전트 타입은 호출 간에 영속 메모리를 가집니다:\n- **사용자 범위**: `~/.claude/agent-memory/<agent-type>/MEMORY.md`\n- **프로젝트 범위**: `.claude/agent-memory/<agent-type>/MEMORY.md`\n- **로컬 범위**: `.claude/agent-memory-local/<agent-type>/MEMORY.md`\n\n## Worktree 격리\n\n`isolation: \"worktree\"`를 설정해 에이전트에게 자체 git worktree를 제공합니다 — 저장소의 격리된 복사본. 에이전트가 만드는 변경 사항은 사용자가 병합하기 전까지 작업 디렉토리에 영향을 주지 않습니다.\n\n```\n내가 변경 사항을 검토하고 병합할 수 있도록 격리된 worktree에서 이 기능을 구현해줘.\n```\n\n## 효과적인 에이전트 프롬프트 작성\n\n서브에이전트는 부모 대화의 컨텍스트가 없이 시작합니다. 좋은 에이전트 프롬프트에는 다음이 포함됩니다:\n- 달성하려는 것과 이유\n- 관련 파일 경로, 함수 이름, 데이터\n- 에이전트가 보고해야 할 내용(형식, 길이, 답해야 할 질문)\n- 에이전트가 하면 안 되는 것(범위 제약)\n- 이미 시도했거나 배제한 것\n\n**나쁜 프롬프트:**\n```\n버그를 수정해줘.\n```\n\n**좋은 프롬프트:**\n```\nsrc/services/user.ts:247의 UserService.getProfile()에 있는 null 참조 버그를 수정해줘.\n사용자에게 연관된 프로파일 레코드가 없을 때 버그가 발생합니다 — getProfile()이 profile이 null인지 먼저 확인하지 않고 profile.preferences를 호출합니다. null 체크를 추가하고 기본 설정 객체 { theme: 'light', notifications: true }를 반환하세요.\n그 후 npm test를 실행해 수정 사항이 기존 테스트를 통과하는지 확인하세요.\n```\n\n## 제한사항\n\n- 서브에이전트는 기본적으로 `acceptEdits` 모드를 사용합니다\n- 에스케이프를 누르면 부모 턴을 취소하지만 실행 중인 백그라운드 에이전트는 취소하지 않습니다 — 작업 패널에서 명시적으로 취소하세요\n- 서브에이전트는 다른 팀메이트를 스폰할 수 없습니다 (팀 로스터는 플랫)\n- 포크 에이전트는 자신을 다시 포크할 수 없습니다\n- 에이전트 결과는 부모에 반환되기 전에 100,000자로 제한됩니다\n"},{"index":16,"id":"section-16-15-스킬","fileName":"15_스킬.md","title":"스킬 (Skills)","markdown":"# 스킬 (Skills)\n\n> 슬래시 커맨드로 호출하는 재사용 가능한 온디맨드 기능을 만드는 방법.\n\n스킬은 재사용 가능한 프롬프트와 워크플로우를 정의하는 마크다운 파일입니다. Claude Code에서 `/skill-name`을 입력하면 Claude가 해당 스킬의 지시사항을 로드하고 설명된 작업을 실행합니다. 세션 간에 반복하는 모든 워크플로우에 유용합니다 — 배포 실행, 변경 내역 작성, PR 검토, 팀 특유의 코딩 컨벤션 적용 등.\n\n## 스킬 작동 방식\n\n스킬은 `SKILL.md` 파일이 있는 `.claude/skills/` 안의 디렉토리입니다. `/skill-name`을 입력하면 Claude Code가 해당 스킬의 `SKILL.md`를 그 액션의 프롬프트로 로드합니다. 스킬은 지시사항, 컨텍스트, 제약, 호출 시 실행되는 인라인 셸 커맨드까지 포함할 수 있습니다.\n\n스킬은 지연 로드됩니다 — 호출될 때만 읽히므로 스킬이 많이 정의되어 있어도 시작 시간이나 컨텍스트 크기에 영향을 주지 않습니다.\n\n## 스킬 만들기\n\n**1. 스킬 디렉토리 만들기:**\n```bash\nmkdir -p .claude/skills/my-skill\n```\n\n스킬은 다음 위치에 있을 수 있습니다:\n- `.claude/skills/` (프로젝트 레벨, 현재 작업 디렉토리 기준)\n- `~/.claude/skills/` (사용자 레벨, 모든 프로젝트에서 사용 가능)\n\n**2. SKILL.md 작성:**\n```markdown\n---\ndescription: 이 프로젝트의 전체 릴리즈 프로세스 실행\nargument-hint: 버전 번호 (예: 1.2.3)\n---\n\n$ARGUMENTS 버전으로 프로젝트를 릴리즈합니다.\n\n단계:\n1. `package.json`의 버전을 $ARGUMENTS로 업데이트\n2. CHANGELOG.md에 이 버전의 새 섹션 추가\n3. `npm test` 실행 및 모든 테스트 통과 확인\n4. \"chore: release v$ARGUMENTS\" 메시지로 커밋\n5. `v$ARGUMENTS` git 태그 생성\n```\n\n**3. 스킬 호출:**\n```\n/my-skill 1.2.3\n```\n\nClaude가 스킬을 로드하고 지시사항을 실행합니다 — `1.2.3`이 `$ARGUMENTS`에 대입됩니다.\n\n## 스킬 프론트매터\n\n`SKILL.md` 상단의 프론트매터로 스킬 동작을 설정합니다. 모든 필드는 선택사항입니다.\n\n| 필드 | 설명 |\n|------|------|\n| `description` | `/skills`에 표시되고 Claude가 언제 사용할지 결정하는 짧은 설명 |\n| `argument-hint` | 슬래시 커맨드 자동완성에 표시되는 힌트 |\n| `allowed-tools` | 이 스킬이 사용할 수 있는 도구 목록(기본값: 모두) |\n| `when_to_use` | Claude가 언제 이 스킬을 적극적으로 사용해야 하는지 설명 |\n| `model` | 이 스킬에 사용할 모델 (예: `claude-sonnet-4-6`) |\n| `user-invocable` | `false`로 설정해 슬래시 커맨드 목록에서 숨김 (Claude는 여전히 사용 가능) |\n| `context` | `fork`로 격리된 서브에이전트 컨텍스트에서 스킬 실행 |\n| `paths` | 일치하는 파일이 터치될 때만 스킬 활성화하는 Glob 패턴 |\n| `version` | 스킬 버전 문자열 |\n| `hooks` | 이 스킬 실행에 범위가 제한된 훅 |\n\n## 인수 대입\n\n`SKILL.md` 어디서나 `$ARGUMENTS`를 사용해 슬래시 커맨드 뒤에 전달된 텍스트를 삽입합니다:\n\n```markdown\n$ARGUMENTS라는 이름의 새 React 컴포넌트를 프로젝트 컨벤션에 따라 생성합니다.\n```\n\n```\n/new-component UserProfile\n```\n\n명명된 인수의 경우, 프론트매터에 인수를 나열하고 `$name` 구문으로 참조합니다:\n\n```yaml\n---\narguments: [name, directory]\n---\n```\n\n## 인라인 셸 커맨드\n\n스킬은 호출 시 실행되는 셸 커맨드를 임베드할 수 있습니다. 출력이 Claude가 보기 전에 프롬프트에 삽입됩니다:\n\n```markdown\n---\ndescription: 최근 변경 사항 검토\n---\n\n컨텍스트를 위한 최근 커밋들:\n\n!`git log --oneline -20`\n\n위 변경 사항을 검토하고 무엇이 달성됐는지 요약해주세요.\n```\n\n`!` 프리픽스 후 백틱으로 감싼 커맨드가 실행되고 해당 블록이 출력으로 교체됩니다.\n\n> ⚠️ 인라인 셸 커맨드는 셸과 동일한 권한으로 실행됩니다. 스킬이 로드될 때가 아니라 호출될 때 실행됩니다.\n\n## 스킬 목록 보기\n\n```\n/skills\n```\n\n모든 범위(프로젝트, 사용자, Managed)의 사용 가능한 모든 스킬과 설명을 표시합니다.\n\n## 네임스페이스 스킬\n\n서브디렉토리의 스킬은 콜론으로 네임스페이스됩니다:\n\n```\n.claude/skills/\n deployment/\n SKILL.md → /deployment\n database/\n migrate/\n SKILL.md → /database:migrate\n seed/\n SKILL.md → /database:seed\n```\n\n## 경로 기반 조건부 스킬\n\n`paths` 프론트매터 필드를 추가해 일치하는 파일 작업 시에만 스킬을 활성화합니다:\n\n```yaml\n---\ndescription: Django 모델 검토\npaths: \"**/*.py\"\nwhen_to_use: Django 모델 파일 편집 시 사용\n---\n```\n\nGlob 패턴과 일치하는 파일을 읽거나, 쓰거나, 편집할 때 스킬이 자동으로 Claude의 컨텍스트에 로드됩니다.\n\n## 사용자 레벨 스킬\n\n`~/.claude/skills/`의 스킬은 각 저장소에 추가하지 않아도 모든 프로젝트에서 사용할 수 있습니다:\n\n```bash\nmkdir -p ~/.claude/skills/standup\ncat > ~/.claude/skills/standup/SKILL.md << 'EOF'\n---\ndescription: 스탠드업 업데이트를 위해 오늘 작업한 내용 요약\n---\n\n이 저장소에서 오늘의 git 커밋을 확인하고 스탠드업 형식으로 요약해주세요: 한 일, 다음에 할 일, 막히는 것. 3-4문장으로 유지해주세요.\nEOF\n```\n\n## 스킬 예시: 컴포넌트 생성기\n\n```markdown\n---\ndescription: 테스트와 함께 새 React 컴포넌트 생성\nargument-hint: ComponentName\nallowed-tools: Write, Bash\n---\n\n$ARGUMENTS라는 이름의 새 React 컴포넌트를 만듭니다.\n\n1. `src/components/$ARGUMENTS/$ARGUMENTS.tsx` 생성:\n - TypeScript를 사용하는 함수형 컴포넌트\n - `$ARGUMENTSProps`라는 Props 인터페이스\n - 컴포넌트를 설명하는 JSDoc 주석\n - default export\n\n2. `src/components/$ARGUMENTS/$ARGUMENTS.test.tsx` 생성:\n - React Testing Library를 사용한 최소 하나의 렌더링 테스트\n - 스냅샷 테스트\n\n3. 컴포넌트를 re-export하는 `src/components/$ARGUMENTS/index.ts` 생성\n\n4. `npx tsc --noEmit`을 실행해 타입 오류 없음 확인\n```\n\n호출:\n```\n/new-component Button\n```\n\n## 훅 vs 스킬 비교\n\n| 기능 | 스킬 | 훅 |\n|------|------|-----|\n| 호출 | 명시적: `/skill-name` 또는 Claude가 필요를 인식 | 자동: 도구 이벤트에 발생 |\n| 용도 | 의도적으로 트리거하려는 반복 가능한 워크플로우 | 부작용, 포맷팅, lint, 차단 |\n| 설정 | `.claude/skills/`의 `SKILL.md` | 설정 JSON의 `hooks` 필드 |\n| 컨텍스트 | 파일, 셸 출력, 상세 지시사항 포함 가능 | 이벤트 JSON 수신, 종료 코드와 출력 반환 |\n"},{"index":17,"id":"section-17-16-커맨드개요","fileName":"16_커맨드개요.md","title":"커맨드 개요","markdown":"# 커맨드 개요\n\n> Claude Code는 두 가지 커맨드 범주를 허용합니다: 실행 시 전달하는 CLI 플래그와 세션 중 입력하는 슬래시 커맨드.\n\n## 두 가지 커맨드 타입\n\n| 타입 | 사용 시점 | 예시 |\n|------|----------|------|\n| CLI 플래그 | 세션 시작 시 설정 — 모델, 출력 형식, 권한 모드 설정 | `claude --permission-mode acceptEdits \"테스트 수정해줘\"` |\n| 슬래시 커맨드 | 실행 중인 세션과 상호작용 — 메모리 관리, 모델 전환, 코드 커밋 | `/commit` |\n\nCLI 플래그는 한 번 소비되고 세션 중간에 변경할 수 없습니다(실행 중인 설정을 변경하는 `/model`과 `/permissions` 제외).\n\n## 도움말 확인\n\n```bash\n# 모든 CLI 플래그 표시\nclaude --help\n\n# 세션 내에서 슬래시 커맨드 목록\n/help\n```\n\n`/help`는 현재 세션에서 사용 가능한 모든 슬래시 커맨드를 나열합니다 — 플러그인과 스킬이 추가한 커맨드 포함.\n\n## CLI 플래그 사용법\n\n```bash\nclaude [플래그] [프롬프트]\n```\n\n```bash\n# 비대화형: 응답 출력 후 종료\nclaude -p \"README.md를 요약해줘\" < README.md\n\n# 세션 모델 설정\nclaude --model opus\n\n# 파일 편집 자동 승인\nclaude --permission-mode acceptEdits\n```\n\n자세한 내용은 [CLI 플래그](./17_CLI플래그.md) 참조.\n\n## 슬래시 커맨드 사용법\n\n세션 내에서 입력 프롬프트에 슬래시 커맨드 입력:\n\n```\n/command [인수]\n```\n\n```\n/init\n/compact 최근 세 작업만 요약해줘\n/model claude-opus-4-5\n```\n\n자세한 내용은 [슬래시 커맨드](./18_슬래시커맨드.md) 참조.\n\n## 키보드 단축키\n\n모든 대화형 Claude Code 세션에서 작동:\n\n| 키 | 동작 |\n|----|------|\n| `Ctrl+C` | 현재 응답 중단 (Claude가 턴 중간에 멈춤) |\n| `Ctrl+D` | Claude Code 종료 |\n| `Ctrl+L` | 터미널 화면 지우기 (대화 기록은 지우지 않음) |\n| `Up` / `Down` | 입력 기록 탐색 |\n| `Tab` | 슬래시 커맨드 이름 자동완성 |\n| `Escape` | 진행 중인 권한 프롬프트 취소 |\n\n> 📝 `Ctrl+C`는 현재 응답을 중단하지만 대화는 유지합니다. 세션을 완전히 종료하려면 `Ctrl+D` 또는 `/exit`를 사용하세요.\n\n## 서브커맨드\n\n메인 `claude` 커맨드 외에도 터미널에서 사용 가능한 서브커맨드:\n\n| 서브커맨드 | 설명 |\n|------------|------|\n| `claude mcp` | MCP 서버 설정 및 관리 |\n| `claude mcp serve` | Claude Code를 MCP 서버로 시작 |\n| `claude doctor` | 설치 및 설정 문제 진단 |\n| `claude update` | Claude Code를 최신 버전으로 업데이트 |\n\n```bash\nclaude mcp --help\nclaude doctor\n```\n"},{"index":18,"id":"section-18-17-cli플래그","fileName":"17_CLI플래그.md","title":"CLI 플래그","markdown":"# CLI 플래그\n\n> 터미널에서 Claude Code를 실행할 때 전달할 수 있는 모든 옵션.\n\n```bash\nclaude [플래그] [프롬프트]\n```\n\n## 핵심 플래그\n\n**`-p, --print`**\nClaude를 비대화형으로 실행. Claude가 프롬프트를 처리하고 응답을 출력한 후 종료합니다. REPL이 시작되지 않습니다.\n```bash\nclaude -p \"src/index.ts의 메인 함수를 설명해줘\"\necho \"이게 뭐야?\" | claude -p\n```\n> ⚠️ `--print` 모드에서는 작업 공간 신뢰 다이얼로그가 건너뜁니다. 신뢰하는 디렉토리에서만 사용하세요.\n\n**`--output-format <형식>`** (`--print`와 함께만 작동)\n| 값 | 설명 |\n|----|------|\n| `text` | 일반 텍스트 출력 (기본값) |\n| `json` | 완전한 결과가 담긴 단일 JSON 객체 |\n| `stream-json` | 실시간 이벤트를 담은 줄바꿈으로 구분된 JSON 스트림 |\n\n**`--verbose`**\n상세 출력 활성화.\n\n**`-v, --version`**\n버전 번호 출력 후 종료.\n\n## 세션 계속 플래그\n\n**`-c, --continue`**\n현재 디렉토리의 가장 최근 대화를 재개합니다.\n```bash\nclaude --continue\nclaude -c \"이제 테스트 추가해줘\"\n```\n\n**`-r, --resume [session-id]`**\n세션 ID로 대화를 재개합니다. 값 없이 사용하면 지난 세션 목록에서 선택합니다.\n```bash\nclaude --resume\nclaude --resume 550e8400-e29b-41d4-a716-446655440000\nclaude --resume \"auth refactor\"\n```\n\n**`--fork-session`**\n`--continue` 또는 `--resume`과 함께 사용해 재개된 대화에서 분기된 새 세션을 만듭니다.\n\n**`-n, --name <이름>`**\n세션 표시 이름 설정.\n\n**`--no-session-persistence`**\n세션 영속성 비활성화. `--print`와 함께만 작동합니다.\n\n## 모델 및 기능 플래그\n\n**`--model <모델>`**\n세션 모델 설정. 별칭(`sonnet`, `opus`, `haiku`) 또는 전체 모델 ID(`claude-sonnet-4-6`) 허용.\n```bash\nclaude --model sonnet\nclaude --model opus\nclaude --model claude-sonnet-4-6\n```\n\n**`--effort <레벨>`**\n세션의 effort 레벨 설정: `low`, `medium` (기본), `high`, `max`.\n```bash\nclaude --effort high \"이 아키텍처를 검토해줘\"\n```\n\n**`--fallback-model <모델>`**\n기본 모델이 과부하될 때 자동 대체 모델 활성화. `--print`와 함께만 작동합니다.\n\n## 권한 및 보안 플래그\n\n**`--permission-mode <모드>`**\n세션의 권한 모드 설정:\n| 모드 | 동작 |\n|------|------|\n| `default` | 커맨드 실행 및 편집 전에 확인 요청 |\n| `acceptEdits` | 파일 편집 자동 적용; 셸 커맨드는 여전히 확인 필요 |\n| `plan` | 계획을 제안하고 실행 전 승인 대기 |\n| `bypassPermissions` | 프롬프트 없이 모든 작업 실행 — 격리된 샌드박스 환경 전용 |\n\n**`--dangerously-skip-permissions`**\n모든 권한 검사를 우회합니다. `--permission-mode bypassPermissions`와 동일.\n> ⚠️ 인터넷 접근 없는 샌드박스 환경에서만 사용하세요.\n\n**`--allowed-tools <도구...>`** (별칭: `--allowedTools`)\nClaude가 사용할 수 있는 도구의 쉼표 또는 공백 구분 목록.\n```bash\nclaude --allowed-tools \"Bash(git:*) Edit Read\"\n```\n\n**`--disallowed-tools <도구...>`**\nClaude가 사용할 수 없는 도구 목록.\n\n**`--tools <도구...>`**\n세션에 사용 가능한 정확한 내장 도구 집합 지정. `\"\"`는 모든 도구 비활성화.\n\n## 컨텍스트 및 프롬프트 플래그\n\n**`--add-dir <디렉토리...>`**\n도구 접근 컨텍스트에 하나 이상의 디렉토리 추가.\n```bash\nclaude --add-dir /shared/libs --add-dir /shared/config\n```\n\n**`--system-prompt <프롬프트>`**\n기본 시스템 프롬프트를 커스텀 프롬프트로 교체.\n\n**`--append-system-prompt <텍스트>`**\n기본 시스템 프롬프트에 텍스트 추가. `--system-prompt`와 달리 내장 지시사항을 유지합니다.\n\n**`--mcp-config <설정...>`**\n하나 이상의 JSON 설정 파일 또는 인라인 JSON 문자열에서 MCP 서버 로드.\n\n**`--strict-mcp-config`**\n`--mcp-config`의 MCP 서버만 사용하고 다른 모든 MCP 설정 무시.\n\n**`--settings <파일-또는-json>`**\nJSON 파일 경로 또는 인라인 JSON 문자열에서 추가 설정 로드.\n\n**`--agents <json>`**\nJSON 객체로 커스텀 에이전트를 인라인으로 정의.\n\n## 출력 제어 플래그\n\n**`--max-turns <n>`**\n비대화형 모드의 에이전틱 턴 수 제한. `--print`와 함께만 작동합니다.\n\n**`--max-budget-usd <금액>`**\nAPI 호출 최대 지출 금액 설정. `--print`와 함께만 작동합니다.\n\n**`--json-schema <스키마>`**\n구조화된 출력 검증을 위한 JSON 스키마 제공.\n\n## Worktree 플래그\n\n**`-w, --worktree [이름]`**\n세션에 새 git worktree 생성. PR 번호나 GitHub PR URL 허용.\n```bash\nclaude --worktree\nclaude --worktree feature-auth\nclaude --worktree \"#142\"\n```\n\n**`--tmux`**\nworktree와 함께 tmux 세션 생성. `--worktree` 필요.\n\n## 디버그 플래그\n\n**`-d, --debug [필터]`**\n디버그 모드 활성화.\n```bash\nclaude --debug\nclaude --debug \"api,hooks\"\nclaude --debug \"!file,!1p\"\n```\n\n**`--debug-file <경로>`**\n디버그 로그를 인라인 표시 대신 파일에 저장.\n\n**`--bare`**\n최소 모드. 훅, LSP, 플러그인 동기화, 어트리뷰션, 자동 메모리, 백그라운드 프리페치, 키체인 읽기, `CLAUDE.md` 자동 발견을 모두 건너뜁니다. 스타트업 지연이 중요하고 이러한 기능이 필요하지 않은 스크립트 파이프라인에 사용하세요.\n\n## 일반적인 플래그 조합\n\n```bash\n# JSON 출력과 함께 비대화형\nclaude -p \"모든 내보낸 타입 목록\" --output-format json\n\n# CI에서 권한 우회 (샌드박스 환경 전용)\nclaude -p \"전체 테스트 스위트 실행하고 실패 수정해줘\" --dangerously-skip-permissions\n\n# 마지막 세션 재개 후 비대화형으로 계속\nclaude --continue -p \"이제 그것에 대한 테스트 작성해줘\"\n\n# 커스텀 MCP 설정으로 엄격한 격리\nclaude --mcp-config ./ci-mcp.json --strict-mcp-config -p \"스키마 분석해줘\"\n\n# 시스템 프롬프트를 교체하지 않고 추가\nclaude --append-system-prompt \"항상 JavaScript가 아닌 TypeScript를 출력하세요.\"\n```\n"},{"index":19,"id":"section-19-18-슬래시커맨드","fileName":"18_슬래시커맨드.md","title":"슬래시 커맨드","markdown":"# 슬래시 커맨드\n\n> 실행 중인 Claude Code 세션에서 입력하는 커맨드.\n\n```\n/command [인수]\n```\n\n세션 내에서 언제든 `/help`를 입력해 모든 커맨드를 볼 수 있습니다.\n\n## 빠른 참조\n\n| 커맨드 | 설명 |\n|--------|------|\n| `/init` | 프로젝트의 `CLAUDE.md` 파일 및 선택적 스킬/훅 생성 |\n| `/memory` | Claude 메모리 파일 편집 (전역, 프로젝트, 로컬) |\n| `/config` | 설정 패널 열기 |\n| `/hooks` | 도구 이벤트의 훅 설정 보기 |\n| `/mcp` | MCP 서버 관리 — 활성화, 비활성화, 재연결 |\n| `/permissions` | 도구의 허용/차단 규칙 관리 |\n| `/plan` | plan 모드 활성화 또는 현재 세션 계획 열기/설명 |\n| `/model` | 현재 세션의 AI 모델 설정 |\n| `/commit` | AI가 생성한 메시지로 git 커밋 생성 |\n| `/review` | 풀 리퀘스트 검토 |\n| `/skills` | 사용 가능한 스킬 목록 |\n| `/compact` | 컨텍스트 사용량 줄이기 위해 대화 기록 요약 |\n| `/clear` | 대화 기록 지우기 및 컨텍스트 해제 |\n| `/help` | 도움말 및 사용 가능한 커맨드 표시 |\n| `/login` | 로그인 또는 Anthropic 계정 전환 |\n| `/logout` | Anthropic 계정에서 로그아웃 |\n\n---\n\n## 프로젝트 및 메모리 커맨드\n\n### `/init`\n\n코드베이스를 분석하고 `CLAUDE.md` 파일과 선택적으로 스킬과 훅을 설정합니다. Claude가 주요 프로젝트 파일(매니페스트, CI 설정, 빌드 스크립트, README)을 조사한 후 인터뷰를 통해 빠진 내용을 채우고 출력 파일을 작성합니다.\n\n설정 내용(사용자 선택에 따라):\n- **프로젝트 `CLAUDE.md`** — 팀 공유 지시사항, 소스 컨트롤에 커밋\n- **개인 `CLAUDE.local.md`** — 이 프로젝트의 개인 설정(gitignore됨)\n- **스킬** — 슬래시 커맨드로 호출하는 온디맨드 워크플로우\n- **훅** — 도구 이벤트에서 자동으로 실행되는 결정론적 셸 커맨드\n\n> 💡 언제든 `/init`을 다시 실행하세요. `CLAUDE.md`가 이미 있으면 Claude가 파일을 덮어쓰는 대신 구체적인 변경 사항을 제안합니다.\n\n### `/memory`\n\nClaude의 메모리 파일 대화형 에디터를 엽니다. 세 가지 메모리 범위:\n\n| 범위 | 파일 | 적용 대상 |\n|------|------|----------|\n| 전역 | `~/.claude/CLAUDE.md` | 모든 프로젝트의 나 |\n| 프로젝트 | 프로젝트 루트의 `CLAUDE.md` | 팀 전체 |\n| 로컬 | 프로젝트 루트의 `CLAUDE.local.md` | 이 프로젝트의 나 (gitignore됨) |\n\n---\n\n## 설정 커맨드\n\n### `/config` (별칭: `/settings`)\nClaude Code 설정을 보고 편집하는 설정 패널 열기.\n\n### `/hooks`\n현재 세션에서 활성화된 훅 설정 표시. 훅을 만들거나 편집하려면 `/init`을 사용하거나 `.claude/settings.json`을 직접 편집하세요.\n\n### `/mcp [enable|disable [server-name]]`\n\n현재 세션의 MCP 서버 관리:\n\n| 인수 | 효과 |\n|------|------|\n| (없음) | MCP 관리 패널 열기 |\n| `enable` | 모든 비활성 MCP 서버 활성화 |\n| `enable <server-name>` | 특정 서버 활성화 |\n| `disable` | 모든 활성 MCP 서버 비활성화 |\n| `disable <server-name>` | 특정 서버 비활성화 |\n| `reconnect <server-name>` | 특정 서버에 재연결 |\n\n> 📝 `/mcp enable/disable`로 만든 변경 사항은 현재 세션에만 적용됩니다.\n\n### `/permissions` (별칭: `/allowed-tools`)\n도구의 허용 및 차단 규칙을 보고 관리하는 권한 패널 열기.\n\n### `/model [모델]`\n세션의 AI 모델 설정:\n```\n/model\n/model sonnet\n/model claude-opus-4-5\n```\n\n---\n\n## 세션 관리 커맨드\n\n### `/plan [open|<설명>]`\n| 인수 | 효과 |\n|------|------|\n| (없음) | plan 모드 토글 |\n| `open` | 현재 계획 열기 및 표시 |\n| `<설명>` | 주어진 설명으로 새 계획 생성 |\n\nplan 모드에서 Claude는 어떤 작업도 실행하기 전에 작성된 계획을 만들고 승인을 기다립니다.\n\n### `/compact [지시사항]`\n대화 기록을 요약하고 컨텍스트 윈도우가 가득 차도 작업을 계속할 수 있게 합니다. 선택적 인수로 요약 방법을 지시할 수 있습니다.\n```\n/compact\n/compact 데이터베이스 스키마 변경에만 집중해줘\n/compact 완료된 최근 세 작업만 요약해줘\n```\n\n### `/clear` (별칭: `/reset`, `/new`)\n전체 대화 기록을 지우고 컨텍스트를 해제해 동일한 작업 디렉토리에서 새 세션을 시작합니다. `/compact`와 달리 요약하는 대신 모든 기록을 제거합니다.\n\n### `/skills`\n현재 세션에서 사용 가능한 모든 스킬을 나열합니다.\n\n---\n\n## Git 커맨드\n\n### `/commit`\nAI가 생성한 커밋 메시지로 git 커밋을 만듭니다. Claude가 현재 git 상태와 diff를 읽고, 스테이징된 변경 사항을 분석하고, \"무엇\"이 아닌 \"왜\"에 초점을 맞춘 간결한 커밋 메시지를 작성합니다.\n\n안전 규칙:\n- 기존 커밋을 절대 amend하지 않음\n- 훅을 건너뛰지 않음 (`--no-verify` 사용 안 함)\n- 시크릿을 포함할 가능성이 있는 파일은 커밋하지 않음\n- 변경 사항이 없으면 빈 커밋을 만들지 않음\n\n> 📝 `/commit`은 `git add`, `git status`, `git commit`에만 접근 가능합니다. push, rebase 등의 다른 git 작업은 실행할 수 없습니다.\n\n### `/review [PR-번호]`\nGitHub CLI(`gh`)를 사용해 풀 리퀘스트에 AI 코드 리뷰를 실행합니다. PR 번호 없이 사용하면 열린 PR 목록을 표시합니다. 리뷰 내용:\n- PR이 하는 일 개요\n- 코드 품질 및 스타일 분석\n- 구체적인 개선 제안\n- 잠재적 문제 또는 리스크\n- 성능, 테스트 커버리지, 보안 고려사항\n\n> 📝 `/review`는 [GitHub CLI](https://cli.github.com/)(`gh`)가 설치되고 인증되어야 합니다.\n\n---\n\n## 계정 및 도움말 커맨드\n\n### `/help`\n현재 세션에서 사용 가능한 모든 슬래시 커맨드 목록 표시 — 내장 커맨드, 스킬 커맨드, 설치된 플러그인이 추가한 커맨드 포함.\n\n### `/login`\nAnthropic 계정에 로그인하거나 계정을 전환합니다.\n\n### `/logout`\nAnthropic 계정에서 로그아웃합니다. 로그아웃 후 다음 세션에서 다시 인증을 요청합니다.\n\n---\n\n## 커스텀 스킬 커맨드\n\n`.claude/skills/<skill-name>/SKILL.md`에 스킬이 생성되면 해당 스킬이 로드된 모든 세션에서 `/<skill-name>`으로 사용할 수 있습니다.\n\n```\n/verify\n/deploy staging\n/fix-issue 123\n```\n\n`/skills`를 실행해 로드된 모든 스킬과 설명을 확인하세요.\n"},{"index":20,"id":"section-20-19-훅레퍼런스","fileName":"19_훅레퍼런스.md","title":"훅 레퍼런스","markdown":"# 훅 레퍼런스\n\n> 모든 훅 이벤트, 입력 페이로드, 출력 스키마, 각 종료 코드가 Claude 동작에 미치는 영향에 대한 전체 레퍼런스.\n\n훅은 Claude의 에이전틱 루프에서 정의된 지점에서 발생하는 셸 커맨드, HTTP 엔드포인트, LLM 프롬프트, 또는 인프로세스 콜백입니다.\n\n## 설정\n\n훅은 설정 파일의 최상위 `hooks` 키로 구성됩니다:\n\n```json\n{\n \"hooks\": {\n \"PreToolUse\": [\n {\n \"matcher\": \"Bash\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"echo 'bash 커맨드 실행 예정' >&2\"\n }\n ]\n }\n ]\n }\n}\n```\n\n## 매처 설정\n\n`matcher` 필드는 이벤트별로 다른 필드와 매칭됩니다:\n\n| 이벤트 | 매칭되는 필드 |\n|--------|-------------|\n| `PreToolUse` / `PostToolUse` / `PostToolUseFailure` / `PermissionRequest` / `PermissionDenied` | `tool_name` |\n| `Notification` | `notification_type` |\n| `SessionStart` | `source` (`startup`, `resume`, `clear`, `compact`) |\n| `Setup` | `trigger` (`init`, `maintenance`) |\n| `SubagentStart` / `SubagentStop` | `agent_type` |\n| `PreCompact` / `PostCompact` | `trigger` (`manual`, `auto`) |\n| `ConfigChange` | `source` |\n| `FileChanged` | 파일 이름 패턴 (예: `\".envrc|.env\"`) |\n\n## 훅 타입\n\n**셸 커맨드:**\n```json\n{\n \"type\": \"command\",\n \"command\": \"jq '.tool_name' && my-validator\",\n \"timeout\": 30,\n \"shell\": \"bash\",\n \"async\": false,\n \"once\": false,\n \"if\": \"Bash(git *)\",\n \"statusMessage\": \"검증 중...\"\n}\n```\n\n필드:\n- `command`: 실행할 셸 커맨드 (필수)\n- `timeout`: 타임아웃(초), 기본 60초\n- `shell`: `bash` (기본) 또는 `powershell`\n- `async`: `true`면 백그라운드에서 비블로킹 실행\n- `asyncRewake`: `true`면 백그라운드 실행, 종료코드 2로 종료 시 모델 깨움\n- `once`: `true`면 한 번 실행 후 자동 제거\n- `if`: 조건부로 훅 건너뛰기 위한 권한 규칙 구문\n- `statusMessage`: 실행 중 스피너에 표시되는 커스텀 메시지\n\n**LLM 평가:**\n```json\n{\n \"type\": \"prompt\",\n \"prompt\": \"이 bash 커맨드가 안전한지 확인하세요: $ARGUMENTS\",\n \"model\": \"claude-haiku-4-5\",\n \"timeout\": 30\n}\n```\n\n**에이전틱 검증기:**\n```json\n{\n \"type\": \"agent\",\n \"prompt\": \"단위 테스트가 실행되고 통과했는지 확인하세요.\",\n \"model\": \"claude-haiku-4-5\",\n \"timeout\": 120\n}\n```\n\n**HTTP 엔드포인트:**\n```json\n{\n \"type\": \"http\",\n \"url\": \"https://my-server.example.com/hook\",\n \"headers\": {\n \"Authorization\": \"Bearer $MY_TOKEN\"\n },\n \"allowedEnvVars\": [\"MY_TOKEN\"],\n \"timeout\": 10\n}\n```\n\n## 기본 훅 입력\n\n모든 훅이 stdin에서 받는 공통 필드:\n\n| 필드 | 타입 | 설명 |\n|------|------|------|\n| `hook_event_name` | `string` | 발생한 이벤트 (예: `\"PreToolUse\"`) |\n| `session_id` | `string` | 현재 세션 식별자 |\n| `transcript_path` | `string` | 세션 JSONL 트랜스크립트 파일의 절대 경로 |\n| `cwd` | `string` | 훅 발생 시점의 현재 작업 디렉토리 |\n| `permission_mode` | `string` | 활성 권한 모드 |\n| `agent_id` | `string` | 서브에이전트에서 발생 시 식별자 |\n\n## 동기 훅 출력 (stdout의 JSON)\n\n블로킹 훅의 경우 종료 전에 JSON을 stdout에 씁니다:\n\n```json\n{\n \"continue\": true,\n \"suppressOutput\": false,\n \"decision\": \"approve\",\n \"reason\": \"커맨드가 안전합니다\",\n \"systemMessage\": \"훅이 이 작업을 승인했습니다.\",\n \"hookSpecificOutput\": {\n \"hookEventName\": \"PreToolUse\",\n \"permissionDecision\": \"allow\"\n }\n}\n```\n\n## 훅 이벤트 상세\n\n### `PreToolUse`\n도구가 실행되기 직전에 발생.\n\n**입력 필드:** `tool_name`, `tool_input`, `tool_use_id`\n\n**종료 코드:**\n| 코드 | 효과 |\n|------|------|\n| `0` | stdout/stderr 표시 안 됨. 훅 출력 JSON 적용 |\n| `2` | stderr를 Claude에게 표시; 도구 호출 **차단** |\n| 기타 | stderr를 사용자에게만 표시; 도구 호출 계속 |\n\n**`hookSpecificOutput` 필드:**\n- `permissionDecision`: `'allow'` | `'deny'` | `'ask'` — 권한 결정 재정의\n- `updatedInput`: 도구가 받을 교체 입력\n- `additionalContext`: 이 턴의 Claude 컨텍스트에 주입될 텍스트\n\n---\n\n### `PostToolUse`\n도구가 성공적으로 완료된 후 발생.\n\n**입력 필드:** `tool_name`, `tool_input`, `tool_response`, `tool_use_id`\n\n**종료 코드:**\n| 코드 | 효과 |\n|------|------|\n| `0` | stdout이 트랜스크립트 모드에 표시 (Ctrl+O) |\n| `2` | stderr를 즉시 Claude에게 시스템 메시지로 표시 |\n| 기타 | stderr를 사용자에게만 표시 |\n\n---\n\n### `Stop`\nClaude가 응답을 종료하기 직전에 발생.\n\n**입력 필드:** `stop_hook_active`, `last_assistant_message`\n\n**종료 코드:**\n| 코드 | 효과 |\n|------|------|\n| `0` | stdout/stderr 표시 안 됨 |\n| `2` | stderr를 시스템 메시지로 주입; Claude **대화 계속** |\n| 기타 | stderr를 사용자에게만 표시; Claude 중지 |\n\n> 💡 Stop 훅의 종료코드 2를 사용해 Claude 출력을 확인하고 조건이 충족되지 않으면 대화를 계속하게 합니다 — 예를 들어 테스트가 여전히 실패하는 경우.\n\n---\n\n### `SessionStart`\n세션 시작 시 발생. 초기 컨텍스트 주입이나 환경 설정에 사용.\n\n**입력 필드:** `source` (`'startup'` | `'resume'` | `'clear'` | `'compact'`), `model`\n\n**`hookSpecificOutput` 필드:**\n- `additionalContext`: 세션 시스템 프롬프트에 주입될 컨텍스트\n- `initialUserMessage`: 세션의 첫 사용자 메시지로 자동 제출\n- `watchPaths`: `FileChanged` 감시기에 등록할 절대 파일 경로\n\n---\n\n### `UserPromptSubmit`\n사용자가 프롬프트를 제출할 때 발생.\n\n**입력 필드:** `prompt`\n\n**종료 코드:**\n| 코드 | 효과 |\n|------|------|\n| `0` | stdout이 Claude에게 추가 컨텍스트로 표시 |\n| `2` | 처리 **차단**; 원본 프롬프트 지워짐; stderr를 사용자에게 표시 |\n| 기타 | stderr를 사용자에게만 표시 |\n\n---\n\n### `PermissionRequest`\n권한 다이얼로그가 표시될 때 발생. UI 없이 프로그래밍 방식으로 승인/거부 가능.\n\n**종료 코드:**\n| 코드 | 효과 |\n|------|------|\n| `0` | `hookSpecificOutput.decision`이 설정된 경우 훅 결정 적용 |\n| 기타 | stderr를 사용자에게 표시; 일반 다이얼로그로 폴백 |\n\n---\n\n### `CwdChanged`\n작업 디렉토리 변경 후 발생.\n\n**입력 필드:** `old_cwd`, `new_cwd`\n\n`CLAUDE_ENV_FILE` 환경 변수가 설정됨 — 환경 변수를 `export KEY=value` 줄로 써서 이후 Bash 도구 호출에 적용합니다.\n\n---\n\n### `FileChanged`\n감시 중인 파일이 수정, 추가, 제거될 때 발생.\n\n**입력 필드:** `file_path`, `event` (`'change'` | `'add'` | `'unlink'`)\n\n---\n\n## 비동기 훅\n\n백그라운드에서 실행되는 훅은 일반 동기 출력 대신 비동기 확인을 stdout에 출력합니다:\n\n```json\n{\n \"async\": true,\n \"asyncTimeout\": 30\n}\n```\n\n> ⚠️ 비동기 훅은 도구 실행을 차단하거나 컨텍스트를 주입할 수 없습니다. 에이전틱 루프를 느리게 하면 안 되는 알림, 로깅, 메트릭 같은 부작용에 사용하세요.\n"},{"index":21,"id":"section-21-20-sdk개요","fileName":"20_SDK개요.md","title":"SDK 개요","markdown":"# SDK 개요\n\n> stdin/stdout 제어 프로토콜을 사용해 자체 도구에 Claude Code를 임베드하는 방법. SDK 세션 API, 메시지 타입, 출력 형식에 대한 레퍼런스.\n\nClaude Code SDK는 다른 애플리케이션에 Claude Code를 임베드하기 위한 제어 프로토콜입니다 — IDE, 자동화 스크립트, CI/CD 파이프라인, 또는 서브프로세스를 스폰하고 stdin/stdout으로 통신할 수 있는 모든 호스트.\n\n라이브러리 API를 직접 노출하는 대신, 구조화된 JSON 메시지 스트림을 통해 실행 중인 `claude` 프로세스와 통신합니다. 호스트 프로세스가 사용자 메시지와 제어 요청을 전송하면 CLI 프로세스가 어시스턴트 메시지, 도구 진행 이벤트, 결과 페이로드를 스트리밍합니다.\n\n## 작동 방식\n\n1. **Claude Code 프로세스 스폰** — `--output-format stream-json`과 `--print`로 시작 (비대화형 모드). stdin과 stdout을 호스트 프로세스로 파이핑.\n\n```bash\nclaude --output-format stream-json --print --verbose\n```\n\n여러 프롬프트를 받는 영속 세션은 `--print`를 생략하고 세션 초기화 후 stdin에 `SDKUserMessage` 객체를 전송합니다.\n\n2. **초기화 요청 전송** — stdin에 `control_request` (`subtype: \"initialize\"`) 작성. CLI가 `SDKControlInitializeResponse`로 응답합니다.\n\n3. **stdout에서 메시지 스트리밍** — stdout에서 줄바꿈으로 구분된 JSON 읽기. 각 줄이 `SDKMessage` 유니온 타입 중 하나입니다.\n\n4. **사용자 메시지 전송** — 대화를 계속하려면 stdin에 `SDKUserMessage` 객체 작성.\n\n## 출력 형식\n\n| 형식 | 설명 |\n|------|------|\n| `text` | 일반 텍스트 응답만. 대화형 모드의 기본값 |\n| `json` | 완료 시 작성되는 단일 JSON 객체. 일회성 스크립트에 적합 |\n| `stream-json` | 줄바꿈으로 구분된 JSON 스트림. 이벤트 발생 시 줄당 하나의 메시지. SDK 사용에 필수 |\n\n## 제어 프로토콜 메시지\n\n제어 프로토콜은 stdin/stdout에서 양방향으로 흐르는 두 가지 최상위 봉투 타입을 사용합니다.\n\n### `SDKControlRequest` (호스트 → CLI)\n\n```json\n{\n \"type\": \"control_request\",\n \"request_id\": \"<고유-문자열>\",\n \"request\": { \"subtype\": \"...\", ...페이로드 }\n}\n```\n\n### `SDKControlResponse` (CLI → 호스트)\n\n```json\n{\n \"type\": \"control_response\",\n \"response\": {\n \"subtype\": \"success\",\n \"request_id\": \"<에코된-id>\",\n \"response\": { ...페이로드 }\n }\n}\n```\n\n오류 시 `subtype`은 `\"error\"`이고 `error` 필드에 메시지가 포함됩니다.\n\n## 초기화 요청\n\n`initialize` 요청은 반드시 먼저 보내야 합니다. 세션을 설정하고 사용 가능한 기능을 반환합니다.\n\n```json\n{\n \"type\": \"control_request\",\n \"request_id\": \"init-1\",\n \"request\": {\n \"subtype\": \"initialize\",\n \"systemPrompt\": \"당신은 CI 자동화 에이전트입니다.\",\n \"appendSystemPrompt\": \"항상 테스트 커버리지를 추가하세요.\",\n \"hooks\": {\n \"PreToolUse\": [\n {\n \"matcher\": \"Bash\",\n \"hookCallbackIds\": [\"my-hook-id\"]\n }\n ]\n },\n \"agents\": {\n \"CodeReviewer\": {\n \"description\": \"코드 품질과 보안을 검토합니다.\",\n \"prompt\": \"당신은 전문 코드 리뷰어입니다...\",\n \"model\": \"opus\"\n }\n }\n }\n}\n```\n\n### 초기화 응답\n\n```json\n{\n \"type\": \"control_response\",\n \"response\": {\n \"subtype\": \"success\",\n \"request_id\": \"init-1\",\n \"response\": {\n \"commands\": [...],\n \"agents\": [...],\n \"output_style\": \"stream-json\",\n \"models\": [...],\n \"account\": {\n \"email\": \"user@example.com\",\n \"organization\": \"Acme Corp\",\n \"apiProvider\": \"firstParty\"\n }\n }\n }\n}\n```\n\n## 사용자 메시지\n\n```json\n{\n \"type\": \"user\",\n \"message\": {\n \"role\": \"user\",\n \"content\": \"이 함수를 async/await으로 리팩터링해줘.\"\n },\n \"parent_tool_use_id\": null\n}\n```\n\n- `parent_tool_use_id`: 이 메시지가 응답하는 도구 사용 ID, 최상위 사용자 메시지는 `null`\n- `priority`: `'now'` | `'next'` | `'later'` — 비동기 메시지 큐잉 스케줄링 힌트\n\n## SDK 메시지 스트림 타입\n\n| 타입 | 설명 |\n|------|------|\n| `system` (`subtype: \"init\"`) | 세션 시작 시 한 번 출력. 활성 모델, 도구 목록, MCP 서버 상태, 권한 모드, 세션 ID 포함 |\n| `assistant` | 모델이 턴을 생성할 때 출력. `tool_use` 블록 포함 가능 |\n| `stream_event` | 스트리밍 중 부분 토큰 출력. 점진적 렌더링에 사용 |\n| `tool_progress` | 몇 초 이상 걸리는 도구의 주기적 상태 업데이트 |\n| `result` | 각 턴 종료 시 출력. `subtype`은 `\"success\"` 또는 오류 서브타입 |\n\n**result 예시:**\n```json\n{\n \"type\": \"result\",\n \"subtype\": \"success\",\n \"result\": \"함수가 리팩터링되었습니다.\",\n \"duration_ms\": 4200,\n \"total_cost_usd\": 0.0042,\n \"num_turns\": 3,\n \"is_error\": false,\n \"session_id\": \"abc123\"\n}\n```\n\n## 기타 제어 요청\n\n| `subtype` | 방향 | 설명 |\n|-----------|------|------|\n| `interrupt` | 호스트 → CLI | 현재 턴 중단 |\n| `set_permission_mode` | 호스트 → CLI | 활성 권한 모드 변경 |\n| `set_model` | 호스트 → CLI | 세션 중간에 모델 전환 |\n| `can_use_tool` | CLI → 호스트 | 도구 호출 권한 요청 |\n| `mcp_status` | 호스트 → CLI | MCP 서버 연결 상태 가져오기 |\n| `get_context_usage` | 호스트 → CLI | 컨텍스트 윈도우 사용량 가져오기 |\n| `rewind_files` | 호스트 → CLI | 특정 메시지 이후 파일 변경 사항 되돌리기 |\n| `hook_callback` | CLI → 호스트 | SDK에 등록된 훅 이벤트 전달 |\n\n## 세션 관리 API\n\n스크립팅 시나리오를 위해 SDK가 `~/.claude/`에 저장된 세션 트랜스크립트를 조작하는 함수를 내보냅니다:\n\n```typescript\nimport {\n query,\n listSessions,\n getSessionInfo,\n getSessionMessages,\n forkSession,\n renameSession,\n tagSession,\n} from '@anthropic-ai/claude-code'\n```\n\n**`query` — 프롬프트 실행 (주요 SDK 진입점):**\n```typescript\nfor await (const message of query({\n prompt: '이 디렉토리에 어떤 파일이 있나요?',\n options: { cwd: '/my/project' }\n})) {\n if (message.type === 'result') {\n console.log(message.result)\n }\n}\n```\n\n**`listSessions` — 저장된 세션 목록:**\n```typescript\nconst sessions = await listSessions({ dir: '/my/project', limit: 50 })\n```\n\n**`getSessionMessages` — 트랜스크립트 읽기:**\n```typescript\nconst messages = await getSessionMessages(sessionId, {\n dir: '/my/project',\n includeSystemMessages: false,\n})\n```\n\n**`forkSession` — 대화 분기:**\n```typescript\nconst { sessionId: newId } = await forkSession(originalSessionId, {\n upToMessageId: 'msg-uuid',\n title: '실험적 분기',\n})\n```\n\n## 사용 사례\n\n**IDE 통합:** IDE가 영속 Claude Code 프로세스를 스폰하고 제어 프로토콜을 통해 메시지를 라우팅합니다. `PreToolUse` 훅 콜백으로 파일 편집을 가로채 적용 전에 IDE 네이티브 UI에 diff를 표시합니다.\n\n**CI/CD 자동화:**\n```bash\nresult=$(echo \"diff를 검토하고 pass/fail을 출력해줘\" | \\\n claude --output-format json --print \\\n --permission-mode bypassPermissions)\n```\n\n**헤드리스 에이전트:** TypeScript SDK에서 스트리밍 출력 형식으로 `query()`를 사용합니다. 지속 데몬 프로세스를 유지하면서 크론 스케줄로 작업을 실행합니다.\n"}];
const tocGrid = document.getElementById("toc-grid");
const sectionsRoot = document.getElementById("sections");
const floatingToc = document.getElementById("floating-toc");
const tocLinks = [];
marked.setOptions({
gfm: true,
breaks: false,
headerIds: false,
mangle: false
});
const renderer = new marked.Renderer();
renderer.link = ({ href, title, tokens }) => {
const text = marked.Parser.parseInline(tokens);
const safeHref = href || "#";
const safeTitle = title ? ` title="${String(title).replace(/"/g, "&quot;")}"` : "";
const external = /^https?:/i.test(safeHref);
const attrs = external ? ' target="_blank" rel="noreferrer noopener"' : "";
return `<a href="${safeHref}"${safeTitle}${attrs}>${text}</a>`;
};
sections.forEach((section, index) => {
const chapter = String(index + 1).padStart(2, "0");
const tocLink = document.createElement("a");
tocLink.className = "toc-link";
tocLink.href = "#" + section.id;
tocLink.dataset.target = section.id;
tocLink.innerHTML = `
<strong>DOC ${chapter}</strong>
<span>${section.title}</span>
`;
tocGrid.appendChild(tocLink);
tocLinks.push(tocLink);
const wrapper = document.createElement("section");
wrapper.className = "doc-section";
wrapper.id = section.id;
const top = document.createElement("div");
top.className = "section-top";
top.innerHTML = `
<div class="section-badge">
<strong>DOC ${chapter}</strong>
<span>${section.fileName}</span>
</div>
<a class="back-link" href="#toc">목차로 돌아가기</a>
`;
const body = document.createElement("article");
body.className = "doc-body";
body.innerHTML = marked.parse(section.markdown, { renderer });
wrapper.appendChild(top);
wrapper.appendChild(body);
sectionsRoot.appendChild(wrapper);
});
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
const currentId = entry.target.id;
tocLinks.forEach((link) => {
link.classList.toggle("active", link.dataset.target === currentId);
});
});
},
{
rootMargin: "-24% 0px -58% 0px",
threshold: 0.12
}
);
document.querySelectorAll(".doc-section").forEach((section) => observer.observe(section));
function toggleFloatingToc() {
if (window.scrollY > 360) {
floatingToc.classList.add("visible");
} else {
floatingToc.classList.remove("visible");
}
}
toggleFloatingToc();
window.addEventListener("scroll", toggleFloatingToc, { passive: true });
</script>
</body>
</html>