서론
Claude Code의 mod(화면에 페인이나 알림을 추가하거나, 처리를 삽입하는 확장)로 무엇을 만들 수 있는지 전체적인 그림을 파악하고 싶어 조사하기 시작했습니다.
mod는 플러그인의 형태로 작성되는 '함수 후크'라고 설명되어 있어, 갑자기 mod를 만지기보다는 기반이 되는 후크와 플러그인부터 순서대로 직접 해보면서 확인하는 시리즈로 만들기로 했습니다.
첫 번째 글에서는 후크 자체를 확인해 보겠습니다.
settings.json에 후크를 하나 작성하여, Claude가 도구를 사용하기 직전에 명령어가 실행되는 것과 그 명령어가 무엇을 받아 처리할 수 있는지 살펴보겠습니다.
| 용어 | 의미 |
|---|
| 후크 | Claude Code의 정해진 타이밍(도구 실행 전후 등)에 자신이 작성한 명령어를 자동으로 실행하는 메커니즘 |
| 도구 | Claude가 파일 조작이나 명령어 실행을 위해 호출하는 기능(Bash, Read 등) |
급하게 보는 사람들을 위한 요약
확인해 본 질문과 답변입니다.
| 질문 | 답변 |
|---|
settings.json에 후크를 하나 작성하면 무슨 일이 일어나나 | hooks에 |
프록시(hook)의 입력을 보려면 jq를 사용한다.
기존 설정을 오염시키지 않도록 실험용 폴더를 만들고, 그곳의 .claude/settings.json에만 프록시를 작성한다.
# 실험용 폴더와, 그 안의 설정 저장소 .claude 를 만들고, 그곳으로 이동하여 현재 위치를 표시
mkdir -p mods-lab/.claude && cd mods-lab && pwd
/Users/ando/projects/my_agent/mods-lab
mods-lab/.claude/settings.json은 mods-lab에서 Claude를 실행했을 때만 적용되는 설정이며, 정리(cleanup)는 마지막에 rm -rf mods-lab으로 한다.
직접 해보기
settings.json에 프록시를 하나 작성하면, 도구 실행 전에 명령어가 실행됨을 확인하기
프록시 작성하기
Bash 도구가 실행되기 직전에, 프록시가 받은 입력을 파일에 추가하는 것만 하는 프록시.
# 여기부터 EOF까지의 내용을 .claude/settings.json 에 쓰기 (기존 내용은 덮어씀)
cat > .claude/settings.json <<'EOF'
{
...
{
"hooks": {
"PreToolUse": [
...
프록시는 '언제(PreToolUse)・어떤 도구로(matcher)・무엇을 실행할지(command)'의 3가지만 작성하면 작동한다.
| 용어 | 의미 |
|---|
| PreToolUse | Claude가 도구를 실행하기 직전에 발생하는 프록시 이벤트 |
| ... | |
Claude에게 ls를 요청하기
# 실험용 폴더에서 Claude Code 를 실행
claude
실행한 후
ls는 실행되지 않았고, Claude는 "PreToolUse 후크가 'Bash는 후크로 금지됨'이라는 메시지로 멈추고 있다"라고 답했다.
| 용어 | 의미 |
|---|
| 종료 코드 | 명령이 끝날 때 반환하는 숫자. 0은 성공. PreToolUse 후크에서는 2를 반환하면 도구 실행을 멈춘다 |
| stderr | 에러나 보충 메시지용 출력처(>&2로 여기에 출력) |
참고: https://code.claude.com/docs/en/hooks 「Exit code 2 behavior per event」
JSON의 permissionDecision으로 중단하기
exit 2
과는 별개로, 종료 코드 0을 반환하며 표준 출력에 JSON을 반환하여 명시적으로 '거부(deny)'한다고 알리는 방식도 있다.
settings.json
한 번에 처리할 수 있도록 command에 echo '<JSON>'를 직접 작성한다 (JSON 내부의 "는 \"로 이스케이프).
# .claude/settings.json을, JSON으로 deny를 반환하는 후크로 덮어쓴다
cat > .claude/settings.json <<'EOF'
{
...
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
...
후크의 명령어가 올바른 JSON을 출력하는지, 등록하기 전에 수동으로 확인했다.
claude를 실행하여 'ls를 실행해 줘'라고 요청하자, ls는 실행되지 않았고, Claude는 "돌아온 메시지는 PreToolUse:Bash hook error: JSON으로 deny 중 뿐"이라고 답했다.
permissionDecision에 들어갈 값은 다음 4가지이다.
| 값 | 의미 |
|---|
allow | 허용한다 |
deny | 거부한다 |
ask | 사용자에게 확인을 요청한다 |
defer | 일반적인 권한 확인에 맡긴다 |
updatedInput으로 도구의 인수를 수정할 수도 있다 (이번에는 미확인).
exit 2와 JSON을 모두 사용했을 경우, exit 2가 우선한다.
참고: https://code.claude.com/docs/en/hooks 「PreToolUse decision control」
exit 2와 JSON의 deny로 Claude에 전달되는 것 비교하기
대화 로그에서 Claude에게 반환된 도구 결과만 추출한다.
# 대화 로그(jsonl)에서 사용자 측 메시지 내의 tool_result만 가져와, 에러인지 여부와 내용을 한 줄씩 표시
jq -c 'select(.type==
# Claude Code를 실행합니다 (실행 후 /hooks를 입력하고 Esc로 닫은 뒤 /exit).
claude
Hooks
3 hooks on 3 events
This menu is read-only. To add or change a hook, edit settings.json or ask Claude.
...
-
`/hooks`
는 읽기 전용입니다. 추가하거나 변경하려면 `settings.json`을 직접 편집하거나 Claude에게 요청하세요 - 이벤트별로 등록된 후크를 표시합니다.
`[Project]`는 `mods-lab/.claude/settings.json`에서, `[User]`는 `~/.claude/settings.json`에서 가져온 것입니다 - 모든 이벤트 목록은 이 화면에서는 확인할 수 없었기 때문에, 요약 표는 공식 문서를 출처로 삼았습니다.
다음 시간에는 이 후크를 플러그인에 넣어서 배포하는 형태를 확인하고, 모드 본체로 넘어가겠습니다.
### 토론 (Discussion)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22