Toolkit Health Check #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Toolkit Health Check | |
| on: | |
| schedule: | |
| # Runs on the 1st and 15th of each month at 9am UTC (~every 2-3 weeks) | |
| - cron: '0 9 1,15 * *' | |
| workflow_dispatch: # Manual trigger | |
| jobs: | |
| audit: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Check reference links | |
| id: links | |
| run: | | |
| echo "## Link Check" > /tmp/audit-report.md | |
| echo "" >> /tmp/audit-report.md | |
| if [ -f skills/updater/scripts/check-links.py ]; then | |
| link_exit=0 | |
| python skills/updater/scripts/check-links.py >> /tmp/audit-report.md 2>&1 || link_exit=$? | |
| else | |
| echo "check-links.py not found at skills/updater/scripts/" >> /tmp/audit-report.md | |
| link_exit=1 | |
| fi | |
| echo "link_problems=$link_exit" >> $GITHUB_OUTPUT | |
| - name: Run hook tests | |
| id: hooktests | |
| run: | | |
| echo "## Hook Tests" >> /tmp/audit-report.md | |
| echo "" >> /tmp/audit-report.md | |
| if [ -f tests/test-hooks.sh ]; then | |
| hook_exit=0 | |
| bash tests/test-hooks.sh >> /tmp/audit-report.md 2>&1 || hook_exit=$? | |
| if [ "$hook_exit" -eq 0 ]; then | |
| echo "All hook tests passed." >> /tmp/audit-report.md | |
| else | |
| echo "**Hook tests FAILED.** See output above." >> /tmp/audit-report.md | |
| fi | |
| else | |
| echo "test-hooks.sh not found." >> /tmp/audit-report.md | |
| hook_exit=1 | |
| fi | |
| echo "hook_problems=$hook_exit" >> $GITHUB_OUTPUT | |
| - name: Check reference freshness | |
| id: freshness | |
| run: | | |
| echo "" >> /tmp/audit-report.md | |
| echo "## Freshness Check" >> /tmp/audit-report.md | |
| echo "" >> /tmp/audit-report.md | |
| cutoff=$(date -d '6 months ago' +%Y-%m-%d 2>/dev/null || date -v-6m +%Y-%m-%d) | |
| stale_file=$(mktemp) | |
| echo "0" > "$stale_file" | |
| for file in $(find skills/ shared/ -name "*.md" -type f); do | |
| date_line=$(grep -i "last verified" "$file" 2>/dev/null | head -1 || true) | |
| if [ -n "$date_line" ]; then | |
| verified_date=$(echo "$date_line" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' || true) | |
| if [ -n "$verified_date" ] && [[ "$verified_date" < "$cutoff" ]]; then | |
| echo "- [STALE] $file — last verified $verified_date" >> /tmp/audit-report.md | |
| echo "$(( $(cat "$stale_file") + 1 ))" > "$stale_file" | |
| fi | |
| fi | |
| done | |
| stale_count=$(cat "$stale_file") | |
| rm -f "$stale_file" | |
| if [ "$stale_count" -eq 0 ]; then | |
| echo "All references are current (verified within 6 months)." >> /tmp/audit-report.md | |
| else | |
| echo "" >> /tmp/audit-report.md | |
| echo "**$stale_count file(s) need re-verification.**" >> /tmp/audit-report.md | |
| fi | |
| echo "stale=$stale_count" >> $GITHUB_OUTPUT | |
| - name: Check file sizes | |
| id: sizes | |
| run: | | |
| echo "" >> /tmp/audit-report.md | |
| echo "## File Size Check (250-line target)" >> /tmp/audit-report.md | |
| echo "" >> /tmp/audit-report.md | |
| # Files with justified exemptions (documented reasons for exceeding 250 lines) | |
| EXEMPT_FILES="skills/precommit/SKILL.md shared/guardrails.md shared/orchestrator.md" | |
| over_count=0 | |
| while IFS= read -r file; do | |
| lines=$(wc -l < "$file") | |
| if [ "$lines" -gt 250 ]; then | |
| is_exempt=false | |
| for exempt in $EXEMPT_FILES; do | |
| if [ "$file" = "$exempt" ]; then | |
| is_exempt=true | |
| break | |
| fi | |
| done | |
| if [ "$is_exempt" = true ]; then | |
| echo "- [EXEMPT] $file — $lines lines (justified: critical enforcement file)" >> /tmp/audit-report.md | |
| else | |
| echo "- [OVER] $file — $lines lines" >> /tmp/audit-report.md | |
| over_count=$((over_count + 1)) | |
| fi | |
| fi | |
| done < <(find skills/ shared/ agents/ -name "*.md" -type f) | |
| if [ "$over_count" -eq 0 ]; then | |
| echo "All non-exempt files under 250 lines." >> /tmp/audit-report.md | |
| fi | |
| echo "over=$over_count" >> $GITHUB_OUTPUT | |
| - name: Skill/agent inventory | |
| run: | | |
| echo "" >> /tmp/audit-report.md | |
| echo "## Inventory" >> /tmp/audit-report.md | |
| echo "" >> /tmp/audit-report.md | |
| skill_count=$(find skills/ -name "SKILL.md" | wc -l | tr -d ' ') | |
| agent_count=$(find agents/ -name "*.md" | wc -l | tr -d ' ') | |
| echo "- Skills: $skill_count" >> /tmp/audit-report.md | |
| echo "- Agents: $agent_count" >> /tmp/audit-report.md | |
| echo "- Total lines: $(find skills/ shared/ agents/ -name '*.md' -exec cat {} + | wc -l | tr -d ' ')" >> /tmp/audit-report.md | |
| - name: Open issue if any problems found | |
| if: steps.freshness.outputs.stale != '0' || steps.links.outputs.link_problems != '0' || steps.sizes.outputs.over != '0' || steps.hooktests.outputs.hook_problems != '0' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const report = fs.readFileSync('/tmp/audit-report.md', 'utf8'); | |
| // Check for existing open health check issue to avoid spam | |
| const existing = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| labels: 'maintenance,automated', | |
| state: 'open' | |
| }); | |
| if (existing.data.length > 0) { | |
| // Update existing issue instead of creating a new one | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: existing.data[0].number, | |
| body: `# Updated Health Check — ${new Date().toISOString().split('T')[0]}\n\n${report}` | |
| }); | |
| } else { | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: `Toolkit Health Check — action needed`, | |
| body: `# Automated Toolkit Health Check\n\n${report}\n\n---\n*Generated by [updater workflow](.github/workflows/updater.yml). Close this issue when resolved — next run will create a new one only if problems recur.*`, | |
| labels: ['maintenance', 'automated'] | |
| }); | |
| } |