Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Validate HTML5 structure and basic syntax. BLOCKING quality gate - stops pipeline if validation fails. Ensures deterministic output quality.
.claude/skills/aiskillstore-html-structure-validate/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 290% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 135% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 116% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 41% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 484% | 0% |
This skill is a BLOCKING quality gate that ensures generated HTML meets minimum structural requirements. It is the first deterministic validation of probabilistic AI-generated output.
The skill checks:
If validation fails, the pipeline STOPS and triggers a hook to notify the user.
This enforces the principle: Python validates, ensuring deterministic quality.
04_page_XX.html generated by AI skilloutput/chapter_XX/page_artifacts/page_YY/06_validation_structure.jsonhtml_file: <str> - Path to 04_page_XX.html
output_dir: <str> - Directory for validation report
strict_mode: <bool> - If true, warnings also fail (default: false)
page_number: <int> - Page number (for reporting)
chapter: <int> - Chapter number (for reporting)Requirement: File must start with proper DOCTYPE
html<!DOCTYPE html>
Check:
<!DOCTYPE html> (case-insensitive)Error if: Missing or incorrect DOCTYPE
Requirement: Proper <html> opening and closing tags
html<html lang="en"> ... </html>
Checks:
<html> tag present</html> closing tag present<html> tagsError if: Missing either tag or improperly paired
Requirement: Complete <head> section with metadata
html<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>...</title> <link rel="stylesheet" href="../../styles/main.css"> </head>
Checks:
<head> and </head> tags present<meta charset="UTF-8"> present<meta name="viewport"> present (warning if missing)<title> tag with content present<link> tag present with href attributeError if: Missing charset, title, or CSS link Warning if: Missing viewport meta tag
Requirement: Proper <body> tags with content
html<body> <div class="page-container"> <main class="page-content"> ... </main> </div> </body>
Checks:
<body> and </body> tags present<div class="page-container"> present<main class="page-content"> present inside containerError if: Missing tags or required container divs
Requirement: All tags must be properly closed
Checks for:
<p> without </p>)<p><h2>text</h2></p>)<br/>, <img/>)<!-- -->)Validation method:
Error if: Any unmatched or improperly nested tags
Requirement: Valid heading hierarchy
html<h1>Chapter Title</h1> <h2>Section Heading</h2> <h3>Subsection</h3>
Checks:
Error if: Heading tags improperly closed Warning if: Suspicious hierarchy
Requirement: Meaningful content in page container
Checks:
<main class="page-content"> contains elementsError if: No content or empty structure
Requirement: All lists properly structured
Checks for each <ul> or <ol>:
<li> elements<li> tags properly closed<li> count matches opening/closing pairs<ul> or <ol> improperly closedError if: Empty lists or unmatched <li> tags
Requirement: Self-closing tags properly formatted
Checks:
<img> tags have src and alt attributes<a> tags have valid href attributesWarning if: Images missing alt text or links missing href
Requirement: Proper table structure
Checks:
<table>, <tr>, <td>, <th> tags properly nestedError if: Malformed table structure
06_validation_structure.jsonjson{ "page": 16, "book_page": 17, "chapter": 2, "validation_type": "structure", "validation_timestamp": "2025-11-08T14:34:00Z", "overall_status": "PASS", "error_count": 0, "warning_count": 1, "checks_performed": [ { "check_name": "DOCTYPE Declaration", "status": "PASS", "details": "Valid HTML5 DOCTYPE found" }, { "check_name": "HTML Tags", "status": "PASS", "details": "Proper <html> opening and closing tags" }, { "check_name": "Head Section", "status": "PASS", "details": "All required meta tags and title present" }, { "check_name": "Body Section", "status": "PASS", "details": "Body and content structure valid" }, { "check_name": "Tag Closure", "status": "PASS", "details": "All tags properly matched and closed" }, { "check_name": "Heading Hierarchy", "status": "PASS", "details": "4 headings found, proper h1-h4 hierarchy" }, { "check_name": "Content Structure", "status": "PASS", "details": "Main content area contains 245 words across 3 paragraphs" }, { "check_name": "List Integrity", "status": "PASS", "details": "1 list with 3 items, all properly formed" }, { "check_name": "Image Tags", "status": "PASS", "details": "No images on this page" }, { "check_name": "Table Tags", "status": "PASS", "details": "No tables on this page" } ], "errors": [], "warnings": [ { "check": "Heading Hierarchy", "message": "First heading is h2, typically should be h1 for page opening", "severity": "LOW" } ], "summary": { "total_checks": 10, "passed": 9, "failed": 0, "warnings": 1, "html_valid": true, "tags_matched": true, "content_substantial": true } }
html, head, body, main, div.page-container) presentThis validation is performed by existing validate_html.py tool, run in structure validation mode:
bashcd Calypso/tools # Validate single page HTML python3 validate_html.py \ ../output/chapter_02/page_artifacts/page_16/04_page_16.html \ --output-json ../output/chapter_02/page_artifacts/page_16/06_validation_structure.json \ --strict-structure # Exit code: # 0 = VALID (continue to next skill) # 1 = INVALID (STOP pipeline)
When validation FAILS:
bash# Trigger hook: .claude/hooks/validate-structure.sh # Receives: # - Page number # - HTML file path # - Validation report path # - Error details # Hook behavior: # - Log failure with details # - Save error report # - Notify user # - STOP pipeline (no further processing)
If validation fails:
Validation provides metrics:
These metrics feed into final quality reports.
✓ Validation completes successfully ✓ All structural checks pass (0 errors) ✓ Validation report saved in JSON format ✓ Exit code 0 returned (or 1 if invalid) ✓ Clear error messages if validation fails
If validation passes:
If validation fails:
validate-structure.sh triggeredvalidate_html.py toolTo test structure validation:
bash# Test with known-good HTML python3 validate_html.py ../output/chapter_01/chapter_01.html # Should show: ✓ VALID # Test with invalid HTML (if needed) python3 validate_html.py broken_html.html # Should show: ✗ INVALID with specific errors
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 8,472 | 6,979 | -18% | 1 | 1 | 0% | 403 | 3,701 | +818% | 0 | 0 | — |
case-02 | fail→fail | 5,891 | 5,666 | -4% | 1 | 1 | 0% | 349 | 3,422 | +881% | 0 | 0 | — |
case-03 | pass→pass | 9,494 | 14,742 | +55% | 1 | 1 | 0% | 1,037 | 5,805 | +460% | 0 | 0 | — |
case-04 | fail→pass | 8,796 | 17,074 | +94% | 1 | 1 | 0% | 1,684 | 6,569 | +290% | 0 | 0 | — |
case-05 | pass→pass | 17,474 | 15,100 | -14% | 1 | 1 | 0% | 2,691 | 5,510 | +105% | 0 | 0 | — |
case-06 | pass→pass | 8,163 | 2,502 | -69% | 1 | 1 | 0% | 1,230 | 3,384 | +175% | 0 | 0 | — |
case-07 | pass→pass | 9,954 | 5,095 | -49% | 1 | 1 | 0% | 1,674 | 3,936 | +135% | 0 | 0 | — |
case-08 | pass→pass | 7,822 | 2,278 | -71% | 1 | 1 | 0% | 1,227 | 3,390 | +176% | 0 | 0 | — |
case-09 | fail→pass | 9,584 | 2,853 | -70% | 1 | 1 | 0% | 1,493 | 3,516 | +135% | 0 | 0 | — |
case-10 | fail→pass | 9,777 | 4,510 | -54% | 1 | 1 | 0% | 1,732 | 3,745 | +116% | 0 | 0 | — |
case-11 | fail→pass | 11,518 | 2,126 | -82% | 1 | 1 | 0% | 2,392 | 3,374 | +41% | 0 | 0 | — |
case-12 | fail→pass | 3,704 | 1,322 | -64% | 1 | 1 | 0% | 548 | 3,200 | +484% | 0 | 0 | — |
case-21 | pass→pass | 8,164 | 2,777 | -66% | 1 | 1 | 0% | 1,283 | 3,486 | +172% | 0 | 0 | — |
case-13 | fail→pass | 23,696 | 1,300 | -95% | 1 | 1 | 0% | 3,694 | 3,233 | -12% | 0 | 0 | — |
case-14 | fail→pass | 10,153 | 1,716 | -83% | 1 | 1 | 0% | 1,654 | 3,283 | +98% | 0 | 0 | — |
case-15 | pass→pass | 6,051 | 3,512 | -42% | 1 | 1 | 0% | 996 | 3,653 | +267% | 0 | 0 | — |
case-16 | fail→pass | 8,550 | 3,358 | -61% | 1 | 1 | 0% | 1,379 | 3,586 | +160% | 0 | 0 | — |
case-17 | fail→pass | 4,637 | 3,118 | -33% | 1 | 1 | 0% | 807 | 3,607 | +347% | 0 | 0 | — |
case-18 | pass→pass | 11,599 | 4,990 | -57% | 1 | 1 | 0% | 1,688 | 3,898 | +131% | 0 | 0 | — |
case-19 | fail→pass | 11,830 | 2,402 | -80% | 1 | 1 | 0% | 1,801 | 3,464 | +92% | 0 | 0 | — |
case-20 | fail→pass | 6,732 | 2,329 | -65% | 1 | 1 | 0% | 1,179 | 3,476 | +195% | 0 | 0 | — |
case-22 | fail→pass | 11,194 | 2,941 | -74% | 1 | 1 | 0% | 1,648 | 3,473 | +111% | 0 | 0 | — |
case-23 | pass→pass | 6,741 | 2,786 | -59% | 1 | 1 | 0% | 1,065 | 3,465 | +225% | 0 | 0 | — |
case-24 | pass→pass | 12,292 | 2,106 | -83% | 1 | 1 | 0% | 1,841 | 3,327 | +81% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted, and 22 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +50 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.