Installation
No separate download: the skill runs the in-repo tool .claude/tools/cli/security-lint.cjs .
-
Ensure Node.js (v18+) is installed: nodejs.org or winget install OpenJS.NodeJS.LTS (Windows), brew install node (macOS).
-
From the project root, the script is invoked automatically; no extra install steps.
Cheat Sheet & Best Practices
AST-based validation: Use ESLint (or equivalent) with selectors/patterns; rules listen for specific node types. Prefer existing community rules before writing custom ones; custom rules need meta (type, fixable, schema) and create .
Process: Check naming (camelCase/PascalCase/snake_case), indentation, import order, function/class structure, comment style. Run in pre-commit and CI; provide auto-fix where possible.
Hacks: Use --fix for auto-fixable rules; combine with security-lint for policy. Define rule metadata clearly for docs and tooling. Use AST selectors for precise pattern matching (node type, attributes, child/sibling).
Certifications & Training
ESLint: Use in project, custom rules, selectors. No cert; skill data: AST-based validation, pre-commit/CI, auto-fix, naming/indent/imports.
Hooks & Workflows
Suggested hooks: Pre-commit: run security-lint (skill script) or ESLint; block commit on failure. Use with developer (secondary), code-reviewer (secondary), qa (CI).
Workflows: Use with code-reviewer (secondary), developer (secondary). Flow: before commit or in CI → run validator → fix or block. See code-review-workflow.md , validation hooks.
Step 1: Identify Code Style Patterns
Analyze the codebase to identify style patterns:
-
Naming conventions (camelCase, PascalCase, snake_case)
-
Indentation style (spaces vs tabs, width)
-
Import organization
-
Function/class structure
-
Comment style
Step 2: AST-Based Validation
Use language-specific AST parsers:
TypeScript/JavaScript: </execution_process>
const ts = require('typescript'); const fs = require('fs');
function validateTypeScriptFile(filePath) { const sourceCode = fs.readFileSync(filePath, 'utf8'); const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true);
const issues = [];
// Validate naming conventions
ts.forEachChild(sourceFile, node => {
if (ts.isFunctionDeclaration(node) && node.name) {
if (!/^[a-z][a-zA-Z0-9]*$/.test(node.name.text)) {
issues.push({
line: sourceFile.getLineAndCharacterOfPosition(node.name.getStart()).line + 1,
message: Function name "${node.name.text}" should be camelCase,
});
}
}
});
return issues; }
</code_example>
<code_example> Python AST Validation:
import ast import re
def validate_python_file(file_path): with open(file_path, 'r') as f: source_code = f.read()
tree = ast.parse(source_code)
issues = []
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
if not re.match(r'^[a-z][a-z0-9_]*$', node.name):
issues.append({
'line': node.lineno,
'message': f'Function name "{node.name}" should be snake_case'
})
return issues
</code_example>
<code_example> Style Checks:
Naming Conventions:
-
Variables: camelCase (JS/TS) or snake_case (Python)
-
Functions: camelCase (JS/TS) or snake_case (Python)
-
Classes: PascalCase
-
Constants: UPPER_CASE
-
Private: prefix with underscore
Formatting:
-
Indentation: 2 spaces (JS/TS) or 4 spaces (Python)
-
Line length: 88-100 characters
-
Trailing commas: Yes (JS/TS)
-
Semicolons: Consistent usage
Structure:
-
Import order: external, internal, relative
-
Function length: < 50 lines
-
File organization: exports, helpers, types </code_example>
<code_example> Usage Examples (Template - implement validator first):
Validate Single File:
After implementing your validator:
node validate-code-style.js src/components/Button.tsx
Validate Directory:
After implementing your validator:
node validate-code-style.js src/components/
Output Format:
{ "file": "src/components/Button.tsx", "valid": false, "issues": [ { "line": 15, "column": 10, "rule": "naming-convention", "message": "Variable 'UserData' should be camelCase: 'userData'", "severity": "error" }, { "line": 23, "column": 5, "rule": "indentation", "message": "Expected 2 spaces, found 4", "severity": "warning" } ], "summary": { "total": 2, "errors": 1, "warnings": 1 } }
</code_example>
<code_example> Pre-commit Hook (Template - implement validator first):
#!/bin/bash
.git/hooks/pre-commit
changed_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '.(ts|tsx|js|jsx|py)$')
for file in $changed_files; do
Replace with your actual validator path
if ! node validate-code-style.js "$file"; then echo "Code style validation failed for $file" exit 1 fi done
</code_example>
<code_example> CI/CD Integration (Template - implement validator first):
.github/workflows/code-style.yml
- name: Validate code style
run: |
Replace with your actual validator path
node validate-code-style.js src/ if [ $? -ne 0 ]; then echo "Code style validation failed" exit 1 fi
</code_example>
Iron Laws
-
ALWAYS use AST-based validation over regex — regex-based style checking breaks on multi-line constructs, comments, and strings; AST-based tools (ESLint, Prettier) are format-independent and semantically accurate.
-
ALWAYS check for existing ESLint/Prettier rules before writing custom ones — custom rules are expensive to maintain; 95% of style needs are covered by existing rules with configuration.
-
NEVER block commits for style warnings, only errors — warnings are informational; blocking CI on warnings creates friction that leads teams to disable style checks entirely.
-
ALWAYS provide auto-fix suggestions alongside findings — reports without auto-fix require manual intervention for each issue; auto-fixable violations have near-100% resolution rates vs 30% for manual.
-
ALWAYS run style validation in both pre-commit hooks and CI — pre-commit catches issues locally before they reach the repository; CI catches cases where hooks were bypassed or aren't installed.
Anti-Patterns
Anti-Pattern Why It Fails Correct Approach
Regex-based style checking Breaks on multi-line, strings, and comments Use AST-based tools (ESLint, Prettier)
Custom rules for covered standards High maintenance; inconsistent with community Configure existing ESLint/Prettier rules first
Blocking CI on warnings Excessive friction causes teams to disable style checks Block only on errors; log warnings
Style validation without auto-fix Manual fixes have low resolution rate Always provide auto-fix commands alongside findings
Running only locally, not in CI Developers bypass pre-commit hooks regularly Run in both pre-commit and CI pipeline
Memory Protocol (MANDATORY)
Before starting: Read .claude/context/memory/learnings.md
After completing:
-
New pattern -> .claude/context/memory/learnings.md
-
Issue found -> .claude/context/memory/issues.md
-
Decision made -> .claude/context/memory/decisions.md
ASSUME INTERRUPTION: If it's not in memory, it didn't happen.