Skip to main content
hooksSource-backedReview first Safety · Privacy ·

Code Complexity Alert Monitor - Hooks

Alerts when code complexity exceeds thresholds in real-time using cyclomatic complexity analysis, line count monitoring, function count analysis, and nesting level detection.

by JSONbored·added 2025-09-19·
Claude Code
HarnessClaude Code
Trigger:Notification
Review first review before installing

Open the source and read safety notes before installing.

Schema details

Install type
cli
Reading time
1 min
Difficulty score
0
Troubleshooting
Yes
Breaking changes
No
Runtime and command metadata
Trigger
Notification
Script language
bash
Script body
#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# Check if it's a supported file type
if [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.jsx ]] || [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]] || [[ "$FILE_PATH" == *.py ]]; then
  echo "🔍 Analyzing code complexity for $FILE_PATH..." >&2
  
  # Check file exists
  if [ ! -f "$FILE_PATH" ]; then
    echo "📁 File does not exist yet, skipping complexity analysis" >&2
    exit 0
  fi
  
  # Line count analysis
  LINES=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "0")
  if [ "$LINES" -gt 500 ]; then
    echo "⚠️ COMPLEXITY: File exceeds 500 lines ($LINES lines) - consider splitting into smaller modules" >&2
  elif [ "$LINES" -gt 300 ]; then
    echo "📊 INFO: File is getting large ($LINES lines) - monitor for complexity" >&2
  fi
  
  # Function/method count analysis
  FUNCTION_COUNT=$(grep -E '(function|def |const.*=>|class |async |export function)' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
  if [ "$FUNCTION_COUNT" -gt 20 ]; then
    echo "⚠️ COMPLEXITY: Too many functions/methods ($FUNCTION_COUNT) - consider modularization" >&2
  elif [ "$FUNCTION_COUNT" -gt 15 ]; then
    echo "📊 INFO: High function count ($FUNCTION_COUNT) - good candidate for refactoring" >&2
  fi
  
  # Nesting level analysis (rough estimate)
  OPEN_BRACES=$(grep -o '{' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
  CLOSE_BRACES=$(grep -o '}' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
  
  if [ "$OPEN_BRACES" -gt 50 ]; then
    echo "⚠️ COMPLEXITY: High nesting detected ($OPEN_BRACES braces) - consider flattening logic" >&2
  fi
  
  # Python-specific checks
  if [[ "$FILE_PATH" == *.py ]]; then
    INDENT_DEPTH=$(grep -E '^[ ]{12,}' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
    if [ "$INDENT_DEPTH" -gt 5 ]; then
      echo "⚠️ COMPLEXITY: Deep indentation detected in Python code - consider function extraction" >&2
    fi
  fi
  
  echo "✅ Complexity analysis completed for $FILE_PATH" >&2
else
  echo "File $FILE_PATH is not a supported type for complexity analysis" >&2
fi

exit 0
Full copyable content
{
  "hooks": {
    "notification": {
      "script": "./.claude/hooks/code-complexity-alert-monitor.sh"
    }
  }
}

About this resource

Features

  • Real-time complexity monitoring for JavaScript, TypeScript, and Python using pattern matching and AST-based analysis with support for ESLint v9.37.0+ complexity rules
  • Configurable line count thresholds (default: 500 lines) with customizable warning (300 lines) and error (500 lines) levels for early detection
  • Function count analysis and alerting to detect over-modularization (>20 functions) or under-modularization (<5 functions) patterns
  • Nesting level detection for code structure using brace counting (JavaScript/TypeScript) and indentation depth analysis (Python 12+ spaces)
  • Instant feedback on code maintainability issues with severity levels (INFO for 300+ lines, WARNING for 500+ lines, ERROR for critical complexity)
  • Multi-language support with pattern matching for .js, .jsx, .ts, .tsx, and .py files with language-specific complexity heuristics
  • Cyclomatic complexity estimation using control flow analysis counting conditional branches, loops, and switch statements
  • Integration with ESLint complexity rules (max-complexity) and Radon ^6.0.0 for Python for comprehensive AST-based complexity analysis

Use Cases

  • Real-time code quality monitoring during development providing immediate feedback when complexity thresholds are exceeded
  • Automated complexity alerts in CI/CD pipelines preventing complex code from being merged into main branches
  • Code review assistance and maintainability checks helping reviewers identify refactoring opportunities before code review
  • Technical debt prevention and early detection catching complexity issues before they accumulate into larger problems
  • Team coding standards enforcement ensuring consistent complexity thresholds across all team members and projects
  • Refactoring guidance identifying specific files and functions that exceed complexity thresholds and need modularization

Installation

  1. Create hooks directory: mkdir -p .claude/hooks
  2. Create hook file: touch .claude/hooks/code-complexity-alert-monitor.sh
  3. Make executable: chmod +x .claude/hooks/code-complexity-alert-monitor.sh
  4. Add configuration from Hook Configuration section above to .claude/settings.json or ~/.claude/settings.json
  5. Alternative: Use the interactive /hooks command in Claude Code

Config paths

  • Local (not committed): .claude/settings.local.json
  • User settings (global): ~/.claude/settings.json
  • Project-wide (committed): .claude/settings.json

Requirements

  • Claude Code CLI installed
  • Project directory initialized
  • Bash shell available
  • jq installed (for JSON parsing from stdin)
  • Optional: ESLint ^9.37.0 (npm install -g eslint) for JavaScript/TypeScript complexity analysis, Radon ^6.0.0 (pip install radon) for Python cyclomatic complexity analysis
  • Standard Unix utilities: grep, awk, wc (for pattern matching and line counting) and file system access for reading source code files

Hook Configuration

{
  "hooks": {
    "notification": {
      "script": "./.claude/hooks/code-complexity-alert-monitor.sh"
    }
  }
}

Hook Script

#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# Check if it's a supported file type
if [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.jsx ]] || [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]] || [[ "$FILE_PATH" == *.py ]]; then
  echo "🔍 Analyzing code complexity for $FILE_PATH..." >&2

  # Check file exists
  if [ ! -f "$FILE_PATH" ]; then
    echo "📁 File does not exist yet, skipping complexity analysis" >&2
    exit 0
  fi

  # Line count analysis
  LINES=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "0")
  if [ "$LINES" -gt 500 ]; then
    echo "⚠️ COMPLEXITY: File exceeds 500 lines ($LINES lines) - consider splitting into smaller modules" >&2
  elif [ "$LINES" -gt 300 ]; then
    echo "📊 INFO: File is getting large ($LINES lines) - monitor for complexity" >&2
  fi

  # Function/method count analysis
  FUNCTION_COUNT=$(grep -E '(function|def |const.*=>|class |async |export function)' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
  if [ "$FUNCTION_COUNT" -gt 20 ]; then
    echo "⚠️ COMPLEXITY: Too many functions/methods ($FUNCTION_COUNT) - consider modularization" >&2
  elif [ "$FUNCTION_COUNT" -gt 15 ]; then
    echo "📊 INFO: High function count ($FUNCTION_COUNT) - good candidate for refactoring" >&2
  fi

  # Nesting level analysis (rough estimate)
  OPEN_BRACES=$(grep -o '{' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
  CLOSE_BRACES=$(grep -o '}' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")

  if [ "$OPEN_BRACES" -gt 50 ]; then
    echo "⚠️ COMPLEXITY: High nesting detected ($OPEN_BRACES braces) - consider flattening logic" >&2
  fi

  # Python-specific checks
  if [[ "$FILE_PATH" == *.py ]]; then
    INDENT_DEPTH=$(grep -E '^[ ]{12,}' "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
    if [ "$INDENT_DEPTH" -gt 5 ]; then
      echo "⚠️ COMPLEXITY: Deep indentation detected in Python code - consider function extraction" >&2
    fi
  fi

  echo "✅ Complexity analysis completed for $FILE_PATH" >&2
else
  echo "File $FILE_PATH is not a supported type for complexity analysis" >&2
fi

exit 0

Examples

Code Complexity Alert Monitor Hook Script

Complete hook script that monitors code complexity in real-time for JavaScript, TypeScript, and Python files

#!/usr/bin/env bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r ".tool_name")
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path // .tool_input.path // \"\"")
if [ -z "$FILE_PATH" ]; then exit 0; fi
if [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.py ]]; then
  LINES=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "0")
  if [ "$LINES" -gt 500 ]; then
    echo "⚠️ COMPLEXITY: File exceeds 500 lines ($LINES lines) - consider splitting" >&2
  fi
fi
exit 0

Hook Configuration

Complete hook configuration for .claude/settings.json to enable complexity monitoring on file write operations

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "./.claude/hooks/code-complexity-alert-monitor.sh"
          }
        ]
      }
    ]
  }
}

Python Complexity with Radon

Enhanced hook script using Radon for accurate Python cyclomatic complexity analysis

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path // .tool_input.path // \"\"")
if [ -z "$FILE_PATH" ] || [[ ! "$FILE_PATH" == *.py ]]; then exit 0; fi
if command -v radon >/dev/null 2>&1; then
  COMPLEXITY=$(radon cc "$FILE_PATH" -a -nc 2>/dev/null | grep -oP "Average complexity: \\K[0-9]+\.[0-9]+" || echo "0")
  if (( $(echo "$COMPLEXITY > 10" | bc -l) )); then
    echo "⚠️ COMPLEXITY: High cyclomatic complexity ($COMPLEXITY) - consider refactoring" >&2
  fi
fi
exit 0

JavaScript/TypeScript Complexity with ESLint

Enhanced hook script using ESLint complexity rule for accurate JavaScript/TypeScript cyclomatic complexity analysis

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path // .tool_input.path // \"\"")
if [ -z "$FILE_PATH" ] || [[ ! "$FILE_PATH" == *.{js,jsx,ts,tsx} ]]; then exit 0; fi
if command -v eslint >/dev/null 2>&1; then
  COMPLEXITY=$(eslint --format json "$FILE_PATH" 2>/dev/null | jq -r ".[0].messages[] | select(.ruleId==\"complexity\") | .message" || echo "")
  if [ -n "$COMPLEXITY" ]; then
    echo "⚠️ COMPLEXITY: $COMPLEXITY" >&2
  fi
fi
exit 0

Multi-Metric Complexity Analysis

Comprehensive hook script that analyzes multiple complexity metrics simultaneously for better detection

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path // .tool_input.path // \"\"")
if [ -z "$FILE_PATH" ]; then exit 0; fi
LINES=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "0")
FUNCTION_COUNT=$(grep -E "(function|def |const.*=>|class |async |export function)" "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
OPEN_BRACES=$(grep -o "{" "$FILE_PATH" 2>/dev/null | wc -l || echo "0")
if [ "$LINES" -gt 500 ] || [ "$FUNCTION_COUNT" -gt 20 ] || [ "$OPEN_BRACES" -gt 50 ]; then
  echo "⚠️ COMPLEXITY: Multiple thresholds exceeded - Lines: $LINES, Functions: $FUNCTION_COUNT, Nesting: $OPEN_BRACES" >&2
fi
exit 0

Troubleshooting

Notification hook not running on file write operations

Verify hook is registered under hooks.notification in .claude/settings.json. Check script has executable permissions: chmod +x. Ensure jq is installed for JSON parsing from stdin input. Test hook manually with a test JSON input. Verify Notification hook type is correct in configuration.

Complexity alerts not showing for TypeScript files

Check file extension matches supported types: .js, .jsx, .ts, .tsx, .py. Verify FILE_PATH extraction from tool_input using jq processes correctly. Test with echo command to debug input parsing. Ensure file exists before analysis.

False positives for brace count in JSX files

Hook counts all braces including JSX elements which inflates nesting metrics. Adjust thresholds in script for JSX-heavy files: increase OPEN_BRACES threshold from 50 to 100. Consider implementing AST-based complexity analysis using ESLint instead of regex pattern matching. Use ESLint complexity rule for accurate cyclomatic complexity.

File does not exist error during notification processing

Hook runs after tool execution but file may not be written yet. Add delay with sleep 1 before analysis. Check tool_name matches write or edit operations. Verify path resolution is absolute. Add file existence check before processing.

Python indentation warnings incorrect for valid code

Hook detects 12+ space indentation as deep nesting. Adjust threshold for projects using different indent styles. Use Radon for accurate Python complexity: radon cc file.py -a. Consider using 8-space threshold for projects with 4-space indentation.

Complexity analysis is too slow for large files

Add timeout wrapper: timeout 5s complexity-command. Limit analysis scope: only analyze files under 1000 lines. Use faster tools: ESLint with --cache for JavaScript, Radon with --min B for Python. Skip analysis for generated files: exclude node_modules, dist, build directories.

ESLint complexity rule not detecting issues

Verify ESLint is installed: eslint --version. Check ESLint configuration includes complexity rule. Ensure ESLint can parse file type: install @typescript-eslint/parser for TypeScript. Test manually with eslint --rule complexity command. Check ESLint version: upgrade to ESLint ^9.37.0 for latest complexity analysis.

Radon not calculating Python complexity correctly

Verify Radon is installed: radon --version. Check Python version compatibility: Radon requires Python 3.7+. Test manually: radon cc file.py -a. Ensure file is valid Python syntax. Use specific complexity threshold: radon cc file.py -nc. Check Radon version: upgrade to Radon ^6.0.0 for latest features.

#complexity#code-quality#notification#monitoring#maintainability

Source citations

Signals

Loading live community signals…

More like this, weekly

A short, calm digest of reviewed Claude resources. Unsubscribe any time.