Claude Code의 mod로 Claude의 움직임을 페인과 토스트에 시각화하기 [mods 입문 ④]
요약
본 글은 Claude Code의 mod 기능을 활용하여 AI 에이전트의 내부 작동 과정을 시각화하는 방법을 다룹니다. 특히, 서브 에이전트 구동(`agent.spawn`)과 툴 호출(`tool.call`) 같은 '사고 외 움직임'을 포착하여 토스트 알림이나 플로우차트로 표시할 수 있습니다. 이를 통해 사용자는 Claude의 요청 흐름 전체를 한눈에 파악할 수 있습니다.
핵심 포인트
- `agent.spawn`, `tool.call` 이벤트를 활용해 에이전트 움직임을 포착 가능
- 토스트 알림이나 플로우차트로 AI의 작동 과정을 시각화하는 실습 제공
- 툴 호출 설명은 고정된 문구가 아니므로, 툴 이름만 대응표로 처리함
서론
Claude Code의 mod를 사용하여 무엇을 만들 수 있는지 전체적인 그림을 파악하기 위해 직접 해본 시리즈의 네 번째 글입니다.
3번째까지에서는 훅(hook)・플러그인(plugin)・mod의 역할 분담과, mod가 화면의 어느 위치에 무엇을 표시할 수 있는지 확인했습니다.
이번에는 그 실전편으로서, 실제로 사용할 수 있는 도구를 하나 만들 것입니다.
주제는 'Claude가 현재 무엇을 하고 있는지'를 시각화하는 것입니다.
Claude가 툴이나 서브 에이전트(sub-agent)를 구동할 때마다 알림을 표시하고, 한 번의 요청 흐름 전체를 옆쪽 페인에 플로우차트 형태로 배열합니다.
처음에는 'Claude가 실행 중 출력하는 영어 설명을 한국어로 번역하는 것'도 생각해봤습니다.
하지만 툴 라인의 설명(예: Read plugin manifests and hook modules)
은 화면의 정해진 문구가 아니라, Claude가 툴을 호출할 때마다 스스로 작성하는 문구입니다.
사전 정의된 사전을 사용해서 대체할 수 없고, mod에서 모델을 불러와 번역하면 툴이 호출될 때마다 사용량이 발생하기 때문에 이번에는 포기했습니다.
대신, 툴 이름 부분만 대응표를 만들어 한국어로 표시했습니다.
| 용어 | 의미 |
|---|---|
| 서브 에이전트 (sub-agent) | Claude가 조사 등을 맡기기 위해 구동하는 다른 Claude. Explore 등의 종류가 있습니다 |
| ... |
바쁜 사람을 위한 요약
확인한 질문과 답변입니다.
| 질문 | 답변 |
|---|---|
| Claude의 '사고 외 움직임'은 mod로 포착할 수 있는가 | 포착 가능하다. 툴은 tool.call, |
서브 에이전트 구동은 agent.spawn. 서브 에이전트 내부의 툴 호출에서도 tool.call이 발생한다. | |
| ... | Box의 테두리와 색상, Text의 색상만으로도 박스와 화살표 형태의 플로우차트를 만들 수 있었다. HTML이나 Mermaid는 페인 안에서는 사용할 수 없다. |
완성된 페인의 표시.
| 표시 | 의미 |
|---|---|
| ▶ | 자신의 요청 (1턴 시작) |
| ... |
사전 준비
환경은 Claude Code 2.1.289, macOS입니다.
시리즈에서 사용해 온 실험용 폴더인 mods-lab을 그대로 사용할 것입니다.
mod의 그리기는 터미널에서 구동한 claude로만 가능하기 때문에, 모든 조작은 터미널에서 진행합니다.
# 실험용 폴더로 이동
dcd mods-lab
참고: https://code.claude.com/docs/en/plugins/mods/overview 「Where mods run」
실습해보기
Claude의 움직임을 토스트로 알리기
토스트만 만드는 mod 만들기
Claude의 '사고 외 움직임'을 포착하는 두 가지 이벤트를 사용합니다.
| 이벤트 | 발생 시점 | 전달되는 정보 |
|---|---|
| agent.spawn | 서브 에이전트 구동 직전 | 종류(e.subagentType) (Explore 등), 짧은 설명(e.description) |
| tool.call | 툴 사용 직전 | 툴 이름(e.tool), 입력(Bash라면 e.description・e.command, Read라면 e.file_path) |
# mod의 폴더와, 명찰 놓을 곳 .claude-plugin, 훅 놓을 곳 hooks를 한 번에 만듭니다.
mkdir -p status-mod/.claude-plugin status-mod/hooks
# 명찰인 plugin.json을 작성합니다.
...
❯ ./register.jsx hooks: agent.spawn, tool.call
❯ ./register.jsx calls: $.ui.toast
✔ Validation passed with warnings
short은 긴 설명을 40자로 잘라 …을 붙이는 작은 함수이고 -
noteOf는 툴마다 다른 입력으로부터, 설명・파일 이름・검색 패턴・명령 순서로 가장 먼저 발견되는 것을 사용합니다. 서브 에이전트의 구동도 내부적으로 Agent라는 툴 호출이기 때문에,
tool.call에서는 Agent를 건너뛰어 토스트가 중복 표시되는 것을 방지합니다.
| 용어 | 의미 |
|---|---|
?? | JavaScript 작성법으로, 왼쪽 값이 없을 때(undefined이거나 null)만 오른쪽 값을 사용한다. |
status-mod를 이 세션에서만 로드하여 Claude Code를 시작
claude --plugin-dir ./status-mod
'Explore의 서브 에이전트에서 mods-lab에 있는 mod 목록을 보여주고, 그 후 hook-input.jsonl의 행 수를 세어줘'라고 요청한다.
이후에도 이 세션을 닫지 않고 사용한다.
오른쪽 상단에 status-mod라는 제목의 토스트가 연달아 나타났다.
대화 로그에서 실제 움직임을 세어보니 다음과 같았다.
🤖 Agent(Explore)「mods-lab의 mod 목록을 보여줘」 ← 서브 에이전트 시작
🔧 Bash「mods-lab의 파일 목록을 보여줘」 ┐
🔧 Bash「플러그인 매니페스트 읽기 …」 │ 서브 에이전트 내부
...
- 서브 에이전트 내부의 도구 호출에서도 mod의
tool.call이 발생한다. - 한 번의 요청에 움직임이 6가지가 있었고, 토스트(기본 4초)는 연달아 바뀌었다.
토스트를 표시할 후보 늘리기
타입 정의에서 '생각하는 것 외의 움직임'을 포착할 수 있는 이벤트를 추가한다.
| 토스트 | 이벤트 | 발생 시점 |
|---|---|---|
| 🔌 MCP | tool.call (이름이 mcp__로 시작) | context7 등의 MCP 도구를 사용했을 때 |
| ⚖ 허가 확인 | tool.check (판정이 ask) | 도구가 실행해도 되는지 판정 단계에 들어갔을 때 |
| 📚 스킬 | skill.prompt | 스킬이 로드되었을 때 |
| 🗜 대화 압축 | session.compact | 대화가 압축될 때 |
| ⚠ 턴 종료 | turn.complete (이유가 answer가 아닐 때) | 중단이나 오류로 끝났을 때 |
표시 시간은 $.ui.toast(text, { timeoutMs: 6000 })으로 6초로 늘렸다.
참고: Claude Code 2.1.288에 포함된 타입 정의 claude-code.d.ts
(plugin-authoring 스킬을 로드하면 작성됨)
'context7에서 React의 useState 설명을 한 줄로 조사해줘'라고 요청하자, 호출된 도구는 다음과 같았다.
{"name":"ToolSearch","input":{"query":"select:mcp__context7__resolve-library-id,mcp__context7__query-docs","max_results":2}}
{"name":"mcp__context7__resolve-library-id","input":{"libraryName":"React","query":"React useState hook description"}}
{"name":"mcp__context7__query-docs","input":{"libraryId":"/reactjs/react.dev","query":"What is useState? one-sentence description of the useState hook"}}
- MCP 도구는
mcp__<서버명>__<도구명>이라는 이름으로 도착한다. 그 전에, 사용할 MCP 도구를 로드하기 위한ToolSearch(Claude Code 내장 도구)도 호출된다.
| 용어 | 의미 |
|---|---|
| MCP | Claude에 도구를 추가하는 외부 서버 메커니즘. context7은 라이브러리 문서를 가져오는 MCP 서버 |
tool.check | 도구를 실행해도 되는지 판정할 때의 이벤트. allow(실행)/ask(판정 단계)/deny(거부) 중 하나가 된다 |
도구 이름을 한국어로 하기
토스트에 ToolSearch나 context7 같은 것이 그대로 나와도 이해하기 어렵다.
도구 이름과 한국어 대응표를 만들고, 표에 없는 것은 원래 이름 그대로 표시한다.
한국어 뒤에 원래 이름도 괄호로 붙여서 어떤 도구인지 알 수 있게 한다.
const TOOL_JA = {
Bash: '명령어를 실행',
Read: '파일을 읽기',
...
status-mod
🔌 Context7:
문서를 검색(query-docs)
- 트ースト의 첫 번째 줄에는 mod 이름이 자동으로 표시됩니다.
- 너비가 부족하면 본문은 줄 바꿈됩니다.
- MCP 이름은
__
으로 구분하여 서버와 도구로 나누고 표를 그립니다. 내장 도구 이름 목록은 타입 정의인BuiltinToolInputs에 있습니다.
| 용어 | 의미 |
|---|---|
split('__') | 문자열을 __로 구분하여 배열로 만듭니다. mcp__context7__query-docs → ['mcp', 'context7', 'query-docs'] |
1회 요청 흐름을 페인에 배치하기
목록으로 배치하기
페인은 /monitor라는 자체 제작 커맨드로 열 수 있습니다.
턴의 시작(turn.start)・움직임・끝(turn.complete)을 한 줄씩 모아 페인에 배치합니다.
on('command.run', { command: 'monitor' }, async $ => {
await $.ui.open({ id: 'monitor', title: 'Claude의 움직임' })
return { text: '움직임 페인을 열었습니다' }
...
/monitor를 입력한 후 같은 요청을 하면, 오른쪽 페인에 흐름이 남아 있었습니다.
▶ 요청: Explore의 서브 에이전트로 mods-lab에 있는 mod 목록을 만들고, 그…
⚖ 허가 확인: Agent
🤖 서브 에이전트(Explore): List mods in mods-lab
...
- 서브 에이전트 내부 호출에는
e.agentId가 붙기 때문에 들여쓰기를 깊게 하여 구분할 수 있었습니다. - 서브 에이전트는 본체의 턴이 끝난 후에도 움직임을 계속하며, 결과는<agent-message …>라는 별도의 메시지로 도착하여 새로운 턴이 시작되었습니다. - auto 모드에서는 '허가 확인'이 거의 모든 도구에 나타났습니다.
| 용어 | 의미 |
|---|---|
monitor | 이 mod에서 붙인 이름입니다. /monitor 커맨드 이름과, 페인을 구분하는 ID($.ui.open의 id와 ui.render의 requestId) 모두에 사용됩니다. |
| auto 모드 | 도구를 실행해도 되는지 여부를 Claude Code가 자동으로 판정하는 모드 |
플로우차트 형태로 만들기
목록으로는 어디부터 어디까지가 서브 에이전트의 움직임인지 읽기 어렵습니다.
페인은 Box의 테두리(borderStyle・borderColor)와 배치 방식(flexDirection), Text의 색상으로 구성되기 때문에, 틀과 화살표로 연결하는 형태로 재구성했습니다.
- 요청은 하늘색, 서브 에이전트는 보라색, 완료는 초록색 테두리입니다.
- 서브 에이전트 내부 도구는 보라색 틀 안에 중첩하여 배치합니다.
- 도구는
✓(초록)/✗(빨강)/…(노랑)와 경과 시간 - 1턴 분량을 모아 최근 3턴을 표시합니다.
╭──────────────────────────────────────────────────────╮
│ ▶ 요청: Explore의 서브 에이전트로 mods-lab에 있는 mod를… │
╰──────────────────────────────────────────────────────╯
...
| 용어 | 의미 |
|---|---|
borderStyle | Box 테두리의 종류입니다. round는 모서리가 둥근 틀을 의미합니다. |
서브 에이전트 결과 턴 구분하기
목록 버전에서 본 ▶ 요청: <agent-message …>를, 무엇이 일어나고 있는지 알 수 있는 제목으로 변경했습니다.
대화 로그에는 Another Claude session sent a message:로 시작하는 형태로 남아 있었지만, turn.start에 도착하는 e.text는 <agent-message에서 시작하고 있었습니다.
판정은 e.text.includes('<agent-message')를 사용합니다.
트ースト와 페인의 역할 분리하기
페인으로 모든 움직임을 추적할 수 있게 되었으므로, 트ースト는 알림 받고 싶은 것에만 한정했습니다.
- MCP 도구를 사용했을 때
- 도구가 실패했을 때 (
next의 결과가deny이거나isError일 경우) - 턴이 에러나 거부로 끝났을 때 (스스로 Esc를 누른 중단은 표시하지 않습니다.)
턴이 끝날 때까지는 마지막에 노란색 틀로 … 처리 중을 표시하고, 끝나면 ■ 완료: N초로 바꿔 그린다.
"Explore의 서브 에이전트로 mods-lab에 있는 mod들을 목록화하고, context7에서 React의 useState를 한 줄로 조사한 다음, 마지막으로 cat no-such-file.txt를 실행해 줘"라고 요청했다.
[하늘색] ▶ 요청: Explore의 서브 에이전트로 mods-lab에 있는 mod들을 목록화하고, c…
✓ 🔧 사용할 도구를 찾기(ToolSearch) 0.0초
[보라색] 🤖 Explore: mods-lab에서 모드 목록 가져오기
...
- MCP의🔌, 실패를 나타내는 빨간
✗,
서브 에이전트 결과의 제목은 의도대로였다. 서브 에이전트는 본체와 병렬로 움직였고, 본체의 Context7이나cat은 서브 에이전트 틀 뒤에 이어졌다.
언제 작동했는지 표시하기
페인(Pain)은 '호출한 순서'대로만 배열될 뿐, 서브 에이전트가 언제 호출되었고 본체와 동시에 움직였는지는 읽기 어려웠다.
각 줄에 요청으로부터 경과된 초수(+Ns)를 붙이고, 서브 에이전트 틀에는 시작 시점과 결과를 반환할 때까지의 초수를 표시한다.
const offset = (at, base) => `+${Math.round((at - base) / 1000)}s`
[보라색] 🤖 Explore: mods-lab에서 모드 목록 가져오기 +5초 시작 → 실행 중…
+7초 ✓ 🔧 명령어 실행(Bash): mods-lab의 파일 목록 가져오기 0.4초 ⚖
+10초 ✓ 🔧 명령어 실행(Bash): 플러그인 매니페스트, 후크 및 등록… 0.4초 ⚖
...
- 요청 5초 후에 서브 에이전트가 시작했고, 내부 도구들이 +7초, +10초, +13초에 작동했음을 읽을 수 있다.
- 결과를 반환할 때까지는 제목이
실행 중…상태로 유지된다.
기호에 글자 설명 추가하기
🤖나 ⚖만으로는 어떤 표시인지 알 수 없었기 때문에, 표시 옆에 글자를 추가했다.
| 전 | 후 |
|---|---|
🤖 Explore: … | 🤖(sub) Explore: … |
🔧 명령어 실행(Bash) | 🔧(tool) 명령어 실행(Bash) |
🔌 Context7: … | 🔌(MCP) Context7: … |
📨 서브 에이전트 결과 도착 | 📨(sub→본체) 서브 에이전트 보고를 받고, 본체가 계속 작업 |
줄 끝의 ⚖ | 줄 끝의 (허가를 판정) |
완성된 register.jsx
const TOOL_JA = {
Bash: '명령어 실행',
Read: '파일 읽기',
...
주요 부분의 역할.
| 부분 | 역할 |
|---|---|
turns | 턴별 움직임을 임시 저장하는 배열. 각 턴은 제목・움직임 목록・시작 시간・종료 방식을 가짐 |
agents | 서브 에이전트의 ID를 통해, 해당 서브 에이전트의 틀을 가져오는 사전(dictionary) |
agent.spawn의 await next(e) | 서브 에이전트가 시작하면 그 agentId가 반환된다. 이 값으로 틀을 agents에 등록한다. |
stepsFor | 서브 에이전트 내부 호출(e.agentId 있음)을, 해당 서브 에이전트의 틀로 분배한다. |
tool.call의 await next(e) | 도구가 끝날 때까지 기다리고, 결과로 ✓ /✗와 초수를 결정한다. |
turn.complete의 e.agentId | 서브 에이전트 턴의 끝에도 오기 때문에, agentId가 있으면 틀 반환만 기록하고, 본체는 완료 처리하지 않는다. |
redraw | 값이 바뀔 때마다 $.ui.invalidate('ui.render')로 다시 그리기를 요청한다. |
stepView / agentView / turnView | 도구 줄, 서브 에이전트 틀, 1턴 분을 구성하는 함수. agentView는 중첩된 틀을 스스로 그린다. |
줄 수의 상한이나, 도구 중간에 예외가 발생했을 때의 처리는 생략했다. 오래 사용할 거라면 추가할 필요가 있다.
참고: https://code.claude.com/docs/en/interactive-mode 「Keyboard shortcuts」「Task list」
로그를 읽는 시각화 툴과의 차이점
Claude Code의 움직임을 눈에 보이게 하는 도구는 이전에도 있었습니다.
대부분은 세션 로그(~/.claude/projects/<프로젝트>/<세션ID>.jsonl)에 추가되는 행을 외부에서 감시하고, 그 차분(diff)을 읽어 '읽고 있다', '편집 중' 등으로 분류하여 표시하는 방식으로 만들어져 있습니다.
거의 실시간으로 작동하는 것도 있지만, 재료는 Claude Code가 작성한 로그 문자열입니다.
이번 페인에 담긴 내용도 대부분은 로그를 읽으면 조립할 수 있습니다.
mod로 달라지는 점은 그것을 Claude Code 내부에서, 정해진 형태의 데이터로부터 자연스럽게 만들 수 있다는 것입니다.
mod는 Claude Code 내에서 발생하는 이벤트 자체에 개입하기 때문에, 별도의 앱을 실행할 필요가 없고, 표시도 Claude Code 화면 안에서 할 수 있습니다.
| 로그를 읽는 툴 | mod |
|---|---|
| 작동 방식 | 다른 앱을 구동하여 로그 파일을 감시한다. |
| ... | agent.spawn의 결과인 agentId와, 그 서브 에이전트의 tool.call의 agentId가 같은 값이므로, 프레임과 행을 확실하게 연결할 수 있다. |
| 타이밍 | 행이 작성된 후에 알게 된다. |
| 움직임 개입 | 할 수 없다 (보기만 가능) |
| 보이는 범위 | 여러 세션이나 과거 로그도 모아서 볼 수 있다. |
| 준비물 | Claude Code에 손댈 필요가 없다. |
이번 페인에서 서브 에이전트의 프레임 안에 내부 툴을 중첩하여 배치하거나, 서브 에이전트의 끝과 본체의 끝을 구분할 수 있었던 것은, mod가 이벤트 항목으로 agentId를 받을 수 있기 때문입니다.
로그 문자열로부터 같은 것을 하려면, 행의 나열에서 대응 관계를 추측해야 합니다.
반면에, mod는 현재 세션만 볼 수 있고, 움직이는 도중에밖에 기록할 수 없습니다.
여러 세션을 비교하거나, 끝난 작업의 회고에는 로그를 읽는 툴 쪽이 더 적합합니다.
참조: https://code.claude.com/docs/en/sessions (로그 형식은 내부 형식으로 간주됨)
요약
토스트와 페인은, 같은 '화면에 표시한다'라는 목적이라도 적합한 사용 방식이 확연히 달랐습니다.
| 부품 | 적합한 사용 방법 |
|---|---|
| 토스트 | 눈을 떼고 있어도 알아차리고 싶은 것. MCP를 사용한, 실패했거나, 에러로 멈춘 경우 |
| 페인 | 한 번의 요청 흐름을 남겨서 나중에 읽어보는 것 |
페인은 정해진 부품만 배치할 수 있지만, 프레임과 색상, 배열 방식만으로 플로우차트 같은 보기 쉬운 화면이 되었습니다.
서브 에이전트는 본체와 병렬로 움직이고, 끝나면 보고가 본체에 도착하여 새로운 턴이 시작된다는 Claude Code의 작동 방식 자체도 페인에서 눈에 보이게 되었습니다.
추가 정보 (おまけ)
[프롬프트]를 누르면 서브 에이전트에게 무엇을 전달했는지 별도의 페인에서 볼 수 있는 것도 가능했습니다. 지속적으로 사용할 만한 스킬이라, 기분 날 때 한번 시도해 보는 것이 재미있을지도 모르겠습니다.

// =====================================================================
// status-mod: Claude가 지금 무엇을 하고 있는지 눈에 보이게 하는 Claude Code의 mod
//
...
토론 (Discussion)

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기