Claude Code Hooks Multi-Agent Observability

repository·main·Indexed 23 days ago

https://github.com/disler/claude-code-hooks-multi-agent-observability

A real-time observability system for Claude Code agents that captures hook events and visualizes them in a web dashboard. It enables developers to trace tool calls, agent lifecycles, and multi-agent orchestration across projects using a data flow of Claude Agents → Hook Scripts → Bun Server → SQLite → WebSocket → Vue Client. The system supports capturing 12 hook event types, including PreToolUse, PostToolUse, and SubagentStop, and integrates with the multi-agent observability-client v1.0.0.

Tokens
21.4K
Snippets
39
Records
90
Agent score
81%

What's inside claude-code-hooks-multi-agent-observability

  1. Overview of Multi-Agent Observability System

    main

    The Multi-Agent Observability System provides real-time monitoring and visualization for Claude Code agents. It captures, stores, and visualizes Claude Code Hook events to enable tracing tool calls, task handoffs, and agent lifecycle events across multiple concurrent agents.

    Data Flow Architecture: Claude Agents → Hook Scripts → HTTP POST → Bun Server → SQLite → WebSocket → Vue Client

  2. Understand the Claude Code subagent priority system

    main

    Claude Code uses a three-tier hierarchy to resolve naming conflicts when multiple subagents are available. The priority order (from highest to lowest) is:

    1. Project-level subagents: Located in the .claude/agents/ directory of your current project. These take precedence over all other sources.
    2. CLI-defined subagents: Defined dynamically via the --agents CLI flag using JSON format. These override user-level subagents but are overridden by project-level ones.
    3. User-level subagents: Located in the ~/.claude/agents/ directory. These are available globally across all projects but have the lowest priority.

    This hierarchy allows you to maintain global baseline subagents while providing project-specific overrides for teams or specialized workflows.

  3. Understand the Claude Code Hook System

    main

    The system uses a hook mechanism to intercept Claude Code lifecycle events. The core of the transmission is send_event.py, which supports all 12 hook event types and can include conversation history using the --add-chat flag.

    Supported Event Types:

    • session_start.py / session_end.py: Logs session metadata and exit reasons.
    • pre_tool_use.py / post_tool_use.py / post_tool_use_failure.py: Manages tool execution lifecycle, including MCP tool detection (mcp_server, mcp_tool_name).
    • permission_request.py: Logs requests for user permission.
    • notification.py: Tracks user interactions with specific notification types (e.g., permission_prompt, idle_prompt).
    • user_prompt_submit.py: Captures user prompts (supports validation via {"decision": "block"} pattern).
    • subagent_start.py / subagent_stop.py: Monitors subagent lifecycle and transcript paths.
    • pre_compact.py: Tracks context compaction.
    • stop.py: Records session completion.
  4. When is the Model Name available in hooks?

    main

    The model name is extracted from assistant messages. Consequently, it is only available for hooks that fire after an assistant message has been generated or during an active assistant turn.

    Hook EventModel Available?Why
    SessionStart❌ NoNo assistant messages yet
    PreUserMessageSubmit❌ NoBefore assistant responds
    PostUserMessageSubmit❌ NoBefore assistant responds
    PreToolUse✅ YesAssistant requested the tool
    PostToolUse✅ YesSame assistant turn
    Stop✅ YesAssistant just finished
    SubagentStop✅ YesSubagent finished
    PreCompact✅ Yes (usually)Assistant has been active

    Note: For hooks that fire before the first assistant message, model_name will be an empty string "".

  5. Use the regex-enabled search bar to filter events

    main

    A regex-enabled search bar (located in apps/client/src/components/EventSearchBar.vue) allows for real-time filtering of the agent event stream.

    Search Behavior

    • Real-time filtering: The UI filters events as you type, using a 300ms debounce to maintain performance.
    • Regex Support: You can use regular expressions to filter events. If an invalid regex pattern is entered, the UI will display a visual error and disable filtering to prevent crashes.
    • Search Scope: The search scans the following fields:
      • source_app: The name of the source application.
      • session_id: The unique session identifier.
      • hook_event_type: The type of event (e.g., tool_use, request_start).
      • Event Data: The stringified JSON content of the event for deep searching.

    Data Flow

    User InputDebounce (300ms)Regex ValidationApply Filter (if valid)

  6. Project Structure Overview

    main

    The repository is organized into several key areas:

    • apps/server/: Bun TypeScript server handling HTTP/WebSocket and SQLite storage.
    • apps/client/: Vue 3 TypeScript dashboard for visualization.
    • .claude/hooks/: Python scripts (run via uv) that intercept Claude Code events (e.g., send_event.py, pre_tool_use.py).
    • .claude/agents/team/: Definitions for specialized agent teams.
    • .claude/settings.json: The central configuration for all 12 Claude Code hook events.
    • scripts/: Utility scripts like start-system.sh and reset-system.sh.
  7. Configure Claude Code Subagent storage locations

    main

    Claude Code supports subagents at two distinct levels of configuration:

    1. Project-level: Stored in .claude/agents/ within your project repository. This is ideal for team collaboration and version-controlling project-specific agents (e.g., a code-reviewer with project-specific standards).
    2. User-level: Stored in ~/.claude/agents/ in your home directory. This is used for personal preferences and global subagents available across all projects.

    Note: The documentation does not explicitly define the priority resolution if a subagent with the same name exists at both levels.

  8. How Human-in-the-Loop (HITL) works in the Observability System

    main

    The Human-in-the-Loop (HITL) pattern allows an agent to pause execution and wait for human intervention via a dashboard.

    The Workflow:

    1. Agent creates a local WebSocket server on a random port.
    2. Agent sends a POST request to the observability server (http://localhost:4000/events) containing the humanInTheLoop data and the responseWebSocketUrl.
    3. Observability Server broadcasts the request to the dashboard.
    4. Human responds via the dashboard UI.
    5. Observability Server connects to the agent's WebSocket URL, sends the response JSON, and closes the connection.
    6. Agent receives the response on its WebSocket and resumes execution.

    Key Ports:

    • Observability HTTP API: http://localhost:4000/events (Fixed)
    • Agent WebSocket Server: Dynamic (Agent-generated, e.g., ws://localhost:50123)
  9. Compare Agent Skills vs Subagents

    main

    Choosing between Agent Skills and Subagents depends on whether you want to extend Claude's capabilities within the current conversation or delegate tasks to a specialized, isolated entity.

    Agent Skills

    • Invocation: Model-driven and implicit. Claude autonomously decides to use a skill based on the request and the skill's description.
    • Context: Operates within the main conversation context. It uses progressive disclosure (loading files only when needed) to manage context efficiently.
    • Best for: Adding specific expertise (e.g., PDF processing, Excel analysis, Git commit generation) while maintaining conversation continuity.

    Subagents

    • Invocation: User-requested or auto-delegated. Can be explicitly invoked (e.g., "Use the code-reviewer subagent") or automatically delegated based on task descriptions.
    • Context: Operates in a separate context window independent from the main conversation. This prevents context pollution and is ideal for long sessions.
    • Best for: Specialized task delegation (e.g., a dedicated debugger, security specialist, or data scientist) and scenarios where you need strict tool control or isolation.
  10. Add a 10-minute time span to the Live Activity Pulse chart

    main

    The LivePulseChart.vue component supports specific time ranges for viewing agent activity. To add a '10m' (10-minute) option:

    1. Update the timeRanges array in apps/client/src/components/LivePulseChart.vue to include '10m'.
    2. Update the aria-label text to include the "10 minutes" option for accessibility.
    3. Verify that the useChartData composable and the chart's bucket/aggregation logic correctly handle the expanded 10-minute window without performance degradation.
  11. Quick Start with the Observability Repository

    main

    To see the system in action using the current repository:

    1. Start the system: Run just start or ./scripts/start-system.sh.
    2. Open the Dashboard: Navigate to http://localhost:5173 in your browser.
    3. Trigger Events: Open Claude Code in your terminal and run a command like: Run git ls-files to understand the codebase.
    4. Observe: Watch the events stream into the Vue client dashboard.
    just start
    # or
    ./scripts/start-system.sh