Skip to main content

TDDAI & Claude Code Hooks - Usage Examples and Best Practices

🎯 Overview​

This guide provides comprehensive examples and best practices for using TDDAI and Claude Code hooks in real-world development scenarios. From simple TDD workflows to complex enterprise integrations, these examples demonstrate how to maximize productivity while maintaining high code quality.

πŸš€ Quick Start Examples​

Basic TDD Workflow​

Scenario: Building a User Authentication System​

# 1. Initialize TDD session
/tdd-start

# Claude response includes injected context:
# [TDD Status] Phase: unknown, Coverage: 85% | [Project Context] 23 files tracked, Type: Node.js
# 2. Enter RED phase - write failing tests
/tdd-red user-authentication

# Hook prevents implementation file edits
# Only test files can be modified during RED phase

Example test file creation:

// tests/auth/AuthService.test.js
describe('AuthService', () => {
test('should authenticate user with valid credentials', async () => {
const authService = new AuthService();
const result = await authService.authenticate('user@example.com', 'password123');

expect(result.success).toBe(true);
expect(result.token).toBeDefined();
expect(result.user.email).toBe('user@example.com');
});

test('should reject invalid credentials', async () => {
const authService = new AuthService();
const result = await authService.authenticate('user@example.com', 'wrongpassword');

expect(result.success).toBe(false);
expect(result.error).toBe('Invalid credentials');
});
});
# 3. Enter GREEN phase - minimal implementation
/tdd-green user-authentication

# Hook allows implementation file edits
# Warns if you try to modify tests during implementation

Minimal implementation:

// src/auth/AuthService.js
class AuthService {
async authenticate(email, password) {
// Minimal implementation to pass tests
if (email === 'user@example.com' && password === 'password123') {
return {
success: true,
token: 'mock-jwt-token',
user: { email }
};
}

return {
success: false,
error: 'Invalid credentials'
};
}
}

export default AuthService;
# 4. Enter REFACTOR phase - improve code quality
/tdd-refactor user-authentication

# Hook reminds to keep tests green during refactoring

Refactored implementation:

// src/auth/AuthService.js
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import UserRepository from '../repositories/UserRepository.js';

class AuthService {
constructor(userRepository = new UserRepository()) {
this.userRepository = userRepository;
}

async authenticate(email, password) {
try {
const user = await this.userRepository.findByEmail(email);

if (!user) {
return { success: false, error: 'Invalid credentials' };
}

const isValidPassword = await bcrypt.compare(password, user.hashedPassword);

if (!isValidPassword) {
return { success: false, error: 'Invalid credentials' };
}

const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);

return {
success: true,
token,
user: { id: user.id, email: user.email }
};
} catch (error) {
return { success: false, error: 'Authentication failed' };
}
}
}

export default AuthService;
# 5. Check final status and metrics
/tdd-status

# Shows updated coverage, quality score, and compliance metrics

Enterprise Drupal Module Development​

Scenario: Creating a Custom AI Content Module​

# Initialize with Drupal ultra-strict mode
npx @bluefly/tddai drupal ultra-strict /path/to/ai_content --zero-tolerance

# Analysis results show custom code score and contrib suggestions

Hook-enforced workflow:

  1. RED Phase: Write PHPUnit tests for entity definitions
  2. GREEN Phase: Generate minimal entity and plugin code
  3. REFACTOR Phase: Add proper Drupal traits and standards
// tests/src/Unit/AIContentEntityTest.php
<?php

namespace Drupal\Tests\ai_content\Unit;

use Drupal\ai_content\Entity\AIContent;
use Drupal\Tests\UnitTestCase;

/**
* Tests the AI Content entity.
*
* @group ai_content
*/
class AIContentEntityTest extends UnitTestCase {

/**
* Test AI Content entity creation.
*/
public function testEntityCreation() {
$entity = AIContent::create([
'title' => 'Test AI Content',
'content' => 'Generated by AI',
'model' => 'gpt-4',
'status' => 1,
]);

$this->assertEquals('Test AI Content', $entity->getTitle());
$this->assertEquals('Generated by AI', $entity->getContent());
$this->assertEquals('gpt-4', $entity->getModel());
$this->assertTrue($entity->isPublished());
}
}
# TDDAI suggests using existing contrib instead of custom code
tddai drupal suggest-contrib /path/to/ai_content

# Output: Consider using 'ai' module + 'node' entities instead of custom entity

🏒 Team Collaboration Examples​

Team Onboarding Workflow​

Setup by Team Lead (One-time)​

cd /team/project
npx @bluefly/tddai setup-wizard

# Creates team-wide configuration
cat tddai.config.yml
# Team configuration
project:
type: typescript
language: typescript
framework: jest

testing:
coverageThreshold: 95
timeout: 30000

tdd:
enforceWorkflow: true
requireTestFirst: true

team:
enforcementLevel: strict
sharedMetrics: true
notifications: true
# Commit configuration
git add .claude/ tddai.config.yml
git commit -m "Setup TDDAI team workflow"
git push

New Team Member Setup (Zero Configuration)​

# Clone and setup
git clone <team-repo>
cd <team-repo>
npm install -g @bluefly/tddai

# All slash commands now work immediately in Claude Code!
/tdd-start

Code Review Integration​

Pre-Commit Hook Example​

#!/bin/sh
# .git/hooks/pre-commit

# Run TDDAI validation before commit
npx @bluefly/tddai validate --strict --pre-commit

if [ $? -ne 0 ]; then
echo "❌ TDD validation failed. Commit blocked."
echo "Run '/tdd-validate' in Claude Code for details."
exit 1
fi

echo "βœ… TDD validation passed."

GitLab CI Integration​

# .gitlab-ci.yml
stages:
- quality-check
- test
- build

tdd-validation:
stage: quality-check
image: node:20
script:
- npm install -g @bluefly/tddai
- tddai validate --strict --junit-output
- tddai report --format json > tdd-report.json
artifacts:
reports:
junit: tddai-junit.xml
paths:
- tdd-report.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"

πŸ”§ Advanced Hook Customization​

Custom Context Injection​

Project-Specific Context Hook​

#!/usr/bin/env node
// .claude/hooks/project-context-injector.js

const { execSync } = require('child_process');
const fs = require('fs');

function gatherProjectContext() {
const contexts = [];

// Custom business context
const businessContext = getBusinessContext();
if (businessContext) {
contexts.push(`[Business] ${businessContext}`);
}

// Deployment status
const deploymentStatus = getDeploymentStatus();
if (deploymentStatus) {
contexts.push(`[Deploy] ${deploymentStatus}`);
}

// Custom metrics
const customMetrics = getCustomMetrics();
if (customMetrics) {
contexts.push(`[Metrics] ${customMetrics}`);
}

return contexts.join(' | ');
}

function getBusinessContext() {
try {
// Read business requirements from project
if (fs.existsSync('.business-requirements.json')) {
const reqs = JSON.parse(fs.readFileSync('.business-requirements.json'));
return `Sprint: ${reqs.currentSprint}, Priority: ${reqs.priority}`;
}
} catch (error) {
return null;
}
}

function getDeploymentStatus() {
try {
// Check deployment status from CI/CD API
const result = execSync('curl -s https://api.gitlab.com/v4/projects/123/deployments', {
timeout: 3000,
encoding: 'utf8'
});

const deployments = JSON.parse(result);
const latest = deployments[0];

return `Latest: ${latest.environment.name} (${latest.status})`;
} catch (error) {
return null;
}
}

function getCustomMetrics() {
try {
// Read custom project metrics
const result = execSync('npx custom-metrics-cli --json', {
timeout: 2000,
encoding: 'utf8'
});

const metrics = JSON.parse(result);
return `Performance: ${metrics.performance}, Security: ${metrics.security}`;
} catch (error) {
return null;
}
}

// Main execution
const input = JSON.parse(process.argv[2] || '{}');
if (input.event === 'UserPromptSubmit') {
console.log(JSON.stringify({
continue: true,
context: gatherProjectContext()
}));
}

Advanced Compliance Guardian​

Multi-Framework Enforcement Hook​

#!/usr/bin/env node
// .claude/hooks/multi-framework-guardian.js

const fs = require('fs');
const path = require('path');

function validateToolUse(toolData) {
const { toolName, args } = toolData;

if (!['Edit', 'Write', 'MultiEdit'].includes(toolName)) {
return { continue: true };
}

const filePath = args.file_path;
const validations = [
validateTDDWorkflow(filePath, toolName),
validateSecurityRules(filePath, toolName),
validateArchitectureRules(filePath, toolName),
validateBusinessRules(filePath, toolName)
];

// Return first blocking validation
for (const validation of validations) {
if (!validation.continue) {
return validation;
}
}

// Combine all contexts
const contexts = validations
.map(v => v.context)
.filter(Boolean);

return {
continue: true,
context: contexts.join(' β€’ ')
};
}

function validateArchitectureRules(filePath, toolName) {
// Enforce clean architecture
if (filePath.includes('/domain/') && filePath.includes('infrastructure')) {
return {
continue: false,
reason: 'Architecture Violation: Domain layer cannot depend on infrastructure'
};
}

// Enforce dependency direction
if (filePath.includes('/controllers/') && filePath.includes('/entities/')) {
return {
continue: true,
context: 'πŸ—οΈ Architecture: Controller β†’ Service β†’ Repository β†’ Entity'
};
}

return { continue: true };
}

function validateBusinessRules(filePath, toolName) {
// Check business-specific rules
if (fs.existsSync('.business-rules.json')) {
const rules = JSON.parse(fs.readFileSync('.business-rules.json'));

// Example: Prevent editing core business logic without approval
if (rules.protectedPaths?.some(p => filePath.includes(p))) {
return {
continue: false,
reason: `Business Rule: ${path.basename(filePath)} requires architecture review approval`
};
}
}

return { continue: true };
}

// Main execution
const input = JSON.parse(process.argv[2] || '{}');
if (input.event === 'PreToolUse') {
console.log(JSON.stringify(validateToolUse(input.data)));
}

πŸ“Š Monitoring and Analytics​

Team Dashboard Integration​

Metrics Collection Hook​

#!/usr/bin/env node
// .claude/hooks/metrics-collector.js

const { execSync } = require('child_process');
const fs = require('fs');

function collectMetrics() {
const metrics = {
timestamp: new Date().toISOString(),
project: getProjectName(),
user: process.env.USER,
tddPhase: getTDDPhase(),
coverage: getCoverage(),
qualityScore: getQualityScore(),
violations: getViolations()
};

// Send to team dashboard
sendToTeamDashboard(metrics);

return metrics;
}

function sendToTeamDashboard(metrics) {
try {
// Send to team analytics endpoint
execSync(`curl -X POST https://team-dashboard.example.com/api/metrics \\
-H "Content-Type: application/json" \\
-d '${JSON.stringify(metrics)}'`, {
timeout: 2000
});
} catch (error) {
// Fail silently for dashboard
}
}

function getViolations() {
try {
const result = execSync('npx @bluefly/tddai validate --json', {
timeout: 5000,
encoding: 'utf8'
});

const validation = JSON.parse(result);
return validation.violations || [];
} catch (error) {
return [];
}
}

// Collect metrics on every prompt (sampling for performance)
const input = JSON.parse(process.argv[2] || '{}');
if (input.event === 'UserPromptSubmit' && Math.random() < 0.1) { // 10% sampling
collectMetrics();
}

console.log(JSON.stringify({ continue: true }));

Real-time Quality Monitoring​

Quality Gate Hook​

#!/usr/bin/env node
// .claude/hooks/quality-gate.js

function checkQualityGates(toolData) {
const { toolName, args } = toolData;

// Only check on file saves
if (toolName !== 'Write' && toolName !== 'Edit') {
return { continue: true };
}

const qualityChecks = [
checkCoverageThreshold(),
checkComplexityLimits(),
checkSecurityVulnerabilities(),
checkPerformanceRegression()
];

const failures = qualityChecks.filter(check => !check.passed);

if (failures.length > 0) {
return {
continue: false,
reason: `Quality Gate Failed: ${failures.map(f => f.reason).join(', ')}`
};
}

const warnings = qualityChecks.filter(check => check.warning);
if (warnings.length > 0) {
return {
continue: true,
context: `⚠️ Quality Warnings: ${warnings.map(w => w.warning).join(', ')}`
};
}

return { continue: true };
}

function checkCoverageThreshold() {
try {
const result = execSync('npm test -- --coverage --silent', {
timeout: 10000,
encoding: 'utf8'
});

const coverageMatch = result.match(/All files\s+\|\s+(\d+\.?\d*)/);
const coverage = coverageMatch ? parseFloat(coverageMatch[1]) : 0;

if (coverage < 95) {
return {
passed: false,
reason: `Coverage ${coverage}% below threshold (95%)`
};
}

if (coverage < 98) {
return {
passed: true,
warning: `Coverage ${coverage}% could be improved`
};
}

return { passed: true };
} catch (error) {
return { passed: true }; // Don't fail on test errors
}
}

function checkComplexityLimits() {
try {
// Run complexity analysis
const result = execSync('npx complexity-report --format json', {
timeout: 5000,
encoding: 'utf8'
});

const report = JSON.parse(result);
const highComplexity = report.functions.filter(f => f.complexity > 10);

if (highComplexity.length > 0) {
return {
passed: false,
reason: `${highComplexity.length} functions exceed complexity limit (10)`
};
}

return { passed: true };
} catch (error) {
return { passed: true };
}
}

// Main execution
const input = JSON.parse(process.argv[2] || '{}');
if (input.event === 'PreToolUse') {
console.log(JSON.stringify(checkQualityGates(input.data)));
}

πŸ—οΈ Enterprise Integration Examples​

Multi-Project Management​

Workspace-Level Configuration​

// .claude/hooks/workspace-manager.js
function getWorkspaceContext() {
const workspacePath = findWorkspaceRoot();
if (!workspacePath) return null;

const projects = getWorkspaceProjects(workspacePath);
const activeProject = getCurrentProject();

return {
workspace: path.basename(workspacePath),
projects: projects.length,
active: activeProject,
status: getWorkspaceStatus(projects)
};
}

function getWorkspaceStatus(projects) {
const statusCounts = projects.reduce((acc, project) => {
const status = getProjectStatus(project);
acc[status] = (acc[status] || 0) + 1;
return acc;
}, {});

return statusCounts;
}

SSO and Enterprise Authentication​

Enterprise Auth Hook​

// .claude/hooks/enterprise-auth.js
function validateEnterpriseAccess(toolData) {
const userRole = getUserRole();
const filePath = toolData.args?.file_path;

// Check role-based file access
if (filePath && !canAccessFile(userRole, filePath)) {
return {
continue: false,
reason: `Access Denied: ${userRole} role cannot modify ${path.basename(filePath)}`
};
}

// Check time-based access
if (!isWithinAllowedHours()) {
return {
continue: false,
reason: 'Access Denied: Outside of allowed development hours'
};
}

return { continue: true };
}

function getUserRole() {
// Integration with enterprise SSO
try {
const result = execSync('enterprise-cli whoami --json', {
timeout: 3000,
encoding: 'utf8'
});

const user = JSON.parse(result);
return user.role;
} catch (error) {
return 'unknown';
}
}

πŸŽ“ Best Practices​

Performance Optimization​

Efficient Hook Design​

// Use caching for expensive operations
const cache = new Map();
const CACHE_TTL = 30000; // 30 seconds

function getCachedResult(key, computeFn) {
if (cache.has(key)) {
const { value, timestamp } = cache.get(key);
if (Date.now() - timestamp < CACHE_TTL) {
return value;
}
}

const value = computeFn();
cache.set(key, { value, timestamp: Date.now() });
return value;
}

// Parallel execution for independent checks
async function runParallelChecks(checks) {
const results = await Promise.allSettled(
checks.map(check => Promise.resolve(check()))
);

return results
.filter(result => result.status === 'fulfilled')
.map(result => result.value);
}

Resource Management​

// Implement timeouts for all external calls
function safeExec(command, timeout = 5000) {
return new Promise((resolve, reject) => {
const child = execSync(command, { timeout });

const timeoutId = setTimeout(() => {
child.kill();
resolve(null); // Return null instead of rejecting
}, timeout);

child.on('exit', () => {
clearTimeout(timeoutId);
resolve(child.stdout);
});
});
}

Error Handling and Reliability​

Graceful Degradation​

function robustHookExecution(hookFn) {
try {
const result = hookFn();

// Validate result format
if (typeof result !== 'object' || result === null) {
return { continue: true };
}

// Ensure required properties
if (typeof result.continue !== 'boolean') {
result.continue = true;
}

return result;
} catch (error) {
// Log error for debugging but don't block user
debugLog('Hook execution error:', error);
return { continue: true };
}
}

Comprehensive Testing​

// Test hook with various inputs
describe('TDD Context Injector Hook', () => {
test('handles UserPromptSubmit event', () => {
const input = {
event: 'UserPromptSubmit',
prompt: 'test prompt'
};

const result = runHook(input);

expect(result.continue).toBe(true);
expect(result.context).toContain('[TDD Status]');
});

test('gracefully handles missing TDDAI', () => {
// Mock TDDAI as unavailable
jest.spyOn(child_process, 'execSync').mockImplementation(() => {
throw new Error('Command not found');
});

const result = runHook({ event: 'UserPromptSubmit' });

expect(result.continue).toBe(true);
expect(result.context).toBeFalsy();
});

test('handles malformed JSON input', () => {
const result = runHookWithRawInput('invalid json');

expect(result.continue).toBe(true);
});
});

Security Best Practices​

Input Validation​

function validateInput(input) {
// Validate event type
const allowedEvents = ['UserPromptSubmit', 'PreToolUse'];
if (!allowedEvents.includes(input.event)) {
return false;
}

// Validate file paths
if (input.data?.args?.file_path) {
const filePath = input.data.args.file_path;
if (!isValidFilePath(filePath)) {
return false;
}
}

return true;
}

function isValidFilePath(filePath) {
// Prevent directory traversal
if (filePath.includes('..')) return false;

// Ensure path is within project
const resolved = path.resolve(filePath);
const projectRoot = process.cwd();
return resolved.startsWith(projectRoot);
}

Safe Command Execution​

function safeCommandExecution(command, args = []) {
// Whitelist allowed commands
const allowedCommands = [
'npx @bluefly/tddai',
'git',
'npm test',
'jest'
];

if (!allowedCommands.some(allowed => command.startsWith(allowed))) {
throw new Error(`Command not allowed: ${command}`);
}

// Sanitize arguments
const sanitizedArgs = args.map(arg =>
arg.replace(/[;&|`$(){}[\]]/g, '')
);

return execSync(`${command} ${sanitizedArgs.join(' ')}`, {
timeout: 10000,
encoding: 'utf8'
});
}

Team Collaboration Guidelines​

Shared Hook Standards​

// Standard hook metadata
const HOOK_METADATA = {
name: 'TDD Context Injector',
version: '2.0.0',
author: 'team-lead@company.com',
description: 'Injects TDD status and project context',
supportedEvents: ['UserPromptSubmit'],
configurationOptions: {
enabledFrameworks: ['jest', 'phpunit'],
contextLevel: 'detailed', // 'minimal', 'detailed', 'verbose'
cacheTimeout: 30000
}
};

// Version compatibility checking
function checkCompatibility() {
const requiredTDDAIVersion = '2.2.0';
const currentVersion = getCurrentTDDAIVersion();

if (semver.lt(currentVersion, requiredTDDAIVersion)) {
console.error(`Hook requires TDDAI ${requiredTDDAIVersion} or higher`);
process.exit(1);
}
}

Documentation Standards​

/**
* TDD Context Injector Hook
*
* @description Automatically injects TDD status, coverage metrics, and project
* context into every Claude Code prompt for enhanced development workflow.
*
* @events UserPromptSubmit
* @requirements @bluefly/tddai@^2.2.0
* @configuration See tddai.config.yml for customization options
*
* @example
* Input: {"event": "UserPromptSubmit", "prompt": "implement login"}
* Output: {"continue": true, "context": "[TDD Status] Phase: RED, Coverage: 85%"}
*
* @performance
* - Cached results for 30 seconds to avoid repeated analysis
* - Timeout: 5 seconds for external command execution
* - Fallback: Graceful degradation if TDDAI unavailable
*
* @author team-lead@company.com
* @version 2.0.0
* @lastUpdated 2024-01-01
*/

This comprehensive guide provides the foundation for implementing sophisticated TDDAI and Claude Code hook integrations that scale from individual developers to enterprise teams while maintaining high code quality, security, and performance standards.