클로드 코드 에이전트 모니터

hackernews | | 📦 오픈소스
#claude #프레임워크
원문 출처: hackernews · Genesis Park에서 요약 및 분석

요약

이 플랫폼은 Claude Code의 네이티브 훅 시스템을 활용해 세션, 도구 사용 등 다양한 이벤트를 실시간으로 포착하고 SQLite에 저장한 뒤 React UI로 스트리밍합니다. 외부 서비스나 API 키 없이 로컬 환경에서 완전히 구동되며, 개발자는 Node.js 스크립트와 도커 컨테이너를 통해 대시보드와 MCP 서버를 손쉽게 설정하고 모니터링할 수 있습니다.

본문

Claude Code Agent Monitor A professional monitoring platform for Claude Code agent activity. Captures sessions, agents, and tool events via native hooks, persists them in SQLite, and streams updates to a React UI over WebSocket — with no external services required. System Overview Claude Code Agent Monitor integrates with Claude Code through its native hook system. When Claude Code performs any action — tool use, session start, subagent orchestration, session end — it fires a hook that calls a small Node.js script bundled with this project. That script forwards the event over HTTP to the dashboard server, which stores it in SQLite and broadcasts it to the browser over WebSocket. End-to-end data pipeline from Claude Code to the browser The server binds to 0.0.0.0 but everything runs on your machine. No data leaves your system. No API keys. No external services. What's Included Every feature is driven by real hook events — nothing is hardcoded or simulated in production mode. Screenshots GitHub Star History This chart tracks how interest in Claude Code Agent Monitor has grown over time. The curve keeps climbing as more developers discover the project, share it, and use it in real workflows. Each new star is a small vote of confidence from the community. Hook Events Captured | Hook Type | Trigger | Dashboard Action | |---|---|---| SessionStart | Claude Code session begins | Creates session and main agent. Stamps awaiting_input_since so the row lands in Waiting from the start (the CLI is at a prompt). Reactivates resumed sessions. Abandons orphaned sessions with no activity for DASHBOARD_STALE_MINUTES (default 180). | UserPromptSubmit | User hits enter on a prompt | Clears the waiting flag and promotes the main agent to . The only reliable signal that text-only assistant turns have started — they emit no PreToolUse before Stop . | PreToolUse | Agent begins using a tool | Clears the waiting flag, sets agent → , current_tool set. If tool is Agent , subagent record created. | PostToolUse | Tool execution completes | Clears the waiting flag (covers permission-prompt approvals mid-tool). current_tool cleared. Agent stays . | Stop | Claude finishes a turn | Non-error: main agent → waiting — UI shows until the next user input. stop_reason=error : marks the agent and session . Background subagents keep running. | SubagentStop | Background agent finished | Matched subagent → . Deliberately does not clear the waiting flag — a backgrounded subagent finishing tells us nothing about the human. Also kicks off a fire-and-forget JSONL scan (scanAndImportSubagents ) that walks the session's subagents/agent-*.jsonl files, pairs tool_use ↔ tool_result blocks by tool_use_id , and emits per-tool PreToolUse + PostToolUse events under each subagent's own agent_id — surfaces tool calls that subagents make internally and which never fire any hooks. | Notification | Agent sends notification | Event logged to activity feed. Permission/input-prompt patterns (e.g. "needs your permission", "waiting for your input") set the agent to waiting and stamp awaiting_input_since . Compaction-related notifications tagged as Compaction events. Triggers a browser notification if enabled. | Compaction | /compact detected in JSONL | Creates a compaction subagent → . Detected via isCompactSummary entries in the transcript. Token baselines preserve pre-compaction totals. Periodic scanner (cadence ~¼ of DASHBOARD_STALE_MINUTES ) catches compactions when no hooks fire. | APIError | API error detected in transcript | Extracted from JSONL during history import, real-time transcript scanning, or the error detection watchdog. Captures quota limits, rate limits, auth failures, and other API errors. Immediately marks sessions and agents as error — previously recorded as events without changing status. | TurnDuration | Per-turn timing recorded | Extracted from JSONL turn boundaries. Records the duration of each assistant turn for latency analysis. | SessionEnd | Claude Code CLI process exits | Drops the waiting flag. If the session is already in , the error state is preserved; otherwise marks all agents and the session as . Evicts the session's transcript from the shared cache. | Quick Start Clone Clone the repository to your machine Install Run npm run setup to install all dependencies Start Run npm run dev — server + client launch automatically Use Claude Start a new Claude Code session — events appear in real-time # 1. Clone git clone https://github.com/hoangsonww/Claude-Code-Agent-Monitor.git cd Claude-Code-Agent-Monitor # 2. Install all dependencies (server + client) npm run setup # 3. Start in development mode npm run dev # → Express server on http://localhost:4820 # → Vite dev server on http://localhost:5173 # 4. (Optional) Build and run the local MCP server npm run mcp:install npm run mcp:build npm run mcp:start # stdio (for MCP host integration) npm run mcp:start:http # HTTP + SSE server on port 8819 npm run mcp:start:repl # interactive CLI with tab completion # 5. Open the dashboard # http://localhost:5173 (dev) # http://localhost:4820 (prod after npm run build && npm start) Alternative: Docker / Podman A multi-stage Dockerfile and docker-compose.yml are included. You can run the monitor with either Docker or Podman and keep the SQLite database in a named volume. # Docker Compose docker compose up -d --build # Podman Compose CLAUDE_HOME="$HOME/.claude" podman compose up -d --build # Plain Docker / Podman docker build -t agent-monitor . docker run -d --name agent-monitor \ -p 4820:4820 \ -v "$HOME/.claude:/root/.claude:ro" \ -v agent-monitor-data:/app/data \ agent-monitor When you run the server directly on the host with npm run dev or npm start , it automatically writes Claude Code hook entries to ~/.claude/settings.json . If you run the dashboard in Docker or Podman, install hooks from the host with npm run install-hooks after the container is up, then restart Claude Code. Optional: Enable MCP and Agent Extensions This repository also ships a local MCP server under mcp/ and extension scaffolding for both Claude Code and Codex. These are optional for the dashboard UI, but recommended for complete local-agent workflows. The MCP server supports stdio (for host integration), HTTP+SSE (for remote clients), and an interactive REPL (for operator debugging). # MCP lifecycle npm run mcp:install npm run mcp:build npm run mcp:start # stdio (default — for MCP hosts) npm run mcp:start:http # HTTP + SSE server on port 8819 npm run mcp:start:repl # interactive CLI with tab completion Verification After starting a Claude Code session, you should see: | Page | Expected | |---|---| | Sessions | Your session listed with status (a fresh CLI is sitting at the prompt) — flips to the moment Claude starts a turn | | Kanban Board | A Main Agent card in the Waiting column until you type your first message; flips to Working on UserPromptSubmit / PreToolUse and back to Waiting after each Stop | | Activity Feed | Events streaming in; click any row to expand payload, use "Session →" to drill into session details | | Dashboard | Stats updating in real-time | Hooks only fire to a running server. If Claude Code was already running when you started the dashboard, restart the Claude Code session. Configuration Environment Variables | Variable | Default | Description | |---|---|---| DASHBOARD_PORT | 4820 | Port the Express server listens on | CLAUDE_DASHBOARD_PORT | 4820 | Port used by the hook handler to reach the server (for custom port setups) | MCP_DASHBOARD_BASE_URL | http://127.0.0.1:4820 | Base URL used by the local MCP server when calling dashboard APIs | MCP_TRANSPORT | stdio | MCP transport mode: stdio , http , repl | MCP_HTTP_PORT | 8819 | Port for the MCP HTTP+SSE server (only when MCP_TRANSPORT=http ) | MCP_HTTP_HOST | 127.0.0.1 | Bind address for the MCP HTTP server | DASHBOARD_DB_PATH | data/dashboard.db | Path to the SQLite database file | NODE_ENV | development | Set to production to serve built client from client/dist/ | Hook Configuration The server writes the following to ~/.claude/settings.json on every startup: { "hooks": { "SessionStart": [ { "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" SessionStart" }] } ], "PreToolUse": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" PreToolUse" }] } ], "PostToolUse": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" PostToolUse" }] } ], "Stop": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" Stop" }] }], "SubagentStop": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" SubagentStop" }] }], "Notification": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" Notification" }] }], "SessionEnd": [ { "hooks": [{ "type": "command", "command": "node \"/path/to/scripts/hook-handler.js\" SessionEnd" }] } ] } } Existing hooks are preserved. The installer only adds or updates entries containing hook-handler.js . Scripts Reference | Script | Command | Description | |---|---|---| setup | npm run setup | Install all dependencies (server + client) | dev | npm run dev | Start server + client in development mode with hot reload | dev:server | npm run dev:server | Start only the Express server with --watch | dev:client | npm run dev:client | Start only the Vite dev server | build | npm run build | TypeScript check + Vite production build to client/dist/ | start | npm start | Start Express in production mode serving built client | install-hooks | npm run install-hooks | Manually write Claude Code hooks to ~/.claude/settings.json | seed | npm run seed | Insert demo sessions, agents, and events (8 sessions / 23 agents / 106 events) | import-history | npm run import-history | Import historical Claude Code sessions from ~/.claude with deep JSONL extraction (API errors, turn durations, thinking blocks, subagent data) | clear-data | npm run clear-data | Delete all data from the database (keeps schema) | test | npm test | Run all server and client tests | test:server | npm run test:server | Server integration tests only (Node built-in test runner) | test:client | npm run test:client | Client unit tests only (Vitest + Testing Library) | mcp:install | npm run mcp:install | Install dependencies for the local MCP package under mcp/ | mcp:typecheck | npm run mcp:typecheck | Type-check MCP source without emitting build output | mcp:build | npm run mcp:build | Compile MCP server into mcp/build/ | mcp:start | npm run mcp:start | Start MCP server (stdio transport — for MCP hosts) | mcp:start:http | npm run mcp:start:http | Start MCP HTTP+SSE server on port 8819 (Streamable HTTP + legacy SSE) | mcp:start:repl | npm run mcp:start:repl | Start interactive MCP REPL with tab completion and colored output | mcp:dev | npm run mcp:dev | Run MCP server in dev mode with tsx (stdio) | mcp:dev:http | npm run mcp:dev:http | Run MCP HTTP server in dev mode with tsx | mcp:dev:repl | npm run mcp:dev:repl | Run MCP REPL in dev mode with tsx | mcp:docker:build | npm run mcp:docker:build | Build MCP container image with Docker (agent-dashboard-mcp:local ) | mcp:podman:build | npm run mcp:podman:build | Build MCP container image with Podman (localhost/agent-dashboard-mcp:local ) | test:mcp | npm run test:mcp | Run MCP server unit tests | format | npm run format | Format all files with Prettier | format:check | npm run format:check | Check formatting without writing | System Architecture Core dashboard telemetry is composed of three processes (Claude hook source, dashboard server, browser UI). When the local MCP sidecar is enabled, it integrates with the same dashboard API via stdio, HTTP+SSE, or interactive REPL transport. Full system architecture — Claude Code process → Hook Layer → Server → Browser Agent State Machine Agent status transitions driven by hook events. waiting is a real persisted status — agents start as waiting and return to it after each turn. Error recovery requires active user retry (UserPromptSubmit or PreToolUse ). A background watchdog detects API errors in transcripts every 15 s. Session State Machine Session status lifecycle. waiting is a UI overlay — persisted as active with awaiting_input_since set. SessionEnd preserves error state. Error recovery requires UserPromptSubmit or PreToolUse . Data Flow Event Ingestion Pipeline Parses JSON and adds hook_type HH->>API: POST {"hook_type":"PreToolUse","data":{...}} API->>TX: BEGIN TRANSACTION TX->>TX: ensureSession(session_id) Note over TX: Creates session + main agent on first contact TX->>TX: process by hook_type Note over TX: SessionStart -> stamp awaiting flag (Waiting) UserPromptSubmit -> clear flag, agent working PreToolUse -> clear flag, agent working PostToolUse -> clear flag, clear current_tool Stop (non-error) -> agent waiting Stop (error) -> agent error, session error SubagentStop -> complete matched subagent (does NOT touch flag); fire-and-forget scanAndImportSubagents emits per-tool Pre/PostToolUse events under each subagent's own agent_id Notification (permission) -> stamp flag SessionEnd -> drop flag, mark all completed TX->>TX: insertEvent(...) TX->>TX: COMMIT API->>WS: broadcast("agent_updated", agent) API->>WS: broadcast("new_event", event) WS->>UI: {"type":"agent_updated","data":{...}} UI->>UI: eventBus.publish -> page re-renders Complete event ingestion from hook fire to browser re-render Client Data Loading Pattern Initial load + WebSocket subscription lifecycle Server Architecture Express app + HTTP server"] DB["server/db.js SQLite + prepared statements better-sqlite3 / node:sqlite fallback"] WS["server/websocket.js WS server + heartbeat"] HOOKS["routes/hooks.js Hook event processing"] SESSIONS["routes/sessions.js Session CRUD"] AGENTS["routes/agents.js Agent CRUD"] EVENTS["routes/events.js Event listing"] STATS["routes/stats.js Aggregate queries"] ANALYTICS["routes/analytics.js Analytics metrics"] PRICING["routes/pricing.js Pricing CRUD + cost calc"] SETTINGS_R["routes/settings.js System info + data mgmt"] WORKFLOWS_R["routes/workflows.js Workflow visualizations"] INDEX --> DB INDEX --> WS INDEX --> HOOKS INDEX --> SESSIONS INDEX --> AGENTS INDEX --> EVENTS INDEX --> STATS INDEX --> ANALYTICS INDEX --> PRICING INDEX --> SETTINGS_R INDEX --> WORKFLOWS_R HOOKS --> DB HOOKS --> WS SESSIONS --> DB SESSIONS --> WS AGENTS --> DB AGENTS --> WS EVENTS --> DB STATS --> DB ANALYTICS --> DB PRICING --> DB SETTINGS_R --> DB WORKFLOWS_R --> DB Server module dependency graph Server Modules | Module | Responsibility | |---|---| server/index.js | Express app setup, middleware (CORS, JSON 1MB limit), route mounting, static serving in production, HTTP server, auto-hook installation on startup | server/db.js | SQLite connection, WAL/FK pragmas, schema migrations (CREATE TABLE IF NOT EXISTS ), all prepared stat

Genesis Park 편집팀이 AI를 활용하여 작성한 분석입니다. 원문은 출처 링크를 통해 확인할 수 있습니다.

공유

관련 저널 읽기

전체 보기 →