Inspiration

Every day, millions of messages, images, and files flow through Slack workspaces. But for someone using a screen reader, relying on captions, or struggling with cognitive strain, a poorly written message or an image without alt text isn't just inconvenient — it's a wall.

The sad reality is that accessibility violations in chat platforms are nearly invisible to the people who create them. Nobody sets out to post an unlabeled image or write a color-dependent instruction. They just don't know. And there's no system to tell them otherwise.

That's what sparked this project: what if Slack could audit itself—not with a manual checklist or a basic linter, but with an AI agent that reviews conversations like a human accessibility expert, understands context, and highlights meaningful issues.


What It Does

Accessibility Audit Bot is a Slack bot that scans your workspace channels for accessibility violations and delivers structured, actionable reports — all triggered by a single slash command: /accessibility-audit.

When invoked, the bot autonomously reads recent messages, digs into threads, analyzes images using computer vision, and checks channel metadata. It then produces two outputs:

  • A Block Kit summary posted to #accessibility-audit-results — issue counts, severity rankings, and a channel-by-channel overview of who passed, who failed, and who was skipped.
  • A full HTML report uploaded as a file — expandable per-channel sections, color-coded findings, WCAG badges, and specific, practical suggestions for each violation.

The bot checks for 15 categories of accessibility issues mapped to WCAG 2.1 criteria, including missing or inadequate image alt text, color-only communication, excessive emoji, vague or context-free messages, bare URLs, long unformatted text, and missing channel descriptions. Every finding is reasoned out by Claude — no regex, no keyword lists, no hardcoded rules.


How I Built It

The bot is built on the Slack Bolt framework in Socket Mode. No public URL is needed — no ngrok or infrastructure headaches. The bot connects outbound to Slack's servers and responds to the /accessibility-audit command from anywhere it is invited.

The core is a Claude agentic loop in auditor.js. When an audit is triggered, Claude is given three tools and complete autonomy to decide what to read, what to focus on, and when to stop:

  • slack_read_channel — retrieves recent messages from a specified Slack channel via the Slack MCP, located at mcp.slack.com/mcp. This MCP server is the required Slack API integration for this hackathon.
  • slack_read_thread — accesses threaded replies stemming from a message, allowing Claude to investigate any conversation thread it identifies as relevant
  • fetch_slack_image — obtains private image files from Slack channels by using the bot token to authenticate, then encodes images as base64 so Claude Vision can analyze their content

Importantly, there are no regex rules, hardcoded patterns, or keyword lists. Instead, every finding — whether it's missing alt-text on a screenshot or an emoji-only message conveying meaning through color — is reasoned out by Claude.

Findings flow into severity-calculator.js, which aggregates counts and ranks channels by weighted severity. formatter.js produces both the Block Kit summary and full HTML report with expandable per-channel sections, color-coded findings, WCAG badges, and actionable advice.

Multimodal Capabilities

When Claude encounters an image, it doesn't just look for an alt-text field in the metadata. It downloads, encodes, and passes the image to Claude Vision, which examines its actual content and compares it with the provided alt text.

This enables findings that are impossible without vision:

  • An image with alt="screenshot" that actually contains a detailed information table — flagged as inadequate alt-text.
  • An auto-generated filename like IMG_20240615_083241.png with no description — flagged as a noisy filename, no context.
  • An infographic that communicates data solely through color, without text labels — flagged as color-only communication, Critical .
  • An image that is genuinely well-described — passed, with no false positives.

The agent also reads threads autonomously. If a message is vague or contains a file reference, Claude calls slack_read_thread for context — because accessibility depends on the ability to follow a conversation without prior knowledge or visual cues.

MCP Integration

The Slack MCP server at mcp.slack.com/mcp is the backbone of the data access layer. Instead of calling Slack's REST API directly for message history, the agent proxies all channel and thread reads through the MCP server via JSON-RPC 2.0 over SSE. Authentication is handled with a user OAuth token, which typically starts with xoxp-.

This separation is intentional: the MCP server provides read access scoped to what a human user can see, while the bot token is used only for posting reports and fetching private image bytes. When Claude calls slack_read_channel, the bot also calls files.list and files.info via the Slack Web API and appends structured file metadata — including alt-text status per attachment — to the MCP tool result before returning it to Claude. Claude gets a complete, enriched picture of each message in a single tool call.

The agentic loop runs for up to 10 rounds, but Claude almost always finishes in 3–5. It reads what it needs, follows the threads worth following, and calls end_turn when it has enough to write a complete findings report.


Challenges I Ran Into

Getting multimodal and MCP to cooperate was the hardest engineering problem. Claude Vision needs image bytes at inference time, but Slack private image URLs return a 401 error when a valid bot token is not present in the Authorization header. The MCP server uses a user token. That means the fetch_slack_image tool has to use a completely different authentication path from the channel read tools — and the agent has to know when to call it, which it figures out from the image metadata returned by slack_read_channel.

Avoiding false positives required significant prompt engineering. Claude is instructed to distinguish between an emoji used decoratively (one wave at the end of a message — fine) and an emoji-only message that's the sole carrier of meaning (just 🔴🟢🟡 with text — a real accessibility violation). Getting that nuance right took many iterations.

Channel metadata surfaced a subtle scoping issue: the bot can only audit channels it's been invited to. The first version tried to audit all workspace channels and silently failed on most of them. The solution was to call conversations.list with the bot's membership filter, check conversations.info for purpose and topic metadata without AI (that's pure structure, not judgment), and skip channels the bot can't see — with a clear note in the report.

Auditing Group DMs introduced more noise than signal. An early version of the bot supported Group DM (MPIM) channel audits using the mpim:history scope. However, in practice, this surfaced a flood of inactive or archived conversations — old group threads that nobody actively uses. This cluttered the report and made it harder to focus on channels that actually matter. Instead of filtering heuristically and risking missed coverage, we removed Group DM support entirely, scoping the audit to channels to which the bot is explicitly invited. The lesson: access doesn't equal relevance.

Structured output from an agentic loop is trickier than it sounds. Claude runs autonomously across multiple rounds, and the final output must be valid JSON that severity-calculator.js can parse. If Claude decides to add commentary around the JSON, the whole pipeline breaks. Enforcing clean JSON output at end_turn while still allowing Claude to reason freely during tool calls required careful system prompt design and output parsing.


Accomplishments That I am Proud Of

The agent genuinely reasons about accessibility. It's not matching patterns — it's reading messages the way a human reviewer would, understanding context, and making judgment calls. Seeing Claude autonomously follow a thread, pull an image, and flag a violation that no rule-based tool would ever catch was a meaningful moment.

Multimodal image review works end-to-end. Downloading a private Slack image, encoding it, and passing it to Claude Vision — then getting back a finding that references the actual content of the image — is a complete pipeline that didn't exist before this project.

Zero infrastructure required. Socket Mode means the bot runs anywhere Node.js runs, with no public URL, no reverse proxy, and no deployment complexity beyond setting environment variables. That made iteration fast and the demo reliable.

The HTML report is genuinely useful. Expandable sections, color-coded severity, WCAG badge references, and per-finding suggestions make the output something a team could actually act on — not just a list of violations.


What I Learned

Accessibility is a judgment challenge, not a pattern-matching problem. Detecting the line between helpful and meaningless, or adequate and inadequate, demands contextual analysis and insight that rules alone can't provide. Real inclusion requires nuanced understanding—every message, every image, every time.

Claude's autonomous review — from browsing threads to cross-referencing metadata and citing WCAG criteria — sets a new standard for accessibility evaluation. This approach elevates accessibility beyond simple linting, establishing it as an exercise in judgment, context, and expertise.

The other big lesson: Socket Mode is underrated. Skipping public endpoints and reverse proxies completely eliminated deployment friction. For a hackathon project that needs to work reliably end-to-end, it was the right call.


What's Next for Accessibility Audit Bot

Scheduled audits. Rather than waiting for someone to run /accessibility-audit, the bot could audit channels on a weekly schedule and surface a digest of new violations — turning accessibility from a one-time check into an ongoing practice.

Per-user coaching. When the bot identifies a violation, it could DM the author with a friendly, specific suggestion — not a public callout, but a quiet nudge that helps people learn over time.

Dashboard and trend tracking. Persisting findings over time would allow teams to see whether their accessibility posture is improving — which channels are repeat offenders, which violation types are most common, and whether fixes are sticking.

Support for more content types. PDFs, presentations, and shared documents are common in Slack but are currently only flagged as "may lack extractable text." Deeper document analysis would make the audit more complete.

Built With

Share this project:

Updates