Accessibility
MicrosoftOfficialPublished by Microsoft
- Skill
- Tool integration
- Software development
- MIT
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The accessibility skill provides a structured approach to managing accessibility requirements across the development lifecycle. It includes a six-phase Accessibility Planner workflow, a command-line scanner for static analysis, and a runtime probe harness for verifying interaction-based accessibility. The skill enforces a doctrine of method adequacy, ensuring that verification methods are only used to decide criteria they are capable of observing, and supports the generation of evidence bundles for review.
What it does
- Provides a six-phase workflow for accessibility discovery, planning, and backlog handoff.
- Wraps the axe-core CLI to perform static accessibility scans on web pages.
- Executes Playwright-based runtime probes to verify interaction behavior and screen-reader announcements.
- Enforces method adequacy rules to distinguish between static findings and interaction-based verification.
- Generates deterministic evidence bundles for accessibility reviews and reporting.
- Maps findings to WCAG 2.2, ARIA Authoring Practices, and other accessibility standards.
When to use it
- When planning accessibility requirements for a new project or feature.
- When performing automated static scans of web content for common accessibility defects.
- When verifying complex interaction behaviors that static analysis cannot fully evaluate.
- When building an evidence register to track accessibility conformance across development phases.
Advantages
- Standardizes accessibility verification across different projects and teams.
- Prevents over-reliance on static analysis for complex interaction-based criteria.
- Supports tiered enforcement postures to match project risk and maturity.
- Integrates with standard CI workflows for automated accessibility testing.
Usage examples
- “Scan my local file index.html for accessibility violations.”
- The skill runs the axe-core scanner against the file and outputs a normalized JSON report of findings.
- “Run the accessibility runtime probes for my project.”
- The skill executes the configured Playwright probes and aggregates the results into a coverage matrix.
Install
1 of its files are not mirrored here, so install it from its source:
https://github.com/microsoft/hve-core/tree/f425e943bf228052a23e6bc4810b5faef030314f/.github/skills/accessibility/accessibility
Documentation by Microsoft
Accessibility — Skill Entry
This skill is the canonical accessibility reference contract for HVE Core. Agents and instructions invoke this skill by name and rely on it to own framework reference resolution, phase guidance resolution, and the scanner CLI entrypoint.
Framework references
Assessment reference (cross-cutting, not a conformance framework):
Assistive-technology announcement model — read this when deciding the announcement-class criteria (WCAG 1.3.1, 4.1.2, 4.1.3): what a screen-reader user should hear, and how to decide it with an accessibility-tree assertion or a manual AT pass.
Accessibility Planner workflow
The Accessibility Planner runs six phases, each keyed to a state id:
Phase 1 — Discovery (
discovery)Phase 2 — Framework Selection (
framework-selection)Phase 3 — Standards Mapping (
standards-mapping)Phase 4 — Plan Risk Assessment (
plan-risk-assessment)Phase 5 — Impact and Evidence (
impact-evidence)Phase 6 — Backlog Handoff (
backlog-handoff)
Phase reference index
Phase 1 — Discovery: capture-coaching.md — read this when running exploration-first capture questioning.
Phase 2 — Framework Selection: framework-selection.md — read this when choosing which frameworks and conformance level apply.
Phase 3 — Standards Mapping: walk the framework references roll-up tables to emit
controlMappings; consumed by Phase 5. No dedicated file — mapping is driven by the framework roll-ups.Phase 4 — Plan Risk Assessment: capture-coaching.md governs the questioning posture when escalation triggers reopen scoping; tier criteria are applied per the Accessibility Planner identity instructions and recorded as
riskClassification.tier. No dedicated file — the accessibility risk surface is narrow enough to stay inline.Phase 5 — Impact and Evidence: impact-assessment.md — read this when building the evidence register, tradeoff log, and seed work-items.
Phase 6 — Backlog Handoff: backlog-handoff.md — read this when rendering work items and validating handoff gates.
Method adequacy (decide vs inform)
Method adequacy is the doctrine that a verification method may only be recorded as satisfying a success criterion when that method can actually decide the criterion. A method that can observe a related signal but cannot confirm the user-facing outcome only informs the criterion; it raises or lowers suspicion but never closes it. This section is the canonical definition; the planner evidence register, the reviewer verdict logic, and the runtime probe harness all resolve adequacy through it.
The machine-readable adequacy source is scripts/runtime_a11y/probe-criteria-map.json. Each probe entry lists the criteria it decides and the criteria it only informs. A result counts as adequate only when the winning method appears in the decides list for that criterion and state.
Failure classes and adequate methods
Accessibility defects generalize into five classes. Static analysis (axe, eslint-plugin-jsx-a11y, snapshot structure counts) can decide only the first class; the remaining four require an interaction-state probe or an assistive-technology (AT) pass to be decided rather than merely informed.
| Class | Representative WCAG SC | What static analysis can do | Adequate method to decide |
|---|---|---|---|
| Static-decidable structure | 1.1.1, 1.4.3, 4.1.2 (name present), 2.4.2, 3.1.1 | Decide | axe / static scan |
| Interaction behavior | 2.1.1, 2.1.2, 2.4.3, 2.4.7, 2.4.11 | Inform only | Keyboard/interaction probe driving keys across focus/open states, or manual keyboard pass |
| Announcement correctness | 1.3.1, 4.1.2 (computed name/role), 4.1.3 | Inform only | Accessibility-tree assertion of computed name/role/live, or manual AT pass (Windows NVDA or human-led JAWS) |
| Adaptive rendering | 1.4.4, 1.4.10, 1.4.12, 2.4.11 | Inform only | Rendered probe at 200% zoom, 320px reflow, and text-spacing states |
| Faux semantics | 1.3.1 (faux headings), 2.4.3 (faux controls) | Cannot see | Heuristic source pass plus accessibility-tree assertion; no element exists for a rule engine to flag |
For the announcement class, the assistive-technology announcement model specifies what the user should hear per criterion and how to decide it. For the interaction and faux-semantics classes, the focus-management anti-pattern catalog enumerates the defects that pass a static scan yet break keyboard and screen-reader users.
Adequacy rule
A control in the interaction, announcement, adaptive-rendering, or faux-semantics classes cannot be recorded as fully satisfied on static evidence alone. Static evidence caps such a control at a partial state until an adequate method is attached.
A criterion whose winning method only
informsit is never a conformance verdict; it is a lead that routes to an adequate method or a manual pass.Preserve the adequacy determination alongside the status so downstream planners and reviewers do not re-promote an inadequately verified control.
This doctrine and its class taxonomy are repository-original content licensed under CC BY 4.0; the underlying success-criterion definitions remain with WCAG 2.2 as cited in wcag-22.md.
Calibration is evidence quality, not a conformance verdict
Calibration establishes that the assistive-technology stack behaves as expected before its output is trusted. Its checkpoints record driver identity, profile fingerprint, and artifact hashes for a journey that passed.
A checkpoint is deliberately not a matrix input. Nothing in the coverage or outcome pipeline reads one, and that separation is intended rather than unfinished. A passing calibration says the harness was working; it does not say the surface satisfies a success criterion. Wiring checkpoints into coverage would turn a statement about the tool into a statement about the product.
If calibration evidence should ever influence coverage, that is new design work requiring its own review: it needs an explicit mapping from a journey to a criterion, surface, and state, and it must respect the same method-adequacy rules as any other evidence.
Gate strictness by assessment tier
The enforcement posture for the interaction, announcement, adaptive-rendering, and faux-semantics classes graduates with the assessment depth tier recorded in riskClassification.tier, so the gate inherits the rigor a project opted into rather than applying one global switch:
basic— the adequate-method probes (keyboard, widget-keyboard, live-region, aria-tree, virtual-sr) report advisory (warn-only); the always-decidable core probes still block.standard(default) — ratchet: the adequate-method probes block on new or changed surfaces and stay advisory over the existing backlog, so no new defect in these classes ships while legacy content is surfaced without freezing the project.comprehensive— the adequate-method probes block on every in-scope surface.
The always-decidable core probes (axe, DOM hygiene, broken links, console errors, target size, contrast, reflow/resize) block at every tier. The CI workflow template implements this dial through the A11Y_TIER and A11Y_RATCHET_SURFACES inputs; the Accessibility Reviewer applies the same graduation to its FAIL and PARTIAL verdicts.
Tooling
The scanner CLI (scripts/scan.py) wraps the Node-based axe-core scanner and normalizes its findings into a stable JSON shape.
Prerequisites
Python 3.11+ with uv available on PATH.
Node.js with
npxavailable on PATH.Network access on first run so
npxcan fetch@axe-core/cli.
Quick Start
uv run scripts/scan.py https://example.com --allow-host example.com
uv run scripts/scan.py ./page.html --output results.json
uv run scripts/scan.py file:///path/to/page.htmlLoopback HTTP(S) targets need no additional option. Every other remote host
requires either a matching, repeatable --allow-host HOST value or the broader
--allow-external confirmation. Local paths and local file: URIs must resolve
to existing regular files. Network shares, remote file authorities, directories,
missing files, credentials, leading-dash targets, and non-HTTP(S) remote schemes
are rejected before the axe CLI starts.
Parameters Reference
| Parameter | Required | Default | Description |
|---|---|---|---|
target | Yes | — | Authorized HTTP(S) URL or existing regular local file to scan. |
--output | No | stdout | Path to write the normalized JSON results. |
--allow-host | No | none | Authorize one non-loopback HTTP(S) host; repeat as needed. |
--allow-external | No | false | Confirm access to any non-loopback HTTP(S) host. |
Remote authorization applies to the initial scanner target only. It does not constrain browser redirects, DNS address changes, subresources, WebSockets, Service Workers, downloads, or other browser-derived requests. Run the scanner only from a workstation whose network reach matches the target's trust level.
Script Reference
Entrypoint: scripts/scan.py
Output shape:
{ "target": "<scanned target>", "summary": { "violations": 0, "passes": 0, "incomplete": 0, "inapplicable": 0 }, "violations": [ { "id": "", "impact": "", "description": "", "nodes": 0 } ] }Exit codes:
0— scan completed successfully.1— scan failed or returned invalid output.2— scanner unavailable (Node.js or@axe-core/climissing).
Troubleshooting
| Symptom | Likely cause | Action | Exit code |
|---|---|---|---|
scanner unavailable error | Node.js or npx not on PATH | Install Node.js so npx resolves, then re-run. | 2 |
| Long pause or download on first run | npx is fetching @axe-core/cli | Allow network access on the first run; later runs use the cache. | — |
Refusing to probe non-loopback host | Remote host was not explicitly authorized | Add --allow-host HOST or confirm with --allow-external. | 2 |
Local scan target does not exist | Local path or file URI cannot be resolved | Supply an existing regular local file, not a directory or share. | 2 |
scan failed or returned invalid output | axe-core CLI errored or emitted non-JSON | Confirm the target URL or file is reachable and well-formed. | 1 |
Empty violations but issues expected | Page rendered after the scan, or rules N/A | Confirm the target fully loads; check summary.inapplicable. | 0 |
Mapping findings to frameworks
Each violation's impact is one of minor, moderate, serious, or critical. axe rule tags decode to WCAG success criteria by stripping the wcag prefix and inserting decimals:
| axe tag | WCAG success criterion |
|---|---|
wcag111 | 1.1.1 Non-text Content |
wcag143 | 1.4.3 Contrast (Minimum) |
WCAG success criteria are normative; the axe techniques that surface them are informative. Treat scanner output as evidence pointing at a criterion, not a conformance verdict.
Runtime probe harness
The runtime probe harness (scripts/runtime_a11y) runs Playwright-based accessibility probes against a project-specific surface inventory and aggregates the results into a coverage matrix. For workflow orchestration, ask the user to run the manual-only accessibility-coverage-matrix skill (/accessibility-coverage-matrix); it is not model-invocable. Use the Accessibility Surface Inventory subagent as the canonical producer of the runtime config. Activate it by name; when it does not resolve, warn the user that the capability is unavailable and stop the dependent step.
Harness prerequisites
Complete these once before any runtime-harness command. They are separate from the scan.py prerequisites above.
Python 3.11+ with uv available on PATH.
Node.js available on PATH, plus system Google Chrome, because the probes target
channel: 'chrome'.Skill-local Node dependencies installed under scripts/runtime_a11y. The CLI fails fast with an install hint when they are missing.
Automated Windows NVDA runs additionally require the manifest-selected Guidepup NVDA asset. Machine setup and asset installation are separate actions from
npm ci.
Install the harness dependencies from the scripts/runtime_a11y directory:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm ci$env:PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = '1'; npm ciPLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 avoids downloading bundled browsers that the harness never uses.
For automated NVDA runs, prepare the Windows machine once, then install the asset selected by the skill-local Guidepup package. Run the asset command again after updating Guidepup:
Set-Location <skill-root>/scripts/runtime_a11y
npx --yes --registry=https://registry.npmjs.org/ @guidepup/[email protected] setup
npx --yes --registry=https://registry.npmjs.org/ @guidepup/[email protected] install nvdaThe commands configure the machine and write versioned assets to the Guidepup user cache. They are not part of ordinary dependency installation. Run the prerequisite-only probe before a calibration session:
uv run scripts/runtime_a11y/__main__.py run-calibration --config <path-to>/a11y-runtime.config.json --prerequisite-onlyThe preflight reports the skill-local library, manifest-selected NVDA asset, and any conflicting NVDA process independently. Do not start a personal NVDA instance before an automated run; the harness starts an isolated session and rejects an existing process.
Product-neutral screen-reader cases live in scripts/runtime_a11y/screen-reader-cases.json. A downstream binding supplies named routes, targets, states, and explicit execution recipes. Catalog digest drift, missing target closure, duplicate identities, unsupported commands, secret-bearing binding keys, and inferred actions fail before browser startup.
Use repeatable run-calibration --journey <id> arguments for an authorized live subset. Run the downstream integrity recipe before product cases and keep real NVDA advisory/manual. For deterministic evidence, use run-all --probe <probe-id> with surface/state filters or a reviewed probeScoping configuration; ordinary run-all must not be treated as permission to start a real screen reader.
Invocation
Run the harness through its script entrypoint. Invoke it from the skill root, which is the directory holding pyproject.toml, so uv resolves the skill's own environment. This matches the invocation convention used by scan.py and the other Python skills, and it needs no PYTHONPATH.
uv run scripts/runtime_a11y/__main__.py run-all --config a11y-runtime.config.json --out results.json
uv run scripts/runtime_a11y/__main__.py probe <probeId> --config a11y-runtime.config.json
uv run scripts/runtime_a11y/__main__.py render-artifacts --matrix coverage-matrix-repo.json --output-dir .copilot-tracking/accessibility/coverage --repo-slug repo
uv run scripts/runtime_a11y/__main__.py compose-evidence --helpTo run from any other working directory, pin the skill as the uv project and use the same script path:
uv run --project <skill-root> <skill-root>/scripts/runtime_a11y/__main__.py run-all --config a11y-runtime.config.json --out results.json--configresolves relative to the current working directory.--outwrites the aggregated JSON document to disk.--base-urloverrides the configured base URL. It must remain a loopback origin unless the host is allowlisted or--allow-externalis supplied.--tracecaptures Playwright traces and screenshots.--allow-externalconfirms intentional probing of a non-loopback host.render-artifactsturns a rendered matrix JSON document into the complete coverage evidence bundle.
Evidence bundle composition
compose-evidence combines downstream-owned catalogs, cadence scope, run context, normalized source envelopes, state proofs, and optional qualified-reviewer supplements into one deterministic evidence bundle. It is separate from render-artifacts: rendering creates coverage, EARL, and manual-plan views from a matrix, while composition creates a revision-bound trust envelope across evidence producers.
The command requires explicit input paths and never infers product scope, Git state, time, retention, branch policy, or a release verdict. A consuming project owns those decisions. The composer validates artifact bytes beneath --artifact-root, preserves conflicts and quarantined results, and always emits non-attestation metadata. Automation, reviewer evidence, and release evidence have separate completeness states.
For pull requests, a valid initial bundle may report reviewer evidence as pending. A qualified reviewer can later provide a privacy-minimized, digest-bound supplement and registry snapshot for deterministic recomposition against the prior bundle. Recomposition supplies both --prior-bundle and its independently retained --prior-bundle-digest; omission or mutation of prior history fails closed. Missing required reviewer evidence blocks release completeness, not ordinary bundle production. Raw screen-reader phrases and restricted transcript paths are forbidden in ordinary bundles; only approved counts, redacted metadata, and digests cross this boundary.
Use --require-completeness automated, reviewer, or release only when the downstream workflow intends that dimension to gate. Valid incomplete bundles are still written for diagnosis. The additional exits are:
| Exit code | Meaning |
|---|---|
5 | Automated evidence is incomplete. |
6 | Reviewer evidence is pending or invalid. |
7 | Release evidence is incomplete. |
Existing exits 0 through 4 retain their meanings. The JSON contracts live beside the runtime at evidence-bundle.schema.json, evidence-source.schema.json, evidence-scope.schema.json, screen-reader-method-cell.schema.json, and qualified-human-result.schema.json.
For a complete adopter path from an inactive template to a first retained bundle and deterministic recomposition, including schema-valid examples for every authored input, read references/evidence-composition-adoption.md.
Visual review capture
capture-visual-review records deterministic screenshot evidence for the configured surfaces and states. It requires visualReview.enabled to be true in the runtime config.
uv run scripts/runtime_a11y/__main__.py capture-visual-review \
--config <path-to>/a11y-runtime.config.json \
--run-root .copilot-tracking/accessibility/local-runs/<run-name>--run-rootselects the evidence directory. It resolves relative to the repository root and must land on a child path inside.copilot-tracking/accessibility/local-runs. Paths outside that root, and traversal segments, are rejected.Omitting
--run-rootallocates a timestamped run directory beneath that same root.--visual-surfaceand--visual-statenarrow the capture to specific configured ids.The server the command targets follows
serveMode. See Server modes.
Server modes
serveMode in the runtime config decides whether the harness manages a server for capture-visual-review.
serveMode | Behavior |
|---|---|
auto | Reuses a healthy server at the configured loopback origin, otherwise builds and starts one it owns and stops afterward. |
served | Requires a server already answering the configured loopback origin, and fails with the expected origin and start command when none responds. |
external | Never probes or starts a server. The configured target must already be reachable. |
off | Never probes or starts a server. |
auto and served accept only loopback origins, because the harness will not manage or health-probe a remote server. A non-loopback target still requires the allowlist or --allow-external, and is only valid with external or off.
Under auto, starting an owned server builds the site first, so a capture that has to start its own server takes several minutes before the first screenshot. Leave a server running at the configured origin to skip that cost, which is the reuse path.
The Docusaurus site in this repository is configured for auto at http://127.0.0.1:3001, which is the same production-build origin the Playwright end-to-end suite uses. Capturing against the production build keeps visual evidence consistent with what continuous integration verifies.
Config summary
The harness loads scripts/runtime_a11y/config-schema.json and expects a runtime config with fields such as baseUrl, serveMode, allowlist, routes, surfaces, and probeScoping. The config defines the surfaces and interaction states the probes execute. A runtime guard blocks non-loopback targets unless the host is allowlisted or the caller supplies --allow-external. serveMode controls server ownership for visual review capture, described under Server modes.
Real-NVDA journeys support three capture modes:
singlereads the cumulative speech log after commands and the configured settle interval.clear-and-captureclears earlier speech before the settle interval, then reads the cumulative log.actionwraps an existing post-start declarative trigger with Guidepup action capture. Assertions can selectactionSpeechoractionNormalizedSpeechto evaluate only output attributed to that trigger.
Action capture waits for Guidepup's one-second speech quiet window. It is appropriate for immediate interaction-driven announcements but does not extend to arbitrary delayed updates and cannot create speech that NVDA does not emit. Keep single, clear-and-capture, accessibility-tree evidence, and manual AT evidence available for those cases. Action mode fails closed when the journey lacks triggerAfterDriverStart, a declarative trigger, a real Guidepup driver, or action-capture support.
Probe inventory and adequacy map
The harness currently includes these probes under scripts/runtime_a11y/runner:
WCAG and ARIA APG probes:
probe-axeprobe-keyboard-traversalprobe-focus-visibleprobe-focus-obscuredprobe-live-regionprobe-aria-treeprobe-widget-keyboardprobe-reflow-resizeprobe-target-sizeprobe-contrastprobe-forced-colorsprobe-reduced-motionprobe-structure-crawlprobe-name-in-labelprobe-use-of-color(1.4.1)probe-text-spacing(1.4.12)probe-hover-focus(1.4.13)probe-link-purpose(2.4.4)probe-input-purpose(1.3.5)probe-forms(3.3.2, informs 3.3.1/3.3.3)probe-context-change(3.2.1, 3.2.2)probe-orientation(1.3.4)probe-audio-control(1.4.2)probe-timing(2.2.1)probe-zoom-blocker(1.4.4, informs 1.4.10)probe-virtual-sr(4.1.2 name/role announcement captured from a virtual screen reader's spoken-phrase log; informs 1.3.1)probe-real-sr(real Windows NVDA announcement assertions through a Guidepup adapter; only decides when configured expectations are present and the AT stack is available)
Non-WCAG defect-scan probes (framework defect-scan):
probe-console-errors(console/page errors)probe-broken-links(same-origin 404s)probe-dom-hygiene(duplicate ids, positive tabindex, missing/duplicate landmarks)probe-title-lang(empty title, invalidlang)
Method adequacy is encoded in scripts/runtime_a11y/probe-criteria-map.json. Each entry records which criteria a probe can decide and which criteria it can only inform. A result only counts as adequate when the winning method is allowed by that mapping.
Coverage engine outputs
The matrix engine in scripts/runtime_a11y/matrix expands the criterion x surface x state grid, merges updates deterministically, and preserves human-confirmed findings over lower-priority automation. It computes adequate-coverage percentages by framework and overall. The render-artifacts command emits a deterministic bundle containing coverage-matrix-{repo-slug}.json, coverage-matrix-{repo-slug}.md, accessibility-results-{repo-slug}.earl.jsonld, manual-at-testplan-{repo-slug}.md, manual-at-testplan-{repo-slug}.yaml, and accessibility-artifacts-{repo-slug}.json.
The EARL (Evaluation and Report Language) JSON-LD export is the normalized results contract for interoperability with the ACT Rules ecosystem and downstream VPAT or EAA review. Each evaluated cell becomes one stable earl:Assertion that records subject, criterion, state, method, method adequacy, result date, and evidence. A result whose winning method only informs its criterion is earl:cantTell, never a false earl:passed. Inapplicable cells are earl:inapplicable; unevaluated cells are omitted. The paired manual plans contain cells that still require a human-deciding method and provide blank result fields for evidence writeback.
Public ARIA-AT and execution contract
The catalog in scripts/runtime_a11y/aria-at-catalog.json is the repository's documented source of truth for generated AT-oriented cases. Its provenance fields are strict and immutable: each mapping records a local catalog version, a canonical upstream URL, a commit-pinned upstream URL, and the upstream commit SHA used for the reviewed refresh. The repository does not copy upstream assertion tables or prose; it paraphrases official W3C and ARIA-AT intent and cites the source in the generated artifacts.
The current public posture is intentionally conservative. The five starter defaults (modal dialog, checkbox, select-only combobox, menu button, and tabs) are citation-bearing manual-only mappings because the richer AT-mode and quick-navigation semantics that these patterns can require are not faithfully modeled by the current structured command boundary. Runtime overrides may create explicit synthetic contract tests, but those are always non-pass candidate evidence and never accessibility conformance evidence. The resolver uses the documented fallback order of state -> surface -> catalog; commands and assertions are stored as atomic arrays, and an explicit empty array intentionally disables execution for a given case.
Unknown patterns remain generic manual drafts or project-refinement markers rather than a fake automation pass. Equally specific ambiguity is treated as a configuration error before rendering or driver startup. The public CLI exposes render-artifacts as an optional mapping configuration step and run-at-plan as the supported path for listing, selecting, executing, and reporting generated AT cases. The real-driver boundary currently supports Guidepup-backed Windows NVDA automation plus manual-only JAWS and other operator-led flows; synthetic execution is a separate evidence channel and never claims a pass. The generated manual plans stay linked to the shared real screen reader testing runbook, while case-specific commands remain inside the generated plan output rather than being written back into the matrix or coverage artifacts.
The generated manual cases, synthetic or real execution evidence, ACT-style result reasoning, EARL outcomes, and later qualified-human review are distinct layers. The public workflow renders representative fixtures through the documented CLI and inspects the six generated artifacts, but it does not commit golden outputs for the inspection bundle.
Exit codes
0indicates the harness completed successfully, even when probes reported findings.Non-zero exit codes indicate a harness error such as invalid config, a failed probe, missing Node.js, uninstalled harness dependencies, missing browser support, or a blocked target.
verify-intent adds two design-intent codes that a consuming project's CI can distinguish:
| Exit code | Meaning | Typical response |
|---|---|---|
3 | A blocking expectation resolved failed | Treat as intent drift; the surface regressed |
4 | A blocking expectation was never evaluated | Treat as coverage drift; the check did not run |
The two are separate because a failed check and an unrun check call for different responses. Reusing one code would let missing coverage read as a regression, or pass silently.
Runtime dependencies
The harness resolves its Node dependencies from a skill-local package under scripts/runtime_a11y (package.json plus committed package-lock.json), pinning [email protected], @axe-core/[email protected], @guidepup/[email protected], and optional real-AT integration through @guidepup/[email protected]. Install the Node dependencies and the separately managed NVDA asset as described under Harness prerequisites. The probes then resolve their dependencies from the local node_modules; the CLI fails fast with an install hint when node_modules is absent, before it probes or starts any server.
Testing
The harness is tested in two tiers. Browserless verdict and pure-helper unit tests run under node --test (repo script test:node) and cover the decision logic in runner/_core.mjs (for example virtualSrNameRoleStatus and liveRegionStatus). Browser smoke tests under tests/runtime_a11y/runner/probe-smoke/ launch system Chrome and drive the real capture path against inline fixtures to prove the DOM-to-verdict pipeline, including nameless controls, live-region firing, forced-color computed styles, and CDP accessibility-node structure. They are named *.smoke.mjs so the default browserless run skips them. PR Validation runs them through the CI-owned npm run ci:test:a11y:smoke entry point. Local reproduction requires system Chrome and the skill-local node_modules.
CI regression gate
Use the ready-to-copy workflow template at references/ci/accessibility-coverage.workflow-template.yml as the documentation-first integration point for a target project. Copy it into the target repository's GitHub Actions workflow directory only after the target project commits an a11y-runtime.config.json and has a build/serve path that the template can invoke. Once authored *.intent.yaml records exist, the template fails closed if the config or current-run results are missing.
The template mirrors the Docusaurus workflow recipe by provisioning system Chrome, setting up Node 24 plus Python and uv, building the target, serving it under a configurable base URL, and running the harness script entrypoint with uv run --project pinned at the vendored skill root. The core high-confidence probes always block: probe-axe, probe-dom-hygiene, probe-broken-links, probe-console-errors, probe-target-size, probe-contrast, and probe-reflow-resize. The interaction-state and announcement probes (probe-keyboard-traversal, probe-widget-keyboard, probe-live-region, probe-aria-tree, probe-virtual-sr, probe-real-sr) are the adequate method for the classes static analysis only informs, and their blocking posture follows the A11Y_TIER dial defined under Gate strictness by assessment tier: basic reports them advisory, standard ratchets (blocking on the surfaces listed in A11Y_RATCHET_SURFACES), and comprehensive blocks them everywhere. The remaining heuristic probes such as use-of-color, hover-focus, link-purpose, name-in-label, and focus-* are surfaced as informational results so they can guide follow-up work without blocking initial adoption. The real-screen-reader probe stays advisory by default unless a project opts into it through configured expected assertions and a supported OS/AT stack; it returns candidate when the platform or AT is unavailable rather than pretending a pass or failure. Decisive coverage of the adaptive-rendering class depends on the target committing the zoom-200, reflow-320, and text-spacing states in its a11y-runtime.config.json.
The parity reference at references/ci/probe-spec-parity.md maps each runtime probe to the closest existing Docusaurus e2e spec and highlights gaps where no equivalent spec currently exists.
The references/ci/act-rule-format.md reference documents how the harness's probes, generated test cases, and EARL results align to the W3C ACT Rules Format (applicability, expectation, passed/failed/inapplicable) so results interoperate with the ACT Rules ecosystem and conformance reporting.
Design intent verification
A consuming project can declare what a surface must convey and have CI check that what shipped still matches. The declaration is a Design Intent Record, human-authored and committed at design-intent/<surface-id>.intent.yaml in that project. Each intent states what the surface must communicate, why, and for whom, and binds every claim to a named check.
The authored-record field contract is in references/design-intent/record-contract.md. Read it when authoring or reviewing a record. This section covers verification.
This skill supplies the step that turns a probe run into a verdict against that declaration.
Invocation
uv run --project <skill-root> <skill-root>/scripts/runtime_a11y/__main__.py verify-intent \
--record design-intent/<surface-id>.intent.yaml \
--results results.json--recordis the authored record. It is never read for anything but its declarations and never rewritten.--resultsis a results document fromrun-all.--outoverrides the output path, which defaults todesign-intent/.verification/<surface-id>.earl.jsonbeside the record.
How results resolve to outcomes
A result row matches an expectation when its surface, state, emitting probe, and criterion all match what the record declares. Because criterion coverage overlaps across probes, the emitting probe is part of the join.
| Situation | Outcome | Mode |
|---|---|---|
| Every matched criterion passed | passed | automatic |
| Any matched criterion failed | failed | automatic |
| Evidence gathered but not decisive | cantTell | automatic |
| No result row matched the expectation | untested | automatic |
The expectation uses assert: custom | untested | manual |
An expectation is one claim over one or more criteria, so the worst criterion outcome governs. Expectations the run did not cover report untested rather than being omitted, which keeps a missing check visible instead of silently absent.
Expectations whose criteria a probe only informs resolve to cantTell in normal operation. That is expected: the probe gathered evidence without settling the claim.
A custom expectation reports untested whether or not the record carries a human override. The adapter records only observed runtime outcome in the artifact. Human override remains authoritative in the record itself and is not merged into the generated artifact outcome.
Interpretation is two-layered by contract, and the generated artifact now carries both layers on every assertion:
observedOutcomeis the generated artifact fieldoutcome. An override never replaces it.effectiveOutcomeapplies fail-safe precedence. Either an observed or humanfailedoutcome yieldsfailed; humanpassedsettles onlyuntested,cantTell, orinapplicable; otherwise the observed outcome remains. This is the value the gate applies.overrideConflictistrueonly when the observed and authored override outcomes are eachpassedorfailedand differ. An override that settles anuntested,cantTell, orinapplicableexpectation is the documented use, not a conflict.
A conclusive conflict fails closed. verify-intent writes one Warning: line to stderr for each conflicting assertion, names the intent, expectation, observed outcome, and override outcome, and returns design-intent drift when the conflicting expectation blocks.
The shipped Python verifier rejects duplicate YAML keys, validates the complete authored schema, and enforces semantic checks for dates, filename and runtime-config bindings, duplicate identifiers, method pairing, and probe adequacy before writing an artifact. This repository's PowerShell validator independently enforces the same contract for source and generated-artifact validation.
Exit codes
0— the artifact was written and no blocking expectation failed.1— the record or results document was malformed. Nothing is written.2— the record or results document could not be read.3— the artifact was written and a blocking expectation failed.4— the artifact was written and a blocking expectation was never evaluated.
Exit codes 3 and 4 are enforcement signals. A consuming project's CI step fails its build on either non-zero exit, exactly as it would for any other command. The artifact is still written so the run can publish it. Which expectations block is the record's decision, through each expectation's blocking flag.
Graphics and diagram semantics have no runtime probe. Those expectations use assert: custom and resolve through human review; see the Graphics ARIA and SVG-AAM reference for the boundary between what automation can decide and what it cannot.
Rendering a record for review
A record states what must be true and how it is checked, but carries no implementation or delivery scope. Reviewers who want prose rather than YAML can render one:
uv run --project <skill-root> <skill-root>/scripts/runtime_a11y/__main__.py project-intent \
--record design-intent/<surface-id>.intent.yaml \
--out handoff.mdOutput is deterministic and renders only what the record already says, adding no analysis and no verification results. Generate it on demand rather than committing it, so it cannot drift from the record it describes. Without --out the Markdown goes to stdout.
Usage notes
Treat this skill as the default accessibility entrypoint for planning and review workflows.
Resolve framework and phase guidance through this skill instead of duplicating its internal reference paths in agents or instructions.
Use the scanner CLI when you need normalized findings from an accessibility scan.
Files
- ATTRIBUTION.mdAdded by AutoGineer836 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SECURITY.md40.9 KiB
- SKILL.md41.5 KiB
- pyproject.toml891 B
- references/ci/accessibility-coverage.workflow-template.yml23.3 KiB
- references/ci/act-rule-format.md5.4 KiB
- references/ci/probe-spec-parity.md15.3 KiB
- references/design-intent/record-contract.md9.6 KiB
- references/evidence-composition-adoption.md8.6 KiB
- references/examples/evidence/asset-journeys.json364 B
- references/examples/evidence/evidence-scope.json396 B
- references/examples/evidence/requirement-methods.json683 B
- references/examples/evidence/run-context.json994 B
- references/examples/evidence/state-proofs.json367 B
- references/frameworks/aria-apg.md88.7 KiB
- references/frameworks/at-announcement-model.md12.5 KiB
- references/frameworks/coga.md81.0 KiB
- references/frameworks/en-301-549.md153.9 KiB
- references/frameworks/graphics-aria-svg-aam.md6.9 KiB
- references/frameworks/section-508.md36.7 KiB
- references/frameworks/wcag-22.md66.2 KiB
- references/phases/backlog-handoff.md26.2 KiB
- references/phases/capture-coaching.md11.4 KiB
- references/phases/framework-selection.md8.3 KiB
- references/phases/impact-assessment.md18.8 KiB
- scripts/runtime_a11y/.npmrc923 B
- scripts/runtime_a11y/__init__.pyScript154 B
- scripts/runtime_a11y/__main__.pyScript89.3 KiB
- scripts/runtime_a11y/_config.pyScript8.1 KiB
- scripts/runtime_a11y/_errors.pyScript1.3 KiB
- scripts/runtime_a11y/_intent.pyScript33.0 KiB
- scripts/runtime_a11y/_projection.pyScript6.9 KiB
- scripts/runtime_a11y/aria-at-catalog.json20.7 KiB
- scripts/runtime_a11y/aria-at-catalog.schema.json5.7 KiB
- scripts/runtime_a11y/composition-summary.schema.json655 B
- scripts/runtime_a11y/config-schema.json12.1 KiB
- scripts/runtime_a11y/criteria-catalog.aria-apg.json1.6 KiB
- scripts/runtime_a11y/criteria-catalog.defect-scan.json2.0 KiB
- scripts/runtime_a11y/criteria-catalog.schema.json5.1 KiB
- scripts/runtime_a11y/criteria-catalog.wcag-22.json9.6 KiB
- scripts/runtime_a11y/design-intent.schema.json10.5 KiB
- scripts/runtime_a11y/evidence-bundle.schema.json11.2 KiB
- scripts/runtime_a11y/evidence-scope.schema.json2.2 KiB
- scripts/runtime_a11y/evidence-source.schema.json3.7 KiB
- scripts/runtime_a11y/evidence_bundle/__init__.pyScript494 B
- scripts/runtime_a11y/evidence_bundle/_adapters.pyScript15.1 KiB
- scripts/runtime_a11y/evidence_bundle/_canonical.pyScript1.3 KiB
- scripts/runtime_a11y/evidence_bundle/_compose.pyScript32.0 KiB
- scripts/runtime_a11y/evidence_bundle/_validate.pyScript5.8 KiB
- scripts/runtime_a11y/matrix/__init__.pyScript643 B
- scripts/runtime_a11y/matrix/_aria_at.pyScript10.7 KiB
- scripts/runtime_a11y/matrix/_artifacts.pyScript6.6 KiB
- scripts/runtime_a11y/matrix/_build.pyScript1.6 KiB
- scripts/runtime_a11y/matrix/_catalog.pyScript7.3 KiB
- scripts/runtime_a11y/matrix/_coverage.pyScript3.0 KiB
- scripts/runtime_a11y/matrix/_ingest_assessor.pyScript4.4 KiB
- scripts/runtime_a11y/matrix/_ingest_planner.pyScript5.6 KiB
- scripts/runtime_a11y/matrix/_ingest_probe.pyScript2.7 KiB
- scripts/runtime_a11y/matrix/_ingest_reports.pyScript3.5 KiB
- scripts/runtime_a11y/matrix/_merge.pyScript3.0 KiB
- scripts/runtime_a11y/matrix/_model.pyScript5.8 KiB
- scripts/runtime_a11y/matrix/_provenance.pyScript4.6 KiB
- scripts/runtime_a11y/matrix/_render_earl.pyScript7.3 KiB
- scripts/runtime_a11y/matrix/_render_json.pyScript2.1 KiB
- scripts/runtime_a11y/matrix/_render_md.pyScript4.5 KiB
- scripts/runtime_a11y/matrix/_render_test_plan.pyScript19.1 KiB
- scripts/runtime_a11y/methods.json1.8 KiB
- scripts/runtime_a11y/package-lock.json12.3 KiB
- scripts/runtime_a11y/package.json554 B
- scripts/runtime_a11y/probe-criteria-map.json11.9 KiB
- scripts/runtime_a11y/qualified-human-result.schema.json4.0 KiB
- scripts/runtime_a11y/runner/_core.mjsScript12.5 KiB
- scripts/runtime_a11y/runner/_shared.mjsScript42.4 KiB
- scripts/runtime_a11y/runner/assertions.mjsScript10.4 KiB
- scripts/runtime_a11y/runner/at-plan-executor.mjsScript40.0 KiB
- scripts/runtime_a11y/runner/calibration-checkpoint.mjsScript2.0 KiB
- scripts/runtime_a11y/runner/calibration-executor.mjsScript51.5 KiB
- scripts/runtime_a11y/runner/case-catalog.mjsScript13.0 KiB
- scripts/runtime_a11y/runner/drivers/command-contract.mjsScript4.2 KiB
- scripts/runtime_a11y/runner/drivers/driver-contract.mjsScript5.4 KiB
- scripts/runtime_a11y/runner/drivers/guidepup-adapter.mjsScript16.0 KiB
- scripts/runtime_a11y/runner/index.mjsScript894 B
- scripts/runtime_a11y/runner/methods.mjsScript1.0 KiB
- scripts/runtime_a11y/runner/probe-aria-tree.mjsScript2.1 KiB
- scripts/runtime_a11y/runner/probe-audio-control.mjsScript1.4 KiB
- scripts/runtime_a11y/runner/probe-axe.mjsScript2.7 KiB
- scripts/runtime_a11y/runner/probe-broken-links.mjsScript4.4 KiB
- scripts/runtime_a11y/runner/probe-console-errors.mjsScript1.7 KiB
- scripts/runtime_a11y/runner/probe-context-change.mjsScript2.5 KiB
- scripts/runtime_a11y/runner/probe-contrast.mjsScript1.8 KiB
- scripts/runtime_a11y/runner/probe-dom-hygiene.mjsScript3.4 KiB
- scripts/runtime_a11y/runner/probe-focus-obscured.mjs2.3 KiB
- scripts/runtime_a11y/runner/probe-focus-visible.mjs1.7 KiB
- scripts/runtime_a11y/runner/probe-forced-colors.mjs2.5 KiB
- scripts/runtime_a11y/runner/probe-forms.mjs2.2 KiB
- scripts/runtime_a11y/runner/probe-hover-focus.mjs2.2 KiB
- scripts/runtime_a11y/runner/probe-input-purpose.mjs2.1 KiB
- scripts/runtime_a11y/runner/probe-keyboard-traversal.mjs2.8 KiB
- scripts/runtime_a11y/runner/probe-link-purpose.mjs2.1 KiB
- scripts/runtime_a11y/runner/probe-live-region.mjs1.4 KiB
- scripts/runtime_a11y/runner/probe-name-in-label.mjs1.5 KiB
- scripts/runtime_a11y/runner/probe-orientation.mjs1.6 KiB
- scripts/runtime_a11y/runner/probe-real-sr.mjs2.0 KiB
- scripts/runtime_a11y/runner/probe-reduced-motion.mjs1.4 KiB
- scripts/runtime_a11y/runner/probe-reflow-resize.mjs1.1 KiB
- scripts/runtime_a11y/runner/probe-structure-crawl.mjs2.0 KiB
- scripts/runtime_a11y/runner/probe-target-size.mjs4.9 KiB
- scripts/runtime_a11y/runner/probe-text-spacing.mjs1.8 KiB
- scripts/runtime_a11y/runner/probe-timing.mjs1.2 KiB
- scripts/runtime_a11y/runner/probe-title-lang.mjs1.9 KiB
- scripts/runtime_a11y/runner/probe-use-of-color.mjs2.4 KiB
- scripts/runtime_a11y/runner/probe-virtual-sr.mjs1.2 KiB
- scripts/runtime_a11y/runner/probe-widget-keyboard.mjs2.1 KiB
- scripts/runtime_a11y/runner/probe-zoom-blocker.mjs1.6 KiB
- scripts/runtime_a11y/runner/route.mjs2.3 KiB
- scripts/runtime_a11y/runner/transcript.mjs2.1 KiB
- scripts/runtime_a11y/runner/validation.mjs1.8 KiB
- scripts/runtime_a11y/runner/visual-review-executor.mjs14.4 KiB
- scripts/runtime_a11y/schema-validation-report.schema.json826 B
- scripts/runtime_a11y/screen-reader-binding.schema.json3.5 KiB
- scripts/runtime_a11y/screen-reader-case.schema.json1.6 KiB
- scripts/runtime_a11y/screen-reader-cases.json6.8 KiB
- scripts/runtime_a11y/screen-reader-method-cell.schema.json2.2 KiB
- scripts/runtime_a11y/validation-manifest.schema.json3.8 KiB
- scripts/runtime_a11y/validation_manifest.py7.1 KiB
- scripts/runtime_a11y/visual-review-manifest.schema.json3.2 KiB
- scripts/runtime_a11y/visual_review.py20.5 KiB
- scripts/scan.py10.9 KiB
- scripts/scanner_npm/.npmrc344 B
- scripts/scanner_npm/package.json203 B
- tests/conftest.py1.4 KiB
- tests/corpus/0_empty(opens on GitHub)Not mirrored: opens on GitHub5 B
- tests/corpus/1_axe_violation91 B
- tests/corpus/2_selector_dense85 B
- tests/corpus/3_empty_fields77 B
- tests/corpus/4_json_like_payload87 B
- tests/fixtures/combobox.html329 B
- tests/fixtures/contrast.html194 B
- tests/fixtures/dialog.html264 B
- tests/fixtures/headings.html182 B
- tests/fuzz_harness.py4.7 KiB
- tests/runtime_a11y/fixtures/aria-at-driver-matrix.json3.7 KiB
- tests/runtime_a11y/fixtures/aria-at-modal-dialog-matrix.json516 B
- tests/runtime_a11y/fixtures/assessor_findings.md330 B
- tests/runtime_a11y/fixtures/planner_state.json464 B
- tests/runtime_a11y/fixtures/probe_results.json329 B
- tests/runtime_a11y/fixtures/report_findings.md443 B
- tests/runtime_a11y/runner/_core.test.mjs10.8 KiB
- tests/runtime_a11y/runner/_shared.test.mjs13.3 KiB
- tests/runtime_a11y/runner/assertions-structured.test.mjs3.5 KiB
- tests/runtime_a11y/runner/at-plan-executor.test.mjs74.3 KiB
- tests/runtime_a11y/runner/calibration-checkpoint.test.mjs3.2 KiB
- tests/runtime_a11y/runner/calibration-executor.test.mjs58.0 KiB
- tests/runtime_a11y/runner/calibration-fixtures.mjs1.5 KiB
- tests/runtime_a11y/runner/case-catalog.test.mjs14.0 KiB
- tests/runtime_a11y/runner/cleanup-ownership.test.mjs2.4 KiB
- tests/runtime_a11y/runner/command-contract.test.mjs4.1 KiB
- tests/runtime_a11y/runner/methods.test.mjs2.2 KiB
- tests/runtime_a11y/runner/probe-broken-links.test.mjs4.7 KiB
- tests/runtime_a11y/runner/probe-smoke/live-region.cases.mjs1.5 KiB
- tests/runtime_a11y/runner/probe-smoke/probe-aria-tree.smoke.mjs2.1 KiB
- tests/runtime_a11y/runner/probe-smoke/probe-forced-colors.smoke.mjs2.6 KiB
- tests/runtime_a11y/runner/probe-smoke/probe-live-region.smoke.mjs1.9 KiB
- tests/runtime_a11y/runner/probe-smoke/probe-virtual-sr.smoke.mjs1.6 KiB
- tests/runtime_a11y/runner/probe-smoke/virtual-sr.cases.mjs998 B
- tests/runtime_a11y/runner/probe-smoke/visual-review.smoke.mjs2.8 KiB
- tests/runtime_a11y/runner/probe-verdicts.test.mjs4.5 KiB
- tests/runtime_a11y/runner/real-sr.test.mjs30.3 KiB
- tests/runtime_a11y/runner/route.test.mjs2.3 KiB
- tests/runtime_a11y/runner/visual-review-executor.test.mjs7.9 KiB
- tests/runtime_a11y/test_aria_at.py20.4 KiB
- tests/runtime_a11y/test_aria_at_dogfood.py4.6 KiB
- tests/runtime_a11y/test_artifacts.py17.5 KiB
- tests/runtime_a11y/test_branch_completion.py5.7 KiB
- tests/runtime_a11y/test_build_coverage.py2.6 KiB
- tests/runtime_a11y/test_catalog.py3.7 KiB
- tests/runtime_a11y/test_cli.py95.0 KiB
- tests/runtime_a11y/test_cli_branches.py26.8 KiB
- tests/runtime_a11y/test_config.py11.3 KiB
- tests/runtime_a11y/test_config_guard.py3.4 KiB
- tests/runtime_a11y/test_coverage.py1.3 KiB
- tests/runtime_a11y/test_evidence_bundle.py43.0 KiB
- tests/runtime_a11y/test_ingest.py1.7 KiB
- tests/runtime_a11y/test_ingest_branches.py5.0 KiB
- tests/runtime_a11y/test_ingest_reports.py2.6 KiB
- tests/runtime_a11y/test_intent.py51.6 KiB
- tests/runtime_a11y/test_live_lifecycle.py8.9 KiB
- tests/runtime_a11y/test_merge.py2.1 KiB
- tests/runtime_a11y/test_merge_branches.py3.0 KiB
- tests/runtime_a11y/test_projection.py12.3 KiB
- tests/runtime_a11y/test_provenance.py4.8 KiB
- tests/runtime_a11y/test_render.py4.0 KiB
- tests/runtime_a11y/test_render_earl.py5.5 KiB
- tests/runtime_a11y/test_sample_bundle.py7.7 KiB
- tests/runtime_a11y/test_validation_manifest.py9.1 KiB
- tests/runtime_a11y/test_visual_review.py21.0 KiB
- tests/test_scan.py10.2 KiB
- tests/test_scan_branches.py4.6 KiB
- uv.lock114.8 KiB
SECURITY.md
title: Accessibility Skill Security Model description: STRIDE threat model for the accessibility skill scanners, runtime browser harness, generated evidence, and design-intent verification boundary author: microsoft/hve-core ms.date: 2026-10-07 ms.topic: reference estimated_reading_time: 18 keywords:
security
STRIDE
accessibility
SSRF
browser automation
threat model
<!-- markdownlint-disable-file -->
Accessibility Skill Security Model
This model covers the Path A axe CLI wrapper (scripts/scan.py), the Path B Playwright and Guidepup/NVDA runtime (scripts/runtime_a11y/ and its Node runner), generated evidence, and offline design-intent verification. The trust buckets are Path A targets (B1), Path A toolchain supply chain (B2), target-derived output (B3), caller and filesystem authority (B4), design-intent verification (B5), Path B configuration and navigation (B6), Playwright, endpoint-managed Chrome, and NVDA desktop control (B7), and Path B evidence and child environment (B8). Each bucket enumerates all six STRIDE categories with the implemented mitigations and residual risks.
See also: repo-wide STRIDE model. This skill participates in the repository-wide threat model at
docs/security/security-model.mdand is registered in its Skill Security Models section.
Executive Summary
The accessibility skill has two browser-backed scanning paths. Path A accepts explicitly authorized HTTP(S) targets or operator-selected local files and invokes the version-pinned axe CLI without a shell. Path B validates project configuration, authorizes its HTTP(S) base target, runs same-origin probes through Playwright's system Chrome channel, and writes bounded evidence beneath controlled run roots.
The skill controls initial destinations, configured routes and triggers, one direct-request redirect chain, machine identifiers, launch arguments, and evidence paths. It does not claim complete Chromium egress control or DNS-rebinding resistance. Endpoint application control owns system Chrome identity and patch posture, while browser-derived requests, inherited child environments, upstream parsers, and Path A remote redirects remain explicit residual risks.
Security Posture Overview
| Dimension | Value |
|---|---|
| Runtime surface | Python CLI and configuration guard; Node/Playwright runners; system Chrome; axe CLI; local evidence writers; offline design-intent adapter |
| Trust buckets | B1 Path A targets, B2 Path A supply chain, B3 output, B4 caller/filesystem, B5 design intent, B6 Path B navigation, B7 browser, B8 evidence/environment |
| Credentials | No first-party credential store; child processes inherit the caller environment (G-INF-3) |
| Network egress | Authorized Path A HTTP(S), npm on Path A cache miss, Path B HTTP(S) browser/direct requests, and target-derived browser requests |
| Open residual gaps | 8; highest per-skill residuals are Medium |
Contents
System Description
Trust Boundaries
Assets
Adversaries
Bucket B1: Path A remote and local targets
Bucket B2: Path A scanner toolchain supply chain
Bucket B3: Target-derived output
Bucket B4: Caller process and filesystem authority
Bucket B5: Design-intent verification
Bucket B6: Path B configuration and navigation
Bucket B7: Playwright, endpoint-managed Chrome, and NVDA
Bucket B8: Path B evidence and child environment
Enterprise Readiness Gaps
References
System Description
Components
scripts/scan.pyclassifies a Path A target, authorizes non-loopback HTTP(S), invokes the pinned axe CLI from the isolatedscripts/scanner_npmproject, normalizes JSON, and writes output.scripts/runtime_a11y/_config.pyloads Path B JSON configuration, enforces schema and URL semantics, and authorizes the base host.scripts/runtime_a11y/__main__.pyselects surfaces and probes, then starts Node/npm/PowerShell children with the caller environment.scripts/runtime_a11y/runner/*.mjsvalidates navigation and identifiers, launches Playwright, drives probes, and emits evidence.Playwright 1.61.1 and
@axe-core/playwright4.12.1 are installed from the skill-local lockfile.Endpoint-managed system Chrome is selected by Playwright
channel: 'chrome'with fixed launch arguments and an ephemeral automation profile.Guidepup 0.34.0 starts the manifest-selected NVDA asset, applies isolated settings, synthesizes allowlisted input, binds the foreground Chrome window, captures bounded speech, and verifies cleanup.
_intent.pyand_projection.pyperform offline design-intent verification and rendering.runtime_a11y/evidence_bundle/validates downstream catalogs and evidence, verifies artifact integrity, reconciles privacy-minimized reviewer supplements, and atomically composes non-attestation bundles.
Data Flow
accTitle: Accessibility scanner and runtime data flow
accDescr: Operator input passes through Path A or Path B validation to browser-backed scanners and bounded local evidence.
flowchart TD
subgraph HOST["Operator Workstation / Runner"]
ACLI["Path A scan.py"]
PCFG["Path B Python config guard"]
NODE["Path B Node runner"]
PW["Playwright 1.61.1"]
CHROME["Endpoint-managed system Chrome"]
NVDA["Guidepup-managed NVDA"]
OUT["Normalized reports, traces, screenshots"]
INTENT["Design-intent verifier"]
end
subgraph LOCAL["Operator-selected local filesystem"]
FILE["Existing regular local file"]
RECORD["Authored intent and local results"]
end
subgraph NPM["npm registry boundary"]
AXE["@axe-core/[email protected]"]
end
subgraph TARGET["Untrusted HTTP(S) target"]
WEB["Authorized initial origin and target content"]
end
ACLI -->|"classify + authorize"| FILE
ACLI -->|"argv, no shell"| AXE
AXE -->|"HTTP(S) fetch and render"| WEB
AXE -->|"JSON stdout"| ACLI
ACLI -->|"normalized JSON write"| OUT
PCFG -->|"validated config + inherited environment"| NODE
NODE -->|"Playwright API"| PW
PW -->|"channel: chrome"| CHROME
NODE -->|"bounded commands + lifecycle"| NVDA
NVDA -->|"OS-level input and speech capture"| CHROME
CHROME -->|"HTTP(S) navigation and browser requests"| WEB
NODE -->|"bounded direct request"| WEB
NODE -->|"reports, traces, screenshots"| OUT
RECORD -->|"YAML/JSON read"| INTENT
INTENT -->|"digest-bound verification output"| OUTTrust Boundaries
Boundary Diagram
┌───────────────────────────────────────────────────────────────────┐
│ TRUST BOUNDARY: Operator Workstation / Runner │
│ Path A CLI ── axe CLI Path B Python ── Node ── Playwright │
│ │ │ │ │
│ └────────────── evidence writers ────────────────┘ │
│ │ system Chrome │
└──────────┬────────────────────┼──────────────────────────┬─────────┘
│ npm │ local file/evidence │ HTTP(S)
┌───────▼────────┐ ┌───────▼────────────────┐ ┌─────▼──────────┐
│ npm registry │ │ Operator filesystem │ │ Untrusted web │
│ package input │ │ selected files/output │ │ target/content │
└────────────────┘ └────────────────────────┘ └────────────────┘Boundary Descriptions
| Boundary | Assets Protected | Controls Enforced |
|---|---|---|
| Path A CLI target to classifier | Host network position, local filesystem, argument semantics | Reject leading dash, credentials, unsupported/ambiguous schemes, network shares, remote file authorities, missing files, and directories; classify before npx |
| Path A remote HTTP(S) target | Internal services reachable from the workstation | Loopback permitted by default; other hosts require --allow-host or --allow-external; residual redirect, DNS, subresource, and browser egress remains G-INF-1 |
| Path A local filesystem | Operator-selected local content | Accept an explicit existing regular local path or local file: URI; reject network-shaped resolved paths before any filesystem probe; reject non-local authority; access runs as the operator and is not repository-confined |
| npm registry | Path A scanner integrity | Exact package version; canonical registry pinned on the argv; scanner-local npm project prevents adopting-repository config inheritance; no lockfile integrity for npx resolution (G-SUP-1) |
| Path B config and CLI to Python guard | Browser destination and host network position | JSON Schema; absolute credential-free HTTP(S); host authorization; external authorization never overrides scheme validation |
| Path B config/environment to JavaScript navigation | Navigation and artifact identity | Reassert and reauthorize the effective HTTP(S) base URL after CLI overrides; route paths and trigger destinations remain same-origin; portable path-bearing identifiers are rejected before writes |
| Python to Node/npm/PowerShell child | Caller environment and execution context | Argument-list spawning; full inherited environment is explicit residual G-INF-3 |
| Playwright and Guidepup to system Chrome and NVDA | Browser/AT identity, foreground input target, desktop state | Fixed Chrome channel; manifest-selected NVDA asset; exact journey selection; allowlisted commands; foreground-window binding; partial-start ownership; bounded teardown; endpoint owns binary identity and patching (G-SUP-2, G-EOP-1) |
| Browser and direct requests to web content | Host network position and target-derived data | Broken-link direct requests retry GET after unsupported HEAD responses and use at most five validated same-origin redirect hops; no complete browser redirect, DNS, worker, socket, download, or process-egress control |
| Browser/runner to evidence | Artifact integrity and confidentiality | Portable identifiers, run-root containment, bounded normalized shape, hashes where supported, and target-derived content treated as untrusted |
| Design-intent record to verifier | Human decision integrity | Safe YAML loading, schema/semantic validation, digest binding, contained atomic writes, and no generator-authored override |
Assets
| Id | Asset | Lifetime | Notes |
|---|---|---|---|
| A1 | Authorized remote target | Invocation | Initial HTTP(S) target and same-origin configured navigation |
| A2 | Operator-selected local file | Invocation | Explicit existing regular file; readable with operator permissions; not repository-confined |
| A3 | Path A and Path B toolchains | Installation/invocation | axe CLI, skill-local Node dependencies, Python environment, and system Chrome |
| A4 | Runtime configuration and environment | Invocation | Project config, CLI values, and inherited child environment |
| A5 | Browser and AT execution context | Invocation | Ephemeral Playwright context/profile, endpoint-managed Chrome, Guidepup-managed NVDA, and foreground window binding |
| A6 | Reports and runtime evidence | Run lifetime | JSON, traces, screenshots, measurements, transcripts, and hashes |
| A7 | Design-intent record | Repository lifetime | Human-authored committed source that the skill reads but does not rewrite |
| A8 | Verification artifact | CI/run lifetime | Digest-bound result generated beside the authored record |
Adversaries
| Id | Adversary | In-scope mitigations |
|---|---|---|
| ADV-a | Caller supplying a hostile target, route, trigger, identifier, or output path | URL and host authorization, same-origin navigation, portable identifiers, containment, and argument-list execution |
| ADV-b | Hostile target or page content | Browser isolation properties, bounded direct redirects, defensive normalization, target-derived content treated as untrusted |
| ADV-c | Compromised scanner, dependency, or browser | Version/lock pins, endpoint application control, fixed Chrome channel, and explicit residual gaps |
| ADV-d | Repository contributor tampering with config, intent, or evidence paths | Schema/semantic validation, no-follow containment where implemented, atomic writes, and digest binding |
| ADV-e | Less-trusted process observing inherited environment or generated evidence | No first-party secret handling; explicit environment and evidence residuals; operators control deployment trust |
Bucket B1: Path A remote and local targets
Spoofing
The classifier parses HTTP(S) authority before host authorization and rejects credentials. The skill does not authenticate target identity beyond URL and endpoint transport behavior.
Tampering
Target text is classified before subprocess execution. Local targets become canonical file URIs; remote targets retain their authorized HTTP(S) form.
Target content remains untrusted browser input and can influence accessibility results.
Repudiation
The normalized result records the resolved target. The skill does not provide durable network-request non-repudiation.
Information Disclosure
Loopback HTTP(S) is allowed by default. Non-loopback hosts require a repeated host allowlist value or explicit external confirmation.
Initial authorization does not bind later DNS answers or constrain every redirect and browser-derived request (G-INF-1).
Local-file access is intentional operator authority. Existing regular files are not limited to the repository, and the skill avoids claiming confinement that it does not enforce.
Denial of Service
Hostile pages and large local files can consume browser CPU or memory. Invocation remains operator-scoped and upstream browser limits apply.
Elevation of Privilege
Network shares, non-local file authorities, leading-dash targets, and shell interpretation are rejected. Network-shaped targets are rejected before any filesystem probe: the raw target is checked with separators normalized, so mixed forms such as
/\server\shareand Windows NT-namespace paths such as\??\UNC\server\shareare caught, and the parsed, home-expanded path is checked as well. Network-shaped paths are also rejected at the filesystem boundary on the resolved path, so afile:URI cannot decode into a UNC path and elicit an outbound request before the scan starts. Reads still occur with the invoking user's filesystem permissions.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Remote target reaches unintended internal service after authorization or redirect | Med | High | Med | Partially Mitigated (G-INF-1) |
| Operator selects a sensitive local regular file | Low | High | Low | Accepted operator capability |
| Hostile target exhausts local browser resources | Low | Med | Low | Partially Mitigated |
Bucket B2: Path A scanner toolchain supply chain
Spoofing
The axe CLI package name, version, and canonical public registry are fixed. A scanner-local npm project prevents npm from inheriting project configuration from an adopting repository. Registry compromise or substitution of that exact release remains G-SUP-1.
Tampering
npx --yes --registry=https://registry.npmjs.org/ @axe-core/[email protected] --stdout -- <target>runs from the scanner-local npm project and uses an argument list and parser boundary without a shell.npx may resolve the pinned package at runtime without a committed integrity lock for this path.
Repudiation
npm/npx logs are external to the skill; no package-resolution audit record is generated by Path A.
Information Disclosure
The subprocess receives the resolved target and inherited environment. The wrapper adds no credential material.
Denial of Service
Missing Node/npx or scanner failure produces a typed nonzero result rather than silent degradation.
Elevation of Privilege
Shell injection through the target is mitigated by argument-list invocation and leading-dash rejection. Browser parser exploitation remains G-TAM-1.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Substituted pinned scanner package | Low | High | Med | Partially Mitigated (G-SUP-1) |
| Target argument command injection | Low | High | Low | Mitigated |
| Axe browser parser exploitation | Low | High | Med | Accepted upstream (G-TAM-1) |
Bucket B3: Target-derived output
Spoofing
Output does not establish an identity. Target-reported text and metadata are data, not authority.
Tampering
Path A requires valid JSON holding a single result object, unwrapping the one-element array that
--stdoutprints, and emits a fixed normalized shape: each violation'sid,impact, anddescriptionare strings capped at 1,024 characters, non-string values become empty strings, andnodesis counted only when it is a list. Path B validates and contains generated artifacts according to each evidence writer's contract.
Repudiation
Run metadata, artifact hashes where present, target identifiers, and intent digests support traceability. The skill does not claim cryptographic non-repudiation.
Information Disclosure
Target-controlled rule descriptions, URLs, DOM snapshots, screenshots, traces, announcements, and metadata can enter evidence (G-INF-2).
Traces and screenshots can preserve page content. Operators must avoid targets containing personal or secret data unless the owning workflow permits that evidence.
Denial of Service
Normalized Path A results bound propagated structure. Path B limits specific collections and artifact sizes where configured, but browser-generated evidence can still be large.
Elevation of Privilege
Evidence is never interpreted as instructions by the runtime. Downstream agents and users must retain the untrusted-content boundary.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Target-derived content leaks through evidence | Med | Med | Med | Partially Mitigated (G-INF-2) |
| Malformed scanner output changes control flow | Med | Low | Low | Mitigated |
| Oversized browser evidence consumes disk | Low | Med | Low | Partially Mitigated |
Bucket B4: Caller process and filesystem authority
Spoofing
The CLIs run as the invoking OS user and do not assert a separate identity.
Tampering
Argument parsers, typed configuration, path containment, regular-file checks, and portable identifiers constrain caller-selected values at their owning boundaries.
Repudiation
Deterministic exit codes and run metadata identify success, usage failure, and runtime failure, but caller identity is not independently attested.
Information Disclosure
The caller can direct output to paths writable by that user. The skill does not elevate permissions or protect data from the invoking user.
Denial of Service
The caller controls invocation frequency and target selection. The skill runs no shared network listener.
Elevation of Privilege
Output and local-file operations execute with caller privileges. Existing no-follow and containment controls protect runtime-owned paths; arbitrary caller-owned output remains operator authority.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Operator overwrites an unintended writable output | Low | Med | Low | Accepted operator authority |
| Repository path redirection targets runtime evidence | Low | High | Low | Mitigated where runtime owns the path |
Bucket B5: Design-intent verification
Spoofing
The adapter evaluates local authored input against local results and does not assert external identity.
Tampering
Duplicate-key rejection, safe YAML loading, authored schema and semantic validation, boolean-only blocking, identifier validation, and deterministic digest binding protect the verification contract.
The verifier reads human override outcome only to derive effective gate behavior; it does not rewrite the observed outcome or authored record.
Repudiation
Verification output records intent and expectation identities plus a digest of the authored revision. Human override metadata remains in the authored record.
Information Disclosure
Verification artifacts echo authored identifiers and selected rationale-adjacent metadata but are not designed to carry credentials.
Denial of Service
Malformed structures fail with typed errors before partial verification output is accepted.
Elevation of Privilege
Directory handles, no-follow checks, regular-file enforcement, exclusive temporary files, and handle-relative atomic rename mitigate repository-controlled output redirection on supported platforms.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Consuming project skips equivalent authoring validation | Med | Med | Med | Accepted repository boundary |
| Symlink redirects verification output | Low | High | Low | Mitigated |
| Malformed record creates ambiguous outcome | Low | Med | Low | Mitigated |
Bucket B6: Path B configuration and navigation
Spoofing
The Python guard requires an absolute credential-free HTTP(S) base URL with a host, then permits loopback, a configured host allowlist, or explicit external authorization. A CLI base-URL override re-enters this guard before
run-allorprobecan start browser work.The JavaScript runner reasserts the HTTP(S) invariant before browser launch.
Tampering
JSON Schema and Python semantic validation reject invalid configuration before child execution. Configured route paths remain relative to the base origin.
Navigate and visit triggers resolve relative or absolute HTTP(S) against the authorized origin and reject origin changes before permissive action handling.
Repudiation
Selected probe, surface, state, target, and result metadata provide run attribution. No remote server identity attestation is claimed.
Information Disclosure
External authorization controls the configured initial host, not every browser-derived request. Route and trigger same-origin checks reduce explicit navigation authority but do not create a network firewall.
Denial of Service
Invalid targets and identifiers fail before browser work. Authorized pages can still stall or consume resources within probe-specific timeouts and browser behavior.
Elevation of Privilege
Protocol-relative, unsupported-scheme, credential-bearing, malformed, and off-origin configured navigation is rejected. Explicit external authorization never overrides scheme or trigger-origin policy.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Configured navigation escapes the authorized origin | Low | High | Low | Mitigated |
| Authorized target causes browser resource exhaustion | Low | Med | Low | Partially Mitigated |
| External authorization is mistaken for browser-wide egress control | Med | Med | Med | Documented residual |
Bucket B7: Playwright, endpoint-managed Chrome, and NVDA
Spoofing
Playwright selects
channel: 'chrome'; launch-bound preflight records the browser-reported version. Guidepup selects the manifest-owned NVDA asset and records its version and effective settings. Binary signature, installation provenance, and patch posture are owned by endpoint controls (G-SUP-2).The one-time Guidepup setup package name, version, and canonical public registry are fixed. Both setup commands run from the isolated
scripts/runtime_a11ynpm project so an adopting repository cannot select their registry.
Tampering
Playwright, axe, and Guidepup dependencies are locked in the skill-local package lock. Chrome receives fixed hardening arguments; NVDA receives isolated settings and allowlisted commands; generic caller arguments are not accepted.
Target content reaches independent Playwright/system-Chrome parser and rendering surfaces (G-TAM-2).
Repudiation
Readiness records Chrome, Guidepup, NVDA asset, profile, and foreground-window evidence. It does not attest binary hashes or signatures.
Information Disclosure
Browser requests originate from the workstation network position. NVDA speech can contain target-derived text and remains restricted evidence. No complete interception policy constrains redirects, subresources, Service Workers, WebSockets, downloads, DNS changes, peer IPs, or browser-internal connections.
The broken-link direct-request helper is narrower: it disables automatic redirects, retries with GET when HEAD returns 405 or 501, and follows at most five validated same-origin HTTP(S) hops.
Denial of Service
Browser or NVDA launch, foreground binding, and cleanup failures fail readiness. Partial NVDA starts retain cleanup ownership, failed-start retries require proven cleanup, and browser teardown is bounded. Hostile content or endpoint instability can still exhaust, crash, or stall an authorized run.
Elevation of Privilege
Playwright creates an ephemeral automation profile and does not receive a caller-controlled user-data directory or generic launch arguments. NVDA commands synthesize OS-level input only after foreground binding, but focus can still change between verification and dispatch (G-EOP-1). Browser sandbox and endpoint policy remain external controls.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Substituted or stale system Chrome | Low | High | Med | Endpoint-owned (G-SUP-2) |
| Browser/parser exploitation by target content | Low | High | Med | Partially Mitigated (G-TAM-2) |
| Browser-derived request reaches unintended destination | Med | High | Med | Accepted workstation residual |
| Synthesized NVDA input reaches the wrong foreground app | Low | High | Med | Partially Mitigated (G-EOP-1) |
Bucket B8: Path B evidence and child environment
Spoofing
Probe, route, surface, state, journey, and visual-review machine identifiers use one portable grammar and are validated before path construction. The grammar rejects trailing-dot aliases and Windows reserved device names, including device names followed by an extension.
Configuration-supplied aliases do not override a schema-validated identifier. The calibration journey identifier is taken from the validated
idand re-asserted before any path is composed.Reviewer and approver claims complete evidence only when stable pseudonymous identifiers and record digests match a current downstream-produced registry snapshot for the declared method scope.
Tampering
Runtime-owned evidence uses contained roots, regular-file checks, atomic patterns, and hashes where supported. Invalid identifiers are rejected rather than normalized into collisions.
Calibration evidence paths are asserted to remain beneath the resolved run root before any directory is created, so a configured identifier cannot steer a write outside that root.
Visual-review artifact paths carry route, surface, and state as separate validated segments, so distinct routes sharing a surface and state cannot overwrite each other's evidence.
Evidence composition validates closed schemas, domain-separated digests, artifact bytes, expected/deferred obligation partitions, and prior-bundle continuity before atomic finalization.
Repudiation
Evidence records probe, surface, state, timestamps, browser metadata, source and bundle hashes, and reviewer-history continuity where available. It is traceability evidence, not a non-repudiation guarantee.
Information Disclosure
Python-spawned Node/npm/PowerShell children inherit the complete caller environment (G-INF-3). The skill does not claim secret filtering.
Traces, screenshots, transcripts, and measurements can include target content as described in B3.
Ordinary composed bundles reject raw speech, transcript paths, credential-shaped values, and unrestricted reviewer identity. A downstream registry producer remains responsible for minimizing its snapshot before invocation.
Denial of Service
Artifact limits and bounded collections constrain selected outputs. Child tools and browser evidence can still consume local process, disk, and memory resources.
Large caller catalogs and evidence histories can consume memory during pure composition; downstream workflows own input size and retention policy.
Elevation of Privilege
Child commands use argument lists and fixed runner modules. Environment inheritance can alter tool behavior, but no untrusted caller-to-command-string boundary is introduced.
Risk Rating
| Threat | Likelihood | Impact | Residual Risk | Status |
|---|---|---|---|---|
| Ambient secret exposed to a child process | Low | High | Med | Accepted residual (G-INF-3) |
| Identifier collision or path traversal corrupts evidence | Low | High | Low | Mitigated |
| Target content leaks through trace or screenshot | Med | Med | Med | Partially Mitigated (G-INF-2) |
Enterprise Readiness Gaps
The following limitations let operators choose an appropriate execution environment. Severity values are project assessments, not CVSS scores.
| Id | Gap | Severity | Status |
|---|---|---|---|
| G-SUP-1 | Path A pins @axe-core/[email protected], but npx resolves it without a committed integrity lock for that invocation. (audit: A-SUP-1) | SupplyChain-Low | Review upgrades and prefer pre-provisioned trusted caches where stronger integrity is required |
| G-INF-1 | Path A authorizes the initial remote HTTP(S) host, but browser redirects, DNS rebinding/address changes, subresources, Service Workers, WebSockets, downloads, and browser-internal requests can still use the workstation network position. (audit: A-SSRF-1) | InfoDisc-Med | Run only against intended targets from a network position with matching trust; use network-level egress policy for stronger isolation |
| G-TAM-1 | Path A renders targets in the browser engine bundled by the axe CLI toolchain. (audit: A-BRWS-1) | Tampering-Med | Keep the toolchain patched and isolate hostile targets |
| G-INF-2 | Reports, traces, screenshots, transcripts, and metadata from both paths can reproduce target-controlled content. (audit: A-INF-1) | InfoDisc-Med | Treat evidence as untrusted and avoid secret or personal-data targets unless the workflow permits retention |
| G-SUP-2 | Path B selects endpoint-managed system Chrome but does not authenticate its binary, signature, installation source, or patch posture | SupplyChain-Med | Endpoint application control and patch management own Chrome trust |
| G-TAM-2 | Playwright and system Chrome expose an independent parser, rendering, and automation surface to target content | Tampering-Med | Keep locked dependencies and Chrome patched; use controlled workstations for untrusted content |
| G-INF-3 | Node/npm/PowerShell children inherit the caller environment, which may contain ambient secrets or behavior-changing settings | InfoDisc-Med | Run in a least-privilege environment and avoid unrelated secrets; filtering awaits a supported cross-platform contract |
| G-EOP-1 | Guidepup/NVDA sends OS-level input after foreground-window verification, but another application or system dialog can steal focus between verification and command dispatch | EoP-Med | Reserve an unlocked interactive desktop, bind Chrome before and after action boundaries, use exact journey selection, and stop on focus uncertainty |
Path A local-file scanning is not folded into G-INF-1. It is an explicit operator-authorized capability to read any selected existing regular local file with the operator's permissions, without repository confinement. A separate local-file disclosure gap is warranted only if a less-trusted caller or confinement requirement becomes supported.
References
Repository security model
🤖 Crafted with precision by ✨Copilot following brilliant human instruction, then carefully refined by our team of discerning human reviewers.
Requirements and compatibility
Written for: GitHub Copilot, Claude Code
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Claude Code frontmatter, Needs Python, Needs Node.js
The author says: Requires Python 3.11+ and uv; the scanner additionally needs Node.js and network access to fetch the pinned axe-core CLI from the public npm registry.
Security
What our scanner noticed· Low risk
- Instructions that use the network
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Microsoft
- Publisher
- Microsoft (Official)
- Source
- microsoft/hve-core · .github/skills/accessibility/accessibility · commit f425e94
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Microsoft.
Get it from the source
1 of this skill’s files are not mirrored here, so there is no ZIP. Get the complete skill from its source: microsoft/hve-core