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:
- RED Phase: Write PHPUnit tests for entity definitions
- GREEN Phase: Generate minimal entity and plugin code
- 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.