AIDive

문서에도 없는 Claude Code Mod 직접 만들었다, 가드가 뚫린다

AIDive · 게시

코딩 에이전트AI 보안

'이걸 원한다면'에서 테트리스까지, 12일

Claude Code Mods는 Claude Code 엔진 안에서 실행되며 엔진의 이벤트를 함수로 훅하는 TypeScript 모듈이다. Claude Code를 이끄는 Boris Cherny는 다섯 단어로 이를 발표했다: "Claude mods are landing now." 이 글은 2,400개의 좋아요를 모았고, 그 시점에 이미 누군가는 터미널 안에 테트리스를 만들어 두었다. 테트리스, 둠, 그리고 Claude가 테스트를 실행하는 동안 자라나는 펫까지, 모두 프롬프트 위에 렌더링되며, 토큰은 0개다.

발표 글은 어떤 문서 페이지도 링크하지 않는다. 대신 12일 전 Anthropic 엔지니어가 연 GitHub 이슈를 링크하는데, 거기엔 한 가지 조건이 적혀 있었다. Alice Poteat는 이 기능이 출시될지 여부는 커뮤니티의 반응이 좌우할 가능성이 크다고 썼다. 177개의 댓글이 달린 뒤, 사람들은 플래그로 감춰진 바이너리를 두드려 보고, 타임아웃을 측정하고, 그 위에 게임을 만들었다.

Measure Value
Likes on the announcement 2,400
Comments on the GitHub issue 177
Typed surface in this week's build 10,700 lines
Events on nouns (issue-thread build) 84 on 19
Mods on GitHub inside 48 hours 31

이 글을 쓰는 시점 기준 문서 페이지는 404를 반환한다. 이 기사는 Claude Code를 확장하는 네 가지 방법과, 의도적으로 만들고 부순 유용한 Mod 하나, 그리고 출시하기 전에 아직 불안정한 부분을 다룬다.

Mod는 중간에 있는 함수다

소스 트리는 이를 한 문장으로 정의한다: Mod는 동작이 hooks module 안에 있는 Claude Code plugin이다. 하나의 register 항목이 엔진의 이벤트를 함수로 훅한다. 디스크 위에서 보면, 이는 plugin 폴더 하나, 정확히 하나의 모듈을 지정하는 hooks manifest 하나, 그리고 그 모듈 자체다.

모든 hook은 세 가지의 함수다: 모든 side effect가 통과하는 문 $, 이벤트, 그리고 continuation, 즉 당신 아래에 있는 체인의 나머지. hook은 middleware처럼 중첩된다. 먼저 등록된 hook이 그 이벤트를 소유하며, 그 아래 어떤 것도 이를 막을 수 없다. 그 순서는 설정되는 것이지, 설치 순서로 정해지지 않는다. Alice Poteat의 말을 빌리면, 순서는 설치 시점이 아니라 설정으로 정해진다.

주변 접근권 같은 건 없다. Mod가 하는 모든 일은 $를 통과하므로, 관리자는 어떤 이벤트든 감사(audit)하고, 허용하고, 거부하고, 기록할 수 있다. 한 댓글 작성자는 이렇게 요약했다: 플러그인이 한 일은 정확히 그것이 실행한 호출들뿐이다. *에 걸린 hook 하나가 모든 이벤트를 보므로, 감사 로그는 함수 하나로 끝난다. Mod는 화면을 그릴 수도 있는데, 인터페이스가 React이기 때문이다. Bun 위에서 프로세스 내부(in process)로 실행되며, 99번째 백분위수 기준 50마이크로초가 걸린다. 환경 변수 하나로 켜고 끌 수 있다. $ 위에 실제로 무엇이 있는지는 아직 초기 액세스 파트너들과 함께 설계되는 중이다.

Claude Code를 확장하는 네 가지 방법, 그리고 각각의 용도

shell hook은 엔진이 정해진 순간에 호출하는 스크립트다. 표준 입력으로 JSON을 받고 종료 코드(exit code)로 답한다. 이 답변에는 상한선이 있다: 컨텍스트로 돌려줄 수 있는 건 8,000자, 일부 hook은 2,000자다. Pratham의 말을 빌리면, Windows에서는 이런 hook들이 종종 이상하게 깨진다.

plugin은 하나의 상자다. 매니페스트 하나가 skill, agent, hook, MCP 서버를 한데 묶는다. 마켓플레이스에서 설치하거나 디스크의 폴더에서 바로 불러올 수 있고, 명령어 하나가 무엇이든 실행되기 전에 그 상자를 검증한다.

skill은 모델이 필요할 때 읽는 산문(prose)이다. 본문은 일치하는 prompt가 들어올 때만 로드된다. 여전히 동작을 바꾸는 가장 저렴한 방법이다.

Mod는 같은 상자에 파일 하나가 더 있을 뿐이다: 모듈 하나를 지정하는 hooks manifest, 그리고 그 모듈은 TypeScript로 작성되고, 타입이 있으며, 프로세스 내부에서, 모든 엔진 이벤트에 대해 동작한다. 차이는 그게 전부다.

Mechanism What it is Runs Ceiling
Shell hook Script called at a fixed moment Subprocess, exit code 8,000 chars back (2,000 for some hooks)
Plugin Bundle of skills, agents, hooks, MCP servers Installed or loaded from disk Validated before it runs
Skill Prose loaded on a matching prompt In the model's context Cheapest change
Mod Plugin plus a TypeScript hooks module In process, on every event Typed, early access

이 타입들은 슬래시 명령어 하나에서 나오는데, 이 명령어는 $가 제공하는 것의 전체 목록을 그대로 당신의 프로젝트에 적어 넣는다. 기존 shell hook들은 폐기된 게 아니라 감싸졌을(wrapped) 뿐이다. 어느 초기 빌드에서, Spencer Morley는 이 wrapper가 로드에 실패하고도 여전히 선언된 채로 남아 있는 것을 지켜보았다. 경험칙은 이렇다: Claude가 아는 것을 바꾸려면 skill을 쓰고, 어떤 순간에 스크립트를 실행하려면 shell hook을, 번들을 배포하려면 plugin을, 엔진 안에 자리 잡으려면 Mod를 쓴다. shell hook은 그 플래그가 꺼져 있는 모든 곳에서 여전히 동작한다.

Anthropic 자체의 세 가지, 소스로 읽기

바이너리 안에는 Mod 세 개가 내장되어 있고 그 소스는 GitHub에 있다: 보안 기본값 하나, diff 패널 하나, 그리고 telemetry 하나.

보안 기본값은 가장 바깥쪽에 자리 잡는다. managed settings가 설정된 머신에서, 혹은 Team이나 Enterprise 조직에서는, 사용자가 설치한 그 무엇도 이보다 위에 있을 수 없다. 이 hook은 12개의 이벤트를 훅하고, 각 hook은 세 가지 동작 중 하나를 한다: user tier를 통과시키거나, user tier의 호출자를 이름으로 거부하거나, 그냥 지나간다. 이는 fail closed 방식이며, 문서 주석도 두 단어로 그렇게 밝힌다. 스레드가 신경 쓴 부분이 바로 여기다: 관리자가 $에서 권한 하나를 제거하면, 그 아래에 등록된 어떤 것도 그것을 호출할 수 없다. 한 댓글 작성자의 말을 빌리면, 이는 플러그인에게 무언가를 하지 말라고 부탁하는 것과는 완전히 다른 범주의 이야기다.

diff는 transcript 옆에 놓이는 패널로, 세션의 커밋되지 않은 변경 사항을 파일 단위로 보여주며 Claude가 편집할 때마다 갱신된다. 세션 시작 시 등록되며 27개의 helper 파일에 걸쳐 있어, 장난감 수준이 아니다.

telemetry는 엔진 생성 내부에서 $에 noun 하나를 추가한다. 아래에 있는 것을 await한 뒤 그것과 자기 자신을 함께 반환한다. 내부 빌드에서만 실행된다.

README는 소스에서 하나를 실행하고 소스에서 하나를 테스트하라고 안내한다. 오늘 빌드의 help는 validate, eval, details를 나열한다. test 항목의 help는 여전히 응답하는데도, 목록에는 test가 없다. 내장 티어는 당신의 사본도 거부한다: 같은 이름으로 plugin을 배포해 봐야, 바이너리는 자기 자신의 것을 로드한다.

42줄: 모델로부터 비밀을 숨기는 Mod

타입을 적어 넣는 슬래시 명령어는 이 빌드 기준으로 11,700줄을 생성한다: 23개의 noun에 걸친 84개의 이벤트다. tool call hook은 결과 또는 거부로만 응답하며, 텍스트로는 답하지 않는다. 이 부분은 core에서 정해진다.

이 Mod는 파일 세 개로 이루어진다: plugin manifest, 한 줄짜리 hooks manifest, 그리고 모듈 자체. 모듈은 42줄이다. 아래에 있는 것을 await하고, 결과를 스크럽(scrub)한 뒤 돌려준다. 네 가지 패턴이 두 가지 벤더 키 형태, GitHub 토큰, 그리고 key, secret, token이라는 이름의 변수에 할당된 모든 값을 커버한다.

validate는 실행되기 전에 소스를 읽는다. 그 모듈이 훅하는 이벤트와 $에서 호출하는 단 하나의 것을 이름으로 알려준다. 유일한 경고는 author 누락뿐이다. 플래그를 켠 채 디스크에서 로드하면, 테스트 파일에는 애초에 가짜로 만들어진 키 두 개가 들어 있고, 모델은 "redacted"라고 읽는다. 모델 자신의 말을 빌리면, 값들이 redacted 상태로 돌아왔기 때문에 그 안에 무엇이 있는지 볼 수 없다는 것이다.

Measure Value
Module length 42 lines
Hop latency, worker included 28 ms
Tokens added to the session 0

엔진은 이 hop을 hooks module에 의해 resolved된 것으로 기록한다. 인벤토리에는 skill도, agent도, 상시 작동하는 것도 전혀 없다. 한 가지 한계는 남는다: 모델로부터 숨겨진 것이 화면으로부터도 숨겨진 것은 아니다. transcript에는 여전히 그 tool이 출력한 내용이 보인다. Ship Notes의 Max가 한 줄로 지적했듯, 그건 다른 Mod의 몫이다.

부숴보기: 느린 가드는 우회된 가드다

같은 Mod에 한 줄을 추가한다: 아래에 있는 것을 호출하기 전에 15초 동안 sleep. 10초 뒤, 엔진은 이를 포기하고 hook이 예산을 초과해 스킵되었다고 보고하며, 그 아래에 있는 것이 대신 실행된다. 명령어는 어쨌든 실행되어 "hi"를 출력한다.

sleep을 throw로 바꿔도: 574밀리초, 같은 판정, 스킵, 명령어는 실행된다.

Case Time Verdict
Healthy hook 28 ms Resolved
Throw 574 ms Skipped, command ran
Hang over 10 s Skipped, command ran

두 실패 모두 같은 단어로 끝난다: 스킵됨. 스레드는 일주일 전 이미 이 비대칭성을 측정해 두었다. 로드 시점에 없는 capability는 fail closed다. 예산을 넘긴 hook은 fail open이다: 시끄럽지만 우회된다는 것이, Spencer Morley의 말이다. 이유 없이 그냥 막히면 모델은 다른 tool로 넘어갈 뿐이다. Pratham은 모델이 다른 tool을 골라 어쨌든 파일을 쓰는 것을 지켜보았다.

지금 테이블 위에 놓인 답은 catch다. Alice Poteat는 hook의 반환값에 catch를 두자고 제안하는데, 이는 시간을 너무 끌거나 throw할 때 실행된다. 다시 쓰인 write는 여전히 모델에게 알려줄 문구가 필요하다: 모델은 캐싱 때문에 자신이 쓰려고 했던 것을 그대로 보게 되므로, 컨텍스트 줄 하나를 덧붙여야 한다. 예산은 곧 격리이기도 하다. hooks worker는 별도로 실행되며, 그것이 죽으면 엔진은 이를 재기동하고 해당 세션의 hook을 꺼버린다. 해법은 더 긴 예산이 아니라 명시적으로 선언된 catch다.

Mod의 48시간, 그리고 한 문장으로 얻는 것

이틀 만에: 프롬프트 위에서 테트리스와 다른 게임 일곱 개를 Claude가 작업하는 동안 플레이할 수 있게 되었고, 토큰은 0개다. 1993년 원작 둠은 자체 프로세스로 실행되며, Mod는 로컬 HTTP를 통해 여기에 접근해 초당 10번씩 다시 그린다. 스피너 안에는 숨쉬는 듯한 페이서가 있고, hooks worker 안에서 260,000개의 파라미터로 돌아가는 스토리 모델이 API 토큰 없이 실행된다.

레지스트리는 validate로 31개의 Mod를 스캔했다. 그중 14개는 host 프로세스를 실행할 수 있다. 13개는 모든 tool call을 볼 수 있다.

커뮤니티 스레드의 데모 8은 한 문장이면 모델이 비밀을 읽기 전에 숨기는 plugin을 작성해 준다고 약속했다. 우리는 그걸 직접 요청해 보았다.

Measure Value
Time 4 min
Turns 34
Cost $1.23
Lines (plus a test file) 190, against our 42
Tests 4 pass in a third of a second

결과물은 무엇을 숨겼는지 종류별로 표시하고, 깨끗하게 검증을 통과하며, API 키도 모델 호출도 필요 없다. 한 댓글은 이렇게 정리했다: allowlist가 진짜 제품이고, 테트리스는 그냥 데모다.

결론: 지금 만들고, 나중에 출시하라

레지스트리 자체의 수치가 경고다. 31개 중 14개의 Mod가 host 프로세스를 실행할 수 있는데, 검증 수단은 정적 footprint 하나뿐이다. eval의 help 문구 자체가 이를 말해준다: 테스트 통과가 보안 검증은 아니라고.

Signal Value
Events on the 8th 20
Events on the 15th 84
CLI versions in a fortnight 14
Hacker News points 2
Replies to the compatibility question 0

10초짜리 예산은 타입이 아니라 런타임 안에 산다고, Marat는 지적했다. 체인지로그 줄도, 문서 페이지도, 출시 포스트도 없다. 한 경쟁자는 Anthropic이 이를 베꼈다고 주장한다: Ahmad Awais는 Command Code의 mods를 가리키며 그들의 예제 mod를 직접 작성한 당사자이니, 이 발언은 그 점을 감안해서 받아들여야 한다. "early access, APIs may change"라는 문구가 달린 포스트는 357개의 좋아요를 모았다.

이미 hook을 작성하고 있고 감사 로그, redaction, 패널을 원한다면 지금 하나 만들어라. 팀에 배포하기 전이라면 기다려라, 계약(contract)이 아직 쓰이지 않았으니까. 같은 개방성 덕분에, fail open하는 예산, MCP call 타입 불일치, wrapper 실패가 모두 며칠 만에 사용자들에 의해 발견되었다.

출처

자주 묻는 질문

Claude Code Mod란 무엇인가?
Mod는 동작이 TypeScript hooks module 안에 있는 Claude Code plugin이다. 이 모듈은 엔진의 이벤트에 함수를 등록하고 Bun 위에서 프로세스 내부로 실행되며, 모든 side effect는 `$` 객체를 통과한다.
Claude Code의 hook, plugin, skill, Mod는 어떻게 다른가?
shell hook은 정해진 순간에 호출되어 종료 코드로 응답하는 스크립트다. plugin은 skill, agent, hook, MCP 서버의 번들이다. skill은 일치하는 prompt가 들어올 때 모델이 로드하는 산문이다. Mod는 plugin에 파일 하나가 더해진 것으로, 프로세스 내부에서 모든 엔진 이벤트를 훅하는 타입이 있는 TypeScript 모듈이다.
Claude Code Mod가 비밀을 모델로부터 숨길 수 있는가?
그렇다. tool 결과를 await하고 key, secret, token 패턴을 스크럽한 뒤 redaction된 텍스트를 반환하는 42줄짜리 Mod는 hop당 28ms, 토큰 0개가 추가된다. 다만 화면의 transcript에서 값을 숨기지는 못하며, 그건 별도의 Mod가 필요하다.
느린 Claude Code Mod는 왜 fail open하는가?
hooks worker는 각 hook에 10초의 예산을 준다. 이를 초과하거나 throw하는 hook은 스킵된 것으로 표시되고 그 아래의 체인이 대신 실행되어, 가드하려던 명령어가 그대로 실행된다. Anthropic이 제안한 해법은 hook의 반환값에 명시적으로 선언된 catch다.
Claude Code Mod는 설치해도 안전한가?
아직 기본적으로는 아니다. 첫 48시간에 등록된 31개의 Mod 중 14개는 host 프로세스를 실행할 수 있고 13개는 모든 tool call을 볼 수 있으며, 검증 수단은 정적 footprint뿐이다. managed settings는 Anthropic의 보안 기본값을 사용자가 설치한 그 무엇보다 위에 둔다.
지금 Claude Code Mod를 만들어야 할까?
이미 hook을 작성 중이고 감사 로그, redaction, diff 패널을 원한다면 지금 만들어라. 팀에 배포하는 건 기다려라: 이 기능은 early access이고, API는 일주일 만에 이벤트가 20개에서 84개로 바뀌었으며, 아직 문서 페이지도 체인지로그 줄도 없다.

관련 영상