🚢 Shipwreck Supply Co.
A store that sank on purpose, so the gribbles have something to chew on.
Shipwreck is the deliberately broken example website for Gribble, the AI website audit agent. It is three things at once:
- An integration test. Every page carries known defects, catalogued in
HOLES.md.pnpm evalruns a gate audit and scores what Gribble found against that list. - An evaluation set. Change a prompt, swap a model, tweak a rule: run it here and read the recall and the false positives before you believe the change.
- A demo. It is a small, real-looking SvelteKit store with a catalog, product pages, a cart, a checkout that never quite checks out, a ship's log and a contact form. Broken in about sixty documented ways.
The metaphor is doing a lot of work here. A gribble is a tiny marine isopod that bores into ship hulls from places nobody looks. A shipwreck is what you get when nobody looked. We built the wreck so that we could count the holes.
pnpm install
pnpm exec playwright install --with-deps chromium # the browser Gribble drives
pnpm dev # the store on http://localhost:5173
pnpm build && pnpm preview # the production build on http://localhost:4173The site is fully prerendered by @sveltejs/adapter-static. The cart lives in localStorage; there
is no backend, which is why the checkout is a dead end and the stock endpoint answers 404.
Both of those are on the list.
pnpm audit:gate # deterministic checks, no model needed, about two minutes
pnpm audit:review # the AI reviewer walks .gribble/flows/*.md (needs model credentials)
pnpm eval # build, gate audit, then score the report against HOLES.mdgribble.yaml starts pnpm preview for you and points Gribble at the production build.
Review mode uses pi's stored credentials (reusePiAuth: true); run pnpm exec gribble login
if you have none.
pnpm eval (or pnpm eval:report for an existing .gribble/runs/latest.json) prints recall per
category, the holes that were missed, and every finding that matches no planted hole. Those last
ones are the interesting part: either the site has a hole we did not know about, or Gribble is
seeing things. Both get written up.
Recall per category
a11y 8/8 100.0%
links 5/5 100.0%
...
Gate recall: 50/52 (96.2%)
Missed holes (2)
P3 perf/image-format / The hero is a JPEG that would be a fraction of the size as WebP or AVIF.
The exit code is 1 when gate recall drops below the threshold (--min-recall, default 0.9), so the
Evaluate workflow fails when a Gribble change starts missing holes it used to find.
Roughly sixty holes across every rule family Gribble implements: broken and empty links, failed
requests, console errors, a 2.6 MB hero, layout shift, missing and duplicate titles, two h1s,
skipped headings, an accidental noindex, a page with no lang, unlabeled fields, nameless
buttons, low contrast, small touch targets, overlapping buttons, horizontal overflow, lorem ipsum
and TODOs, leaked translation keys, a Stripe secret in an inline script, duplicate ids, a layout
that forgot the viewport meta, a checkout flow that fails at the last step, and copy that breaks
the store's own guidelines. Plus a handful of things that look wrong and
are not, to keep the false-positive count honest.
The catalogue is HOLES.md. It is dry on purpose. The jokes live here and on the site;
the ground truth does not get to be funny.
src/routes/(shop)/ the store, with header, footer and viewport meta
src/routes/(bare)/ a "focused" layout that forgot the viewport meta and the navigation
src/lib/ products, posts, the cart store, the language map
static/ images, robots.txt, a sitemap that misses a few routes
.gribble/ gribble.yaml, rules.yaml, guidelines.md, flows/ and the committed baseline
scripts/evaluate.mjs the scorer
HOLES.md the ground truth
EVAL-NOTES.md run history and Gribble bugs found while building this
- Plant it in the site. Keep the rest of the page clean; one hole per element.
- Add a row to
HOLES.mdwith the rule, the route, amatchstring and whether gate or review is expected to catch it. - Run
pnpm eval. If Gribble misses it and the rule is implemented, that is a Gribble bug: write it up inEVAL-NOTES.mdrather than bending the site until it passes.
MIT. Salvage freely.