Validate Lisp code (Clojure, Racket, Scheme, Common Lisp) for syntax errors, parenthesis balance, and semantic issues. This skill should be used when validating Lisp code files, checking for syntax errors before execution, or validating LLM-generated Lisp code including incomplete or partial expressions. Provides structured JSON output optimized for automated workflows.
67
81%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
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:
Use this skill to:
┌─ 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 fallbackBefore validating, check which tools are installed:
python3 scripts/check_tools.pyThis shows:
# 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
# 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| 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)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 textOutput (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# .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"# 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# .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 0import 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)# 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)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-jokerWhat it detects:
{ closed with ))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:
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 guileSupported Scheme dialects (when raco unavailable):
Validation stages:
What it detects:
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-sbclWhat it detects:
Note: SBCL provides verbose output requiring parsing; SBLint provides machine-readable format.
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-pythonWhen to use:
Supported grammars:
tree-sitter-clojure)tree-sitter-commonlisp)tree-sitter-elisp)Output: Marks ERROR and MISSING nodes in parse tree
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.]When validating LLM-generated partial code:
# Force tree-sitter for incomplete code
python3 scripts/validate.py partial_code.clj --tree-sitterInterpreting results for incomplete code:
Serious structural errors beyond incompleteness warrant attention.
# 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/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 textEach 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]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 --jsonDetailed information is available in the references/ directory:
Load this when determining which validation tools to use.
Contains:
Use when:
Load this when parsing validation tool output.
Contains:
Use when:
Load this when integrating validation into LLM workflows.
Contains:
Use when:
Unbalanced parentheses:
error: Unexpected EOF (missing closing parenthesis)
error: Unmatched delimiter: )Undefined symbols:
error: Unresolved symbol: foo
error: Unbound variable: barArity mismatches:
error: Wrong number of args (3) passed to function (expects 2)Clojure:
# Primary: clj-kondo
brew install borkdude/brew/clj-kondo
# Or: npm install -g clj-kondo
# Secondary: joker
brew install candid82/joker/jokerRacket/Scheme:
# Install Racket (provides raco)
brew install racket # macOS
# Or download from: https://racket-lang.org
# Install raco packages
raco pkg install review syntax-warnCommon Lisp:
# Install Roswell
brew install roswell # macOS
# Install SBCL and SBLint
ros install sbcl
ros use sbcl
ros install cxxxr/sblintUniversal (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-elispAlways check which tools are available before validating:
python3 scripts/check_tools.pyThis provides:
check_tools.py to verify available validatorsAll validation scripts use consistent exit codes:
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
fiProblem: 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-kondoProblem: 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.3Problem: 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 parensProblem: 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")'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 {}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.tool7d2d2f2
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.