AIDive

Claude Code 프롬프트 그만 치세요: 작업 4개가 파일 4개로

AIDive · 게시

코딩 에이전트자동화와 워크플로

매번 다시 치는 프롬프트 4개가 파일 4개가 된다

Claude Code 확장은 같은 프롬프트를 다시 치지 않으려고 레포에 넣어 두는 파일입니다. skill, hook, subagent, MCP 서버, 이렇게 네 가지가 있습니다. 우리는 JSON 파일을 데이터베이스로 쓰는 작은 청구서 API라는 실제 레포 하나에서 반복되는 작업 네 개를 돌렸습니다. 작업마다 처음에는 틀린 확장을 골랐고, 틀린 선택은 매번 화면에서 실패했습니다. 그다음 각 작업을 커밋된 파일로 만들었습니다. 이 페이지는 네 가지 동작과, 어떤 종류를 쓸지 정해 주는 선택 카드를 다룹니다.

두 가지 결과가 아래 내용 전체의 바탕입니다. hook은 흔히 보장이라고 하고 메모리 파일의 규칙은 부탁이라고 합니다. 그런데 우리의 첫 hook은 실행되어 경고를 출력했는데도 쓰기가 그대로 통과했습니다. 실행되기만 하는 hook과 실제로 막는 hook의 차이는 hook 섹션에서 다룹니다. 처음 연결한 docs 서버는 아무것도 바꾸지 못했고, 실제로 답을 준 것은 도구 자체의 docs 서버였습니다. 또 대부분이 따라 하는 hook 레시피는 별도 스크립트 파일이 필요하지만, 우리 것은 전부 settings 파일 안에 들어갑니다.

네 파일 중 무엇이든 쓰기 전에, 세션이 이미 무엇을 불러오는지부터 알아야 합니다.

네 가지의 정체와 세션이 이미 불러오는 것

Claude Code 확장은 프롬프트 입력창에 같은 지시를 다시 치지 않으려고 레포에 추가하는 파일입니다. 종류는 네 가지이고, 이미 아는 분은 다음 섹션으로 넘어가도 됩니다.

  • skill은 레포에 철해 둔 실행 절차서입니다. Claude는 그 작업이 나올 때만 단계를 불러오고, 이름을 쳐서 직접 시작할 수도 있습니다.
  • hook은 git의 커밋 hook과 비슷하지만 Claude 자신의 행동을 대상으로 합니다. 편집 같은 이벤트가 일어날 때, Claude의 의도와 상관없이 실행되는 스크립트입니다.
  • subagent는 빈 책상에서 일을 시작하는 외주 담당자입니다. 브리핑을 받아 자료를 읽고, 읽은 더미 대신 보고서를 돌려줍니다.
  • MCP 서버는 Claude가 호출할 수 있는 API 클라이언트입니다. 데이터베이스나 도구의 docs처럼 디스크에 없는 데이터를 위한 것입니다.

무엇이든 측정하려면 먼저 기준선이 필요합니다. 새 세션을 열고 context 명령을 실행하세요. 첫 마디를 하기 전에 불러온 모든 것이 표로 출력됩니다. 우리 벤치에서는 1m 컨텍스트 윈도우 중 합계가 26.2k 토큰이었고, 메모리 파일 줄도 MCP 줄도 전혀 없었습니다. 이제부터 Claude에게 맡기는 모든 작업은 이 표에 줄을 하나 더하거나, 그대로 두거나 둘 중 하나입니다.

첫 번째 작업: 릴리스 체크리스트가 skill이 된다

skill은 자기 폴더에 철해 두는 체크리스트로, Claude는 부를 때만 읽습니다. 첫 번째 작업은 프롬프트 입력창에 계속 붙여 넣던 릴리스 체크리스트입니다. 타입 검사, 테스트, 버전 올리기, changelog 한 줄 추가, 커밋, 태그 순서입니다.

가장 먼저 떠오르는 자리는 메모리 파일이지만 그것은 틀린 선택입니다. 그 파일의 내용은 모든 세션의 모든 턴마다 로드되기 때문입니다. 우리는 단계를 거기에 넣고 context 표를 다시 읽었습니다. 릴리스 중이든 아니든 로드되는 210토큰짜리 Memory files 줄이 생겨 있었습니다. docs도 같은 말을 합니다. 그 파일의 한 섹션이 절차로 커졌다면 skill로 옮기라는 것입니다.

맞는 선택은 skills 디렉터리 아래 폴더 하나를 만들고 .claude/skills/release/SKILL.md에 단계를 적는 것입니다. 맨 위에 짧은 설명을 두고 frontmatter에 한 줄, disable-model-invocation: true를 추가합니다. 이 줄은 skill을 Claude 자신의 목록에서 빼서 당신만 시작할 수 있게 합니다. 커밋하고 태그를 다는 작업에는 바로 이것이 필요합니다. 그다음 슬래시와 이름을 치면 체크리스트가 실행됩니다.

context 측정값 합계 Memory files 줄
기준선, 새 세션 26.2k / 1m 없음
메모리 파일에 넣은 체크리스트 26.4k / 1m 210 토큰
skill로 만든 체크리스트 26.2k / 1m 없음, skill은 목록에 없음

실행하자 Claude는 여섯 단계를 1분도 안 되어 끝냈습니다. 타입 검사, 테스트 34개, 버전 0.4.0에서 0.4.1로 올리기, changelog 한 줄, 커밋, 태그입니다. 우리 체크리스트의 결함도 하나 잡아냈습니다. 적어 둔 대로의 커밋 명령은 추적되지 않는 파일을 건너뛰기 때문에, Claude는 새 changelog를 먼저 stage하고 그 사실을 알렸습니다. 이제 릴리스는 직접 치는 명령이 되었고, 팀 전체가 쓸 수 있도록 레포에 들어 있으며, 입력하기 전까지 컨텍스트 비용은 0입니다.

두 번째 작업: 지켜야 할 규칙이 hook이 된다

hook은 도구가 실행되기 전, 여기서는 편집이나 쓰기 직전에 Claude Code가 돌리는 스크립트이고, 그 스크립트의 응답이 다음에 일어날 일을 정합니다. 두 번째 작업은 절대 깨지면 안 되는 규칙입니다. 이 레포에서 저장 데이터 파일은 손으로 편집하지 않고, 모든 변경은 마이그레이션을 거칩니다.

이 규칙을 메모리 파일에 대문자로 적어도 강제되지는 않습니다. docs는 분명하게 말합니다. 그 파일은 컨텍스트이지 강제 설정이 아니며, "이 파일을 편집하지 마"라는 지시는 부탁이지 보장이 아닙니다. 편집을 막는 hook이야말로 강제입니다.

처음 떠올리는 hook이 우리가 처음 쓴 것입니다. settings 파일에서 데이터 파일 쓰기를 감시하고, 경고를 출력하고, 종료 코드 0으로 끝납니다. 로깅 스크립트와 같습니다. 그다음 Claude에게 마이그레이션 없이 파일에서 직접 청구서 금액을 바꾸라고 했습니다. hook은 실행되어 경고가 출력됐지만 쓰기는 통과했습니다. 세 번째 청구서의 단가가 8000에서 12000으로 바뀐 것입니다. Claude의 답변에는 hook 이야기가 한마디도 없었습니다. 깨끗하게 종료하고 아무것도 출력하지 않는 hook은 아무 결정도 내리지 않은 것이고, 그 경고는 Claude에게 닿지 않기 때문입니다.

보장은 hook이 실행되는 것이 아니라 hook이 돌려주는 응답입니다. 해결책은 같은 hook을 유지하되 deny 결정을 돌려주게 하는 것입니다. Claude가 읽게 하려는 이유를 담은 짧은 JSON 한 줄입니다. 종료 코드 2로 끝내도 똑같이 막힙니다. hook 전체는 .claude/settings.json의 인라인 명령 하나이고 스크립트 파일은 없습니다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c 'if (.tool_input.file_path // \"\") | test(\"data/.*\\\\.json$\") then {hookSpecificOutput: {hookEventName: \"PreToolUse\", permissionDecision: \"deny\", permissionDecisionReason: \"Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions).\"}} else empty end'"
          }
        ]
      }
    ]
  }
}

같은 요청에서 편집은 거부되었고 데이터 파일은 그대로였습니다. Claude가 본 오류는 다음과 같습니다. PreToolUse:Edit hook error: Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions). Claude는 아무것도 바꾸지 않았다고 말하고, 안전장치를 무시할지 마이그레이션을 쓸지 물었습니다.

한계는 Claude가 직접 짚었습니다. 이 hook은 편집과 쓰기 도구만 감시하고, 이후 실행에서 Claude는 대신 셸로 변경하겠다고 제안했습니다. hook이 셸까지 덮거나, 셸을 허용 목록에서 빼 두어야 합니다. 문 하나만 지키는 방어는 여전히 부탁이기 때문입니다. hook은 대화 바깥에서 실행되므로 컨텍스트 비용은 0입니다.

세 번째 작업: 넘쳐나는 감사가 subagent가 된다

subagent는 자기만의 빈 컨텍스트를 가진 별도의 Claude 세션입니다. 브리핑을 받아 필요한 것을 읽고, 요약만 돌려줍니다. 세 번째 작업은 대화를 넘치게 하는 감사입니다. 소스 폴더의 모든 파일을 README 규칙과 대조해서, 위반마다 파일과 줄을 나열하는 일입니다.

인라인으로 시키면 Claude는 모든 파일을 대화 안으로 읽어 들이고, 그 내용은 세션이 끝날 때까지 남습니다. 우리 실행에서 Claude는 소스 파일 19개를 모두 읽었고, context 표의 Messages 줄은 부풀었으며, 결과는 그 더미에 파묻혔습니다.

맞는 선택은 .claude/agents/ 아래 파일, 여기서는 .claude/agents/conventions-auditor.md입니다. 이름, 언제 쓰는지에 대한 설명, 쓸 수 있는 도구, 고정한 모델을 적습니다. 모델 고정이 중요한 이유는 subagent가 기본적으로 세션이 쓰는 모델을 그대로 물려받는데, 읽기 작업 대부분에는 큰 모델이 필요 없기 때문입니다.

같은 질문을 그대로 다시 했더니 Claude는 직접 파일을 읽었습니다. 두 번 모두 목록에 있었는데도 agent를 호출하지 않았습니다. 위임은 2번 중 0번이었습니다. 통한 방법은 프롬프트 맨 앞에서 이름을 부르는 것이었습니다. "use the conventions auditor subagent". 호출은 한 번 나갔고 짧은 요약이 돌아왔습니다.

실행 전체 컨텍스트 Messages 줄
인라인 감사 46.1k 19.3k
이름을 부른 subagent 34.1k 7.2k

결과의 품질도 비슷했습니다. subagent는 인라인 실행이 놓친 경로 버그를 잡았고, 인라인 실행이 찾은 버그 하나는 놓쳤습니다. 그러니 파일은 subagent를 존재하게 하고, 프롬프트는 Claude가 그것을 쓰게 합니다. Claude가 스스로 고르기 전까지는 이름을 불러야 합니다. 한계가 하나 있습니다. 비용은 줄지 않았습니다. 두 실행의 비용은 같았습니다. 읽기는 여전히 일어나고, 다만 당신의 윈도우 안에서 일어나지 않을 뿐입니다.

네 번째 작업: Claude가 닿을 수 없는 데이터가 MCP 서버가 된다

MCP 서버는 Claude가 호출할 수 있는 API 클라이언트이고, 존재 이유는 모델보다 새로운 데이터나 디스크 밖에 있는 데이터입니다. 여기서 반사적으로 고르는 선택은 틀렸고, 우리도 먼저 그것을 골랐습니다.

테스트 라이브러리용 공개 docs 서버를 연결하고 Claude에게 fake timer를 쓰는 테스트를 부탁했습니다. 아무것도 달라지지 않았습니다. Claude는 이미 그 라이브러리를 알고 있었고, 우리가 서버를 지목했을 때만 호출했습니다. 모델이 이미 아는 docs는 Claude가 닿을 수 없는 데이터가 아닙니다.

진짜 시험은 Claude Code 자체에 대한 질문, 모델보다 새로운 hook 설정에 대한 질문입니다. hook이 실패했을 때 막게 하는 설정은 무엇이고, 어느 버전에서 추가되었고, 정확한 JSON은 무엇인가. 서버가 없을 때 Claude는 설치된 버전의 설정 스키마를 읽었지만 찾지 못했고, 그 설정을 찾을 수 없으며 추측하지 않겠다고 답했습니다. 정직하지만 쓸모없는 답입니다. 그 설정은 존재하기 때문입니다. 모델의 지식 이후에 나왔을 뿐입니다.

해결책은 Claude Code 자신의 docs 서버를 레포에 추가하는 것입니다. 팀 전체가 받는 레포 루트의 파일에 설정이 들어가도록 project 범위로 추가합니다.

claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp

이 명령은 .mcp.json을 씁니다. Claude Code는 다음 세션에서 승인하기 전까지 서버를 pending으로 표시하고, 그 뒤부터 서버의 도구를 Claude가 쓸 수 있습니다. 같은 질문을 서버 이름을 말하지 않고 평범한 말로 했습니다. Claude는 docs를 검색해 페이지를 찾았고, 설정과 버전, 추가할 JSON을 링크와 함께 답했습니다.

그 설정은 "onFailure": "block"이고, 실패한 hook이 동작을 통과시키지 않고 막게 합니다. v2.1.295에서 추가되었는데, 우리 설치는 아직 2.1.294였습니다. 이것이 한계입니다. Claude는 버전을 확인하지 않았기 때문에 우리 설치에서는 쓸 수 없다고 말하지 않았습니다. 그러니 버전은 직접 확인해야 합니다. context 표에서 서버는 도구 이름만 보이는 형태로 나타나고, Claude가 하나를 쓰려 할 때까지 필요할 때 로드됩니다.

파일 네 개, 선택 카드 한 장

네 가지 작업이 끝난 뒤 git status에는 정확히 파일 네 개가 보입니다. hook에는 자체 스크립트가 필요 없기 때문입니다.

  • .claude/skills/release/SKILL.md
  • .claude/settings.json
  • .claude/agents/conventions-auditor.md
  • .mcp.json

커밋하면 이 레포에서 여는 다음 세션은 물론 클론하는 누구든 이 파일들을 모두 갖게 됩니다.

매번 선택이 옳았던 이유는 docs가 제공하는 표이고, 이것을 결정 카드로 두고 쓰면 됩니다.

상황 확장
또다시 붙여 넣는 절차 Skill
묻지 않고 매번 일어나야 하는 일 Hook
다시 볼 일 없는 출력으로 대화를 넘치게 하는 부수 작업 Subagent
Claude가 볼 수 없는 곳에서 계속 복사해 오는 데이터 MCP 서버

종류끼리 조합할 수도 있습니다. docs는 skill과 MCP 서버를 짝지어 놓았습니다. 서버가 연결을 제공하고, skill이 그것을 잘 쓰는 법을 Claude에게 가르칩니다. skill은 포크된 subagent 안에서 실행할 수도 있어서, 읽기가 당신의 윈도우 밖에 머뭅니다. 다른 레포에도 같은 구성이 필요해지면, 플러그인이 이 모두를 함께 배포하는 상자입니다.

카드는 종류를 정할 뿐 품질을 정하지는 않습니다. 기록만 하는 hook, 이름을 부르지 않은 subagent, 모델이 이미 아는 docs용 서버는 모두 올바른 종류에 있었는데도 실패했습니다. 카드에서 종류를 고른 다음, 파일이 그저 존재하는 데서 끝나지 말고 답하게 만드세요.

결론: 언제 무엇을 쓰고, 언제 쓰지 않고, 단 하나의 규칙

다시 치던 네 가지 작업은 모두 먼저 틀린 방식으로 시도되어 화면에서 실패했고, 지금은 레포 안에서 동작하는 파일입니다. 릴리스는 직접 치는 명령입니다. 데이터 규칙은 편집을 거부하고 Claude가 먼저 묻게 만드는 hook입니다. 감사는 요약으로 돌아옵니다. docs 질문은 Claude가 혼자서는 찾지 못한 설정과 버전을 받아 옵니다.

처음에 열었던 hook, 실행되었는데도 쓰기를 통과시킨 그 hook이 이 모든 것의 밑바닥에 있는 규칙을 가르쳐 줬습니다. hook은 명령이 돌려주는 것으로만 결정하므로, 기록만 하는 hook은 변장한 부탁입니다.

이 중 어느 것도 쓰지 않는 경우도 있습니다.

  • Claude가 계속 틀리는 규칙은 절차가 아니라 한 줄로 메모리 파일에 두는 것이 맞습니다.
  • 기록을 보면서 앞뒤로 방향을 잡아야 하는 작업은 subagent가 아니라 메인 스레드에 둡니다.
  • 모델이 이미 아는 라이브러리의 docs 서버는 컨텍스트만 쓰고 아무것도 바꾸지 못합니다. 모델이 가질 수 없는 것을 연결하고, 이미 가진 것은 연결하지 마세요.

기억할 규칙은 이것입니다. 다시 치는 작업마다 전용 파일을 주고, 카드에서 종류를 고르고, 그중 묻지 않는 것은 hook뿐임을 아세요.

무료 자료

  • 영상 팩

    Skill, hook, subagent, MCP: 파일 4개와 선택 카드

    Claude Code에 다시 치던 작업 네 개를 먼저 틀린 방식으로 시도하고, 복사해 쓸 수 있는 파일로 만들었습니다. 한 페이지짜리 선택 카드도 있습니다.

    읽는 데 7분 · Claude Code 프롬프트 그만 치세요: 작업 4개가 파일 4개로

출처

자주 묻는 질문

Claude Code에서 skill, hook, subagent, MCP 서버 중 무엇을 써야 하나요?
계속 붙여 넣는 절차에는 skill, 묻지 않고 매번 일어나야 하는 일에는 hook, 대화를 넘치게 하는 부수 작업에는 subagent, Claude가 볼 수 없는 데이터에는 MCP 서버를 쓰세요. docs가 이것을 결정 표로 제공합니다.
내 Claude Code hook은 실행됐는데 왜 편집을 막지 못했나요?
hook은 명령이 돌려주는 것으로만 결정합니다. 경고를 출력하고 exit code 0으로 끝나는 hook은 아무 결정도 내리지 않은 것이라 편집이 통과합니다. permissionDecision deny를 돌려주거나 exit code 2로 끝나면 막힙니다.
릴리스 체크리스트는 CLAUDE.md에 두나요, skill에 두나요?
skill에 두세요. 메모리 파일의 내용은 모든 세션의 모든 턴마다 로드됩니다(우리 6단계 체크리스트는 210토큰). 반면 disable-model-invocation을 설정한 skill은 이름을 칠 때까지 컨텍스트 비용이 없습니다.
Claude Code는 왜 내 subagent를 자동으로 호출하지 않나요?
설명이 우리 프롬프트와 거의 글자 그대로 일치했는데도 Claude는 2번 중 2번 직접 파일을 읽었습니다. 프롬프트 맨 앞에서 subagent 이름을 부르자 위임했고, Messages 줄은 19.3k에서 7.2k토큰으로 줄었습니다.
Claude Code에 MCP 서버를 추가할 가치가 있는 때는 언제인가요?
데이터가 모델보다 새롭거나 디스크 밖에 있을 때입니다. 모델이 이미 아는 라이브러리의 docs 서버는 아무것도 바꾸지 못했지만, Claude Code docs 서버는 설치된 버전의 스키마에 없던 hook 설정에 대한 질문에 답했습니다.
Claude Code docs MCP 서버를 레포에 어떻게 추가하나요?
claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp를 실행하세요. 레포 루트에 .mcp.json이 쓰이고, 다음 세션에서 승인하기 전까지 서버는 pending으로 표시됩니다.

관련 영상