# Agent Site Standards Kit
Five plain-markdown standards files that tell an AI coding agent how to build and ship a site
that is indexable, quotable by AI answer engines, structurally described, accessible to
WCAG 2.1 and 2.2 AA, and deployable on Cloudflare Pages, Netlify or Vercel without a rewrite.
Written by J.A. Watte. Free to copy, adapt, and ship. No attribution required, no signup, no tracking.
Source and 346 free verification tools: https://jwatte.com/tools/
---
## HOW TO USE THIS FILE
1. Split the five blocks below into five files at your project root:
`DESIGN.md`, `SEO.md`, `SCHEMA.md`, `A11Y.md`, `DEPLOY.md`
(or keep it as one file named `STANDARDS.md`; agents read either shape).
2. Add a pointer to them from `AGENTS.md` at your project root, so every agent finds them
without being told. See the AGENTS.md stub at the end.
3. Fill in every `FILL:` marker. An unfilled marker is the single most common reason an agent
invents a value instead of using yours.
4. Prompt: *"Read STANDARDS.md. Build/refit this site to it. Work presentation-only where the
file says presentation-only, keep every change additive and reversible, and verify contrast
by computation rather than by eye."*
5. Verify with the free audits listed in the VERIFY block at the bottom. Do not accept the
agent's own report that it complied.
---
# 1. DESIGN.md
> Visual system. Nothing in this file changes markup semantics, routing, or content.
> Presentation only. If a change requires touching HTML structure, stop and ask.
## Ground rules
- Exactly one accent color, in three shades. Muted beats saturated.
- Headings get emphasis from size, not weight. Weight 300 to 400, never 700.
- Off-white ground, charcoal ink. Pure `#ffffff` on pure `#000000` is a default, not a decision.
- Subtraction is the job. Three easing curves and one duration, not forty animation classes.
## Tokens
```css
:root {
/* Ground and ink. FILL: replace with your two decisions, keep them off-pure */
--ground: #f1f0eb;
--ground-raised: #ffffff;
--ink: #1a1a1a;
--ink-2: #4a4a4a; /* secondary text. MUST pass 4.5:1 on --ground */
--ink-3: #6b6b6b; /* captions/metadata. MUST pass 4.5:1 on --ground */
--hairline: #dedcd6; /* borders only. Never used as text. */
/* Accent. FILL: one hue, three shades */
--accent: #8a6a3d;
--accent-hover: #6f5530;
--accent-soft: #efe7da;
/* Type scale: light and tight at display sizes */
--fs-display: clamp(2.75rem, 6vw, 5rem);
--fs-h1: clamp(2.25rem, 4.5vw, 3.5rem);
--fs-h2: clamp(1.6rem, 3vw, 2.25rem);
--fs-body: 1.0625rem; /* 17px. Never below 16px for body copy. */
--lh-display: 1.05;
--lh-heading: 1.15;
--lh-body: 1.55; /* 1.5 is the WCAG 1.4.12 floor. Do not go under. */
--ls-display: -0.02em;
/* Space: one very large named token, and the discipline to use it */
--sp-1: 0.5rem; --sp-2: 1rem; --sp-3: 1.5rem; --sp-4: 2.5rem;
--sp-5: 4rem; --sp-6: 6rem; --sp-section: 9rem;
/* Motion: three curves, one duration */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-io: cubic-bezier(0.645, 0.045, 0.355, 1);
--ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19);
--dur: 0.3s;
--radius: 6px;
--focus-ring: 3px solid var(--accent);
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
## Rules the agent must not break
1. **Every color pair used for text must be computed, not eyeballed.** Before shipping any token,
compute the WCAG contrast ratio of every text token against every surface it can land on.
Normal text needs 4.5:1. Text at 18.66px bold or 24px regular and above needs 3:1. Non-text
UI (icons, input borders, focus indicators, chart strokes) needs 3:1 under SC 1.4.11.
A token that cannot reach its floor against any declared surface is a bug in the palette,
not a styling choice to work around.
2. **`--hairline` is never a text color.** Border tokens sit at ratios that are legal for borders
and illegal for words. Keeping them in a separate group prevents the most common accidental failure.
3. **Never remove a focus indicator.** `outline: none` without a replacement is an SC 2.4.7 failure.
Use `:focus-visible` and give the ring 3:1 against both the component and the adjacent background.
4. **Do not use color alone to carry meaning** (SC 1.4.1). Pair every color state with a shape,
an icon, or a word.
5. **Do not build any interaction that requires a drag** without a click or keyboard alternative
(SC 2.5.7, new in WCAG 2.2 AA).
6. If a design reference you were given (a DESIGN.md pulled from another brand, a screenshot,
a Figma export) conflicts with rules 1 to 5, **rules 1 to 5 win** and you say so in your summary.
## Using a third-party DESIGN.md
Design briefs extracted from well-known brands are a fast way to get a coherent starting point,
and they carry two hazards worth stating plainly:
- **They describe a real company's visual identity.** Learning from one, or using it on an internal
page, is fine. Shipping a production site that reproduces a competitor's exact look invites
trademark and brand-confusion problems. Take the structure, not the fingerprint.
- **They are usually silent on accessibility numbers.** A brief can name a "muted caption" color
without saying whether that color clears 4.5:1 on the canvas it sits on. Run rule 1 on every
imported palette before you use it, and expect to lighten or darken the lowest-emphasis tokens.
---
# 2. SEO.md
> Discoverability by classic search. Every rule here is verifiable from the rendered HTML.
## Per-page requirements
- **One `
` per page**, matching the page's actual subject. Headings descend without skipping
levels (this is also SC 1.3.1, so it is an accessibility rule as well as a search one).
- **``**: 50 to 60 characters. Front-load the distinguishing words.
- **``**: **150 to 170 characters, hard ceiling 170.** Longer descriptions
get truncated in results, which wastes the part you cared about. Gate this in CI; a hand rule
is not a rule. Lead with the concrete finding, not a summary of what the page covers.
- **Canonical**: absolute, self-referencing, one per page, `https`, no trailing-slash inconsistency.
Pick trailing-slash or no-trailing-slash once and enforce it in redirects.
- **Open Graph and Twitter card**: `og:title`, `og:description`, `og:image` (absolute URL,
1200x630), `og:url`, `og:type`, `twitter:card=summary_large_image`.
- **Every image has width and height attributes** so the layout does not shift. This is a Core
Web Vitals rule and a reading-comfort rule at the same time.
## Sitemap
- `sitemap.xml` at the root, referenced from `robots.txt`.
- **`lastmod` must be true.** Emit it from a real `dateModified` field, not from the build clock.
A sitemap where every URL changed today is a sitemap search engines learn to ignore. If a page
has no modification date, emit its publish date, and never emit `lastmod` at all rather than
emitting a fake one.
- `priority` and `changefreq` are advisory. Use them to express your own hierarchy (home 1.0,
hub pages 0.8, articles 0.7, legal pages 0.3) and do not expect them to move rankings.
- Add a second `sitemap-image.xml` if images are a traffic source.
- Keep any single sitemap under 50,000 URLs and 50 MB uncompressed; split with a sitemap index
beyond that.
## robots.txt
```
User-agent: *
Allow: /
Sitemap: https://FILL-your-domain.example/sitemap.xml
```
Use an **allow-list posture for AI crawlers, not a deny-list**, unless you have a specific reason
to block. See AEO below.
## Internal linking
- Every page reachable within three clicks of the home page.
- No orphan pages: if it is in the sitemap it must be linked from somewhere in the navigable site.
- Link text describes the destination. "Read more" and "click here" fail SC 2.4.4 and tell a
search engine nothing.
- Cross-link related content 3 to 5 times per long page. Depth is what makes a corpus compound.
---
# 3. SCHEMA.md
> Structured data. The goal is one coherent entity graph, not a pile of disconnected blocks.
## The `@id` graph rule
Give every recurring entity a stable `@id` and reference it by `@id` everywhere else. A site with
one Person node referenced eleven times is legible. A site with eleven anonymous Person blocks is
eleven strangers.
```
https://FILL-your-domain.example/#organization Organization, site-wide
https://FILL-your-domain.example/#person Person, the author or owner
https://FILL-your-domain.example/#website WebSite, plus SearchAction
https://FILL-your-domain.example/{path}#webpage WebPage, one per page
https://FILL-your-domain.example/{path}#breadcrumb BreadcrumbList, one per page
```
## The one-canonical-page-node rule
**Emit exactly one page-type node per page.** A page carrying both a `WebPage` block and a
`ProfilePage` block is asking a search engine to decide what the page is, and the answer will
not be stable. If a page is a profile, emit `ProfilePage` and have `Person.mainEntityOfPage`
point at that exact `@id`. Otherwise emit `WebPage`. Never both.
This is not theoretical. Two anonymous `WebPage` blocks sitting alongside a `ProfilePage` on the
same URL is enough to break the binding between a person entity and their bio page.
## Minimum viable graph for a small site
| Node | Where | Why |
| --- | --- | --- |
| `Organization` | every page | the anchor everything else references |
| `Person` | every page | authorship, E-E-A-T, `sameAs` identity fan-out |
| `WebSite` + `SearchAction` | every page | site name in results, sitelinks search box |
| `BreadcrumbList` | every page | breadcrumb display, hierarchy signal |
| `WebPage` or `ProfilePage` | every page, pick one | what this URL is |
| `FAQPage` | pages with real Q/A | only if the questions are visible on the page |
| `Article` / `BlogPosting` | articles | `datePublished`, `dateModified`, `author` by `@id` |
| `LocalBusiness` subtype | contact/location pages | address, hours, `geo`, service area |
| `Product` / `Offer` | commerce | see the shipping caveat below |
| `ItemList` | collection pages | carousel eligibility |
## Rules that prevent the common failures
1. **FAQ parity is mandatory.** Every `Question` in `FAQPage` must exist as visible text on the
page, worded the same way. Schema that describes content the visitor cannot see is the
fastest way to lose rich-result eligibility.
2. **`sameAs` is an identity claim, so make it verifiable.** List only profiles you control and
that link back where possible. Ten unverifiable links are worth less than three verified ones.
3. **`dateModified` must be honest** and must match what the sitemap says. Two different modified
dates for the same URL is a trust signal in the wrong direction.
4. **`shippingDetails` and `hasMerchantReturnPolicy` belong on physical goods**, not on services.
Detect physical goods by the presence of `gtin`, `mpn`, `isbn`, `productID` or `itemCondition`.
Adding shipping fields to a `Service` or `LocalBusiness` is a false positive that generic
validators will happily encourage.
5. **Recurse into every object value when validating, not just `@graph`.** Nested `Review` and
`AggregateRating` inside `Product.review` or `OfferCatalog.itemListElement.itemOffered` are
easy to miss with a shallow walker, and their absence gets reported as "no schema found."
6. **`speakable` takes CSS selectors.** Point it at real selectors that exist in your markup
(`h1`, `h2`, `.summary`, `.faq-answer`). Do not use XPath.
---
# 4. AEO / GEO.md
> Answer Engine Optimization and Generative Engine Optimization. Being retrievable and quotable
> by AI answer engines, and findable in a geographic market.
## Files to publish
| File | Purpose |
| --- | --- |
| `/llms.txt` | curated map of the site for language models, per llmstxt.org |
| `/llms-full.txt` | the expanded version with more context |
| `/AGENTS.md` | operator briefing for coding agents, per agents.md |
| `/feed.xml` and `/feed.json` | RSS and JSON Feed 1.1 |
| `/.well-known/security.txt` | security contact, RFC 9116 |
| `/.well-known/api-catalog` | machine-readable resource linkset, RFC 9727 |
| `/humans.txt` | optional, cheap, and humanizing |
| `/ai.txt` | your AI training and usage policy in plain language |
## Markdown companions
Publish a `.md` twin of every substantive page and advertise it in the HTML head:
```html
```
If your host lets you negotiate content, serve markdown to `Accept: text/markdown` and set
`Vary: Accept` on those responses so a CDN does not collapse the markdown and HTML cache entries
into one. Without `Vary: Accept` you will eventually serve markdown to a browser or HTML to an
agent, at random, and it will be very hard to reproduce.
## AI crawler posture
Decide deliberately, then write it down in `robots.txt`. An allow-list posture looks like this:
```
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=yes
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: CCBot
Allow: /
User-agent: Applebot-Extended
Allow: /
```
Blocking every AI crawler and then wondering why you are never cited in an AI answer is a
self-inflicted wound. Blocking them deliberately, because your content is your product, is a
legitimate business decision. Both are fine. Doing it by accident is not.
## What actually makes a page quotable
- **Answer the question in the first two sentences of the section**, then support it. Retrieval
systems lift passages, not pages.
- **One idea per heading**, and make the heading the question a person would type.
- **Put the number in the sentence**, not only in a chart or an image. An answer engine cannot
quote a PNG.
- **Date everything** and keep `dateModified` truthful. Freshness is a retrieval input.
- **Cite your sources inline with real links.** Pages that cite get cited.
## GEO for a local business
- Name, address and phone identical **character for character** everywhere they appear:
your site, `LocalBusiness` schema, Google Business Profile, Apple Business Connect, directories.
"Suite 4" and "Ste. 4" are two different businesses to a matching algorithm.
- Emit `geo` coordinates, `openingHoursSpecification`, and `areaServed`.
- A page per service and a page per service area, each with genuinely different content. Cloned
city pages with the city name swapped are the oldest and most reliably penalized trick in local SEO.
- Verify your map pin by coordinate, not by looking at the embed. A pin can sit a mile off and
still look correct at the zoom level your page loads at.
---
# 5. A11Y.md
> WCAG 2.1 and 2.2, Level AA. This is the file that keeps a generated site out of trouble.
## Scope statement
Target: **WCAG 2.2 Level AA**. WCAG 2.2 is backward compatible with 2.1, so conforming to 2.2 AA
means conforming to 2.1 AA as well, with one exception worth knowing: **SC 4.1.1 Parsing was
removed in WCAG 2.2** because the failures it described are now handled by browsers. If a
checklist still gates on 4.1.1, that checklist is 2.1-era. Do not spend effort there.
## The criteria to check on every page
**Perceivable**
- 1.1.1 Non-text Content: every `` has `alt`. Decorative images get `alt=""`. Filenames
are not descriptions. An image inside a link with no other link text needs the `alt` to carry
the link's purpose.
- 1.2.1 / 1.2.2: prerecorded video has captions; audio-only has a transcript.
- 1.3.1 Info and Relationships: real landmarks (`header`, `nav`, `main`, `footer`), one `main`,
no skipped heading levels, related inputs grouped in `fieldset` with a `legend`, tables with
real `
`.
- 1.3.5 Identify Input Purpose: `autocomplete` on name, email, tel, address fields.
- 1.4.1 Use of Color: never color alone.
- 1.4.3 Contrast (Minimum): 4.5:1 normal text, 3:1 large text.
- 1.4.4 Resize Text: usable at 200% zoom.
- 1.4.10 Reflow: no horizontal scrolling at 320 CSS px width.
- 1.4.11 Non-text Contrast: 3:1 for UI components and meaningful graphics.
- 1.4.12 Text Spacing: survives line-height 1.5, paragraph spacing 2em, letter-spacing 0.12em,
word-spacing 0.16em without clipping.
- 1.4.13 Content on Hover or Focus: dismissible, hoverable, persistent.
**Operable**
- 2.1.1 Keyboard: every interactive element reachable and operable by keyboard.
- 2.1.4 Character Key Shortcuts: single-character shortcuts must be remappable or off by default.
- 2.2.1 / 2.2.2: adjustable timing; anything auto-playing longer than five seconds can be paused.
- 2.4.1 Bypass Blocks: a visible-on-focus skip link as the first focusable element.
- 2.4.2 Page Titled: unique, descriptive ``.
- 2.4.3 Focus Order: DOM order matches visual order.
- 2.4.4 Link Purpose: link text makes sense out of context.
- 2.4.6 Headings and Labels: descriptive.
- 2.4.7 Focus Visible: never remove it without replacing it.
- **2.4.11 Focus Not Obscured (Minimum), new in 2.2 AA**: sticky headers and cookie banners must
not fully cover the focused element. This is the single most commonly introduced 2.2 failure,
because sticky headers are everywhere.
- 2.5.3 Label in Name: the accessible name contains the visible label text, so voice control works.
- **2.5.7 Dragging Movements, new in 2.2 AA**: every drag interaction needs a single-pointer
alternative.
- **2.5.8 Target Size (Minimum), new in 2.2 AA**: **24 by 24 CSS pixels minimum**, with
documented exceptions for inline links in text and essential controls. Note the two numbers
that get confused constantly: **24x24 is AA (2.5.8, WCAG 2.2). 44x44 is AAA (2.5.5, WCAG 2.1).**
A design brief that says "WCAG AA, 44x44" has conflated them.
**Understandable**
- 3.1.1 Language of Page: `` or your actual language.
- 3.2.2 On Input: changing a field does not change context without warning.
- **3.2.6 Consistent Help, new in 2.2 AA**: if a help mechanism appears on multiple pages, it
appears in the same relative order on each.
- 3.3.1 / 3.3.2: errors identified in text and inputs labelled with instructions.
- 3.3.3 / 3.3.4: error suggestions, and reversible or confirmable submissions.
- **3.3.7 Redundant Entry, new in 2.2 AA**: do not ask for the same information twice in one
process unless it is essential.
- **3.3.8 Accessible Authentication (Minimum), new in 2.2 AA**: no cognitive function test
(puzzle, memory task, transcription) without an alternative. Allow paste into password fields.
**Robust**
- 4.1.2 Name, Role, Value: every custom control exposes all three. Buttons with only an icon
need `aria-label`.
- 4.1.3 Status Messages: dynamic updates announced via `role="status"` or `aria-live`.
## Rules for the agent
1. Compute contrast; do not estimate it.
2. Never emit `outline: none` without a `:focus-visible` replacement.
3. Never use `aria-label` to overwrite a visible label with different words (SC 2.5.3).
4. Never put an interactive element inside another interactive element.
5. Never set `tabindex` above 0.
6. Include a `prefers-reduced-motion` block in every stylesheet you generate.
7. Ship a `/accessibility/` page with the conformance level claimed, the known gaps, and a
contact route. A statement that admits a gap is worth more than one that claims perfection.
---
# 6. DEPLOY.md
> Getting the built output onto a host. Measured August 2026. Free tiers change; re-check.
## The build contract
- Output is a directory of static files. Name it and state it: `_site`, `dist`, `build`, `public`.
- The build command runs a gate before it runs the build. If the gate fails, nothing deploys.
```
# gate first, build second
node predeploy-check.mjs && npx @11ty/eleventy
```
## Host comparison, free tiers, as of August 2026
| | Cloudflare Pages | Netlify | Vercel |
| --- | --- | --- | --- |
| Free tier shape | free plan | 300 credits | Hobby plan |
| Builds | 500/month, 1 concurrent, 20 min timeout | credit-metered | 100 deployments/day |
| Files per deploy | 20,000 | not published as a hard cap | not published as a hard cap |
| Max asset size | 25 MiB | | |
| Custom domains | 100 per project | included with SSL | 50 per project |
| Requests | no published bandwidth cap on free | credit-metered | up to 1,000,000 edge requests |
| Redirects | 2,000 static, 100 dynamic | `_redirects` / `netlify.toml` | `vercel.json` |
| Header rules | 100 rules, 2,000 chars each | `_headers` / `netlify.toml` | `vercel.json` |
| Next paid tier | Workers Paid $5/mo | Personal $9/mo, 1,000 credits | Pro $20/user/mo |
| **Commercial use on free** | allowed | allowed | **not allowed** |
**The Vercel line is the one that matters to a small business.** Vercel's own documentation states
that the Hobby plan "restricts users to non-commercial, personal use only." A business site on
Hobby is out of policy regardless of how little traffic it gets. Cloudflare Pages and Netlify have
no equivalent restriction on their free tiers. If you are shipping a business site and want to pay
nothing, that is a two-horse race.
Netlify has also moved to a **credit** model rather than published bandwidth and build-minute
allowances, so the old "100 GB and 300 build minutes" framing no longer describes it. Free is 300
credits, Personal is $9 a month for 1,000. The per-credit conversion is not on the pricing page,
so budget by watching your own first month rather than by arithmetic.
## Portable configuration
Write redirects and headers in the host's native file, but keep the *intent* in `DEPLOY.md` so a
migration is a translation rather than an archaeology project.
```
# Intent (translate per host)
/old-path /new-path 301
/api/* /.netlify/functions/:splat 200
Security headers on all HTML:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: FILL: start report-only, then enforce
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Cache:
/assets/* immutable, 1 year, content-hashed filenames
/*.html must-revalidate
```
## Pre-deploy gate, minimum contents
The gate is the whole reason a generated site stays trustworthy over time. Fail the build on any of:
1. Any meta description over 170 characters.
2. Any page with zero or more than one `
`.
3. Any `heroImage` or `og:image` path that does not exist on disk.
4. Any internal link to a URL not present in the build output.
5. Any JSON-LD block that does not parse.
6. Any `lastmod` in the sitemap later than today.
7. Any image without width and height attributes.
8. Any `outline: none` without an adjacent `:focus-visible` rule.
A gate that cannot find its target and passes anyway is worse than no gate. Make every "not found"
branch increment an error counter and exit non-zero.
## After deploy, before you believe it
- Compare the `ETag` against the pre-deploy value, or re-fetch until you see `Age: 0` with a new
`ETag`. Byte size alone is a weak signal, because a date-string swap is length-neutral.
- A host that prints "deploy is live" is telling you the upload finished, not that the CDN flipped.
- If a service worker is registered, a local audit harness can silently audit the **production**
copy instead of your build. Unregister it before measuring.
---
# 7. AGENTS.md stub
Put this at your project root so agents find the standards without being told.
```markdown
# AGENTS.md
## Standards this project follows
Read these before writing any code:
- `DESIGN.md` : visual system, tokens, motion. Presentation only.
- `SEO.md` : titles, descriptions, canonicals, sitemap truthfulness.
- `SCHEMA.md` : the @id entity graph and the one-page-node rule.
- `AEO.md` : llms.txt, markdown companions, AI crawler posture.
- `A11Y.md` : WCAG 2.2 AA. Non-negotiable. Overrides DESIGN.md on conflict.
- `DEPLOY.md` : build output, host config, the pre-deploy gate.
## Stack
FILL: e.g. Eleventy 3 + Nunjucks + vanilla JS. No frameworks, no bundler, no TypeScript.
## Do not
- Introduce a dependency without asking.
- Change routing, content, or markup semantics when the task is styling.
- Remove a focus indicator.
- Emit schema describing content that is not visible on the page.
- Report a check as passing without running it.
## Verify before claiming done
Run the checks in the VERIFY block of STANDARDS.md and paste the actual output.
```
---
# 8. VERIFY
Do not accept an agent's self-report. Every check below runs in a browser, needs no signup,
no API key, and no account. Append `?url=` and your address to run it directly.
**One-pass orchestrators**
| Check | Run it |
| --- | --- |
| Everything in one pass (10 panels: SEO, schema, E-E-A-T, voice, mobile, performance, accessibility, indexing, retrieval, plus a generated fix prompt) | `https://jwatte.com/tools/mega-analyzer/?url=` |
| Ranking authority, hygiene, AEO, performance, security, trust, compliance in seven parallel probes | `https://jwatte.com/tools/mega-seo-analyzer/?url=` |
| Ten AEO probes: schema, attribution, retrievability, freshness, accessibility, tokenizer, prompt injection, AI-bot meta, speakable | `https://jwatte.com/tools/mega-aeo-analyzer/?url=` |
| Ten local probes: NAP, LocalBusiness schema, service area, reviews, hyperlocal, hours, geo, multi-location, categories | `https://jwatte.com/tools/mega-geo-analyzer/?url=` |
| Seven security layers: TLS, post-quantum hybrid key exchange, HTTP security headers, SPF/DKIM/DMARC/CAA, CSP strictness, MITRE ATT&CK mapping | `https://jwatte.com/tools/mega-security-analyzer/?url=` |
| Up to 10 URLs side by side as a score matrix | `https://jwatte.com/tools/mega-batch/` |
**Targeted checks**
| Check | Run it |
| --- | --- |
| WCAG 2.1 + 2.2 AA, with critical AA failures separated from warnings | `https://jwatte.com/tools/wcag-accessibility-audit/?url=` |
| Schema completeness and JSON-LD graph linting | `https://jwatte.com/tools/schema-completeness/?url=` |
| FAQ schema parity against visible page text | `https://jwatte.com/tools/faq-schema-parity/?url=` |
| Sitemap `lastmod` truthfulness | `https://jwatte.com/tools/sitemap-lastmod-truthfulness/?url=` |
| Sitemap orphans and delta | `https://jwatte.com/tools/sitemap-audit/?url=` |
| llms.txt structural validation against the spec | `https://jwatte.com/tools/llms-txt-quality-scorer/?url=` |
| Agent-readiness of the whole domain | `https://jwatte.com/tools/agent-ready-audit/?url=` |
| E-E-A-T signal audit | `https://jwatte.com/tools/eeat-analyzer/?url=` |
| Readability and reading level | `https://jwatte.com/tools/readability-analyzer/?url=` |
Full catalog of 346 free tools, 266 audits, 43 generators and 37 utilities:
`https://jwatte.com/tools/`
**Manual checks no tool can do for you**
- Tab through the whole page with the mouse untouched. Can you reach and operate everything,
and can you always see where you are?
- Turn the page greyscale. Does anything stop making sense?
- Zoom to 200% and then set the browser to a 320px viewport. Does anything scroll sideways?
- Read the generated copy out loud. If you would not say it, do not ship it.
---
*Version 1.0, August 2026. Written by J.A. Watte, jwatte.com. Free to use, adapt and redistribute.
Standards and free-tier limits change; re-verify anything here before you rely on it.*