Loading...
Automatically generates and updates project documentation from code comments, README files, and API definitions
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/documentation-generator.sh",
"matchers": [
"write",
"edit"
]
}
}
},
"scriptContent": "#!/usr/bin/env bash\n\n# Read the tool input from stdin\nINPUT=$(cat)\nTOOL_NAME=$(echo \"$INPUT\" | jq -r '.tool_name')\nFILE_PATH=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path // \"\"')\n\nif [ -z \"$FILE_PATH\" ]; then\n exit 0\nfi\n\n# Check if it's a documentation-relevant file\nif [[ \"$FILE_PATH\" == *.js ]] || [[ \"$FILE_PATH\" == *.jsx ]] || [[ \"$FILE_PATH\" == *.ts ]] || [[ \"$FILE_PATH\" == *.tsx ]] || [[ \"$FILE_PATH\" == *.py ]] || [[ \"$FILE_PATH\" == *.go ]] || [[ \"$FILE_PATH\" == *.rs ]] || [[ \"$FILE_PATH\" == *README* ]] || [[ \"$FILE_PATH\" == *.md ]]; then\n echo \"📚 Documentation-relevant file detected: $FILE_PATH\" >&2\n \n # Create docs directory if it doesn't exist\n mkdir -p ./docs\n \n # JavaScript/TypeScript documentation\n if [[ \"$FILE_PATH\" == *.js ]] || [[ \"$FILE_PATH\" == *.jsx ]] || [[ \"$FILE_PATH\" == *.ts ]] || [[ \"$FILE_PATH\" == *.tsx ]]; then\n echo \"🟡 JavaScript/TypeScript file - checking for documentation...\" >&2\n \n # Check for JSDoc comments\n if [ -f \"$FILE_PATH\" ]; then\n JSDOC_COMMENTS=$(grep -c '/\\*\\*' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n FUNCTIONS=$(grep -c '^\\s*\\(function\\|const\\s.*=>\\|class\\)' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n \n echo \"📊 Found $JSDOC_COMMENTS JSDoc comments and $FUNCTIONS functions/classes\" >&2\n \n if [ \"$JSDOC_COMMENTS\" -gt 0 ]; then\n # Try generating JSDoc documentation\n if command -v npx &> /dev/null; then\n if npx jsdoc --version &> /dev/null 2>&1; then\n echo \"📝 Generating JSDoc documentation...\" >&2\n npx jsdoc \"$FILE_PATH\" -d ./docs/jsdoc 2>/dev/null && echo \"✅ JSDoc documentation generated\" >&2\n fi\n \n # Try jsdoc2md for markdown output\n if npx jsdoc2md --version &> /dev/null 2>&1; then\n echo \"📝 Generating Markdown documentation...\" >&2\n npx jsdoc2md \"$FILE_PATH\" > \"./docs/$(basename \"$FILE_PATH\" .js).md\" 2>/dev/null && echo \"✅ Markdown documentation generated\" >&2\n fi\n fi\n else\n echo \"💡 Consider adding JSDoc comments to improve documentation coverage\" >&2\n fi\n \n # TypeScript-specific documentation\n if [[ \"$FILE_PATH\" == *.ts ]] || [[ \"$FILE_PATH\" == *.tsx ]]; then\n if command -v npx &> /dev/null && npx typedoc --version &> /dev/null 2>&1; then\n echo \"📝 Generating TypeDoc documentation...\" >&2\n npx typedoc \"$FILE_PATH\" --out ./docs/typedoc 2>/dev/null && echo \"✅ TypeDoc documentation generated\" >&2\n else\n echo \"💡 Install TypeDoc for comprehensive TypeScript documentation: npm install -g typedoc\" >&2\n fi\n fi\n fi\n \n # Python documentation\n elif [[ \"$FILE_PATH\" == *.py ]]; then\n echo \"🐍 Python file - checking for documentation...\" >&2\n \n if [ -f \"$FILE_PATH\" ]; then\n DOCSTRINGS=$(grep -c '\"\"\"\\|'\\''\\''\\'''' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n FUNCTIONS=$(grep -c '^def\\s\\|^class\\s' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n \n echo \"📊 Found $DOCSTRINGS docstrings and $FUNCTIONS functions/classes\" >&2\n \n # Try generating Python documentation\n if command -v pdoc &> /dev/null; then\n echo \"📝 Generating pdoc documentation...\" >&2\n pdoc \"$FILE_PATH\" --html --output-dir ./docs/python 2>/dev/null && echo \"✅ Python documentation generated\" >&2\n elif command -v python &> /dev/null; then\n if python -c \"import pydoc\" 2>/dev/null; then\n echo \"📝 Generating pydoc documentation...\" >&2\n python -m pydoc -w \"$FILE_PATH\" 2>/dev/null && echo \"✅ Python documentation generated\" >&2\n fi\n fi\n \n if [ \"$DOCSTRINGS\" -eq 0 ] && [ \"$FUNCTIONS\" -gt 0 ]; then\n echo \"💡 Consider adding docstrings to Python functions and classes\" >&2\n fi\n fi\n \n # Go documentation\n elif [[ \"$FILE_PATH\" == *.go ]]; then\n echo \"🐹 Go file - checking for documentation...\" >&2\n \n if [ -f \"$FILE_PATH\" ] && command -v go &> /dev/null; then\n COMMENTS=$(grep -c '^//\\s' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n echo \"📊 Found $COMMENTS documentation comments\" >&2\n \n echo \"📝 Generating Go documentation...\" >&2\n go doc \"$FILE_PATH\" > \"./docs/$(basename \"$FILE_PATH\" .go).txt\" 2>/dev/null && echo \"✅ Go documentation generated\" >&2\n fi\n \n # Rust documentation\n elif [[ \"$FILE_PATH\" == *.rs ]]; then\n echo \"🦀 Rust file - checking for documentation...\" >&2\n \n if [ -f \"$FILE_PATH\" ] && command -v cargo &> /dev/null; then\n DOC_COMMENTS=$(grep -c '^///\\|^//!' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n echo \"📊 Found $DOC_COMMENTS documentation comments\" >&2\n \n if [ \"$DOC_COMMENTS\" -gt 0 ]; then\n echo \"📝 Generating Rust documentation...\" >&2\n cargo doc --no-deps --target-dir ./docs/rust 2>/dev/null && echo \"✅ Rust documentation generated\" >&2\n else\n echo \"💡 Consider adding /// documentation comments to Rust code\" >&2\n fi\n fi\n \n # README and markdown documentation\n elif [[ \"$FILE_PATH\" == *README* ]] || [[ \"$FILE_PATH\" == *.md ]]; then\n echo \"📝 Markdown file - analyzing documentation structure...\" >&2\n \n if [ -f \"$FILE_PATH\" ]; then\n HEADERS=$(grep -c '^#' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n CODE_BLOCKS=$(grep -c '^```' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n LINKS=$(grep -c '\\[.*\\](.*)' \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n \n echo \"📊 Document structure: $HEADERS headers, $CODE_BLOCKS code blocks, $LINKS links\" >&2\n \n # Check for common README sections\n if [[ \"$FILE_PATH\" == *README* ]]; then\n echo \"📋 Checking README completeness...\" >&2\n \n REQUIRED_SECTIONS=(\"Installation\" \"Usage\" \"API\" \"Contributing\" \"License\")\n MISSING_SECTIONS=()\n \n for section in \"${REQUIRED_SECTIONS[@]}\"; do\n if ! grep -qi \"^#.*$section\" \"$FILE_PATH\"; then\n MISSING_SECTIONS+=(\"$section\")\n fi\n done\n \n if [ ${#MISSING_SECTIONS[@]} -eq 0 ]; then\n echo \"✅ README contains all recommended sections\" >&2\n else\n echo \"💡 Consider adding these sections: ${MISSING_SECTIONS[*]}\" >&2\n fi\n \n # Check for project metadata\n if [ -f \"package.json\" ]; then\n PROJECT_NAME=$(jq -r '.name // \"unknown\"' package.json 2>/dev/null)\n PROJECT_DESC=$(jq -r '.description // \"\"' package.json 2>/dev/null)\n \n if ! grep -q \"$PROJECT_NAME\" \"$FILE_PATH\"; then\n echo \"💡 Consider mentioning project name '$PROJECT_NAME' in README\" >&2\n fi\n fi\n fi\n \n # Check for broken links (basic check)\n if [ \"$LINKS\" -gt 0 ]; then\n echo \"🔗 Found $LINKS links - consider running a link checker\" >&2\n fi\n fi\n fi\n \n # General documentation quality tips\n echo \"\" >&2\n echo \"📋 Documentation Best Practices:\" >&2\n echo \" • Add clear function/method descriptions\" >&2\n echo \" • Include parameter types and return values\" >&2\n echo \" • Provide usage examples in documentation\" >&2\n echo \" • Keep README updated with latest changes\" >&2\n \nelse\n echo \"File $FILE_PATH is not relevant for documentation generation, skipping\" >&2\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/documentation-generator.sh",
"matchers": [
"write",
"edit"
]
}
}
}#!/usr/bin/env bash
# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Check if it's a documentation-relevant file
if [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.jsx ]] || [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]] || [[ "$FILE_PATH" == *.py ]] || [[ "$FILE_PATH" == *.go ]] || [[ "$FILE_PATH" == *.rs ]] || [[ "$FILE_PATH" == *README* ]] || [[ "$FILE_PATH" == *.md ]]; then
echo "📚 Documentation-relevant file detected: $FILE_PATH" >&2
# Create docs directory if it doesn't exist
mkdir -p ./docs
# JavaScript/TypeScript documentation
if [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.jsx ]] || [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]]; then
echo "🟡 JavaScript/TypeScript file - checking for documentation..." >&2
# Check for JSDoc comments
if [ -f "$FILE_PATH" ]; then
JSDOC_COMMENTS=$(grep -c '/\*\*' "$FILE_PATH" 2>/dev/null || echo "0")
FUNCTIONS=$(grep -c '^\s*\(function\|const\s.*=>\|class\)' "$FILE_PATH" 2>/dev/null || echo "0")
echo "📊 Found $JSDOC_COMMENTS JSDoc comments and $FUNCTIONS functions/classes" >&2
if [ "$JSDOC_COMMENTS" -gt 0 ]; then
# Try generating JSDoc documentation
if command -v npx &> /dev/null; then
if npx jsdoc --version &> /dev/null 2>&1; then
echo "📝 Generating JSDoc documentation..." >&2
npx jsdoc "$FILE_PATH" -d ./docs/jsdoc 2>/dev/null && echo "✅ JSDoc documentation generated" >&2
fi
# Try jsdoc2md for markdown output
if npx jsdoc2md --version &> /dev/null 2>&1; then
echo "📝 Generating Markdown documentation..." >&2
npx jsdoc2md "$FILE_PATH" > "./docs/$(basename "$FILE_PATH" .js).md" 2>/dev/null && echo "✅ Markdown documentation generated" >&2
fi
fi
else
echo "💡 Consider adding JSDoc comments to improve documentation coverage" >&2
fi
# TypeScript-specific documentation
if [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]]; then
if command -v npx &> /dev/null && npx typedoc --version &> /dev/null 2>&1; then
echo "📝 Generating TypeDoc documentation..." >&2
npx typedoc "$FILE_PATH" --out ./docs/typedoc 2>/dev/null && echo "✅ TypeDoc documentation generated" >&2
else
echo "💡 Install TypeDoc for comprehensive TypeScript documentation: npm install -g typedoc" >&2
fi
fi
fi
# Python documentation
elif [[ "$FILE_PATH" == *.py ]]; then
echo "🐍 Python file - checking for documentation..." >&2
if [ -f "$FILE_PATH" ]; then
DOCSTRINGS=$(grep -c '"""\|'\''\''\'''' "$FILE_PATH" 2>/dev/null || echo "0")
FUNCTIONS=$(grep -c '^def\s\|^class\s' "$FILE_PATH" 2>/dev/null || echo "0")
echo "📊 Found $DOCSTRINGS docstrings and $FUNCTIONS functions/classes" >&2
# Try generating Python documentation
if command -v pdoc &> /dev/null; then
echo "📝 Generating pdoc documentation..." >&2
pdoc "$FILE_PATH" --html --output-dir ./docs/python 2>/dev/null && echo "✅ Python documentation generated" >&2
elif command -v python &> /dev/null; then
if python -c "import pydoc" 2>/dev/null; then
echo "📝 Generating pydoc documentation..." >&2
python -m pydoc -w "$FILE_PATH" 2>/dev/null && echo "✅ Python documentation generated" >&2
fi
fi
if [ "$DOCSTRINGS" -eq 0 ] && [ "$FUNCTIONS" -gt 0 ]; then
echo "💡 Consider adding docstrings to Python functions and classes" >&2
fi
fi
# Go documentation
elif [[ "$FILE_PATH" == *.go ]]; then
echo "🐹 Go file - checking for documentation..." >&2
if [ -f "$FILE_PATH" ] && command -v go &> /dev/null; then
COMMENTS=$(grep -c '^//\s' "$FILE_PATH" 2>/dev/null || echo "0")
echo "📊 Found $COMMENTS documentation comments" >&2
echo "📝 Generating Go documentation..." >&2
go doc "$FILE_PATH" > "./docs/$(basename "$FILE_PATH" .go).txt" 2>/dev/null && echo "✅ Go documentation generated" >&2
fi
# Rust documentation
elif [[ "$FILE_PATH" == *.rs ]]; then
echo "🦀 Rust file - checking for documentation..." >&2
if [ -f "$FILE_PATH" ] && command -v cargo &> /dev/null; then
DOC_COMMENTS=$(grep -c '^///\|^//!' "$FILE_PATH" 2>/dev/null || echo "0")
echo "📊 Found $DOC_COMMENTS documentation comments" >&2
if [ "$DOC_COMMENTS" -gt 0 ]; then
echo "📝 Generating Rust documentation..." >&2
cargo doc --no-deps --target-dir ./docs/rust 2>/dev/null && echo "✅ Rust documentation generated" >&2
else
echo "💡 Consider adding /// documentation comments to Rust code" >&2
fi
fi
# README and markdown documentation
elif [[ "$FILE_PATH" == *README* ]] || [[ "$FILE_PATH" == *.md ]]; then
echo "📝 Markdown file - analyzing documentation structure..." >&2
if [ -f "$FILE_PATH" ]; then
HEADERS=$(grep -c '^#' "$FILE_PATH" 2>/dev/null || echo "0")
CODE_BLOCKS=$(grep -c '^```' "$FILE_PATH" 2>/dev/null || echo "0")
LINKS=$(grep -c '\[.*\](.*)' "$FILE_PATH" 2>/dev/null || echo "0")
echo "📊 Document structure: $HEADERS headers, $CODE_BLOCKS code blocks, $LINKS links" >&2
# Check for common README sections
if [[ "$FILE_PATH" == *README* ]]; then
echo "📋 Checking README completeness..." >&2
REQUIRED_SECTIONS=("Installation" "Usage" "API" "Contributing" "License")
MISSING_SECTIONS=()
for section in "${REQUIRED_SECTIONS[@]}"; do
if ! grep -qi "^#.*$section" "$FILE_PATH"; then
MISSING_SECTIONS+=("$section")
fi
done
if [ ${#MISSING_SECTIONS[@]} -eq 0 ]; then
echo "✅ README contains all recommended sections" >&2
else
echo "💡 Consider adding these sections: ${MISSING_SECTIONS[*]}" >&2
fi
# Check for project metadata
if [ -f "package.json" ]; then
PROJECT_NAME=$(jq -r '.name // "unknown"' package.json 2>/dev/null)
PROJECT_DESC=$(jq -r '.description // ""' package.json 2>/dev/null)
if ! grep -q "$PROJECT_NAME" "$FILE_PATH"; then
echo "💡 Consider mentioning project name '$PROJECT_NAME' in README" >&2
fi
fi
fi
# Check for broken links (basic check)
if [ "$LINKS" -gt 0 ]; then
echo "🔗 Found $LINKS links - consider running a link checker" >&2
fi
fi
fi
# General documentation quality tips
echo "" >&2
echo "📋 Documentation Best Practices:" >&2
echo " • Add clear function/method descriptions" >&2
echo " • Include parameter types and return values" >&2
echo " • Provide usage examples in documentation" >&2
echo " • Keep README updated with latest changes" >&2
else
echo "File $FILE_PATH is not relevant for documentation generation, skipping" >&2
fi
exit 0Hook runs on every file edit causing slow workflows
Refine matchers to specific extensions: ['write:*.js', 'write:*.ts', 'edit:*.md', 'edit:README*']. Use postToolUse with targeted matchers instead of wildcard to reduce unnecessary executions.
JSDoc generation fails with 'npx jsdoc not found' error
Check jsdoc availability before running: npx jsdoc --version &> /dev/null before generation. Add npm install -g jsdoc to project setup or include in package.json devDependencies.
Documentation tools timeout on large codebases
Add timeout limits to each tool execution: timeout 60s npx jsdoc. Process individual files instead of entire directories. Consider incremental documentation generation for changed files only.
TypeDoc fails with module resolution errors in TypeScript
Ensure tsconfig.json exists with proper module settings. Run TypeDoc from project root: npx typedoc --tsconfig ./tsconfig.json. Check for conflicting TypeScript versions between project and TypeDoc.
Python pdoc generation creates no output for modules
Verify module has __init__.py if package. Use absolute imports and check PYTHONPATH. Run pdoc with explicit module paths: pdoc --html --output-dir ./docs mymodule rather than file paths.
Loading reviews...
Join our community of Claude power users. No spam, unsubscribe anytime.
Automated accessibility testing and compliance checking for web applications following WCAG guidelines
Automatically generates or updates API documentation when endpoint files are modified
Automatically formats code files after Claude writes or edits them using Prettier, Black, or other formatters