accessibility
Extends `qa-frontend.v2.md`. Load when dispatched with `mode: accessibility`.
> /plugin marketplace add LerianStudio/ringHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Extends `qa-frontend.v2.md`. Load when dispatched with `mode: accessibility`.
Agent definition
accessibility.mdQA Analyst (Frontend) — Accessibility Testing Mode
Extends `qa-frontend.v2.md`. Load when dispatched with `mode: accessibility`.
What to Test
- WCAG 2.1 AA compliance
- axe-core automated scan for violations
- Keyboard navigation (Tab, Enter, Escape, Arrow keys)
- Screen reader announcements (ARIA live regions, landmark roles)
- Focus management (modal open/close, error announcement)
- Color contrast ratios (minimum 4.5:1 for normal text)
- Touch targets (minimum 44×44px)
Automated Scan (axe-core)
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
describe('TransactionList — Accessibility', () => {
it('has no axe violations', async () => {
const { container } = render(
<TransactionList items={mockTransactions} />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has no axe violations in loading state', async () => {
const { container } = render(<TransactionList items={[]} isLoading />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has no axe violations in error state', async () => {
const { container } = render(
<TransactionList items={[]} error={new Error('Failed')} />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});Keyboard Navigation
describe('Keyboard Navigation', () => {
it('navigates list with arrow keys', async () => {
const user = userEvent.setup();
render(<TransactionList items={mockTransactions} />);
const list = screen.getByRole('list');
const items = screen.getAllByRole('listitem');
await user.tab(); // focus first item
expect(items[0]).toHaveFocus();
await user.keyboard('{ArrowDown}');
expect(items[1]).toHaveFocus();
});
it('opens detail on Enter', async () => {
const user = userEvent.setup();
const onSelect = vi.fn();
render(<TransactionList items={mockTransactions} onSelect={onSelect} />);
await user.tab();
await user.keyboard('{Enter}');
expect(onSelect).toHaveBeenCalledWith('1');
});
});Focus Management
describe('Modal Focus Management', () => {
it('traps focus inside modal when open', async () => {
const user = userEvent.setup();
render(<TransactionDetailModal isOpen={true} onClose={vi.fn()} />);
// First focusable element inside modal gets focus
expect(screen.getByRole('dialog')).toBeInTheDocument();
const closeButton = screen.getByRole('button', { name: /close/i });
expect(closeButton).toHaveFocus();
});
it('returns focus to trigger on close', async () => {
const user = userEvent.setup();
const { rerender } = render(<TransactionDetailModal isOpen={true} />);
const trigger = screen.getByRole('button', { name: /view details/i });
rerender(<TransactionDetailModal isOpen={false} />);
expect(trigger).toHaveFocus();
});
});Output Format
## VERDICT: [PASS | FAIL]
## Accessibility Testing Summary
| Metric | Value |
|--------|-------|
| Components Scanned | N |
| axe Violations | N |
| Keyboard Tests | N passed / N total |
| WCAG Level | AA |
## Violations Report
[If any violations]
### [Violation ID]: [Description]
- **Severity:** critical/serious/moderate/minor
- **Location:** `ComponentName` — `selector`
- **WCAG Criterion:** [e.g., 1.3.1 Info and Relationships]
- **Fix:** [specific code change]
## Keyboard Navigation Results
| Flow | Status |
|------|--------|
| Tab through list items | ✅ PASS |
| Arrow key navigation | ✅ PASS |
| Enter to open detail | ✅ PASS |
| Escape to close modal | ✅ PASS |
| Focus trap in modal | ✅ PASS |
## Next Steps
[PASS: "WCAG 2.1 AA compliant." | FAIL: list violations with fixes.]
Read more
QA Analyst (Frontend) — Accessibility Testing Mode
Extends `qa-frontend.v2.md`. Load when dispatched with `mode: accessibility`.
What to Test
- WCAG 2.1 AA compliance
- axe-core automated scan for violations
- Keyboard navigation (Tab, Enter, Escape, Arrow keys)
- Screen reader announcements (ARIA live regions, landmark roles)
- Focus management (modal open/close, error announcement)
- Color contrast ratios (minimum 4.5:1 for normal text)
- Touch targets (minimum 44×44px)
Automated Scan (axe-core)
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
describe('TransactionList — Accessibility', () => {
it('has no axe violations', async () => {
const { container } = render(
<TransactionList items={mockTransactions} />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has no axe violations in loading state', async () => {
const { container } = render(<TransactionList items={[]} isLoading />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has no axe violations in error state', async () => {
const { container } = render(
<TransactionList items={[]} error={new Error('Failed')} />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});Keyboard Navigation
describe('Keyboard Navigation', () => {
it('navigates list with arrow keys', async () => {
const user = userEvent.setup();
render(<TransactionList items={mockTransactions} />);
const list = screen.getByRole('list');
const items = screen.getAllByRole('listitem');
await user.tab(); // focus first item
expect(items[0]).toHaveFocus();
await user.keyboard('{ArrowDown}');
expect(items[1]).toHaveFocus();
});
it('opens detail on Enter', async () => {
const user = userEvent.setup();
const onSelect = vi.fn();
render(<TransactionList items={mockTransactions} onSelect={onSelect} />);
await user.tab();
await user.keyboard('{Enter}');
expect(onSelect).toHaveBeenCalledWith('1');
});
});Focus Management
describe('Modal Focus Management', () => {
it('traps focus inside modal when open', async () => {
const user = userEvent.setup();
render(<TransactionDetailModal isOpen={true} onClose={vi.fn()} />);
// First focusable element inside modal gets focus
expect(screen.getByRole('dialog')).toBeInTheDocument();
const closeButton = screen.getByRole('button', { name: /close/i });
expect(closeButton).toHaveFocus();
});
it('returns focus to trigger on close', async () => {
const user = userEvent.setup();
const { rerender } = render(<TransactionDetailModal isOpen={true} />);
const trigger = screen.getByRole('button', { name: /view details/i });
rerender(<TransactionDetailModal isOpen={false} />);
expect(trigger).toHaveFocus();
});
});Output Format
## VERDICT: [PASS | FAIL] ## Accessibility Testing Summary | Metric | Value | |--------|-------| | Components Scanned | N | | axe Violations | N | | Keyboard Tests | N passed / N total | | WCAG Level | AA | ## Violations Report [If any violations] ### [Violation ID]: [Description] - **Severity:** critical/serious/moderate/minor - **Location:** `ComponentName` — `selector` - **WCAG Criterion:** [e.g., 1.3.1 Info and Relationships] - **Fix:** [specific code change] ## Keyboard Navigation Results | Flow | Status | |------|--------| | Tab through list items | ✅ PASS | | Arrow key navigation | ✅ PASS | | Enter to open detail | ✅ PASS | | Escape to close modal | ✅ PASS | | Focus trap in modal | ✅ PASS | ## Next Steps [PASS: "WCAG 2.1 AA compliant." | FAIL: list violations with fixes.]
Proven engineering practices, enforced through skills. Ring is a comprehensive skills library and workflow system for AI agents that transforms how AI assistants approach software development.
Repo: LerianStudio/ring
Other agents on ring.
- codebase-explorer
Deep codebase exploration agent for architecture understanding, pattern discovery, and comprehensive code analysis. Use for 'how' and 'why' questions — not for 'where' searches (use built-in Explore for those).
Open agent - review-slicer
Review Slicer: Adaptive classification engine that evaluates semantic cohesion to decide whether slicing improves review quality. Sits between Mithril pre-analysis and reviewer dispatch. Classification-only — does NOT read source code.
Open agent - backend-go
Senior Backend Engineer specialized in Go for high-demand financial systems. Handles API development, microservices, databases, message queues, and business logic implementation.
Open agent - backend-ts
Senior Backend Engineer specialized in TypeScript/Node.js for scalable systems. Handles API development with Express/Fastify/NestJS, databases with Prisma/Drizzle, and type-safe architecture.
Open agent - bff-ts
Senior BFF (Backend for Frontend) Engineer specialized in Next.js API Routes with Clean Architecture, DDD, and Hexagonal patterns. Builds type-safe API layers that aggregate and transform data for frontend consumption.
Open agent - code-reviewer
Foundation Review: Reviews code quality, architecture, design patterns, algorithmic flow, and maintainability. Runs in parallel with other reviewers at Gate 8.
Open agent

