Claude Code 스킬의 reference.md와 스크립트가 실제로 로드되는 경우 (‘실행되었으나 로드되지 않은’ 스크립트는 16회 중
요약
본 기사는 Claude Code 스킬의 파일 로딩 및 실행 방식에 대한 심층 분석입니다. 특히 `reference.md`와 같은 대용량 지원 파일이 실제로 컨텍스트에 로드되는지, 그리고 스크립트가 '실행되었으나 로드되지 않았다'는 문서화된 약속을 따르는지를 20회 테스트를 통해 검증했습니다.
핵심 포인트
- 대용량 `reference.md` 파일은 요청과 호출 메시지에 관계없이 토큰 크기가 일정하게 유지됨.
- 모델은 `SKILL.md`에 언급되지 않은 파일을 찾거나 읽는 경향을 보임.
- 스크립트의 소스 코드는 모델이 실행할 때 컨텍스트에서 제외되는지 명확히 확인해야 함.
16개의 Claude Code 실행 중 스킬의 번들링된 scripts/check-entry.sh를 실행한 13건은 해당 스크립트의 소스 코드를 컨텍스트에 로드했습니다(Read 또는 cat 사용). 비록 스킬 문서에서는 그러한 스크립트를 "실행되었을 뿐, 로드되지는 않았다"고 명시하고 있음에도 불구하고 말입니다. 나머지 내용은 20회의 claude -p 실행 전반에 걸쳐 Claude Code 2.1.285에서 문서화된 바와 같습니다: reference.md는 첫 번째 요청과 호출 메시지 모두에 포함되지 않았으며, 파일 내용이 1,182자이든 25,405자이든 토큰 크기는 동일했습니다. 그리고 모델은 SKILL.md가 해당 파일을 가리킨 16회 중 16회에서 이를 읽었으며, 그렇지 않은 4회에서는 전혀 읽지 않았습니다.
스킬이 반드시 하나의 파일일 필요는 없습니다. Claude Code 문서는 SKILL.md를 간결하게 유지하고 세부 사항은 reference.md로, 예시는 개별 파일로, 반복 가능한 로직은 scripts/ 디렉터리로 분리할 것을 제안합니다. 그들이 설명하는 방식은 추가 파일들은 필요할 때까지 비용이 들지 않으며, 스크립트는 읽히는 것이 아니라 실행된다는 것입니다. 이처럼 스킬을 분리하기 전에, 저는 그 설명 방식을 문자 그대로 얼마나 받아들여야 하는지 알고 싶었습니다. 세 가지 질문이 이를 결정합니다. 대용량 번들 파일은 모델이 읽기 전까지 비용이 발생하나요? 모델은 SKILL.md에 언급되지 않은 파일을 찾을 수 있나요? 그리고 스크립트의 소스 코드는 모델이 실행할 때 모델의 컨텍스트에서 제외되나요?
그래서 저는 세 개의 지원 파일을 가진 작은 스킬 하나를 만들고, 각 파일에 다른 곳에는 존재하지 않는 마커 문자열을 넣은 뒤, SKILL.md에서 해당 파일들을 가리키는 네 가지 방식과 함께 이 스킬을 20회 동안 claude -p로 실행했습니다. 모델의 최종 답변은 그것이 읽어낸 내용 중 일부를 보여줍니다. ~/.claude/projects/ 아래의 세션 기록에는 모든 내용이 담겨 있으며, 요청별 토큰 카운트도 함께 제공됩니다. 그리고 아래에 있는 모든 숫자는 해당 기록에서 가져온 것입니다.
모든 실행은 2026-09-30에 Claude Code 2.1.285 (claude --version)로 이루어졌습니다. 18개는 --model opus를 사용했으며, 이는 claude-opus-5-5로 해결되었고, 2개는 --model sonnet을 사용하여 claude-sonnet-5-5로 해결되었습니다. 문서 인용구는 Claude Code skills 페이지(https://code.claude.com/docs/en/skills.md)와 platform.claude.com의 두 Agent Skills 페이지에서 가져왔으며, 모두 같은 날짜에 trafilatura를 사용하여 가져온 것입니다.
문서가 약속하는 것
Claude Code skills 페이지는 "지원 파일 추가(Add supporting files)"라는 짧은 섹션에서 이 내용을 다루고 있습니다:
스킬에는 디렉터리에 여러 파일을 포함할 수 있습니다. 이렇게 하면
SKILL.md가 필수적인 내용에 초점을 맞추면서, Claude가 필요할 때만 상세한 참고 자료에 접근하도록 할 수 있습니다. 대규모 참고 문서(reference docs), API 사양 또는 예제 모음은 스킬이 실행될 때마다 컨텍스트(context)로 로드될 필요가 없습니다.
다음으로 파일별 레이블이 지정된 디렉터리 트리가 이어집니다. reference.md와 examples.md는 "필요할 때 로드됩니다(loaded when needed)". 스크립트는 다른 레이블을 받습니다:
그런 다음 페이지는 파일을 연결하는 방법을 설명합니다: "Claude가 각 파일이 무엇을 포함하고 언제 로드해야 하는지 알 수 있도록 SKILL.md에서 지원 파일을 참조하십시오(Reference supporting files from SKILL.md)". 그 예시는 두 개의 마크다운 링크가 있는 "추가 자료(Additional resources)" 섹션이며, 각각 완전한 API 세부 정보는 [reference.md](reference.md)를 참조하십시오와 사용 사례 예시는 [examples.md](examples.md)를 참조하십시오입니다.
같은 페이지에서는 Claude Code 스킬이 'Agent Skills 오픈 표준을 따른다'고 언급하며, platform.claude.com의 Agent Skills 개요는 스크립트에 대해 더 직설적입니다. "지침에 실행 가능한 스크립트가 언급될 경우, Claude는 이를 bash를 통해 실행하고 출력(스크립트 코드 자체는 컨텍스트에 절대 들어가지 않음)만 받습니다." Agent Skills 모범 사례 페이지에서는 유틸리티 스크립트의 이점 중 하나로 "토큰 절약 (컨텍스트에 코드를 포함할 필요 없음)"을 나열하며, 스킬 작성자들에게 지침에서 Claude가 스크립트를 실행해야 하는지 명확히 할 것을 요청합니다. 예시로는 "필드 추출을 위해 analyze_form.py를 실행하라"와 같이 실행하도록 요구하거나, 참고 자료로 읽도록 요구하는 방식이 있습니다.
실험실 (The lab)
이 스킬은 changelog-entry라고 불리며 임시 프로젝트의 .claude/skills/changelog-entry/ 폴더에 존재합니다. 이 스킬 외에도, 해당 프로젝트는 README와 disableBundledSkills를 true로 설정하는 .claude/settings.json을 포함하고 있어 스킬 목록에는 정확히 하나의 항목만 있었습니다. 프런트매터(frontmatter)에는 이름(name)과 한 문장의 설명(description)만 있습니다. 본문은 세 가지 규칙을 제시합니다: [parser]와 같은 영역 태그로 시작하는 과거 시제 글머리 기호를 작성하고, 끝에 엔트리 코드인 (BODY-M3V8)를 붙이며, 파일을 생성하거나 편집하지 말라는 것입니다.
각 지원 파일은 자체 마커를 가지고 있으며, 파일을 사용하면 답변이 보이는 방식으로 변경됩니다:
| 파일 | 크기 | 마커 | 항목에 추가하는 내용 |
|---|---|---|---|
SKILL.md | 12~18줄 | BODY-M3V8 | 엔트리 코드 |
| ... | |||
reference.md는 두 번째 코드를 언급하며 "릴리스 스크립트는 트레인 태그를 포함하지 않는 모든 글머리 기호를 거부한다"고 말합니다. 이 스크립트가 테스트를 작동하게 만듭니다. 그 소스에는 주석 # Source marker: SRC-W5N3이 포함되어 있으며, 런타임에 printf 'RUN-%s%s' 'H8' 'T6'을 사용하여 출력 마커를 생성하므로, 문자열 RUN-H8T6은 오직 그 출력에서만 존재합니다. SRC-W5N3이 기록(transcript)에 나타나면 스크립트의 소스가 모델에 도달했다는 의미입니다. RUN-H8T6이 나타나면 스크립트가 실행되었다는 의미입니다. 이 둘은 서로 없이도 발생할 수 있습니다. |
변했던 것은 SKILL.md가 파일들을 참조하는 방식이었습니다:
- link, 문서 자체의 패턴: '추가 자료(Additional resources)' 섹션에
완벽한 서식 규칙은 [reference.md](reference.md)를 참조하십시오,완성된 항목을 보려면 [examples/sample-entry.md](examples/sample-entry.md)를 참조하십시오및답변하기 전에 항목을 확인하려면, [scripts/check-entry.sh](scripts/check-entry.sh)에 불릿(bullet)만 인수로 사용하여 실행하십시오와 같은 내용이 포함됩니다. - must, 링크가 없는 번호 순서: '무엇을 작성하기 전에, 이 스킬 디렉토리의 reference.md를 읽어야 합니다', '또한 이 스킬 디렉토리의 examples/sample-entry.md도 읽어야 합니다', 그리고 '초안 작성이 끝난 후에는, 이 스킬 디렉토리에서 scripts/check-entry.sh를 불릿(bullet)만 인수로 사용하여 실행하고 출력되는 내용을 따라야 합니다.'와 같은 내용입니다.
- none:
SKILL.md에 언급되지 않은 디스크상의 동일한 세 파일입니다. - at: 첫 두 링크 대신
@reference.md및@${CLAUDE_SKILL_DIR}/examples/sample-entry.md를 사용합니다.
두 프롬프트 모두 스킬을 명시했기 때문에 모델이 스스로 이를 선택할지 여부는 테스트의 일부가 아니었습니다(별도 기사에서 측정했습니다). 첫 번째 프롬프트는 '입력 파일이 비어 있을 때 파서가 더 이상 충돌하지 않는다'는 항목에 대한 내용을 요청했습니다. 두 번째 프롬프트는 --config의 깨지는 변경 사항(breaking change)을 설명했으며, 이는 reference.md에서 BREAKING: 규칙을 발동시켜야 합니다.
총 20회의 실행: 각 프롬프트별로 link, must, none을 각각 두 번씩 (12회); 첫 번째 프롬프트와 300줄의 부록으로 25,405자로 패딩된 reference.md를 사용한 must (2회); at (2회); 프로젝트 루트에 미끼(decoy)로 관련 없는 reference.md를 배치한 at (2회); 그리고 Sonnet 모델을 사용한 첫 번째 프롬프트와 link (2회). 모든 실행은 프로젝트 루트에서 다음 명령줄을 사용했으며, Sonnet 쌍의 경우 --model sonnet이 추가되었습니다:
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 claude -p "$PROMPT"
--output-format stream-json --verbose --model opus
--permission-mode default --allowedTools "Bash" --max-turns 10
...
--allowedTools "Bash"는 권한 요청 프롬프트에서 실행이 중단되는 일이 없도록 미리 승인된 셸 명령어입니다. 총 20회 실행 모두 subtype: success로 끝났으며, 권한 거부나 실패한 도구 호출은 없었습니다. 이 모든 것을 합쳐 $1.12가 소요되었습니다.
스킬 실행 전: 설명(description)만 있고 그 외는 없음
지원 파일이 '매번' 비용을 발생시킨다면, 세션의 첫 번째 요청에 나타날 것이므로 저는 변형별로 해당 요청을 비교했습니다. 첫 프롬프트를 보낸 12개의 Opus 실행은 입력, 캐시 읽기 및 캐시 쓰기를 계산하여 정확히 19,152 토큰의 첫 요청을 보냈습니다. 이 12개 실행에는 543바이트에서 936바이트 사이의 네 개의 SKILL.md 파일, 1,182바이트와 25,405문자 크기의 reference.md, 그리고 프로젝트 루트에 있는 더미(decoy) 파일이 포함되었습니다. 두 번째 프롬프트를 보낸 6개의 Opus 실행은 모두 19,173 토큰을 전송했고, 두 Sonnet 실행은 각각 19,158토큰을 전송했습니다. 본문이나 지원 파일 중 어느 것도 카운트를 단 하나의 토큰도 움직이지 않았습니다.
전사 기록(transcripts) 역시 일치합니다. 제가 프롬프트에 이름을 붙인 것을 제외하고, 첫 응답 전에 스킬의 유일한 흔적은 내용이 한 줄인 skill_listing 첨부 파일입니다: "- changelog-entry: 이 저장소의 코드 변경 사항에 대한 변경 로그 항목을 작성합니다. 사용자가 변경 로그 항목, 릴리스 노트 라인 또는 CHANGELOG 업데이트를 요청할 때 사용합니다." 20개 전사 기록 중 어느 곳에서도 첫 응답 전에 어떤 마커도 나타나지 않았습니다. 문서에도 그렇게 명시되어 있습니다: "CLAUDE.md 내용과 달리, 스킬의 본문은 사용될 때만 로드되므로, 장문의 참고 자료는 필요할 때까지 거의 비용이 들지 않습니다."
스킬 실행 시: 본문(body)에 더해 문서에서 보여주지 않는 한 줄
20회 실행 모두에서 모델의 첫 번째 행동은 Skill 호출이었습니다. 해당 도구 결과는 한 줄인 "Launching skill: changelog-entry"였으며, Claude Code는 그 후 렌더링된 본문을 담고 메타로 표시된 단일 사용자 메시지를 추가했습니다. 프런트매터(frontmatter)는 사라졌고, 첫 번째 줄은 SKILL.md에 전혀 포함되지 않았습니다:
Base directory for this skill: /…/proj/.claude/skills/changelog-entry
# Changelog entry
...
모델이 변경 설명을 스킬의 인자(arguments)로 전달했을 때, 즉 20회 중 13회에 발생했을 때, 본문 뒤에 ARGUMENTS: … 줄이 이어졌습니다. 이는 플레이스홀더가 없는 본문에 대한 대체 방식이며, 인자 관련 문서에서 다루었습니다.
스킬 페이지에는 "Base directory" 줄이 언급되어 있지 않지만, 이 부분이 문서의 상대 링크가 작동하게 만드는 요소입니다. Read 도구 설명에는 "file_path는 절대 경로여야 한다"고 되어 있으며, 20회 실행에서 발생한 모든 33개의 Read 호출은 해당 디렉토리 아래의 절대 경로를 사용했습니다. Bash 명령어들은 프로젝트 루트에서 cd .claude/skills/changelog-entry를 사용한 경우를 제외하고는 모두 cd 또는 절대 경로를 통해 동일한 디렉토리에 도달했습니다. 이 중 어느 것도 실패하지 않았습니다.
호출(invocation) 단계는 보조 파일이 초기에 포함될 수 있는 두 번째 장소입니다. @ 라인이 없는 16회 실행에서, Skill 호출 이후의 요청은 본문의 길이와 인자 전달 여부에 따라 328토큰에서 558토큰으로 증가했습니다. 첫 프롬프트가 사용된 must runs는 인자가 있을 때 514토큰, 없을 때 452토큰만큼 증가했으며, 이는 정상적인 경우와 패딩된 reference.md를 사용하는 경우가 동일했습니다. 스킬을 호출하는 과정은 본문만 가져왔고, 문서화된 대로 보조 파일에서는 아무것도 가져오지 않았습니다.
스킬 실행 후: 모든 포인터가 추적됨
다음은 포인터 스타일에 따른 20회 실행 기록입니다. "In context"는 파일의 마커가 도구 결과나 전사(transcript)의 첨부 파일에 나타나는 것을 의미합니다.
Pointer in SKILL.md | Model | Runs | reference.md in context | example in context | script executed | script source in context |
|---|---|---|---|---|---|---|
| markdown links (docs pattern) | Opus | 4 | 4 | 4 | 4 | 4 |
| ... | ||||||
The must row에는 두 개의 패딩된 실행(padded runs)이 포함되어 있습니다. 어떤 포인터에 대해서든, reference.md와 예제는 호출 직후의 첫 단계에서 16회 중 16회 모델에 도달했습니다. 이는 병렬 Read 호출로, 여러 파일의 하나의 cat으로, 또는 세 번 실행된 예제의 경우 본문과 함께 도착하는 첨부파일 형태로 이루어졌습니다. 포인터가 없는 경우에는 4회 중 4회 아무것도 읽히지 않았습니다. none 실행은 스킬 디렉토리를 나열하지 않았고, 검색하지도 않았으며, 파일을 열지도 않았습니다. 각 실행은 본문만으로 답변이 구성된 후, 3.1초에서 3.7초 사이에 두 개의 요청을 거쳐 완료되었습니다. |
답변들은 그 가격을 보여줍니다. reference.md의 train 태그는 포인터가 있는 실행 16회 중 16회의 답변에 나타났고, none 실행 4회 중 0회에는 나타나지 않았는데, 이 none 실행 항목들은 reference.md에서 배포 스크립트가 거부할 내용이었습니다. 깨지는 --config 변경의 경우, 포인터 답변 4회 중 4회는 영역 태그 뒤에 BREAKING:을 포함했고, none 답변 2회 중 0회만 그렇게 했습니다. 네 개의 none 답변 모두 항목 코드 앞에 마침표를 찍었는데, 이는 reference.md 규칙에서 제외된 내용입니다. SKILL.md가 언급하지 않은 지원 파일은
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기