This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
YOU SHOULD ALWAYS run npm run check:all before committing to ensure all rules pass against the latest code changes. This ensures code quality and compliance with defined rules across the entire working directory, not just changed files.
# Build TypeScript to dist/
npm run build
# Development mode with file watching
npm run dev
# Run all tests
npm test
# Run a specific test file
npm test -- tests/unit/selectors/SelectFilesRule.test.ts
# Type checking without emitting files
npm run typecheck
# Lint the codebase
npm run lint
# Clean build output
npm run cleanCode Guardian is a Git-aware, rule-based code validation system that analyzes only changed files between Git branches. It's built on three core abstractions:
- Selectors: Find items to validate (files, lines, AST nodes)
- Assertions: Check properties of selected items
- Combinators: Compose rules using logical operations
All rules extend from BaseRule and implement the Rule interface with an evaluate(context) method.
Rules are composed using a factory pattern. The most common pattern is:
for_each -> select -> assertExample: For each TypeScript file, assert no console.log statements exist.
EvaluationContext: Carries repository, diff, cache through evaluationRuleResult: Standardized output with violationsRuleFactory: Creates rules from YAML configuration
The GitRepository adapter provides diff information between branches (e.g., main and HEAD). Only files that have been added, modified, deleted, or renamed in this diff are available for validation. Files are loaded on-demand when assertions need content. This Git-aware approach ensures efficient validation focused on actual changes rather than scanning the entire repository.
-
Create rule class extending appropriate base:
SelectorRulefor finding itemsAssertionRulefor checking propertiesCombinatorRulefor logical composition
-
Create builder implementing
RuleBuilderinterface -
Register in
src/config/index.ts:factory.register('your_rule_type', new YourRuleBuilder());
-
Follow test patterns in
tests/unit/- usecreateMockContext()helper
- Assertions within Combinators: Assertions cannot be evaluated directly - they must be used within a combinator (typically
for_each) - File Content Loading: The
ForEachRuleautomatically loads file content when needed - Path Handling: Always use absolute paths internally
- AST Languages: Currently supports TypeScript, JavaScript, TSX, HTML, CSS via
@ast-grep/napi - Pattern Matching: File patterns use minimatch glob syntax
-
File content validation:
type: for_each select: type: select_files path_pattern: '**/*.ts' assert: type: assert_match pattern: 'console\.log' should_match: false
-
Architecture enforcement:
type: for_each select: type: select_files path_pattern: 'src/domain/**/*.ts' assert: type: assert_match pattern: 'from.*infrastructure' should_match: false
-
Security checks with multiple conditions:
type: all_of rules: - type: for_each # ... check for secrets - type: for_each # ... check for vulnerabilities
Tests use consistent mock patterns:
const createMockContext = (files: FileInfo[]): EvaluationContext => {
const mockRepository = {
getFiles: jest.fn().mockResolvedValue(files),
getFileContent: jest.fn().mockImplementation(/* ... */),
getDiff: jest.fn(),
};
// ... return context
};Integration tests in tests/integration/ validate complete rule evaluation against example configurations.