Add CodeAI accessibility agent + skill (a11y-architect)#73329
Open
stephenliang wants to merge 2 commits into
Open
Add CodeAI accessibility agent + skill (a11y-architect)#73329stephenliang wants to merge 2 commits into
stephenliang wants to merge 2 commits into
Conversation
Add a CodeAI-specific accessibility agent and skill (usable by Claude and Codex), based on the generic ECC a11y-architect agent and accessibility skill, re-grounded in CodeAI practice: design-system-first components, the apps/ vs frontend/ regimes, focus-ring conventions, and Blockly's constraints. Documentation only; no runtime code. - .agents/skills/accessibility/SKILL.md: the skill (cross-tool; both Claude and Codex discover .agents/skills) - .agents/skills/accessibility/checklist.md: canonical org build checklist (ground truth) - .agents/skills/accessibility/blockly.md: Blockly-lab accessibility reference - .claude/agents/a11y-architect.md: repo-local Claude subagent that defers to the skill Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…runs - skill Step 1 leads with the design-system-first priority order (component > justified raw native element > never a div/span widget) - add a div-button sweep (onClick/onKeyDown/role on div/span/p) so audits stop missing keyboard-inaccessible controls - agent: require a per-interactive-element component decision in the output - agent: drop yarn typecheck/test/build from worktree verification (no node_modules; sandbox blocks copy-out) in favor of ./tools/hooks/pre-commit Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a CodeAI-specific accessibility agent and skill, usable by both Claude and Codex, for building and auditing UI to WCAG 2.2 Level AA (the floor, not the target). It is based on the generic ECC
a11y-architectagent andaccessibilityskill, re-grounded in CodeAI's own practice: the design-system-first component hierarchy, theapps/(legacy) vsfrontend/(new code, strictjsx-a11y) regimes, our focus-ring conventions and tokens, and the accessibility constraints of our Blockly-based labs. This is documentation only — no runtime code is touched.Artifacts
The skill is the knowledge base and the agent is a thin workflow persona that defers to it; the checklist is the org's ground truth and wins whenever it disagrees with the skill.
.agents/skills/accessibility/SKILL.md— the skill, and the source of truth for everything else. It is cross-tool: both Claude and Codex discover.agents/skills(.claude/skillssymlinks to it). It mirrors the ECC accessibility skill's POUR structure and verbiage, with CodeAI specifics woven directly into the How-It-Works steps rather than bolted on as a separate section..agents/skills/accessibility/checklist.md— the canonical org accessibility build checklist and keyboard/screen-reader self-test steps; the skill's declared ground truth..agents/skills/accessibility/blockly.md— a Blockly-lab accessibility reference, forked out because its rules differ sharply: two separate Blockly stacks, no screen-reader support in either, and theming (high-contrast and colorblind palettes) as the only shipped accessibility win..claude/agents/a11y-architect.md— a repo-local Claude subagent that reads the skill as its rubric and routes work through the design system; the generic ECC prompt-defense baseline is stripped.Example: agent test runs
Two end-to-end runs on real
apps/components, showing the agent's judgment in both directions — convert what should be a control, and leave alone what only looks like one. Both were throwaway demonstrations and are not part of this PR.1. A true div-button → a justified native control (
StudentRubricView.tsx)A Lab2 rubric panel that already uses the design system (MUI
Typography,@code-dot-org/component-libraryicons). Its evidence-level header was a hand-rolled<div onClick={() => setCollapsed(...)}>disclosure toggle: keyboard-unreachable, no role, no accessible name, collapse state conveyed by color alone. The agent swept for interactive behavior on non-interactive elements, made an explicit component decision before writing code (no DSCO disclosure/accordion primitive fits an inline icon+label toggle; an MUIAccordionwould restructure the card), then chose a native<button aria-expanded aria-controls>and recorded the rationale as a code comment. It also named the icon-only goal-switcher buttons, gave the loading spinner arole="status", and hid the decorativeProgressRingSVG.WCAG 2.2 addressed across the file: 2.1.1 (Keyboard), 4.1.2 (Name/Role/Value), 4.1.3 (Status Messages), 1.1.1 (Non-text Content), 1.4.1 (Use of Color), 2.4.11 (Focus Appearance).
2. Restraint: a clickable wrapper correctly left alone (
LtiSectionSyncDialog.tsx)A late-2023 multi-view LTI roster-sync dialog. The sweep flagged a
<div onClick={handleDocsClick}>, but the agent reasoned it is an analytics-capture wrapper aroundSafeMarkdown's real<a>links — already keyboard-reachable — not a div-button, so it left the element in place and documented why instead of wrapping it in a redundant control. In the same pass it fixed the genuine barriers, e.g. dropping a bogusrole="grid"and giving the summary table a<caption>andscope="col"headers:<h2 style={styles.dialogHeader} id={HEADING_ID_SYNC_RESULT}> {dialogTitle} </h2> + {/* + * The onClick here fires analytics when the user clicks any link + * inside the description markdown. It is intentionally on a non- + * interactive wrapper; the actual interactive elements (links) are + * rendered by SafeMarkdown and remain keyboard-operable. + */} <div onClick={handleDocsClick}> <SafeMarkdown openExternalLinksInNewTab markdown={dialogDescription} /> </div> - <div style={styles.summaryContainer} aria-labelledby={'roster-sync-status'}> + <div style={styles.summaryContainer}> @@ summary table @@ - <table style={styles.summaryTable} role={'grid'}> + <table style={styles.summaryTable}> + <caption style={styles.visuallyHidden}> + {i18n.ltiSectionSyncDialogTitle()} + </caption> <thead> <tr> - <th style={styles.tableHeaderLeft}> + <th style={styles.tableHeaderLeft} scope="col"> {i18n.ltiSectionSyncDialogHeaderSectionName()} </th> {/* …the other three headers likewise gain scope="col"… */}It also added a
role="dialog" aria-modal aria-labelledbywrapper, a spinnerrole="status"live region, made duplicate "Primary Instructor" dropdown labels unique per section, and bumped a 2.83:1 header color to a 4.5:1-passing token.Both runs verified with
./tools/hooks/pre-commit(clean), used only./tools/hooks/pre-commitfor verification (noyarnfrom the worktree), and flagged what they could not self-verify — keyboard and screen-reader passes,forced-colors, andprefers-reduced-motion— rather than claiming them.Links
Testing story
Documentation only; no runtime code, so no automated suite applies. The content was verified by a factual-claim audit against the live repo — confirming the disabled
jsx-a11yrules inapps/.eslintrc.js, the@axe-core/playwrightdependency, themixins.focus-stylesmixin and--borders-brand-teal-primarytoken, thedesign-systemskill, every referenced Blockly path, the intra-skill relative links, and the agent frontmatter — plus an internal-consistency and CLAUDE.md/AGENTS.md conventions review across the four files. The two agent test runs above are a further end-to-end check that the agent + skill produce house-style output../tools/hooks/pre-commitlints only changed files of the relevant types, and these are all markdown, so no js/ts/ruby lint applies.