An HTTP server that audits submitted HTML for SEO, accessibility, and custom validation rules. It runs Lighthouse against the markup, sends the Lighthouse findings and rules to an LLM agent, and returns a self-contained HTML report.
The server supports three interchangeable auditors, selected with the AUDITOR environment variable:
claude(default) — Claude Agent SDK, runs the locally installedclaudeCLI.vercel— AI SDKToolLoopAgentover any OpenAI-compatible endpoint (LM Studio / Ollama / llama.cpp / cloud).copilot— GitHub Copilot SDK, drives the locally installed Copilot CLI.
The repository also contains a browser client for injecting an audit button into an AEM preview page. Its TypeScript source is bundled with Webpack into src/client/dist/loader.js and served by the server at /ui-assets/loader.js.
- Node.js 20 or newer
- npm
- A Chromium-compatible browser environment for Puppeteer
- For the
vercelauditor: an OpenAI-compatible chat completions endpoint (LM Studio, Ollama, llama.cpp, or a hosted provider) - For the
claudeauditor: theclaudeCLI installed and authenticated (viaANTHROPIC_API_KEYorclaude login) - For the
copilotauditor: thecopilotCLI installed and authenticated (viaGITHUB_TOKENorcopilot login)
Puppeteer downloads a compatible browser during dependency installation unless it is already available in the local cache. In restricted environments, make sure Chrome or Chromium is available and Puppeteer can launch it.
The claude and copilot auditors drive locally installed CLI tools. Install them globally with npm and log in once.
npm install -g @anthropic-ai/claude-code
claude --versionAuthenticate — either with your Claude subscription or with an API key:
claude login # browser-based OAuth with your claude.ai account (Pro/Max subscription)
# alternative: set ANTHROPIC_API_KEY in .env for pay-as-you-go Anthropic Console creditsnpm install -g @github/copilot
copilot --versionAuthenticate — either with your GitHub Copilot subscription or with a token:
copilot login # GitHub OAuth with your Copilot subscription
# alternative: set GITHUB_TOKEN in .envnpm install
cp .env.example .envEdit .env with the LLM endpoint and model you want to use.
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Port used by the HTTP server |
ENVIRONMENT |
development |
When set to development, failed Lighthouse audits are also written to reports/ |
AUDITOR |
claude |
Which agent runs audits: claude (Claude Agent SDK), vercel (AI SDK ToolLoopAgent), or copilot (GitHub Copilot SDK) |
LLM_BASE_URL |
http://localhost:1234/v1 |
Base URL for an OpenAI-compatible API (vercel auditor) |
LLM_API_KEY |
local |
API key sent to the LLM provider (vercel auditor) |
LLM_MODEL |
model-name |
Model name passed to the chat completions API (vercel auditor) |
ANTHROPIC_API_KEY |
(unset) | API key for the Claude auditor (Anthropic Console credits); omit to use the claude login subscription |
GITHUB_TOKEN |
(unset) | GitHub token for the Copilot auditor; omit to use the copilot login subscription |
The .env file is ignored by Git. Do not commit API keys or other credentials.
Start the development server with automatic reloads:
npm run devBuild the TypeScript source:
npm run buildRun the compiled server:
npm startRun ESLint:
npm run lintThe server listens at http://localhost:3000 by default.
Set AUDITOR in .env or the environment to pick the agent implementation:
AUDITOR=vercel npm run dev # AI SDK ToolLoopAgent + LLM_BASE_URL endpoint
AUDITOR=claude npm run dev # Claude Agent SDK + local claude CLI (default)
AUDITOR=copilot npm run dev # GitHub Copilot SDK + local copilot CLIEach agent CLI must be logged in before it can be used:
- Claude (
claude) — runclaude loginin a terminal to authenticate with your Claude subscription. Alternatively, setANTHROPIC_API_KEYin.envto use pay-as-you-go Anthropic Console credits instead. - Copilot (
copilot) — runcopilot loginin a terminal to authenticate with your GitHub Copilot subscription. Alternatively, setGITHUB_TOKENin.env. - Vercel (
vercel) — no login needed; it uses theLLM_BASE_URL/LLM_API_KEY/LLM_MODELendpoint directly.
Serves a compiled browser client asset from src/client/dist. For example:
http://localhost:3000/ui-assets/loader.js
Submit an HTML document and one or more plain-text validation rules as JSON.
Request:
{
"markup": "<!doctype html><html><head><title>Example</title></head><body><h1>Hello</h1></body></html>",
"rules": [
"Page must have a visible phone number",
"Page must have a clear call to action"
]
}Example with curl:
curl --location 'http://localhost:3011/audit' \
--header 'Content-Type: application/json' \
--data '{
"markup": "<!doctype html><html><head><title>Example</title></head><body><h1>Hello</h1><p>Some content</p><h2>Subtitle</h2></body></html>",
"rules": [
"Page must have a visible Hero banner with a headline and a call-to-action button",
"Page must display a visible phone number",
"Page must have a Privacy Policy link in the footer",
"Should have a valid heading structure (h1, h2, h3) and semantic HTML elements"
]
}'The request body must contain a non-empty string markup and a non-empty array of strings called rules. Invalid requests receive HTTP 400. Errors during Lighthouse or LLM processing receive HTTP 500 with an HTML error page.
- The submitted markup and validation rules are packed into a prompt.
- The auditor is resolved from the
AUDITORenvironment variable. - The selected agent inspects the markup and calls its audit tools:
lighthouse_audit— runs Lighthouse (SEO + accessibility) via Puppeteer against a temporary local HTTP server.check_links— runs the link checker over a list of URLs.
- The agent returns an
AuditReportas JSON, which is validated againstauditReportZodSchema. /auditrenders the result as a self-contained HTML report;/agentreturns the raw JSON.- Temporary files, the local HTTP server, and the browser are cleaned up.
src/
server.ts Express server, static files, POST /audit + POST /agent endpoints
agents/
index.ts Auditor factory keyed on the AUDITOR env var
audit-report-zod-schema.ts Zod schema + AuditReport type for LLM output
system-prompt.ts Shared system prompt for all auditors
claude/
auditor-claude.ts Claude Agent SDK runner (local claude CLI + MCP tools)
claude-tools.ts MCP tool definitions for the Claude auditor
copilot/
auditor-copilot.ts GitHub Copilot SDK runner (local copilot CLI)
copilot-tools.ts defineTool definitions for the Copilot auditor
vercel/
auditor-vercel.ts AI SDK ToolLoopAgent (OpenAI-compatible endpoint)
vercel-tools.ts AI SDK tool() definitions for the Vercel auditor
helpers/
response-parser.ts parseLlmOutput() — cleanup + JSON.parse + zod validate
tools/
lighthouse/lighthouse-runner.ts Temporary HTML server and Lighthouse runner
links-checker/links-checker.ts Link checker implementation
report/generator.ts Self-contained HTML report generator
client/
loader.ts Browser script for the AEM audit button
components/ Client-side UI components
helpers/ Client-side helpers
dist/ Webpack output; served at /ui-assets
middleware/
access-control-headers.ts CORS and OPTIONS response middleware
types/ Shared TypeScript interfaces
public/ Root static files
webpack.config.cjs Browser client Webpack configuration
eslint.config.js ESLint flat configuration
.env.example Example environment configuration
Build the browser client once with:
npm run build:clientDuring npm run dev, Webpack watches src/client and rebuilds src/client/dist/loader.js whenever client sources change. Nodemon separately watches server TypeScript sources and restarts the server when they change.
To run only the client watcher:
npm run dev:clientEdit files under src/client, not the generated JavaScript in src/client/dist.
Make sure the machine has a compatible Chrome or Chromium installation and that the process is allowed to launch a headless browser. The server includes --no-sandbox and --disable-dev-shm-usage launch arguments for common server environments.
Check that LLM_BASE_URL, LLM_API_KEY, and LLM_MODEL match the configured provider. The endpoint must support OpenAI-compatible chat completions and structured JSON responses.
The claude auditor authenticates with ANTHROPIC_API_KEY if it is set; otherwise it falls back to the OAuth login stored by claude login. If you omit the API key and get "Not logged in · Please run /login", run claude login once in a terminal (same user account as the server).
With ANTHROPIC_API_KEY set, Claude Code bills through the Anthropic Console (pay-as-you-go). Without it, the auditor uses your claude login subscription. The CLI prefers an API key over the subscription whenever one is present in the environment.
The copilot auditor authenticates with GITHUB_TOKEN if it is set; otherwise it falls back to the OAuth login stored by copilot login. If you omit the token and get "Not logged in", run copilot login once in a terminal (same user account as the server).
Set PORT in .env, for example:
PORT=3011No license has been specified for this project.