Pagefind lands on the ai-labs splash — search across the four-repo rollup
The skill says every splash ships search-by-default and I had quietly demoted it to a follow-up. Caught. Pagefind is now wired: header popover with `/` shortcut, full `/search/` page, three filter facets (kind / from / tag), and the UI tokenized to the splash's three-mode contract. 38 detail pages indexed across ai-labs and its three children.
Why Care?
The maintain-splash-pages skill is explicit: every splash ships search-by-default. It cites Pagefind specifically — confirmed twice already in memopop-site and lfm/splash — and lists it as a v1 acceptance criterion, not a follow-up. When the ai-labs splash went live earlier tonight, I'd quietly relegated Pagefind to a "follow-up" in the changelog entry. The user caught that and called it out: the skill says it's part of v1. Fair. This entry closes the gap.
What landed: a header search box that opens a popover, a full /search/ page with autofocus and a literate intro, a global / keyboard shortcut, and data-pagefind-body markers on every changelog and context-v detail page. The Pagefind UI's CSS variables map to the splash's semantic tokens so search inherits the dark/light/vibrant mode pivot. Three filter facets (kind:, from:, tag:) let a reader scope by document type, source repo, or topic.
For a pseudomonorepo splash that rolls up four repos (ai-labs itself plus context-vigilance-kit, memopop-ai, dididecks-ai), the from: facet is the load-bearing one — a reader interested in just the MemoPop work can filter to it without needing to remember which entries came from where.
What's New?
SearchBox.astroatsplash/src/components/. Two variants:compact(a<details>popover triggered from the header) andfull(a permanent panel used on/search/). Both mount the Pagefind UI bundle. Lifted fromlfm/splashwith one substantive adaptation — see below./search/page atsplash/src/pages/search.astro. Full SearchBox with autofocus, a short literate intro, a hint about the dev-vs-build index discrepancy.Pagefind integration in
splash/astro.config.mjs—pagefind()runs afterastro buildand copies the static index intodist/pagefind/.build.format: 'directory'was already set (Pagefind needs stable per-page URLs).data-pagefind-body+ filter spans onchangelog/[...slug].astroandcontext-v/[...slug].astro. Each detail page now carries hidden filter spans forkind,from, and anytagvalue. Theentry-head__metarow + back-link + tag chips are wrapped indata-pagefind-ignoreso the indexed body is the article content, not the chrome.data-pagefind-ignore="all"on the<ul>lists inchangelog/index.astroandcontext-v/index.astroso list teasers don't compete with detail-page entries for the same query.Header gets
<SearchBox compact />in the actions area + aSearchnav link. Mounts to the right of the brand, opens a 380px popover, dismisses on outside-click, focusable via/from anywhere.Pagefind UI tokenized via CSS variables —
--pagefind-ui-primary→--color-accent, etc. — so the search UI pivots through the splash's three modes (dark/light/vibrant) with the rest of the page.Deps:
astro-pagefind@^1.8.6+pagefind@^1.5.2added tosplash/package.json, lockfile updated.
The one substantive adaptation from the lfm/splash crib
lfm/splash is a single-project splash (one repo, no submodules). Its filter facets are kind:Changelog | kind:Context + tag:<value>. That works because every entry is from the same source.
ai-labs is a pseudomonorepo splash. Every changelog and context-v entry carries provenance — from (which peer) and from_path (where in that peer's tree) — stamped at rollup time. The skill says explicitly: pseudomonorepos add a third facet: from:<peer>. So the detail pages here emit a <span data-pagefind-filter="from:${from}" hidden> alongside the kind: and tag: spans. A reader interested in only the context-vigilance-kit corner can filter to from:context-vigilance-kit and search just that slice.
The from value is the same provenance value already shown as the pill at the top of every detail card (rendered visibly via <span class="pill pill--accent">{from}</span>), so the filter taxonomy matches what a reader can see on the page.
Verification
Clean build:
$ rm -rf dist && pnpm build
... 42 page(s) built in 2.25s
[pagefind] Pagefind indexed 42 pages
[pagefind] Pagefind wrote index to dist/pagefind
$ cat dist/pagefind/pagefind-entry.json | head -5
{"version":"1.5.2","languages":{"en":{"hash":"en_3dbbe946ce","wasm":"en","page_count":38}}}The 42 / 38 split is the right shape: 42 routes total in the build, 38 have data-pagefind-body (every changelog detail page + every context-v detail page). The four non-indexed routes are the home, /search/, /changelog/ index, and /context-v/ index — none should appear in search results because their content is the same content the detail pages already index.
$ grep -c "data-pagefind-body" dist/changelog/2026-05-11_02/index.html
1
$ grep -c "data-pagefind-ignore" dist/changelog/index.html
1After deploy: confirm the search box renders in the header, opens on click and on / keypress, returns results when you type "Pagefind" or "splash" or "context", and that kind:, from:, and tag: filters appear once a query has results.
What's still incomplete versus the skill
Two gaps remain after this entry:
/llms.txt+/llms-full.txtendpoints. The children both serve these now (context-vigilance-kit since 2026-05-09, memopop-ai since 2026-05-11). The mechanical port for the ai-labs splash takes about an hour — copy the two endpoint files from CVK, copy thesrc/llms/*.mdsource-of-truth templates, adapt for two collections vs. one, register a CHANGELOG_INDEX + CONTEXTV_INDEX token map. The sitemap filter inastro.config.mjsis already forward-looking — it excludes/llms.txtand/llms-full.txtfrom sitemap generation, so the endpoint can land without further config changes.SortControlson/changelog/and/context-v/list pages. The skill specifies server-pre-sorted default (date_modifieddesc), per-pagelocalStoragepersistence, and a JS-driven re-order on<li>data-sort-* attributes. Lift verbatim fromlfm/splash/src/components/SortControls.astrowhen prioritized.
Neither is a deploy blocker.
What I learned
When the skill says "v1" about a particular component, treat it as v1 — don't quietly demote it to a follow-up just because the rest of the surface already works. The skill exists precisely so future-me doesn't have to rediscover that Pagefind is the search engine of choice, that the data-pagefind-body silent-opt-out gotcha exists, and that the Pagefind UI's CSS variables are the integration seam for theming. The lift from lfm/splash took longer to justify deferring than it would have to just do in the first place.
The user catching it as quickly as they did — within an hour of the "live!!!!!" celebration — is the right velocity for this kind of correction. Skill-driven conventions are a backstop, not optional polish.
Related
The skill:
lossless-skills/skills/maintain-splash-pages.md. Specifically the Search — Pagefind by default section and the acceptance checklist'sSearch returns results when typing into the header popover or /search pageline.The exploration that named Pagefind:
astro-knots/context-v/explorations/Implementing-Full-Text-Search-by-Default.md.Reference impls cribbed from:
lfm/splash/src/components/SearchBox.astro(latest),ai-labs/memopop-ai/apps/memopop-site/src/components/SearchBox.astro(first instance),ai-labs/context-vigilance-kit/splash/src/components/SearchBox.astro(sibling).Yesterday's Pages deploy entry:
2026-05-11_02.md— which incorrectly listed Pagefind as a follow-up. This entry is the correction.
