lisp-validator
npx skills add https://github.com/waddie/lisp-validator-skill --skill lisp-validator
Agent 安装分布
Skill 文档
Lisp Validator
Overview
This skill validates Lisp code across multiple dialects (Clojure, Racket, Scheme, Common Lisp) using dialect-specific tools optimized for LLM workflows. Critical for validating incomplete or partially-generated code during LLM-guided editing, it provides structured error output with precise file:line:col information for targeted fixes.
Key capabilities:
- Auto-detects Lisp dialect from file extension and content
- Handles incomplete code via tree-sitter (critical for LLM workflows)
- Provides structured JSON output for machine parsing
- Multi-tool validation for comprehensive error detection
- Installation detection and guidance for missing tools
When to Use This Skill
Use this skill to:
- Validate Lisp code files before execution or commit
- Check LLM-generated Lisp code for syntax errors
- Validate incomplete or partial expressions during code generation
- Detect unbalanced parentheses and structural issues
- Lint entire projects for style and semantic issues
- Determine which validation tools are available on the system
Workflow Decision Tree
ââ Code complete? âââââ
â â
YES NO (incomplete/partial)
â â
ââ Detect dialect ââ Use tree-sitter
â (handles incomplete)
ââ Clojure? âââ clj-kondo + joker
ââ Racket/Scheme? âââ raco tools
ââ Common Lisp? âââ SBLint + SBCL
ââ Elisp? âââ tree-sitter
ââ Unknown? âââ tree-sitter fallback
Quick Start
Check Available Tools
Before validating, check which tools are installed:
python3 scripts/check_tools.py
This shows:
- Which validation tools are available
- Tool installation status per dialect
- Installation commands for missing tools
- Recommendations based on detected tools
Validate Any Lisp File (Auto-Detect)
# Auto-detects dialect and uses appropriate validator
python3 scripts/validate.py <file-or-directory>
# Examples
python3 scripts/validate.py src/core.clj
python3 scripts/validate.py project/src/
Output: JSON with findings, severity, file:line:col locations
Format Options
# JSON output (default, best for parsing)
python3 scripts/validate.py file.clj --format json
# Human-readable text
python3 scripts/validate.py file.clj --format text
# Summary only
python3 scripts/validate.py file.clj --format summary
Quick Reference
| Task | Command |
|---|---|
| Check available tools | python3 scripts/check_tools.py |
| Auto-detect & validate | python3 scripts/validate.py src/ |
| Validate incomplete code | python3 scripts/validate.py file.clj --tree-sitter |
| Force specific dialect | python3 scripts/validate.py file.scm --dialect scheme |
| Clojure-specific | python3 scripts/validate_clojure.py src/ |
| Racket/Scheme-specific | python3 scripts/validate_scheme.py src/ |
| Common Lisp-specific | python3 scripts/validate_common_lisp.py src/ |
| Human-readable output | python3 scripts/validate.py src/ --format text |
| JSON output (default) | python3 scripts/validate.py src/ --format json |
| Summary only | python3 scripts/validate.py src/ --format summary |
Exit Codes:
0– No issues found2– Warnings only (code should run)3– Errors present (code may not run)
Examples
Example 1: Validating During Code Generation
When generating Clojure code incrementally with an LLM:
# After each edit, validate with tree-sitter (handles incomplete code)
python3 scripts/validate.py partial.clj --tree-sitter --format summary
# Once complete, run comprehensive validation
python3 scripts/validate.py complete.clj --format text
Output (incomplete code):
0 errors, 1 warnings (tree-sitter)
Output (complete code):
Target: complete.clj
Dialect: clojure
No issues found!
Summary: 0 errors, 0 warnings
Tools used: clj-kondo, joker
Example 2: CI/CD Integration
# .github/workflows/validate-lisp.yml
name: Validate Lisp Code
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install validation tools
run: |
curl -sLO https://raw.githubusercontent.com/borkdude/clj-kondo/master/script/install-clj-kondo
chmod +x install-clj-kondo && ./install-clj-kondo
- name: Check available tools
run: python3 scripts/check_tools.py
- name: Validate Clojure code
run: |
python3 scripts/validate.py src/ --format json > validation-results.json
cat validation-results.json | jq
- name: Fail on errors
run: |
errors=$(jq '.summary.total_errors' validation-results.json)
if [ "$errors" -gt 0 ]; then
echo "â Found $errors errors"
exit 1
fi
echo "â
Validation passed"
Example 3: Progressive Validation Workflow
# Stage 1: Fast structural check (< 1s)
python3 scripts/validate_tree_sitter.py src/core.clj
# Stage 2: Comprehensive validation (if stage 1 passes)
python3 scripts/validate_clojure.py src/core.clj
# Stage 3: Auto-format (only if validation passes)
if [ $? -eq 0 ]; then
cljfmt fix src/core.clj
fi
Example 4: Pre-Commit Hook
# .git/hooks/pre-commit
#!/bin/bash
echo "Validating Lisp files..."
# Get staged .clj files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.clj$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
# Validate each file
for FILE in $STAGED_FILES; do
python3 scripts/validate.py "$FILE" --format summary
if [ $? -eq 3 ]; then
echo "â Validation failed for $FILE"
echo "Fix errors before committing"
exit 1
fi
done
echo "â
All files validated successfully"
exit 0
Example 5: Handling Validation Errors in Scripts
import subprocess
import json
def validate_and_report(file_path):
"""Validate a file and provide structured feedback."""
result = subprocess.run(
["python3", "scripts/validate.py", file_path, "--format", "json"],
capture_output=True,
text=True
)
data = json.loads(result.stdout)
if data["summary"]["total_errors"] > 0:
print(f"â ï¸ Found {data['summary']['total_errors']} errors in {file_path}:")
for finding in data["findings"]:
if finding["severity"] == "error":
location = f"{finding['file']}:{finding['line']}:{finding['col']}"
print(f" {location}: {finding['message']}")
return False
print(f"â
{file_path} validated successfully")
return True
# Use it
if not validate_and_report("src/main.clj"):
exit(1)
Example 6: Checking Tool Installation
# Check which tools are available
python3 scripts/check_tools.py
# Install missing high-priority tools
python3 scripts/check_tools.py --json | \
jq -r '.tools | to_entries[] | select(.value.available == false and .value.priority == "high") | .key'
Output:
=== Lisp Validation Tools Status ===
CLOJURE:
[â] clj-kondo (2024.03.13)
Primary Clojure validator with JSON output
[â] joker
Secondary Clojure validator with complementary checks
UNIVERSAL:
[â] tree-sitter-python (installed)
Tree-sitter Python library (more reliable than CLI)
[â] tree-sitter
Universal parser for incomplete/partial code (CLI)
=== Recommendations ===
CLOJURE:
â¹ï¸ Consider installing joker (complementary checks)
UNIVERSAL:
â¹ï¸ Consider tree-sitter Python library (more reliable)
Dialect-Specific Validation
Clojure
Primary tool: clj-kondo (JSON output, comprehensive) Secondary tool: joker (complementary checks)
# Using dialect-specific validator
python3 scripts/validate_clojure.py <file-or-directory>
# Skip joker (faster, clj-kondo only)
python3 scripts/validate_clojure.py src/ --no-joker
What it detects:
- Unbalanced parentheses
- Mismatched delimiters (
{closed with)) - Unexpected EOF
- Undefined symbols
- Arity mismatches
- Unused bindings
- Style issues
Output structure:
{
"target": "src/core.clj",
"dialect": "clojure",
"findings": [
{
"file": "src/core.clj",
"line": 10,
"col": 15,
"end_line": 10,
"end_col": 20,
"severity": "error",
"message": "Unexpected EOF.",
"type": "unexpected-eof",
"tool": "clj-kondo"
}
],
"summary": {
"total_errors": 1,
"total_warnings": 0,
"tools_used": ["clj-kondo", "joker"]
}
}
Exit codes:
- 0: No issues
- 2: Warnings only
- 3: Errors present
Racket/Scheme
Tools used: raco expand, raco review, raco warn (tiered validation) Note: raco tools work for both Racket and generic Scheme when Racket is installed
# Using dialect-specific validator
python3 scripts/validate_scheme.py <file-or-directory>
# Force raco tools (default if available)
python3 scripts/validate_scheme.py file.rkt --raco
# Fallback to specific Scheme dialect
python3 scripts/validate_scheme.py file.scm --no-raco --dialect guile
Supported Scheme dialects (when raco unavailable):
- guile
- chez
- chicken
- mit
Validation stages:
- Fast check (raco expand): Safe syntax validation without execution
- Surface lint (raco review): Quick error detection
- Deep analysis (raco warn): Comprehensive warnings with suggestions
What it detects:
- Unbound identifiers
- Duplicate bindings
- Arity mismatches
- Type errors (Typed Racket)
- Unused variables
- Style violations
Common Lisp
Primary tool: SBLint (machine-readable output) Secondary tool: SBCL (deep semantic validation)
# Using dialect-specific validator
python3 scripts/validate_common_lisp.py <file-or-directory>
# Skip SBCL (faster, SBLint only)
python3 scripts/validate_common_lisp.py src/ --no-sbcl
What it detects:
- Undefined variables
- Undefined functions
- Unused variables
- Style warnings
- Compilation errors
- Read errors (syntax)
Note: SBCL provides verbose output requiring parsing; SBLint provides machine-readable format.
Tree-Sitter (Incomplete Code)
Critical for LLM workflows: Handles partial/incomplete expressions
# Using tree-sitter validator
python3 scripts/validate_tree_sitter.py <file>
# Use Python library (more reliable)
python3 scripts/validate_tree_sitter.py file.lisp
# Use CLI only
python3 scripts/validate_tree_sitter.py file.lisp --no-python
When to use:
- Code is incomplete (missing closing parens)
- Validating partial expressions during generation
- Traditional validators fail on incomplete code
- Structural validation without semantic analysis
Supported grammars:
- Clojure (
tree-sitter-clojure) - Common Lisp (
tree-sitter-commonlisp) - Emacs Lisp (
tree-sitter-elisp)
Output: Marks ERROR and MISSING nodes in parse tree
Validation Workflows
Progressive Validation (Recommended)
Validate in stages from fast to comprehensive:
# Stage 1: Fast check (< 1s)
python3 scripts/validate_tree_sitter.py file.clj
# Stage 2: Comprehensive (if stage 1 passes)
python3 scripts/validate_clojure.py file.clj
# Stage 3: Auto-format (only if validation passes)
# [Apply formatter like cljfmt, raco fmt, etc.]
Incomplete Code Validation
When validating LLM-generated partial code:
# Force tree-sitter for incomplete code
python3 scripts/validate.py partial_code.clj --tree-sitter
Interpreting results for incomplete code:
- ERROR nodes: Unparseable sections
- MISSING nodes: Expected tokens absent
- “Unexpected EOF” is expected for incomplete code
Serious structural errors beyond incompleteness warrant attention.
Project-Wide Validation
# Validate entire project (auto-detects files)
python3 scripts/validate.py project/src/
# Clojure project
python3 scripts/validate_clojure.py src/
# Racket package
python3 scripts/validate_scheme.py src/ --raco
# Common Lisp system
python3 scripts/validate_common_lisp.py src/
Using Validation Scripts
Main Orchestrator
scripts/validate.py auto-detects dialect and routes to appropriate validator.
Options:
--dialect <dialect> Force specific dialect
--tree-sitter Force tree-sitter (incomplete code)
--format <format> Output format (json|text|summary)
Examples:
# Auto-detect
python3 scripts/validate.py src/
# Force dialect
python3 scripts/validate.py file.scm --dialect scheme
# Incomplete code
python3 scripts/validate.py partial.clj --tree-sitter
# Human-readable output
python3 scripts/validate.py src/ --format text
Dialect-Specific Validators
Each validator provides focused validation for its dialect:
Clojure:
python3 scripts/validate_clojure.py <target> [--no-joker]
Racket/Scheme:
python3 scripts/validate_scheme.py <target> [--no-raco] [--dialect <dialect>]
Common Lisp:
python3 scripts/validate_common_lisp.py <target> [--no-sbcl]
Tree-sitter:
python3 scripts/validate_tree_sitter.py <file> [--no-python]
Tool Checker
scripts/check_tools.py shows installation status and provides installation guidance.
# Text output (default)
python3 scripts/check_tools.py
# JSON output
python3 scripts/check_tools.py --json
Reference Documentation
Detailed information is available in the references/ directory:
references/tool_comparison.md
Load this when determining which validation tools to use.
Contains:
- Complete tool comparison matrix
- Detailed tool profiles (installation, usage, output formats)
- Dialect-specific recommendations
- Performance comparison
- Exit code standards
- Optimal tool combinations for LLM workflows
Use when:
- Selecting validation tools for a project
- Understanding tool capabilities and limitations
- Comparing different validators
- Setting up CI/CD pipelines
references/error_patterns.md
Load this when parsing validation tool output.
Contains:
- Regex patterns for each tool’s output format
- Structured output formats (JSON, parseable text)
- Unstructured output parsing strategies (SBCL, Scheme dialects)
- Unified error schema for normalization
- Common error types by dialect
- Edge cases and parsing best practices
Use when:
- Parsing validation output programmatically
- Normalizing errors across multiple tools
- Implementing custom error handlers
- Debugging parsing issues
references/integration_strategies.md
Load this when integrating validation into LLM workflows.
Contains:
- Core principles (progressive validation, structured output)
- Dialect-specific strategies and pipelines
- LLM-specific patterns (edit validation loop, partial expression validation)
- CI/CD integration examples
- Performance optimization techniques
- Error recovery strategies
Use when:
- Implementing LLM-guided code editing workflows
- Setting up automated validation pipelines
- Optimizing validation performance
- Handling validation errors in LLM context
Interpreting Validation Results
Error Severity Levels
- error: Code will not run (syntax errors, undefined symbols)
- warning: Code may run but has issues (unused variables, style)
- info: Informational messages (suggestions, style recommendations)
Common Error Types
Unbalanced parentheses:
error: Unexpected EOF (missing closing parenthesis)
error: Unmatched delimiter: )
Undefined symbols:
error: Unresolved symbol: foo
error: Unbound variable: bar
Arity mismatches:
error: Wrong number of args (3) passed to function (expects 2)
Acting on Validation Results
- Errors first: Fix syntax and structural errors before warnings
- Location precision: Use file:line:col to locate exact problem
- Suggestions: Some tools (raco warn) provide fix suggestions
- Multiple tools: Different tools may catch different issues
- Incomplete code: Distinguish between “incomplete” and “invalid”
Installation Guidance
Recommended Tools by Dialect
Clojure:
# Primary: clj-kondo
brew install borkdude/brew/clj-kondo
# Or: npm install -g clj-kondo
# Secondary: joker
brew install candid82/joker/joker
Racket/Scheme:
# Install Racket (provides raco)
brew install racket # macOS
# Or download from: https://racket-lang.org
# Install raco packages
raco pkg install review syntax-warn
Common Lisp:
# Install Roswell
brew install roswell # macOS
# Install SBCL and SBLint
ros install sbcl
ros use sbcl
ros install cxxxr/sblint
Universal (all dialects):
# tree-sitter CLI
npm install -g tree-sitter-cli@0.19.3
# tree-sitter Python library (more reliable)
pip install tree-sitter tree-sitter-commonlisp tree-sitter-clojure tree-sitter-elisp
Checking Installation Status
Always check which tools are available before validating:
python3 scripts/check_tools.py
This provides:
- Installation status per tool
- Platform-specific installation commands
- Dialect-specific recommendations
- Warnings for missing high-priority tools
Best Practices
- Check tools first: Run
check_tools.pyto verify available validators - Use structured output: JSON format for programmatic parsing
- Validate incrementally: After each code edit in LLM workflows
- Handle incomplete code: Use tree-sitter for partial expressions
- Combine tools: Multiple validators catch different error types
- Read references: Load relevant reference docs for detailed guidance
- Interpret exit codes: 0=success, 2=warnings, 3=errors
- Fix errors before warnings: Prioritize structural issues
- Use progressive validation: Fast check â comprehensive â auto-fix
- Cache when possible: clj-kondo and raco warn support caching
Exit Codes
All validation scripts use consistent exit codes:
- 0: Validation passed (no errors or warnings)
- 2: Warnings only (code should run)
- 3: Errors present (code may not run)
Use these for automation:
if python3 scripts/validate.py src/; then
echo "â Validation passed"
else
exit_code=$?
if [ $exit_code -eq 2 ]; then
echo "â Warnings present"
elif [ $exit_code -eq 3 ]; then
echo "â Errors found"
fi
fi
Troubleshooting
“Tool not found” errors
Problem: clj-kondo not found even though it’s installed
# 1. Check if tool is in PATH
which clj-kondo
# 2. Verify installation
clj-kondo --version
# 3. Check PATH variable
echo $PATH
# 4. If not found, install it
brew install borkdude/brew/clj-kondo
# or
npm install -g clj-kondo
“Cannot parse output” errors
Problem: Tree-sitter parse errors on valid code
This usually means you’re using tree-sitter CLI 0.20+. Downgrade to 0.19.3:
# Uninstall current version
npm uninstall -g tree-sitter-cli
# Install correct version
npm install -g tree-sitter-cli@0.19.3
# Verify version
tree-sitter --version
# Should output: tree-sitter 0.19.3
“Unexpected EOF” on complete code
Problem: Getting EOF errors but code looks complete
# Use tree-sitter to find exact error location
python3 scripts/validate_tree_sitter.py file.clj
# Check for hidden characters or mismatched delimiters
cat -A file.clj # Shows hidden characters
# Count delimiters
grep -o '(' file.clj | wc -l # Count opening parens
grep -o ')' file.clj | wc -l # Count closing parens
False positives
Problem: Joker flags macro-introduced bindings as errors
# Cross-reference with clj-kondo only
python3 scripts/validate_clojure.py file.clj --no-joker
# Compare tools side by side
python3 scripts/validate_clojure.py file.clj --format json | \
jq '.findings[] | select(.tool == "joker")'
Performance issues
Problem: Validation takes too long on large projects
# Skip secondary tools for faster validation
python3 scripts/validate_clojure.py src/ --no-joker
python3 scripts/validate_common_lisp.py src/ --no-sbcl
# Validate only changed files (with git)
git diff --name-only --cached | \
grep '\.clj$' | \
xargs python3 scripts/validate.py
# Parallel validation for multiple files
find src -name '*.clj' | \
xargs -P 4 -I {} python3 scripts/validate.py {}
JSON parsing errors
Problem: Cannot parse validation output as JSON
# Ensure you're getting JSON output
python3 scripts/validate.py file.clj --format json | jq
# Check for stderr contamination
python3 scripts/validate.py file.clj --format json 2>/dev/null | jq
# Validate JSON structure
python3 scripts/validate.py file.clj --format json | python3 -m json.tool