Real-time monitoring and visualization for Claude Code agents through comprehensive hook event tracking. You can watch the full breakdown here.
This system provides complete observability into Claude Code agent behavior by capturing, storing, and visualizing Claude Code Hook events in real-time. It enables monitoring of multiple concurrent agents with session tracking, event filtering, and live updates.
Claude Agents β Hook Scripts β HTTP POST β Bun Server β SQLite β WebSocket β Vue Client
Before getting started, ensure you have the following installed:
- Claude Code - Anthropic's official CLI for Claude
- Astral uv - Fast Python package manager (required for hook scripts)
- Bun, npm, or yarn - For running the server and client
- Anthropic API Key - Set as
ANTHROPIC_API_KEY
environment variable - OpenAI API Key (optional) - For multi-model support with just-prompt MCP tool
- ElevenLabs API Key (optional) - For audio features
To setup observability in your repo,we need to copy the .claude directory to your project root.
To integrate the observability hooks into your projects:
-
Copy the entire
.claude
directory to your project root:cp -R .claude /path/to/your/project/
-
Update the
settings.json
configuration:Open
.claude/settings.json
in your project and modify thesource-app
parameter to identify your project:{ "hooks": { "PreToolUse": [{ "matcher": ".*", "hooks": [ { "type": "command", "command": "uv run .claude/hooks/pre_tool_use.py" }, { "type": "command", "command": "uv run .claude/hooks/send_event.py --source-app YOUR_PROJECT_NAME --event-type PreToolUse" } ] }], // ... (mirror the above for other event types) } }
Replace
YOUR_PROJECT_NAME
with a unique identifier for your project (e.g.,my-api-server
,react-app
, etc.). -
Ensure the observability server is running:
# From the observability project directory (this codebase) ./scripts/start-system.sh
Now your project will send events to the observability system whenever Claude Code performs actions.
You can quickly view how this works by running this repositories .claude setup.
# 1. Start both server and client
./scripts/start-system.sh
# 2. Open http://localhost:5173 in your browser
# 3. Open Claude Code and run the following command:
Run git ls-files to understand the codebase.
# 4. Watch events stream in the client
# 5. Copy the .claude folder to other projects you want to emit events from.
cp -R .claude <directory of your codebase you want to emit events from>
claude-code-hooks-multi-agent-observability/
β
βββ apps/ # Application components
β βββ server/ # Bun TypeScript server
β β βββ src/
β β β βββ index.ts # Main server with HTTP/WebSocket endpoints
β β β βββ db.ts # SQLite database management & migrations
β β β βββ types.ts # TypeScript interfaces
β β βββ package.json
β β βββ events.db # SQLite database (gitignored)
β β
β βββ client/ # Vue 3 TypeScript client
β βββ src/
β β βββ App.vue # Main app with theme & WebSocket management
β β βββ components/
β β β βββ EventTimeline.vue # Event list with auto-scroll
β β β βββ EventRow.vue # Individual event display
β β β βββ FilterPanel.vue # Multi-select filters
β β β βββ ChatTranscriptModal.vue # Chat history viewer
β β β βββ StickScrollButton.vue # Scroll control
β β β βββ LivePulseChart.vue # Real-time activity chart
β β βββ composables/
β β β βββ useWebSocket.ts # WebSocket connection logic
β β β βββ useEventColors.ts # Color assignment system
β β β βββ useChartData.ts # Chart data aggregation
β β β βββ useEventEmojis.ts # Event type emoji mapping
β β βββ utils/
β β β βββ chartRenderer.ts # Canvas chart rendering
β β βββ types.ts # TypeScript interfaces
β βββ .env.sample # Environment configuration template
β βββ package.json
β
βββ .claude/ # Claude Code integration
β βββ hooks/ # Hook scripts (Python with uv)
β β βββ send_event.py # Universal event sender
β β βββ pre_tool_use.py # Tool validation & blocking
β β βββ post_tool_use.py # Result logging
β β βββ notification.py # User interaction events
β β βββ stop.py # Session completion
β β βββ subagent_stop.py # Subagent completion
β β
β βββ settings.json # Hook configuration
β
βββ scripts/ # Utility scripts
β βββ start-system.sh # Launch server & client
β βββ reset-system.sh # Stop all processes
β βββ test-system.sh # System validation
β
βββ logs/ # Application logs (gitignored)
If you want to master claude code hooks watch this video
The hook system intercepts Claude Code lifecycle events:
-
send_event.py
: Core script that sends event data to the observability server- Supports
--add-chat
flag for including conversation history - Validates server connectivity before sending
- Handles all event types with proper error handling
- Supports
-
Event-specific hooks: Each implements validation and data extraction
pre_tool_use.py
: Blocks dangerous commands, validates tool usagepost_tool_use.py
: Captures execution results and outputsnotification.py
: Tracks user interaction pointsstop.py
: Records session completion with optional chat historysubagent_stop.py
: Monitors subagent task completion
Bun-powered TypeScript server with real-time capabilities:
- Database: SQLite with WAL mode for concurrent access
- Endpoints:
POST /events
- Receive events from agentsGET /events/recent
- Paginated event retrieval with filteringGET /events/filter-options
- Available filter valuesWS /stream
- Real-time event broadcasting
- Features:
- Automatic schema migrations
- Event validation
- WebSocket broadcast to all clients
- Chat transcript storage
Vue 3 application with real-time visualization:
-
Visual Design:
- Dual-color system: App colors (left border) + Session colors (second border)
- Gradient indicators for visual distinction
- Dark/light theme support
- Responsive layout with smooth animations
-
Features:
- Real-time WebSocket updates
- Multi-criteria filtering (app, session, event type)
- Live pulse chart with session-colored bars and event type indicators
- Time range selection (1m, 3m, 5m) with appropriate data aggregation
- Chat transcript viewer with syntax highlighting
- Auto-scroll with manual override
- Event limiting (configurable via
VITE_MAX_EVENTS_TO_DISPLAY
)
-
Live Pulse Chart:
- Canvas-based real-time visualization
- Session-specific colors for each bar
- Event type emojis displayed on bars
- Smooth animations and glow effects
- Responsive to filter changes
- Event Generation: Claude Code executes an action (tool use, notification, etc.)
- Hook Activation: Corresponding hook script runs based on
settings.json
configuration - Data Collection: Hook script gathers context (tool name, inputs, outputs, session ID)
- Transmission:
send_event.py
sends JSON payload to server via HTTP POST - Server Processing:
- Validates event structure
- Stores in SQLite with timestamp
- Broadcasts to WebSocket clients
- Client Update: Vue app receives event and updates timeline in real-time
Event Type | Emoji | Purpose | Color Coding |
---|---|---|---|
PreToolUse | π§ | Before tool execution | Session-based |
PostToolUse | β | After tool completion | Session-based |
Notification | π | User interactions | Session-based |
Stop | π | Response completion | Session-based |
SubagentStop | π₯ | Subagent finished | Session-based |
PreCompact | π¦ | Context compaction | Session-based |
-
Copy the event sender:
cp .claude/hooks/send_event.py YOUR_PROJECT/.claude/hooks/
-
Add to your
.claude/settings.json
:{ "hooks": { "PreToolUse": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "uv run .claude/hooks/send_event.py --source-app YOUR_APP --event-type PreToolUse" }] }] } }
Already integrated! Hooks run both validation and observability:
{
"type": "command",
"command": "uv run .claude/hooks/pre_tool_use.py"
},
{
"type": "command",
"command": "uv run .claude/hooks/send_event.py --source-app cc-hooks-observability --event-type PreToolUse"
}
# System validation
./scripts/test-system.sh
# Manual event test
curl -X POST http://localhost:4000/events \
-H "Content-Type: application/json" \
-d '{
"source_app": "test",
"session_id": "test-123",
"hook_event_type": "PreToolUse",
"payload": {"tool_name": "Bash", "tool_input": {"command": "ls"}}
}'
Copy .env.sample
to .env
in the project root and fill in your API keys:
Application Root (.env
file):
ANTHROPIC_API_KEY
β Anthropic Claude API key (required)ENGINEER_NAME
β Your name (for logging/identification)GEMINI_API_KEY
β Google Gemini API key (optional)OPENAI_API_KEY
β OpenAI API key (optional)ELEVEN_API_KEY
β ElevenLabs API key (optional)
Client (.env
file in apps/client/.env
):
VITE_MAX_EVENTS_TO_DISPLAY=100
β Maximum events to show (removes oldest when exceeded)
- Server:
4000
(HTTP/WebSocket) - Client:
5173
(Vite dev server)
- Blocks dangerous commands (
rm -rf
, etc.) - Prevents access to sensitive files (
.env
, private keys) - Validates all inputs before execution
- No external dependencies for core functionality
- Server: Bun, TypeScript, SQLite
- Client: Vue 3, TypeScript, Vite, Tailwind CSS
- Hooks: Python 3.8+, Astral uv, TTS (ElevenLabs or OpenAI), LLMs (Claude or OpenAI)
- Communication: HTTP REST, WebSocket
If your hook scripts aren't executing properly, it might be due to relative paths in your .claude/settings.json
. Claude Code documentation recommends using absolute paths for command scripts.
Solution: Use the custom Claude Code slash command to automatically convert all relative paths to absolute paths:
# In Claude Code, simply run:
/convert_paths_absolute
This command will:
- Find all relative paths in your hook command scripts
- Convert them to absolute paths based on your current working directory
- Create a backup of your original settings.json
- Show you exactly what changes were made
This ensures your hooks work correctly regardless of where Claude Code is executed from.
And prepare for Agentic Engineering
Learn to code with AI with foundational Principles of AI Coding
Follow the IndyDevDan youtube channel for more AI coding tips and tricks.