CR-2026-03-25: Claude Code AsciiDoc Attribute Validation Hook

Change Summary

Field Value

Change ID

CR-2026-03-25-claude-code-hooks-001

Requested By

Self (PRJ-claude-code-features)

Target Date

2026-03-25

Systems Affected

~/.claude/hooks.json, ~/.claude/hooks/ scripts

Risk Level

Medium (workflow impact on failure)

Rollback Time

< 1 minute (restore backup)

Change Window

Any (personal development environment)

Category

Normal (follows full process)

Business Justification

Problem Statement

AsciiDoc files in the domus-* documentation ecosystem use Antora attributes ({attribute-name}) defined in antora.yml. When Claude Code edits .adoc files, undefined attributes cause:

  1. Build warnings - Antora logs "skipping reference to missing attribute"

  2. Broken rendering - Literal {attribute-name} appears instead of value

  3. Delayed detection - Errors found at build time, not edit time

  4. Rework cycles - Must stop, identify, fix, rebuild, verify

Root Cause History

Incident Impact Resolution Time

RCA-2026-02-26-001

6 missing attributes across 3 files

45 minutes

RCA-2026-03-19-001

Relative xrefs in nested directories

30 minutes

Ad-hoc occurrences

~2 per week average

15-30 minutes each

Benefits (Quantified)

Benefit Measurement Value

Error prevention

Catch undefined attrs at edit time

~2 incidents/week × 30 min = 1 hour/week saved

Reduced context switches

No need to stop work, debug, rebuild

Improved focus and flow state

Documentation quality

Guaranteed attribute resolution

Zero broken renders from attrs

Learning reinforcement

Immediate feedback on patterns

Faster antora.yml familiarity

ROI Estimate: 1 hour/week × 52 weeks = 52 hours/year recovered

Technical Specification

Hook Architecture

Claude Code hooks execute shell commands at defined lifecycle events. This change adds a PostToolUse hook for the Edit tool targeting .adoc files.

Environment Variables

Variable Description

$ARGUMENTS

JSON string containing tool arguments (includes file_path)

stdin

Full tool_input JSON (available but not used by this hook)

$TOOL_NAME

Tool that triggered the hook (e.g., "Edit")

$TOOL_RESULT

Result of tool execution (PostToolUse only)

Exit Code Semantics

Code Meaning Behavior

0

Success (may include warnings)

Tool execution proceeds/completes

1

Script error

Logged, tool continues

2

Blocking error (with JSON)

Tool execution blocked, user sees message

This hook uses exit 0 for all cases (including warnings) to avoid blocking edits. Warnings are informational, not blocking.

Official Documentation

hooks.json Schema Reference

{
  "hooks": {
    "<HookEvent>": [
      {
        "matcher": "<tool-name-regex>",
        "hooks": [
          {
            "type": "command",
            "command": "<shell-command>",
            "timeout": <seconds>
          }
        ]
      }
    ]
  }
}

Valid <HookEvent> values:

  • PreToolUse - Before tool execution

  • PostToolUse - After tool execution

  • SessionStart - When Claude Code session begins

  • UserPromptSubmit - When user submits prompt

Risk Analysis

Risk Matrix

Risk Description Probability Impact Mitigation

Hook timeout

Validation takes >5s, delays edits

Low

Low

5s timeout configured; typical execution <1s

False positives

Built-in attrs flagged as undefined

Medium

Low

80+ built-in attrs whitelisted in script

antora.yml not found

File outside Antora structure

Medium

None

Graceful skip with debug logging

Hook script error

Syntax or logic bug in validator

Low

Low

Exit 0 on error; test suite validates

Workflow disruption

Excessive warnings annoying

Low

Low

Warnings are informational only

Impact Assessment

Scenario Impact

During change

None - configuration update only

After change - success

~1s added to .adoc edits; warnings on undefined attrs

After change - failure

Rollback to backup; <1 minute recovery

Worst case

Hook causes Edit operations to hang; kill hook process, restore backup

Pre-Change Checklist

Prerequisites

  • Backup strategy documented (SessionStart hook creates daily backups)

  • Rollback procedure documented below

  • Validation script created and tested

  • Test suite created with 5 test cases

  • D2 diagram created with animation

  • Current hooks.json captured (Phase 1)

Current State

Metric Pre-Change Value

Total hook events configured

4 (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart)

PostToolUse Edit hooks

1 (shellcheck for .sh files)

AsciiDoc validation

None

Backup location

~/.claude/backups/

Implementation Procedure

Phase 1: Capture Current State

# Create timestamped backup
cp ~/.claude/hooks.json ~/.claude/backups/hooks.json.$(date +%Y%m%d-%H%M%S).bak

# Verify backup
ls -la ~/.claude/backups/hooks.json.*.bak | tail -1

# Capture current hook count
jq '.PostToolUse | length' ~/.claude/hooks.json

Expected output: 1 (existing shellcheck hook)

Phase 2: Install Validation Script

The validation script has been pre-created at ~/.claude/hooks/validate-asciidoc-attrs.sh.

# Verify script exists and is executable
ls -la ~/.claude/hooks/validate-asciidoc-attrs.sh

# Run test suite
~/.claude/hooks/test-validate-asciidoc-attrs.sh

Expected: All 5 tests pass

Phase 3: Update hooks.json

Add AsciiDoc attribute validator to existing PostToolUse Edit hooks array.

Before (existing shellcheck only):

"PostToolUse": [
  {
    "matcher": "Edit",
    "hooks": [
      {
        "type": "command",
        "command": "FILE_PATH=$(echo \"$ARGUMENTS\" | grep -o '\"file_path\":\"[^\"]*\"' | cut -d'\"' -f4); if [ -n \"$FILE_PATH\" ]; then case \"$FILE_PATH\" in *.sh|*.bash|*.zsh) if command -v shellcheck >/dev/null 2>&1; then shellcheck \"$FILE_PATH\" 2>&1 | head -10 || echo \"ShellCheck: no issues\"; else echo \"ShellCheck: not installed\"; fi ;; *) echo \"Validation: skipped (not a shell script)\" ;; esac; fi",
        "timeout": 10
      }
    ]
  }
]

After (shellcheck + adoc validator):

"PostToolUse": [
  {
    "matcher": "Edit",
    "hooks": [
      {
        "type": "command",
        "command": "FILE_PATH=$(echo \"$ARGUMENTS\" | grep -o '\"file_path\":\"[^\"]*\"' | cut -d'\"' -f4); if [ -n \"$FILE_PATH\" ]; then case \"$FILE_PATH\" in *.sh|*.bash|*.zsh) if command -v shellcheck >/dev/null 2>&1; then shellcheck \"$FILE_PATH\" 2>&1 | head -10 || echo \"ShellCheck: no issues\"; else echo \"ShellCheck: not installed\"; fi ;; *) echo \"Validation: skipped (not a shell script)\" ;; esac; fi",
        "timeout": 10
      },
      {
        "type": "command",
        "command": "~/.claude/hooks/validate-asciidoc-attrs.sh",
        "timeout": 5
      }
    ]
  }
]

Phase 4: Verify Configuration

# Validate JSON syntax
jq . ~/.claude/hooks.json > /dev/null && echo "JSON valid"

# Count PostToolUse Edit hooks
jq '.PostToolUse[0].hooks | length' ~/.claude/hooks.json

Expected: 2 (shellcheck + adoc validator)

Phase 5: Functional Testing

Test Action Expected Result

Test 1

Edit a .adoc file with valid attributes

No warning displayed

Test 2

Edit a .adoc file with {nonexistent-attr}

"WARNING: Undefined AsciiDoc attributes: {nonexistent-attr}"

Test 3

Edit a .md or .txt file

No validation (skipped)

Test 4

Edit a .sh file with shellcheck issues

ShellCheck warnings displayed (existing behavior)

Post-Change Validation

State Comparison

Metric Pre-Change Post-Change

Total hook events

4

4 (unchanged)

PostToolUse Edit hooks

1

2

AsciiDoc validation

None

Active

Edit operation time (typical)

~100ms

~1.1s (validation adds ~1s)

Monitoring Checklist

  • No hook timeout errors in Claude Code output

  • Edit operations complete normally

  • Valid .adoc files show no warnings

  • Invalid .adoc files show appropriate warnings

  • ShellCheck still works for .sh files

Rollback Procedure

Trigger Conditions

Initiate rollback if ANY of:

  • Hook causes Edit operations to fail or hang

  • False positive rate >50% (valid files flagged)

  • Hook timeout delays workflow significantly

  • Unexpected errors in Claude Code output

Rollback Steps

# 1. List available backups
ls -la ~/.claude/backups/hooks.json.*.bak | tail -5

# 2. Restore most recent backup (replace TIMESTAMP)
cp ~/.claude/backups/hooks.json.YYYYMMDD-HHMMSS.bak ~/.claude/hooks.json

# 3. Verify restoration
jq '.PostToolUse[0].hooks | length' ~/.claude/hooks.json
# Expected: 1

# 4. Restart Claude Code session (exit and re-enter)

Rollback Verification

  • hooks.json restored to previous state

  • PostToolUse Edit hooks = 1

  • Edit operations work without validation

  • No unexpected warnings

Scope Management

In Scope

  • PostToolUse hook for Edit tool on .adoc files

  • Attribute validation against antora.yml

  • Warning output for undefined attributes

  • Built-in attribute whitelist

Out of Scope (Future CRs)

  • xref validation (requires parsing, different approach)

  • Real-time antora.yml caching

  • Integration with Antora build process

  • MCP server for attribute lookup

Amendment Process

If scope changes are required during implementation:

  1. Document the proposed change in this CR under "Amendments" section

  2. Assess impact on timeline, risk, and benefits

  3. Approve minor changes (self-approval for low-risk)

  4. Escalate major changes to new CR

Amendments

No amendments at this time.

Sign-Off

Role Name Date

Author

Evan Rosado

2026-03-25

Technical Review

Claude (AI)

2026-03-25

Approval

Evan Rosado

2026-03-25

Lessons Learned

To be completed post-implementation.

Questions to Answer

  • Did the hook catch any real issues during normal workflow?

  • Was the 5s timeout sufficient?

  • Any unexpected false positives?

  • Should this approach extend to other validation types?

Appendix A: Validation Script

Full source: ~/.claude/hooks/validate-asciidoc-attrs.sh

Table 1. Script Summary
Feature Implementation

File type check

[[ ! "$FILE_PATH" =~ \.adoc$ ]] → skip

Attribute extraction

grep -oE '\{[a-zA-Z][a-zA-Z0-9_-]*\}'

antora.yml discovery

Walk up directory tree, fallback to git root

Built-in whitelist

80+ standard AsciiDoc attributes

Output

WARNING message with attribute list

Appendix B: Test Suite

Full source: ~/.claude/hooks/test-validate-asciidoc-attrs.sh

Test Case Input Expected

Non-.adoc file

readme.md

Skip (PASS)

Valid attributes

File with {defined-attr}

No warning (PASS)

Invalid attributes

File with {undefined-attr}

WARNING displayed (PASS)

No attributes

Plain .adoc file

No warning (PASS)

Built-in attributes

File with {nbsp}, {toc}

No warning (PASS)