! 접두사로 shell 명령을 실행해 diff, 파일 내용, 테스트 결과를 자동 주입하여 Claude에게 모호한 설명 대신 실제 정보를 전달한다
대부분의 사람들이 만드는 slash command는 이런 모양이다:
현재 변경 사항의 코드 품질을 검토하고 구체적인 제안을 해줘.
작동은 하지만 근본적인 한계가 있다: Claude가 "현재 변경 사항이 무엇인지"를 스스로 추측해야 한다. 만약 command가 능동적으로 컨텍스트를 주입할 수 있다면 결과는 완전히 달라진다.
이 글에서는 command를 "눈을 가진" 명령어로 만드는 방법을 다룬다 — 트리거 시점에 파일 내용, git 상태, 프로젝트 정보를 자동으로 읽어 프롬프트에 끼워넣고, Claude가 추측하지 않도록 만드는 것이다.
!`명령어`로 Shell 출력 주입하기커스텀 slash command는 프롬프트 안에 shell 명령어를 임베드할 수 있는데, 문법은 백틱으로 명령어를 감싸고 앞에 느낌표를 붙이는 것이다: !`명령어`. 트리거되면 명령어가 먼저 실행되고, 그 출력이 자리 표시자를 대체하며, Claude가 받는 것은 최종적으로 조립된 프롬프트다.
다음은 현재의 git diff입니다:
!`git diff HEAD`
이 변경 사항을 검토하고, 로직 오류와 보안 문제에 중점을 두세요.
여러 줄 명령어는 펜스드 코드 블록 형식으로, 시작 부분에
```!를 쓴다:```! node --version git status --short ```
/review를 트리거하면 Claude가 실제로 받는 내용은 다음과 같다:
다음은 현재의 git diff입니다:
diff --git a/app/models/user.rb b/app/models/user.rb
index 3a2f1c8..9b4e2d1 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -12,6 +12,9 @@ class User < ApplicationRecord
...
이 변경 사항을 검토하고, 로직 오류와 보안 문제에 중점을 두세요.
수동으로 복사해 붙여넣을 필요가 없다. command가 트리거되는 순간, diff는 이미 안에 들어가 있다.
---
allowed-tools: Bash(cat:*)
---
다음은 현재 파일의 전체 내용입니다:
!`cat $ARGUMENTS`
이 파일에서 잠재적인 성능 문제를 모두 찾아내고, 구체적인 줄 번호와 수정 방법을 제시하세요.
사용법: /perf app/models/order.rb
$ARGUMENTS가 파일 경로를 받고, cat이 내용을 읽어 주입한다. Claude가 받는 것은 실제 코드이지, "현재 파일을 봐주세요" 같은 모호한 설명이 아니다.
allowed-tools는 frontmatter에서cat명령어를 사전 승인한 것으로, 트리거할 때 권한 확인이 뜨지 않는다. 이 줄이 없으면 매번 실행할 때마다 "허용"을 수동으로 클릭해야 한다. 아래 예제들도 같은 방식으로 선언해야 한다.
현재 브랜치와 변경 상태:
!`git status --short`
!`git log --oneline -10`
위 정보를 바탕으로 변경 내용과 동기를 포함한 간결한 PR 설명을 생성해주세요.
이 /pr command는 "내가 무엇을 바꿨는지" 설명할 필요가 없다. 스스로 읽으러 간다.
프로젝트 기술 스택:
!`cat .claude/context/stack.md`
현재 데이터베이스 구조 (주요 테이블):
!`head -100 db/schema.rb`
위 배경을 바탕으로 $ARGUMENTS를 위한, 프로젝트 규약에 맞는 마이그레이션 스크립트를 작성하세요.
프로젝트 배경 정보를 미리 .claude/context/ 디렉터리에 적어두고, command가 트리거될 때 필요에 따라 읽어들이면 된다. 매번 프로젝트 상황을 반복해서 설명할 필요가 없다.
최근 테스트 실행 결과:
!`bundle exec rspec --format progress 2>&1 | tail -30`
위는 실패한 테스트입니다. 근본 원인을 분석하고 수정 방안을 제시하세요. 테스트 자체는 변경하지 마세요.
/fix-tests가 트리거되면 직접 테스트를 돌려 결과를 가져온다. Claude가 보는 것은 실제 오류 메시지다.
위의 것들을 조합하면 /review는 꽤 정밀해진다:
---
description: 현재 변경 사항을 검토하고, diff와 관련 배경을 자동 주입
allowed-tools: Bash(git diff:*), Bash(cat:*)
---
## 이번 변경 사항
!`git diff HEAD`
## 변경된 파일 목록
!`git diff HEAD --name-only`
## 프로젝트 코딩 규약 요약
!`cat .claude/context/coding-standards.md 2>/dev/null || echo "(규약 파일 없음)"`
---
위 변경 사항을 검토해주세요:
1. 로직 정확성: 처리되지 않은 경계 조건이나 로직 오류가 있는지
2. 보안 문제: SQL 인젝션, 권한 검증, 민감 정보 노출
3. 규약 부합도: 프로젝트 코딩 규약에 부합하는지
4. 가독성: 네이밍, 주석, 구조
각 문제에 대해 파일명, 줄 번호, 구체적인 제안을 제시하세요. 문제가 없으면 없다고 말하고, 억지로 채우지 마세요.
이 command는 사용자 측에서 어떠한 준비도 필요하지 않다 — 트리거되는 순간 diff, 파일 목록, 코딩 규약이 모두 자동 주입된다.
Shell 명령어는 실패할 수 있다 (파일이 없거나, 명령어가 PATH에 없거나 등). ||로 기본값을 제공해 command가 중단되지 않도록 한다:
!`git diff HEAD 2>/dev/null || echo "(git 변경 사항 없음 또는 git 저장소가 아님)"`
!`cat .env.example 2>/dev/null || echo "(.env.example 파일 없음)"`
!`which rspec > /dev/null 2>&1 && bundle exec rspec --dry-run 2>&1 | head -20 || echo "(RSpec를 감지하지 못함)"`
명령어가 실패할 때 Claude는 빈칸 대신 설명 텍스트를 받게 되고, 그에 맞춰 응답 전략을 조정할 수 있다.
! 명령어의 출력은 모두 context window에 들어간다. 흔한 함정 몇 가지:
큰 파일 전체를 cat 하지 말 것
# 위험: 수만 줄이 주입될 수 있음
!`cat db/schema.rb`
# 더 나은 방법: 필요한 부분만 가져오기
!`grep -A 5 "create_table \"orders\"" db/schema.rb`
로그 파일에는 줄 수 제한
!`tail -50 log/development.log`
테스트 출력 잘라내기
!`bundle exec rspec 2>&1 | tail -40`
context가 정밀할수록 Claude의 답변은 좋아진다. 코드베이스 전체를 집어넣는다고 더 똑똑해지지 않는다. 노이즈 속에서 길을 잃을 뿐이다.
흔한 질문: 프로젝트 배경 정보는 CLAUDE.md에 두어야 할까, 아니면 !로 동적 주입해야 할까?
판단 기준:
| 정보 유형 | 어디에 둘지 |
|---|---|
| 매번 필요한 프로젝트 배경 (기술 스택, 디렉터리 구조, 규약) | CLAUDE.md |
| 시간에 따라 변하는 상태 (현재 diff, 테스트 결과, 파일 내용) | ! 동적 주입 |
| 특정 작업에서만 필요한 배경 (어떤 모듈의 설계 설명) | !cat으로 필요할 때 읽기 |
CLAUDE.md는 영속적인 배경 지식이고, !는 작업 시점의 즉각적인 스냅샷이다. 둘은 상호 보완적이며, 중복시키지 말 것.
.claude/commands/ 디렉터리.claude/
├── commands/
│ ├── review.md # 검토: diff + 규약 주입
│ ├── test.md # 테스트 작성: 대상 파일 주입
│ ├── fix-tests.md # 테스트 수정: 실패 결과 주입
│ ├── pr.md # PR 설명: git log + status 주입
│ ├── explain.md # 코드 설명: 파일 내용 주입
│ └── migrate.md # 마이그레이션 작성: schema 조각 주입
├── context/
│ ├── stack.md # 기술 스택 설명
│ └── coding-standards.md # 코딩 규약
└── settings.json
context/ 디렉터리에는 정적인 배경 파일을 두고, 각 command가 필요에 따라 읽어들이게 한다. 이 구조는 그대로 git에 커밋해 팀과 공유할 수 있다.
정적 command:
현재 코드 변경 사항을 검토해주세요.
Claude는 먼저 "변경 사항이 어디 있나요"라고 묻거나 스스로 찾아야 하고, 결과는 안정적이지 않다.
컨텍스트 인식 command:
이게 diff (실제 내용 첨부), 이게 관련 규약 (실제 내용 첨부)입니다. 검토해주세요.
Claude는 곧바로 분석에 들어간다. 답변은 정확하고, 군말이 없으며, 왔다 갔다 확인할 필요가 없다.
차이는 Claude의 능력에 있는 것이 아니라, 당신이 얼마나 많은 실제 정보를 건네줬느냐에 있다.