mcpField
S
sc-principles

sc-principles

github.com/tony363Testing & quality2096 installsUpdated 30w ago
Repository

About sc-principles

sc-principles is a Python code-validation skill that checks code against KISS, Functional Core/Imperative Shell, SOLID, and Let It Crash principles. It offers configurable thresholds, selective checks, and JSON reporting for development workflows.

Key features

  1. 01Checks four engineering principles
  2. 02Measures complexity and code structure
  3. 03Detects I/O and error-handling patterns
  4. 04Configurable checks and thresholds
  5. 05JSON reports and pre-commit mode

Use cases

  1. 01Review Python code for principle violations
  2. 02Run selected checks during refactoring
  3. 03Block commits that fail validation
  4. 04Generate machine-readable validation reports

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/tony363/superclaude --skill sc-principles

After installing, type/sc-principlesin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

scripts/
__init__.py
shared.py
validate_crash.py
validate_kiss.py
validate_purity.py
validate_solid.py
tests/
__init__.py
test_shared.py
test_validate_crash.py
test_validate_kiss.py
test_validate_purity.py
test_validate_solid.py

Details

From the project README

/sc:principles - Code Principles Validator

Mandatory validation skill enforcing four fundamental software engineering principles:

  1. KISS (Keep It Simple, Stupid) - Code should be as simple as possible
  2. Functional Core, Imperative Shell - Business logic must be pure; I/O belongs at edges
  3. SOLID - Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
  4. Let It Crash - Fail fast for bugs; handle errors explicitly at boundaries

Quick Start

# Full validation (all four principles)
/sc:principles src/

# KISS only validation
/sc:principles src/ --kiss-only

# Purity only validation
/sc:principles src/ --purity-only

# SOLID only validation
/sc:principles src/ --solid-only

# Let It Crash only validation
/sc:principles src/ --crash-only

# Strict mode (warnings become errors)
/sc:principles src/ --strict

# Generate detailed report
/sc:principles src/ --report

Behavioral Flow

1. INITIALIZE
   ├── Detect scope root
   ├── Find changed Python files (git diff)
   └── Determine file contexts (core vs shell)

2. ANALYZE
   ├── Parse AST for each file
   ├── Calculate complexity metrics (KISS)
   ├── Detect I/O patterns (Purity)
   ├── Check structural patterns (SOLID)
   └── Analyze error handling (Let It Crash)

3. VALIDATE
   ├── Compare against thresholds
   ├── Classify violations (error vs warning)
   └── Apply context rules (core stricter than shell)

4. REPORT/BLOCK
   ├── Output violations with locations
   ├── Generate actionable recommendations
   └── Exit 0 (pass) or 2 (blocked)

Validation Rules

KISS Gate
MetricThresholdSeverityDescription
Cyclomatic Complexity> 10errorNumber of independent paths through code
Cyclomatic Complexity> 7warningEarly warning for growing complexity
Cognitive Complexity> 15errorWeighted complexity (nested structures count more)
Function Length> 50 lineserrorLines of code per function (inclusive count)
Nesting Depth> 4 levelserrorIf/for/while/with/try nesting
Parameter Count> 5warningFunction parameters

Cognitive vs Cyclomatic Complexity:

  • Cyclomatic counts decision points (branches)
  • Cognitive weights nested structures more heavily: 1 + nesting_depth per control structure
  • Example: if (if (if ...)) has low cyclomatic but high cognitive (hard to read)
Purity Gate

The "Functional Core, Imperative Shell" pattern:

LayerPath PatternsI/O AllowedSeverity
Core*/domain/*, */logic/*, */services/*, */utils/*, */core/*NOerror
Shell*/handlers/*, */adapters/*, */api/*, */cli/*, */scripts/*, */tests/*YESwarning

Note: Files in */archive/*, */examples/*, */benchmarks/*, conftest.py, setup.py, and *__main__.py are treated as shell (I/O allowed).

Detected I/O Patterns:

CategoryExamples
File I/Oopen(), read(), write(), Path.read_text()
Networkrequests.get(), httpx, urllib, socket
Databaseexecute(), query(), session.add(), cursor
Subprocesssubprocess.run(), os.system(), Popen
Global Stateglobal, nonlocal keywords
Side Effectsprint(), logging.*, logger.*
Async I/Oasync def, await, async for, async with
SOLID Gate

Detects structural violations of SOLID design principles.

PrincipleDetectionSeverityDescription
SRPFile >300 lines, class with >5 public methodswarningSingle Responsibility - one reason to change
OCPif/elif chains on type, isinstance cascadeswarningOpen-Closed - extend, don't modify
LSPOverride that raises NotImplementedErrorerrorLiskov Substitution - honor contracts
ISPInterface/protocol with >7 methodswarningInterface Segregation - small interfaces
DIPDirect instantiation in business logicwarningDependency Inversion - depend on abstractions

Code Smells to Flag:

SmellPrincipleRecommended Fix
File >300 linesSRPExtract responsibilities into modules
if/else type chainsOCPStrategy pattern or registry
Override that throwsLSPHonor base contract or don't inherit
10+ method interfaceISPSplit into focused interfaces
new Service() in logicDIPDependency injection
Let It Crash Gate

Detects anti-patterns in error handling based on the "Let It Crash" philosophy.

PatternSeverityDescription
Bare except:errorCatches all exceptions including KeyboardInterrupt
except Exception: (no re-raise)warningSwallows errors without handling
except: passerrorSilent failure, debugging nightmare
Nested try/except fallbackswarningComplex error paths, hard to debug

When to Let It Crash:

  • Validation failures → crash with clear error
  • Programming errors → surface immediately
  • Internal operations → let them fail

When to Handle Errors (exceptions to rule):

  • Data persistence → protect against data loss
  • External APIs → retry, fallback, graceful degradation
  • Resource cleanup → RAII, finally blocks
  • User-facing operations → graceful error messages

Not Flagged (appropriate handling):

  • Error handling in */adapters/*, */api/*, */cli/* paths
  • Explicit logging before swallowing
  • Re-raise after logging

Flags

FlagTypeDefaultDescription
--kiss-onlyboolfalseRun only KISS validation
--purity-onlyboolfalseRun only purity validation
--solid-onlyboolfalseRun only SOLID validation
--crash-onlyboolfalseRun only Let It Crash validation
--no-kissboolfalseSkip KISS validation
--no-purityboolfalseSkip purity validation
--no-solidboolfalseSkip SOLID validation
--no-crashboolfalseSkip Let It Crash validation
--thresholdint10Max cyclomatic complexity
--max-cognitiveint15Max cognitive complexity
--max-linesint50Max function line count
--max-depthint4Max nesting depth
--max-paramsint5Max parameter count
--max-file-linesint300Max file line count (SRP)
--max-interface-methodsint7Max interface methods (ISP)
--strictboolfalseTreat all warnings as errors
--core-onlyboolfalseOnly validate core layer files
--allboolfalseAnalyze all files, not just changed
--reportboolfalseGenerate detailed JSON report

Integration Flags

For use by other skills and pre-commit hooks:

FlagDescription
--pre-commitRun as pre-commit hook (blocks commit on failure)
--inlineReal-time validation during implementation
--jsonOutput JSON format for programmatic use

Exit Codes

CodeMeaningAction
0Validation passedProceed
2Violations detectedBlocked - refactor required
3Validation errorManual intervention needed

Personas Activated

  • code-warden - Primary reviewer for principles enforcement
  • optimizer - For complex refactoring guidance
  • guardian - For metrics integration

Validator Scripts

Located in scripts/ directory:

validate_kiss.py
python .claude/skills/sc-principles/scripts/validate_kiss.py \
  --scope-root . \
  --threshold 10 \
  --max-lines 50 \
  --json
validate_purity.py
python .claude/skills/sc-principles/scripts/validate_purity.py \
  --scope-root . \
  --core-only \
  --json

Pre-commit Integration

Add to .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: kiss-check
        name: KISS Validation
        entry: python .claude/skills/sc-principles/scripts/validate_kiss.py --scope-root . --json
        language: python
        types: [python]
        pass_filenames: false

      - id: purity-check
        name: Purity Validation
        entry: python .claude/skills/sc-principles/scripts/validate_purity.py --scope-root . --json
        language: python
        types: [python]
        pass_filenames: false

Refactoring Guidance

When violations are detected, apply these patterns:

For Complexity Violations
  1. Extract Method - Split large functions into smaller, named pieces
  2. Guard Clauses - Replace nested if/else with early returns
  3. Strategy Pattern - Replace complex switch/if-else with polymorphism
  4. Decompose Conditional - Name complex conditions as explaining variables

Before:

def process(data, config, user):
    if data:
        if config.enabled:
            if user.has_permission:
                for item in data:
                    if item.valid:
                        # deep logic here

After:

def process(data, config, user):
    if not can_process(data, config, user):
        return None
    return process_items(data)

def can_process(data, config, user):
    return data and config.enabled and user.has_permission

def process_items(data):
    return [process_item(item) for item in data if item.valid]
For Purity Violations
  1. Dependency Injection - Pass dependencies as arguments
  2. Repository Pattern - Isolate database operations
  3. Adapter Pattern - Wrap external APIs
  4. Return Don't Print - Return values, let callers handle output

Before:

# In domain/calculator.py (CORE - should be pure)
def calculate_discount(user_id):
    user = db.query(User).get(user_id)  # I/O in core!
    print(f"Calculating for {user.name}")  # Side effect!
    return 0.2 if user.is_premium else 0.1

After:

# In domain/calculator.py (CORE - now pure)
def calculate_discount(user: User) -> float:
    """Pure function - no I/O, just logic."""
    return 0.2 if user.is_premium else 0.1

# In adapters/discount_service.py (SHELL - I/O allowed)
def get_user_discount(user_id: int) -> float:
    user = user_repository.get(user_id)
    discount = calculate_discount(user)
    logger.info(f"Discount for {user.name}: {discount}")
    return discount
For SOLID Violations
  1. SRP (Single Responsibility) - Extract into modules
  2. OCP (Open-Closed) - Use strategy pattern or registry
  3. LSP (Liskov Substitution) - Honor base contracts
  4. ISP (Interface Segregation) - Split fat interfaces
  5. DIP (Dependency Inversion) - Inject dependencies

Before (OCP violation):

def process_payment(payment_type, amount):
    if payment_type == "credit":
        return process_credit(amount)
    elif payment_type == "debit":
        return process_debit(amount)
    elif payment_type == "crypto":  # New type = code change!
        return process_crypto(amount)

After (OCP compliant):

PROCESSORS = {
    "credit": process_credit,
    "debit": process_debit,
    "crypto": process_crypto,  # Add here, no function change
}

def process_payment(payment_type, amount):
    processor = PROCESSORS.get(payment_type)
    if not processor:
        raise ValueError(f"Unknown payment type: {payment_type}")
    return processor(amount)
For Let It Crash Violations
  1. Remove catch-all blocks - Let bugs surface
  2. Remove defensive guards - Validate at boundaries instead
  3. Flatten try/except - Handle at edges, not everywhere

Before (catch-all anti-pattern):

def get_user(user_id):
    try:
        user = db.query(User).get(user_id)
        return user
    except:  # BAD: catches everything, hides bugs
        return None

After (let it crash):

def get_user(user_id):
    # Let database errors surface - they indicate real problems
    return db.query(User).get(user_id)

# Handle at the boundary (API layer)
@app.get("/users/{user_id}")
def api_get_user(user_id: int):
    try:
        return get_user(user_id)
    except DBError as e:
        logger.error("Database error", error=e, user_id=user_id)
        raise HTTPException(500, "Database unavailable")

Examples

Example 1: Full Validation
$ /sc:principles src/ --report

KISS Validation: BLOCKED
Files analyzed: 12
Errors: 3, Warnings: 5

Violations:
  [ERROR] src/services/order.py:45 process_order: complexity = 15 (max: 10)
  [ERROR] src/utils/parser.py:12 parse_data: length = 78 (max: 50)
  [WARNING] src/domain/calc.py:8 calculate: parameters = 7 (max: 5)

Purity Validation: BLOCKED
Core violations: 2, Shell warnings: 1

Violations:
  [ERROR] src/domain/user.py:23 get_status: database - db.query (context: core)
  [ERROR] src/services/report.py:56 generate: file_io - open (context: core)

Recommendations:
  - COMPLEXITY: Extract helper functions, use early returns
  - DATABASE: Use repository pattern. Business logic receives data, not queries
  - FILE I/O: Move file operations to adapter layer
Example 2: KISS Only
$ /sc:principles src/ --kiss-only --threshold 8

KISS Validation: PASSED
Files analyzed: 12
Errors: 0, Warnings: 2
Example 3: Strict Mode
$ /sc:principles src/ --strict

# All warnings become errors
# Any warning will block

Quality Integration

This skill integrates with SuperClaude quality gates:

  • Contributes to simplicity dimension (weight: 0.08)
  • Contributes to purity dimension (weight: 0.02)
  • Triggers simplification strategy when simplicity < 70
  • Triggers purification strategy when purity < 70

Related Skills

  • /sc:improve --type principles - Auto-refactor for principles compliance
  • /sc:implement - Includes principles validation by default
  • /sc:analyze - Code analysis includes principles metrics

Test Coverage

The validators have comprehensive test coverage (59 tests across 4 suites):

Purity Validator Tests (16):

  • Async function detection (async def)
  • Await expression detection
  • Async for loop detection
  • Async with context manager detection
  • Shell vs core severity differentiation
  • False positive regression (set.add, parser.add_argument, asyncio.run, callback.call)
  • Edge cases (syntax errors, unicode, empty files)

KISS Validator Tests (15):

  • Function length (inclusive count)
  • Cyclomatic complexity
  • Cognitive complexity
  • Nesting depth
  • Parameter count
  • Edge cases (syntax errors, unicode, empty files)

SOLID Validator Tests (15):

  • SRP: File length, class method count, private methods excluded
  • OCP: isinstance cascades
  • LSP: NotImplementedError in concrete overrides, ABC/Protocol excluded
  • ISP: Fat Protocol and ABC interfaces
  • DIP: Direct service instantiation in core paths
  • Edge cases (syntax errors, empty files)

Crash Validator Tests (13):

  • Bare except detection
  • except: pass detection
  • Exception swallowed in core paths
  • Exception with re-raise (OK)
  • Specific exception handling (OK)
  • Nested try/except depth
  • Shell path relaxation (adapters, api)
  • Edge cases (syntax errors, empty files, try/finally)

Run tests:

python -m pytest .claude/skills/sc-principles/tests/ -v

Version: 2.1.0 Validators: validate_kiss.py, validate_purity.py, validate_solid.py, validate_crash.py Shared: shared.py (common find_python_files utility) Agent: code-warden Traits: principles-enforced Tests: 59 passing (all 4 validators)

Comments

Markdown supported