byteforce

CPN 한국어 자습서 · Claude Code in Action

2 · 직접 해보기

커스텀 명령

Custom commands

Claude Code에서 / 를 입력하면 기본 명령들이 뜹니다. 여기에 직접 만든 명령을 더할 수 있습니다. .claude/commands/ 폴더에 <이름>.md 파일을 두면 그 파일 이름이 곧 /이름 명령이 되고, $ARGUMENTS 자리표시자로 인자까지 받을 수 있습니다.

전체 내레이션영상 나레이션 한국어 번역 (전체)

Stephen Grider · Anthropic 기술 스태프

Claude Code를 실행하고 슬래시(/)를 입력하면 Claude Code에 기본으로 들어 있는 여러 명령이 보입니다. 이 기본 명령들에 더해, 직접 만든 커스텀 명령도 손쉽게 추가할 수 있습니다. 커스텀 명령은 자주 반복하게 되는 작업을 자동화하는 데 유용합니다. 만드는 법을 예로 보여 드리죠.

프로젝트 디렉터리 안에서 .claude 폴더를 찾습니다. 그 안에 commands라는 새 디렉터리를 만들고, 다시 그 안에 audit.md라는 새 파일을 만듭니다. 우리가 만드는 파일 이름 — 여기서는 audit — 이 곧 나중에 실행할 명령의 이름이 됩니다.

이 명령의 목표는 이 프로젝트에 설치된 여러 의존성을 점검(audit)하고, 취약점이 있으면 업데이트한 뒤, 테스트를 돌려 아무것도 깨지지 않았는지 확인하는 것입니다.

명령 파일을 만들었으면 Claude Code를 재시작합니다. 재시작을 잊지 마세요. 다시 열고 /audit을 입력하면 방금 만든 명령이 표시됩니다. 이걸 실행하면 우리가 시킨 그대로 합니다 — 명령을 돌려 취약한 패키지가 있는지 보고, 필요하면 고치고, 테스트를 실행합니다.

명령은 인자도 받을 수 있습니다. 예를 들어 보죠. write-test라는 또 다른 명령을 만듭니다. 이 명령을 실행할 때마다, 프로젝트 안의 아주 특정한 파일에 대한 테스트를 만들고 싶습니다. 명령 텍스트 안에 $ARGUMENTS라는 자리표시자를 넣습니다. 명령을 실행할 때 파일 경로를 넘기면, 그 경로가 $ARGUMENTS 자리에 끼워집니다.

이제 Claude Code를 다시 재시작하고 write-test 명령을 실행할 수 있습니다. 분명히 해 두자면, 넘기는 인자가 꼭 파일 경로일 필요는 없습니다. 원하는 어떤 문자열이든 넘길 수 있습니다. 그래서 어떤 특정 폴더의 파일에 대한 테스트를 가볍게 요청하면서, Claude에게 어디를 봐야 할지 약간의 방향만 줄 수도 있습니다.

이 장에서 배우는 것What you'll learn

약 1분
1

/ 를 누르면 보이는 기본 명령에 내 명령을 더한다

2

.claude/commands/<이름>.md파일 이름이 곧 명령 이름

3

예) audit.md — 의존성 점검 → 취약점 수정 → 테스트

4

명령 파일을 만들면 Claude Code 재시작이 필수

5

$ARGUMENTS 자리표시자로 인자를 받는다

6

인자는 파일 경로뿐 아니라 임의의 문자열도 가능

먼저 짚고 갈 용어
커스텀 명령(custom command)
자주 반복하는 작업을 한 줄로 자동화하는 사용자 정의 슬래시 명령.
.claude/commands/
프로젝트 안에서 커스텀 명령 파일들을 두는 폴더. 없으면 직접 만든다.
<이름>.md
명령 본문을 담는 마크다운 파일. 파일 이름이 그대로 명령 이름이 된다.
재시작
명령 파일을 추가·수정한 뒤에는 Claude Code를 다시 실행해야 인식된다.
$ARGUMENTS
명령에 넘긴 인자가 끼워지는 자리표시자. 파일 경로든 임의 문자열이든 가능.

기본 명령에 내 명령을 더한다

Add your own slash command

Claude Code에서 / 를 누르면 기본 명령 목록이 뜹니다. 여기에 직접 만든 명령을 더할 수 있습니다. 자주 반복하는 작업 — 예컨대 의존성 점검 — 을 한 번에 돌리고 싶을 때 제격입니다. 만드는 자리는 프로젝트 안의 .claude/commands/ 폴더입니다.

명령 실험실 · 파일을 골라 보세요

프로젝트 구조

my-app/   .claude/     commands/       audit.md       write-test.md   src/

명령 실행

파일 이름이 곧 명령 이름입니다. $ARGUMENTS 가 든 명령은 실행할 때 넘긴 값이 그 자리에 끼워집니다 — 파일 경로든, 그냥 던지는 한 문장이든 됩니다.

파일 하나로 명령 만들기

audit.md → /audit

.claude/commands/ 안에 audit.md 를 만들면, 그 파일 이름이 곧 명령 이름(/audit)이 됩니다. 파일 본문에는 Claude가 할 일을 평범한 말로 적습니다.

.claude/commands/audit.md
# /audit 을 실행하면 Claude 가 이 내용을 그대로 수행합니다.
이 프로젝트에 설치된 의존성을 모두 점검하세요.
취약점이 있으면 해당 패키지를 업데이트하고,
마지막으로 테스트를 실행해 아무것도 깨지지 않았는지 확인하세요.
잊지 말 것 · 재시작

명령 파일을 만들었으면 Claude Code를 재시작해야 인식됩니다. 다시 열고 /audit 을 입력하면 방금 만든 명령이 보이고, 실행하면 의존성 점검 → 취약점 수정 → 테스트까지 진행합니다.

인자를 받는 명령

$ARGUMENTS

명령은 인자도 받습니다. 본문에 $ARGUMENTS 자리표시자를 넣어 두면, 명령을 실행할 때 넘긴 값이 그 자리에 끼워집니다.

.claude/commands/write-test.md
# /write-test <값> 으로 실행하면 넘긴 값이 $ARGUMENTS 에 들어갑니다.
$ARGUMENTS 에 해당하는 파일에 대한 테스트를 작성하세요.
엣지 케이스를 포함하고, 작성 후 테스트를 실행해 통과를 확인하세요.

재시작한 뒤 인자를 붙여 실행합니다. 인자는 파일 경로일 필요가 없습니다 — 임의의 문자열이면 됩니다.

Claude Code · 인자를 넘겨 실행
> /write-test src/auth.ts          # 경로를 넘기면 그 파일을 테스트
> /write-test payments 폴더의 환불 로직   # 그냥 문장으로 방향만 줘도 됨

정리 & 점검

Recap & check
핵심 정리
  • .claude/commands/<이름>.md 를 만들면 파일 이름이 곧 /명령.
  • 본문에는 Claude가 할 일을 평범한 말로 적는다(예: 점검 → 수정 → 테스트).
  • 파일을 만들거나 고친 뒤에는 Claude Code 재시작이 필수.
  • $ARGUMENTS 로 인자를 받고, 인자는 임의 문자열도 가능.

Q1커스텀 명령 /audit 을 만들려면 어떤 파일을 두나요?

Q2명령 파일을 새로 만든 직후 해야 할 일은?

Q3$ARGUMENTS 에 대한 설명으로 옳은 것은?


LAB · 실습 콘솔SLASH COMMAND · $ARGUMENTS

커스텀 명령 확장기

명령 파일 하나가 어떻게 슬래시 명령이 되고, 실행할 때 넘긴 인자가 $ARGUMENTS 자리에 끼워지는지 직접 확인합니다.

index.js
// 커스텀 명령 확장기 — .claude/commands/<이름>.md 파일 하나가 곧 /이름 슬래시 명령이 된다.
// 실행할 때 넘긴 인자는 본문의 $ARGUMENTS 자리표시자에 그대로 끼워진다.

// 파일 경로에서 명령 이름을 뽑는다: .claude/commands/audit.md → /audit
function commandName(path) {
  const file = path.split("/").pop();       // audit.md
  return "/" + file.replace(/\.md$/, "");   // /audit
}

// 본문의 $ARGUMENTS 를 넘긴 인자로 치환해, Claude가 받을 최종 프롬프트를 만든다.
function expand(body, args) {
  const usesArgs = body.indexOf("$ARGUMENTS") >= 0;
  return { prompt: body.split("$ARGUMENTS").join(args || ""), usesArgs: usesArgs };
}

// ── 여기서부터 직접 고쳐 보세요 ──
// .claude/commands/ 아래에 둔 명령 파일들(경로 → 본문).
const files = {
  ".claude/commands/audit.md":
    "의존성을 점검하고, 취약점이 있으면 업데이트한 뒤, 테스트를 실행해 확인하세요.",
  ".claude/commands/write-test.md":
    "다음 대상에 대한 단위 테스트를 작성하세요: $ARGUMENTS\n엣지 케이스를 포함하고, 작성 후 테스트를 돌려 통과를 확인하세요.",
};

// 실행할 명령과 인자(인자는 파일 경로든 그냥 문장이든 됩니다).
const runs = [
  { cmd: "/audit", args: "" },
  { cmd: "/write-test", args: "src/auth.ts" },
  { cmd: "/write-test", args: "payments 폴더의 환불 로직" },
  { cmd: "/deploy", args: "" },   // 파일 없음 — 등록되지 않은 명령
];

// 파일 목록으로 명령 등록부를 만든다(파일 이름이 곧 명령 이름).
const registry = {};
Object.keys(files).forEach(function (path) { registry[commandName(path)] = files[path]; });
console.log("등록된 명령: " + Object.keys(registry).join(" · "));
console.log("");

runs.forEach(function (run) {
  const body = registry[run.cmd];
  if (!body) {
    console.log(run.cmd + " → 그런 명령이 없습니다(파일이 없거나 재시작 전).\n");
    return;
  }
  const r = expand(body, run.args);
  const note = r.usesArgs
    ? (run.args ? "인자 \"" + run.args + "\" 끼움" : "$ARGUMENTS 있으나 인자 없음 → 빈 값")
    : "인자 없이 실행";
  console.log(run.cmd + (run.args ? " " + run.args : "") + "  [" + note + "]");
  console.log("Claude가 받는 프롬프트 ↓");
  r.prompt.split("\n").forEach(function (line) { console.log("  " + line); });
  console.log("");
});
MEMBER SESSION REQUIRED · REGISTRATION IS FREE

여기부터는 등록한 분에게 열립니다.

전 코스는 계속 무료입니다. 등록하면 이 코스의 남은 16개 레슨을 끝까지 읽을 수 있습니다.

등록하고 이어서 읽기

이미 등록하셨다면 그때 쓰신 이메일을 넣어 주세요.