feat: Add document-accessibility-wizard for Office and PDF accessibility audits#4
feat: Add document-accessibility-wizard for Office and PDF accessibility audits#4accesswatch merged 5 commits into
Conversation
…nning, confidence levels, severity scoring, template analysis, remediation tracking, metadata dashboard, batch remediation scripts, VPAT/ACR export, comparison reports, CI/CD integration guide)
…for document-accessibility-wizard
…istent memory to document-accessibility-wizard
…platform references - Add extract_document_metadata and batch_scan_documents tools to MCP server - Add Agent Teams enterprise config (AGENTS.md) - Add cross-platform handoff guide for Claude Code and Copilot - Add advanced scanning patterns (background, worktree, large libraries) - Add plugin packaging guide for agent distribution - Add platform references with all documentation sources and feature mapping - Add SessionEnd quality gate hook script - Update copilot-instructions.md with hidden helpers, skills, hooks, teams, docs - Update README.md with new project structure entries
There was a problem hiding this comment.
Pull request overview
Adds a new document-accessibility-wizard agent system (Copilot + Claude Code) and supporting assets to audit Office/PDF documents for accessibility, including configuration templates, prompts, hooks, and MCP server tooling.
Changes:
- Introduces the
document-accessibility-wizardorchestrator plus hidden helper agents, agent skills, and agent team coordination docs. - Adds scan configuration templates and Copilot prompt files for common document-audit workflows (single file, folder, delta scan, VPAT, remediation scripts, CI/CD).
- Extends the desktop MCP server with document metadata extraction and batch scanning tools; updates README/VS Code tasks to surface the new workflows.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| templates/pdf-config-strict.json | Strict PDF scan config template (severity filter + size limit). |
| templates/pdf-config-moderate.json | Moderate PDF scan config template (errors + warnings). |
| templates/pdf-config-minimal.json | Minimal PDF scan config template (errors only). |
| templates/office-config-strict.json | Strict Office scan config template for docx/xlsx/pptx. |
| templates/office-config-moderate.json | Moderate Office scan config template for docx/xlsx/pptx. |
| templates/office-config-minimal.json | Minimal Office scan config template for docx/xlsx/pptx. |
| templates/README.md | Usage docs for copying/customizing config templates. |
| example/document-testing-guide.md | Guide for creating test documents with intentional a11y issues. |
| desktop-extension/server/index.js | Adds MCP tools: extract_document_metadata and batch_scan_documents. |
| README.md | Documents the new wizard, helper agents, skills, hooks, prompts, templates, and MCP tools. |
| .vscode/tasks.json | Adds tasks for document discovery, git delta listing, and initializing scan configs. |
| .github/skills/report-generation/SKILL.md | Defines report structure, scoring, VPAT mapping, remediation tracking. |
| .github/skills/document-scanning/SKILL.md | Defines file discovery + delta detection conventions and skip patterns. |
| .github/skills/accessibility-rules/SKILL.md | Defines rule namespaces and WCAG 2.2 mappings for document rules. |
| .github/prompts/setup-document-cicd.prompt.md | Prompt workflow to generate CI/CD scanning setup. |
| .github/prompts/quick-document-check.prompt.md | Prompt workflow for minimal/high-confidence single-file triage. |
| .github/prompts/generate-vpat.prompt.md | Prompt workflow to generate VPAT/ACR from an audit report. |
| .github/prompts/generate-remediation-scripts.prompt.md | Prompt workflow to generate batch remediation scripts. |
| .github/prompts/create-accessible-template.prompt.md | Prompt workflow for accessible Office template guidance. |
| .github/prompts/compare-audits.prompt.md | Prompt workflow to compare audit reports for remediation progress. |
| .github/prompts/audit-single-document.prompt.md | Prompt workflow to run a strict single-document audit. |
| .github/prompts/audit-document-folder.prompt.md | Prompt workflow to run a moderate recursive folder audit. |
| .github/prompts/audit-changed-documents.prompt.md | Prompt workflow for git-diff delta scanning and comparison. |
| .github/hooks/scripts/session-stop.js | SessionEnd hook script for report completeness checks. |
| .github/hooks/scripts/session-start.js | SessionStart hook script for auto-detecting configs/prior reports. |
| .github/hooks/document-a11y.json | Hook configuration wiring SessionStart/SessionEnd scripts. |
| .github/docs/plugin-packaging.md | Packaging/distribution guide for agents/hooks/skills/prompts. |
| .github/docs/platform-references.md | Reference map of upstream docs used for features/format decisions. |
| .github/docs/cross-platform-handoff.md | Guidance for handoff between Claude Code and Copilot workflows. |
| .github/docs/advanced-scanning-patterns.md | Advanced scanning strategies (background, worktrees, large libraries). |
| .github/copilot-instructions.md | Updates workspace instructions to include document audit system. |
| .github/agents/document-inventory.agent.md | Hidden helper agent for discovery/inventory/delta detection. |
| .github/agents/document-accessibility-wizard.agent.md | Main Copilot document audit wizard (multi-phase orchestration spec). |
| .github/agents/cross-document-analyzer.agent.md | Hidden helper agent for cross-document scoring/pattern analysis. |
| .github/agents/AGENTS.md | Defines document/web/full audit “team” compositions and workflows. |
| .claude/agents/document-accessibility-wizard.md | Claude Code variant of the document audit wizard. |
| 'Audit Information', | ||
| 'Executive Summary', | ||
| 'Accessibility Scorecard', | ||
| 'Confidence Summary' |
There was a problem hiding this comment.
The SessionEnd quality gate only checks for a small subset of sections. The report-generation skill defines additional required sections (e.g., Cross-Document Patterns, Findings by File, Remediation Priority, Metadata Dashboard). Expand requiredSections to align with the skill’s REQUIRED sections (or centralize the list) so incomplete reports don’t pass.
| 'Confidence Summary' | |
| 'Confidence Summary', | |
| 'Cross-Document Patterns', | |
| 'Findings by File', | |
| 'Remediation Priority', | |
| 'Metadata Dashboard' |
| ### Parallel Sub-Agent Execution | ||
|
|
||
| When scanning batches with multiple document types, spawn sub-agents in parallel for maximum efficiency: | ||
|
|
||
| 1. **Group files by type** — Word, Excel, PowerPoint, PDF | ||
| 2. **Spawn one sub-agent per document type** — each runs in its own isolated context window | ||
| 3. **Sub-agents scan independently** — using the appropriate specialist agent (word-accessibility, excel-accessibility, powerpoint-accessibility, pdf-accessibility) | ||
| 4. **Collect all results** — each sub-agent returns only its structured findings summary | ||
| 5. **Synthesize in Phase 3** — the wizard combines all results for cross-document analysis | ||
|
|
||
| This parallel approach means scanning 12 documents across 4 types takes roughly the same time as scanning the largest single-type group, rather than scanning all 12 sequentially. | ||
|
|
||
| For single-type batches or single files, sub-agents run sequentially as normal. | ||
|
|
There was a problem hiding this comment.
This section claims Copilot can “spawn sub-agents in parallel” and that each runs “in its own isolated context window”, but advanced-scanning-patterns.md states Copilot sub-agents run within the main conversation context (no true background/parallel). Please align this guidance (e.g., process by type group sequentially, and reserve true parallel task language for Claude Code only).
| ### Parallel Sub-Agent Execution | |
| When scanning batches with multiple document types, spawn sub-agents in parallel for maximum efficiency: | |
| 1. **Group files by type** — Word, Excel, PowerPoint, PDF | |
| 2. **Spawn one sub-agent per document type** — each runs in its own isolated context window | |
| 3. **Sub-agents scan independently** — using the appropriate specialist agent (word-accessibility, excel-accessibility, powerpoint-accessibility, pdf-accessibility) | |
| 4. **Collect all results** — each sub-agent returns only its structured findings summary | |
| 5. **Synthesize in Phase 3** — the wizard combines all results for cross-document analysis | |
| This parallel approach means scanning 12 documents across 4 types takes roughly the same time as scanning the largest single-type group, rather than scanning all 12 sequentially. | |
| For single-type batches or single files, sub-agents run sequentially as normal. | |
| ### Grouped Sub-Agent Delegation | |
| When scanning batches with multiple document types, optimize efficiency by grouping work by document type while staying within the main conversation context: | |
| 1. **Group files by type** — Word, Excel, PowerPoint, PDF | |
| 2. **For each type group, delegate to the matching specialist sub-agent** — word-accessibility, excel-accessibility, powerpoint-accessibility, or pdf-accessibility | |
| 3. **Process type groups sequentially** — complete one document-type group before moving to the next | |
| 4. **Within each group, scan files sequentially** — maintaining shared context for consistent findings and recommendations | |
| 5. **Collect all results** — each delegation returns structured findings summaries | |
| 6. **Synthesize in Phase 3** — the wizard combines all results for cross-document analysis | |
| This grouped, sequential approach reduces redundant context switching, keeps the assistant’s understanding consistent within each document type, and still scales effectively to larger document libraries without relying on true background or parallel execution. |
| `Accessibility Property Health:`, | ||
| ` Title: ${title ? "PASS" : "FAIL"}`, | ||
| ` Author: ${creator ? "PASS" : "FAIL"}`, | ||
| ` Language: ${language ? "FAIL — not set" : (() => { const doc = ext === ".docx" ? getZipXml(buf, entries, "word/document.xml") : ""; return xmlHas(doc, "w:lang") ? "PASS" : "FAIL — not set"; })()}`, |
There was a problem hiding this comment.
In Accessibility Property Health, the language check is inverted: when dc:language is present it currently reports FAIL — not set. This makes the language health incorrect for any document that actually has dc:language set (and also doesn’t provide a sensible result for .pptx/.xlsx). Flip the condition and/or fall back to format-appropriate language detection only when the core property is missing.
| ` Language: ${language ? "FAIL — not set" : (() => { const doc = ext === ".docx" ? getZipXml(buf, entries, "word/document.xml") : ""; return xmlHas(doc, "w:lang") ? "PASS" : "FAIL — not set"; })()}`, | |
| ` Language: ${language ? "PASS" : (() => { const doc = ext === ".docx" ? getZipXml(buf, entries, "word/document.xml") : ""; return xmlHas(doc, "w:lang") ? "PASS" : "FAIL — not set"; })()}`, |
| const fileStat = await stat(filePath).catch(() => null); | ||
| const fileSize = fileStat ? fileStat.size : buf.length; | ||
|
|
||
| if (ext === ".pdf") { |
There was a problem hiding this comment.
extract_document_metadata parses PDFs purely based on the file extension. Unlike scan_pdf_document, it doesn’t validate the %PDF- header before calling parsePdfBasics, so non-PDF files renamed to .pdf will produce misleading metadata (and may incur unnecessary full-buffer parsing). Add the same header validation used in the PDF scan tool and return a clear error when invalid.
| if (ext === ".pdf") { | |
| if (ext === ".pdf") { | |
| // Validate PDF header to avoid parsing non-PDF files renamed as .pdf | |
| const pdfHeader = buf.slice(0, 5).toString("ascii"); | |
| if (pdfHeader !== "%PDF-") { | |
| return { | |
| content: [ | |
| { | |
| type: "text", | |
| text: "Invalid PDF file: missing %PDF- header. The file may not be a valid PDF.", | |
| }, | |
| ], | |
| }; | |
| } |
| try { | ||
| buf = await fsReadFile(fp); | ||
| } catch (err) { | ||
| errors.push(`${basename(fp)}: ${err.message}`); | ||
| continue; | ||
| } | ||
|
|
||
| const defaultSev = severityFilter || ["error", "warning", "tip"]; | ||
| let findings = []; | ||
|
|
||
| if (ext === ".pdf") { | ||
| const header = buf.toString("latin1", 0, 8); | ||
| if (!header.startsWith("%PDF-")) { | ||
| errors.push(`${basename(fp)}: not a valid PDF`); | ||
| continue; | ||
| } | ||
| const config = await loadPdfConfig(fp); | ||
| if (severityFilter) config.severityFilter = severityFilter; | ||
| const result = scanPdf(buf, config); | ||
| findings = result.findings; | ||
| } else { |
There was a problem hiding this comment.
batch_scan_documents ignores key PDF config safeguards: it never checks config.enabled === false and it doesn’t enforce config.maxFileSize before reading/scanning. This can cause disabled scans to run and can lead to very large PDFs being scanned unexpectedly. Mirror the checks used in the single-file PDF scan/CI script (skip/record an error when disabled or oversized).
| try { | |
| buf = await fsReadFile(fp); | |
| } catch (err) { | |
| errors.push(`${basename(fp)}: ${err.message}`); | |
| continue; | |
| } | |
| const defaultSev = severityFilter || ["error", "warning", "tip"]; | |
| let findings = []; | |
| if (ext === ".pdf") { | |
| const header = buf.toString("latin1", 0, 8); | |
| if (!header.startsWith("%PDF-")) { | |
| errors.push(`${basename(fp)}: not a valid PDF`); | |
| continue; | |
| } | |
| const config = await loadPdfConfig(fp); | |
| if (severityFilter) config.severityFilter = severityFilter; | |
| const result = scanPdf(buf, config); | |
| findings = result.findings; | |
| } else { | |
| const defaultSev = severityFilter || ["error", "warning", "tip"]; | |
| let findings = []; | |
| if (ext === ".pdf") { | |
| const config = await loadPdfConfig(fp); | |
| if (severityFilter) config.severityFilter = severityFilter; | |
| let fileStat; | |
| try { | |
| fileStat = await stat(fp); | |
| } catch (err) { | |
| errors.push(`${basename(fp)}: ${err.message}`); | |
| continue; | |
| } | |
| if (config.enabled === false) { | |
| errors.push(`${basename(fp)}: scanning disabled in config`); | |
| continue; | |
| } | |
| if (typeof config.maxFileSize === "number" && fileStat.size > config.maxFileSize) { | |
| errors.push(`${basename(fp)}: file exceeds configured maxFileSize`); | |
| continue; | |
| } | |
| try { | |
| buf = await fsReadFile(fp); | |
| } catch (err) { | |
| errors.push(`${basename(fp)}: ${err.message}`); | |
| continue; | |
| } | |
| const header = buf.toString("latin1", 0, 8); | |
| if (!header.startsWith("%PDF-")) { | |
| errors.push(`${basename(fp)}: not a valid PDF`); | |
| continue; | |
| } | |
| const result = scanPdf(buf, config); | |
| findings = result.findings; | |
| } else { | |
| try { | |
| buf = await fsReadFile(fp); | |
| } catch (err) { | |
| errors.push(`${basename(fp)}: ${err.message}`); | |
| continue; | |
| } |
| const config = JSON.parse(fs.readFileSync(officeConfigPath, 'utf8')); | ||
| const profile = config.profile || 'custom'; | ||
| context.push(`Office scan config: profile=${profile}`); | ||
| } catch { |
There was a problem hiding this comment.
The SessionStart hook reads config.profile, but the provided config templates/tasks create .a11y-office-config.json without a profile field. This will usually report profile=custom, which is misleading. Either add a profile field to generated templates or infer the profile from severityFilter / description.
| if (fs.existsSync(pdfConfigPath)) { | ||
| try { | ||
| const config = JSON.parse(fs.readFileSync(pdfConfigPath, 'utf8')); | ||
| const profile = config.profile || 'custom'; |
There was a problem hiding this comment.
Same issue for the PDF config: SessionStart expects config.profile, but the PDF templates don’t set it, so this hook will generally report profile=custom. Consider adding profile to the template configs or deriving it from severityFilter.
| const profile = config.profile || 'custom'; | |
| const profile = config.profile || config.severityFilter || 'custom'; |
taylorarndt
left a comment
There was a problem hiding this comment.
Approved. Merged into main.
…and hook schema updates (#30) * feat: add CSV reporters, CI linting, EPUB agents, and ecosystem enhancements - Enhancement 1: Register EPUB agents in both AGENTS.md files with new EPUB team - Enhancement 2: Create 5 missing Claude agents (epub-scan-config, cognitive-accessibility, design-system-auditor, epub-accessibility, mobile-accessibility) - Enhancement 3: Wire CSV reporters into all 4 wizard agents (web + document, both platforms) - Enhancement 4: Add markdown-csv-reporter agents, export-markdown-csv prompt, and documentation - Enhancement 5: Add markdown-a11y-lint.mjs CI script and markdown-lint workflow job New files: 23 (agents, prompts, docs, CI script, skill) Modified files: 14 (AGENTS.md, wizards, instructions, workflow, docs) * fix: align rule IDs to canonical format agents and add gap analysis rules - Aligned DOCX/XLSX/PPTX rule tables in both CSV reporters (Copilot + Claude) to canonical format agent IDs - Fixed Warning weight from 3 to 5 in Copilot CSV reporter ROI calculation - Added 5 new rules from Microsoft Accessibility Checker gap analysis: - DOCX-E008 (document-access-restricted/IRM) - DOCX-E009 (content-controls-without-titles) - XLSX-E007 (red-negative-numbers) - XLSX-E008 (workbook-access-restricted/IRM) - PPTX-E007 (presentation-access-restricted/IRM) - Updated format agents (word/excel/powerpoint-accessibility) with new rules - Updated office-scan-config agents with new rules - All rule IDs now consistent across format agents, CSV reporters, help-url-reference, and accessibility-rules SKILL * fix: complete code review fixes (34/34 findings resolved) High severity (previously fixed): - H-01: Manifest-based uninstall (prevents deleting user files) - H-02: ReDoS-resistant bounded regex patterns - H-03: ZIP bomb protection (200MB limit) - H-04: ZIP64 archive detection Medium severity: - M-01: validateFilePath write-mode enforcement at all 9 call sites - M-02: cd exit guard in install.sh embedded updater - M-03: ExecutionPolicy Bypass changed to RemoteSigned - M-04: Multi-line HTML tag limitation documented in a11y-lint - M-05: BOM-aware YAML front matter detection in markdown lint - M-06: Expanded emoji regex to cover supplemental/flag sequences - M-07: Removed stale path reference (previously fixed) - M-08: git clone error handling in install.ps1 and install.sh - M-09: PDFQ.REPO.NO_SCANNED_ONLY guarded against duplicate with PDFBP.TEXT.EXTRACTABLE - M-10: Title regex escaped parens (previously fixed) Low severity: - L-01: PS 5.1-compatible null-coalescing in 4 hook scripts - L-02: Dead imports removed (previously fixed) - L-03: lstatSync + symlink skip in all 4 lint/scan scripts - L-04: Link regex handles nested elements in a11y-lint - L-05: XML regex parsing limitations documented - L-06: Array.isArray checks (previously fixed) - L-08: JSON-safe string escaping in a11y-team-eval.sh - L-09: Hex format hints on contrast task inputs - L-10: Removed unused documentPath input from tasks.json - L-11: cd exit guards in update.sh - L-12: Skipped (JSON does not support comments) Informational: - I-01: Zod semver range fixed to ^3.25.0 - I-02: WCAG 2.1 to 2.2 in manifest.json (3 locations) - I-03: WCAG 2.1 to 2.2 in index.js (5 locations) - I-04: Empty catch blocks annotated in lint scripts - I-05: Concurrent processing opportunity noted - I-06: message.split fallback for messages without periods (5 locations) - I-07: Intentional anti-pattern banners in example files - I-08: Shared code duplication documented between lint scripts * fix: update hook schema to hookSpecificOutput and increase timeouts - Flatten Claude settings.json hook structure (remove nested hooks array) - Add Windows-specific command paths to Claude hooks - Migrate hook scripts from stopReason/systemMessage to hookSpecificOutput pattern - Increase hook timeouts from 5-10s to 10-15s for reliability - Add hookEventName metadata to all hook JSON responses - Update cross-platform handoff documentation - Add audit sessions log * fix: address PR review findings (#1-#4) - #1: gitignore .github/audit/ and remove sessions.log from tracking - #2: restore PreToolUse matcher (Bash|mcp_github) to scope safety gate - #3: migrate install.sh, install.ps1, uninstall.sh to flat hook schema - #4: annotate WCAG 2.4.13 Focus Appearance as (AAA) in CLAUDE.md and copilot-instructions.md * feat: add multi-agent reliability engineering and remove hooks Apply principles from GitHub blog article on multi-agent workflow reliability across the entire agent ecosystem. ## Hook Removal - Delete all hook files (.claude/hooks/, .github/hooks/) - Remove hook references from 60+ documentation files - Clean .claude/settings.json - Remove hook setup from install/uninstall/update scripts ## Multi-Agent Reliability - Create multi-agent-reliability.instructions.md - Add reliability standards to both AGENTS.md manifests - Add structured output contracts to 12 orchestrator files - Add output contracts + handoff transparency to 26 sub-agent files - Add handoff transparency sections to 21 custom prompt files ## Instruction Strengthening - Add Context Discovery, Audit Report Quality Requirements, and Automatic Trigger Detection to CLAUDE.md and copilot-instructions.md - Replace SESSION CONTEXT references with workspace context ## CI Fixes - Fix a11y-lint.mjs and markdown-a11y-lint.mjs for CI workflow All linters pass with 0 errors. * fix: add missing YAML front matter to skill files Ran skills and got errors - four SKILL.md files were missing YAML front matter (name + description). Added front matter to: - cognitive-accessibility/SKILL.md - design-system/SKILL.md - markdown-accessibility/SKILL.md - mobile-accessibility/SKILL.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: add one-liner uninstall to README Mirrors the one-liner install section with curl/irm equivalents for uninstall on macOS/Linux and Windows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: taylorarndt <taylor@techopolis.online> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Adds a comprehensive document-accessibility-wizard agent system for auditing Office documents (.docx, .xlsx, .pptx) and PDFs against WCAG 2.2, PDF/UA, and Matterhorn Protocol standards.
What's Included
Core Agents
.agent.mdand Claude Code.mdformats)document-inventory(file discovery) andcross-document-analyzer(pattern detection)Agent Platform Features
tools,model,agents,handoffs,user-invokable: falseSKILL.mdentrypoints (document-scanning,accessibility-rules,report-generation)SessionStart(auto-detect config/reports) andSessionEnd(quality gate validation)AGENTS.md(Document Audit, Web Audit, Full Audit teams)MCP Server Enhancements
extract_document_metadata— Metadata extraction for Office/PDF docsbatch_scan_documents— Batch scanning with per-file severity scoring (0-100, A-F grades)Audit Capabilities
git diff)Custom Prompts & Configuration
.prompt.md) for one-click workflows: single doc audit, folder audit, delta scan, VPAT generation, remediation scripts, audit comparison, CI/CD setup, quick check, template creationDocumentation
Commits
0fe2bf1— Initial document-accessibility-wizard agents009b59f— 10 improvements (delta scanning, severity scoring, template analysis, remediation tracking, VPAT/ACR, etc.)28f2906— Custom prompts, config templates, VS Code tasks, testing guide874ed4b— Parallel subagents, handoffs, agent skills, hooks, persistent memory7c589a8— MCP enhancements, agent teams, docs, plugin packaging, platform referencesFiles Changed
New Files
.claude/agents/document-accessibility-wizard.md— Claude Code agent.github/agents/document-accessibility-wizard.agent.md— Copilot agent.github/agents/AGENTS.md— Agent Teams config.github/agents/— 7 additional format-specific and helper agents.github/skills/— 3 agent skills with SKILL.md files.github/hooks/— Lifecycle hook config and scripts.github/prompts/— 9 custom prompt files.github/docs/— 4 documentation guidestemplates/— 7 scan configuration templatesModified Files
.github/copilot-instructions.md— Added hidden helpers, skills, hooks, teams, advanced docs sectionsREADME.md— Updated agent counts, project structure, feature descriptionsdesktop-extension/server/index.js— Added 2 new MCP tools