Skip to content
All posts
May 19, 20264 min read

Claude Code Hooks: Build Your Own Quality Gates Without the CI/CD Overhead

Learn how to use Claude Code's hook system to create automated quality gates for your Android projects, catching bugs and enforcing standards before code hits your repository.

AndroidKotlinClaude CodeAutomationBest Practices
Share:

Hook

You're shipping Android apps solo, juggling 22 projects while maintaining quality. Waiting for CI builds to fail on basic issues wastes hours you could spend coding. Claude Code Hooks let you intercept problems at the source, creating automated quality gates that run instantly in your terminal.

Context: The Quality Gate Problem

As a solo Android developer managing multiple apps, I've seen too many hours lost to preventable issues:

  • Code that doesn't compile on CI
  • Missing nullability annotations
  • Inconsistent formatting breaking team standards
  • Tests that should pass but don't run

Traditional CI/CD pipelines catch these issues, but only after you've pushed code. By then, context switches cost productivity. Quality gates should run locally, instantly, and automatically.

Claude Code Hooks solve this by letting you define scripts that execute at specific lifecycle events—before file writes, after commands, or when you start a new conversation.

Setting Up Your First Quality Gate

Let's create a hook that validates Kotlin code quality before files are saved.

Installing Claude Code Hooks

First, install the hooks extension:

bash
claude add hooks

This adds the

code
@claude-hooks
directory to your project with a
code
hooks.json
configuration file.

Configuring Pre-Write Validation

Create a hook that runs ktlint before any Kotlin file is written:

json
{
  "hooks": [
    {
      "event": "pre-write",
      "matcher": "**/*.kt",
      "command": "ktlint --fail --print {}",
      "description": "Format and validate Kotlin files"
    }
  ]
}

[!TIP] The

code
{}
placeholder passes the filename to your command. Use it to target specific files.

Now every time you edit a

code
.kt
file, Claude will run ktlint. If formatting issues exist, the hook fails and Claude shows you the corrected code.

Building Custom Quality Checks

Let's create a more sophisticated hook that validates Android architecture patterns.

Detecting Architecture Violations

I created this hook to enforce dependency direction in my MVVM architecture:

kotlin
// scripts/validate-architecture.kts
#!/usr/bin/env kotlin

val viewModelPattern = Regex("""class \w+ViewModel.*:\s*ViewModel""")
val repositoryPattern = Regex("""class \w+Repository""")
val dataSourcePattern = Regex("""class \w+DataSource""")

val viewModelFiles = File(".").walk().filter { it.path.endsWith("ViewModel.kt") }
val repositoryFiles = File(".").walk().filter { it.path.endsWith("Repository.kt") }

viewModelFiles.forEach { vmFile ->
    vmFile.readText().let { content ->
        if (content.contains("new ") && !content.contains("Repository")) {
            println("❌ ${vmFile.path}: ViewModel should not instantiate dependencies directly")
            System.exit(1)
        }
    }
}

Register this in your hooks configuration:

json
{
  "hooks": [
    {
      "event": "pre-write",
      "matcher": "**/*ViewModel.kt",
      "command": "kotlinc scripts/validate-architecture.kts",
      "description": "Validate ViewModel architecture rules"
    }
  ]
}

Automated Test Discovery

Another powerful hook validates that new feature files have corresponding tests:

bash
#!/bin/bash
# scripts/require-tests.sh

FILE_PATH="$1"
FEATURE_NAME=$(basename "$FILE_PATH" | sed 's/\..*//')
TEST_FILE="src.test.java/com/example/$FEATURE_NAMETest.java"

if [[ ! -f "$TEST_FILE" ]]; then
    echo "⚠️  No test found for $FILE_PATH"
    echo "Create: $TEST_FILE"
    exit 1
fi

This catches missing test coverage before you commit.

Integrating with Existing CI Systems

Hooks don't replace CI—they complement it. Use hooks for fast feedback and CI for comprehensive validation.

Comparing Hook vs CI Performance

Check TypeLocal HookCI Pipeline
Format validation~0.2s~45s
Unit tests~3s~2m
API validation~0.5s~1m
Security scanNot feasible~3m

[!NOTE] Hooks excel at immediate feedback. Reserve heavy lifting for CI.

Creating a Hook Development Workflow

  1. Pre-commit hooks validate code before you even stage changes
  2. Post-command hooks run additional checks after Gradle builds
  3. Session hooks validate project state when you start Claude Code

Here's a post-command hook that runs after successful builds:

json
{
  "hooks": [
    {
      "event": "post-command",
      "matcher": "gradle build",
      "command": "./gradlew test --console=plain",
      "description": "Run tests after successful build"
    }
  ]
}

Advanced: AI-Powered Code Review Hooks

With Claude Code's AI capabilities, hooks can provide intelligent feedback.

Automatic Code Smell Detection

python
#!/usr/bin/env python3
import sys
import re

def detect_code_smells(content):
    smells = []
    
    # Detect large functions
    functions = re.findall(r'fun \w+\([^)]*\)\s*[^{]*\{([^}]*)\}', content, re.DOTALL)
    for i, func in enumerate(functions):
        if len(func.split('\n')) > 25:
            smells.append(f"Function #{i+1} is too long ({len(func.split(chr(10)))} lines)")
    
    # Detect TODOs
    todos = re.findall(r'//\s*TODO:', content)
    smells.extend([f"TODO found: {todo}" for todo in todos])
    
    return smells

if __name__ == "__main__":
    with open(sys.argv[1], 'r') as f:
        content = f.read()
    
    smells = detect_code_smells(content)
    if smells:
        print("Code smells detected:")
        for smell in smells:
            print(f"  ⚠️  {smell}")
        sys.exit(1)

This provides immediate architectural feedback without waiting for external tools.

Key Takeaways

  • Start small: Begin with format validation hooks—they catch 80% of basic issues
  • Layer your approach: Use hooks for immediate feedback, CI for comprehensive checks
  • Custom validation: Write hooks specific to your architecture patterns and team standards
  • Performance matters: Keep hooks fast—under 2 seconds or developers will ignore them
  • Document your hooks: Add README entries explaining why each hook exists and what it catches
Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this