This repository was archived by the owner on May 29, 2026. It is now read-only.
feat(seo): AI-crawler baseline + content layer + validation gates#55
Merged
Conversation
…SON-LD, OG card) Conduction.nl was technically crawlable (SSG, no JS-rendering risk) but commercially invisible to AI agents: no robots.txt, no llms.txt, zero JSON-LD, no og:image, Dutch sitemap stale. This change ships the AI- crawling baseline so we get cited in ChatGPT/Claude/Perplexity answers and our content gets pulled into long-term training corpora — both, on purpose, posture documented in static/robots.txt. Changes - static/robots.txt — explicit allow for OAI-SearchBot, Claude-SearchBot, PerplexityBot, ChatGPT-User, Claude-User, GPTBot, ClaudeBot, CCBot and friends. Two Sitemap: lines (en + nl) for locale-suffix-blind crawlers. - static/llms.txt — llmstxt.org-format index pointing at the 15 shipping apps plus company/contact tells. Dev-tool consumers (Cursor, Aider, MCP doc servers) read this; AI-search adoption is thin but the cost is near zero. - docusaurus.config.js — wraps createConfig() return to inject Organization + WebSite JSON-LD via headTags[] on every page, sets themeConfig.image to the new OG card, and adds twitter:site / twitter:card / og:type baselines via themeConfig.metadata. Also adds sitemap options to the classic preset (changefreq, priority, ignore /academy/tags/** in both locales) so the sitemap is consistent across /sitemap.xml and /nl/sitemap.xml. - static/img/og-conduction.png — new 1200x630 brand OG card. Cobalt #4376FC background, point-up hex motif per brand rules, white wordmark, EUPL-1.2 / ISO 27001 / Made in Amsterdam tells. Out of scope (filed separately): SoftwareApplication JSON-LD per /apps/<slug> page, FAQPage schema on /support, fleet rollout to the 17 per-app docs sites and to the @conduction/docusaurus-preset. Verified: local production build emits both JSON-LD scripts in raw HTML on / and /apps/, og:image + twitter:* meta on every page, og:type stays 'article' on blog posts (not overridden), and both sitemap.xml + nl/sitemap.xml carry 67 URLs each with tag pages excluded.
Conduction writing rules ban em-dashes in published copy. robots.txt counts as published copy (served at conduction.nl/robots.txt and read by every AI crawler). Two em-dashes in the comment header replaced with a colon and a period.
CI now blocks any change that drops the AI-crawler baseline. The validation script runs as a postbuild step so every `npm run build` (local dev + CI) re-asserts the contract. Checks (12, all hard-fail) - robots.txt: exists, has Sitemap lines, allows OAI-SearchBot + Claude-SearchBot + PerplexityBot, has the default User-agent: * Allow: / block. - llms.txt: exists, >= 1 KB (catches an accidental placeholder). - sitemap.xml + nl/sitemap.xml: each emit >= 50 URLs. - Homepage: >= 2 JSON-LD blocks, every block valid JSON, includes Organization and WebSite @type entries. - Homepage: og:image, og:type, twitter:site, twitter:card meta tags present. og:image URL resolves to an actual file in the build (so LinkedIn / Slack / AI previews never render a 404). - /apps/openregister: has SoftwareApplication JSON-LD with applicationCategory and operatingSystem populated. This is the regression marker for the DetailHero schema emission that ships from @conduction/docusaurus-preset >= 3.4.0. Wiring - postbuild npm script runs scripts/validate-ai-baseline.mjs. - validate:ai-baseline npm script for ad-hoc runs. - @conduction/docusaurus-preset bumped to ^3.4.0 so the SoftwareApplication check has a guaranteed source. Adding a check: append to the CHECKS list in scripts/validate-ai-baseline.mjs. Keep the failure message specific so a CI annotation tells the reader exactly what regressed.
…locks PR 1 shipped @conduction/docusaurus-preset 3.4.0 with AI-baseline defaults (Organization JSON-LD, SoftwareApplication via DetailHero, FAQPage via FAQ, postBuild robots.txt fallback, og:image, twitter meta, sitemap options). This commit makes conduction.nl actually consume that baseline and adds the citation-friendly content layer on top. Changes - docusaurus.config.js: drop the hand-rolled headTags wrap, the inline Organization / WebSite JSON-LD constants, and the themeConfig.image / themeConfig.metadata overrides. All of it comes from createConfig() now. ~80 lines removed. - src/pages/apps/*.mdx (15 files): Wikipedia-style 1-paragraph lede injected immediately under <DetailHero/> on every shipping app page. Each lede follows the template "<Name> is an open-source <category> app for the Nextcloud workspace. <Capabilities.> <Distinguishing positioning.> Released under EUPL-1.2 and maintained by Conduction since 2019." Sourced from each app's own docs site / repo, then edited for brand voice (no em-dashes, one claim per sentence, concrete verbs). - src/pages/install.mdx: new 7-question FAQ block (admin install, Nextcloud version range, multi-app install, offline install, uninstall + data, missing-from-store, SLA / support). - src/pages/iso.mdx: new 6-question FAQ block (9001 vs 27001 scope, self-host coverage, BIO alignment, DigiD, commonground.nu stack, certificate request flow). - scripts/validate-ai-baseline.mjs: three more checks pin the FAQPage schema to >= 5 questions each on /support, /install, /iso. Hard-fail on regression. Validation now runs 15 checks total (was 12). Notes - /support already shipped a 6-question <FAQ>. Now that preset 3.4.0 emits FAQPage JSON-LD automatically, the existing block validates without any source change. - mydash README declares AGPL-3.0 while the lede template ends with EUPL-1.2. Filed as a follow-up to verify which is canonical; the lede currently says EUPL-1.2 to match brand positioning. - softwarecatalog has two readings in its docs (IT-asset management vs internal user-sync). The lede goes with the conduction.nl positioning (IT-asset management), which matches the existing tagline in apps-catalog.js.
The centralised ConductionNL/.github documentation workflow only builds on push, schedule, and workflow_dispatch. That meant a PR could drop robots.txt, break a sitemap, or remove SoftwareApplication JSON-LD without the validate-ai-baseline.mjs check ever running in CI. The defect lands; nightly cron catches it the next morning; production is already broken. This workflow runs npm run ci (= npm ci --legacy-peer-deps && npm run build) on every pull_request to development or documentation. The build's existing postbuild step runs the 15-check validator, which exits non-zero on regression. A follow-up explicit invocation acts as belt-and-braces in case anyone removes the postbuild hook. GITHUB_TOKEN is passed so the prebuild app-downloads fetch stays under the 60-req/hr unauthenticated rate limit (same pattern the centralised workflow uses).
This was referenced May 18, 2026
Merged
feat(docs): wire AI-crawler baseline (preset 3.4.0 + validator + llms.txt)
ConductionNL/decidesk#211
Merged
Merged
feat(docs): wire AI-crawler baseline (preset 3.4.0 + validator + llms.txt)
ConductionNL/pipelinq#365
Merged
feat(docs): wire AI-crawler baseline (preset 3.4.0 + validator + llms.txt)
ConductionNL/docudesk#182
Merged
feat(docs): wire AI-crawler baseline (preset 3.4.0 + validator + llms.txt)
ConductionNL/shillinq#140
Merged
Merged
Merged
feat(docs): wire AI-crawler baseline (preset 3.4.0 + validator + llms.txt)
ConductionNL/openbuilt#85
Merged
rubenvdlinde
added a commit
to ConductionNL/larpingapp
that referenced
this pull request
May 18, 2026
….txt) (#136) Matches the fleet rollout pattern from ConductionNL/conduction-website#55: - docs/package.json: @conduction/docusaurus-preset bumped from ^2.6.1 to ^3.4.0 (ships Organization + WebSite JSON-LD on every page, SoftwareApplication via <DetailHero>, FAQPage via <FAQ>, default og:image + twitter meta, postBuild robots.txt fallback). - docs/package.json scripts: postbuild npm hook runs the validator on every build, validate:ai-baseline alias for ad-hoc runs. - docs/scripts/validate-ai-baseline.mjs (new): generic 8-check validator. Asserts robots.txt + Sitemap, AI-bot allow lines, sitemap.xml, Organization + WebSite JSON-LD, og:image, twitter meta, og:image file resolves. Exits 1 on regression. - docs/static/llms.txt (new): llmstxt.org-format index. LarpingApp intro + docs link block + Conduction contact. CI gate runs via ConductionNL/.github documentation workflow on every PR (post that workflow's split-build-from-deploy change).
rubenvdlinde
added a commit
to ConductionNL/openconnector
that referenced
this pull request
May 18, 2026
….txt) (#776) Matches the fleet rollout pattern from ConductionNL/conduction-website#55: - docusaurus/package.json: @conduction/docusaurus-preset bumped from ^2.6.1 to ^3.4.0 (Organization + WebSite JSON-LD on every page, SoftwareApplication via <DetailHero>, FAQPage via <FAQ>, default og:image + twitter meta, postBuild robots.txt fallback). - docusaurus/package.json scripts: postbuild npm hook runs the validator on every build, validate:ai-baseline alias for ad-hoc runs. - docusaurus/scripts/validate-ai-baseline.mjs (new): generic 8-check validator. Exits 1 on regression. - docusaurus/static/llms.txt (new): llmstxt.org-format index with OpenConnector intro and docs link block. The Docusaurus site currently lives at `docusaurus/`. PR #690 is migrating it to `docs/`; when that lands these files will move with the rename. If conflicts arise during that migration, replay this commit on top of the new `docs/` location. CI gate runs via ConductionNL/.github documentation workflow on every PR (post that workflow's split-build-from-deploy change).
This was referenced May 18, 2026
rubenvdlinde
added a commit
that referenced
this pull request
May 18, 2026
PR #55 bumped @conduction/docusaurus-preset to ^3.4.0 in package.json without regenerating package-lock.json. CI uses `npm ci --legacy-peer-deps` which is strict about lockfile sync, so every Documentation workflow run on development since #55 merged has failed at the install step. The AI baseline never reached production. This commit: - Bumps the package.json range from ^3.4.0 to ^3.5.0 (the latest preset published — also matches what the rest of the fleet now uses). - Regenerates package-lock.json against the new range. - The cooldown rule in .npmrc (min-release-age=1) blocks fresh @conduction/* releases by default; this regen used --min-release-age=0 per the .npmrc comment. After this lands, the documentation workflow should install cleanly, the postbuild validate-ai-baseline check should pass, and the deploy job should publish the AI baseline (robots.txt, llms.txt, JSON-LD, og-conduction.png, sitemaps) to www.conduction.nl for the first time.
5 tasks
rubenvdlinde
added a commit
that referenced
this pull request
May 18, 2026
…k override) (#57) Companion to the AI-crawler baseline shipped in #55. Targets Google, Bing, DuckDuckGo, and the AI surfaces those engines feed. Title dedup (7 pages) - about, apps, demo, partners, sidecars, solutions, support: drop the ", Conduction" suffix from frontmatter title:. Docusaurus appends " | Conduction" automatically, so the prior frontmatter produced "Apps, Conduction | Conduction" in browser title + og:title + SERP. After: "Apps | Conduction" (clean). - index: tighten title from "Conduction, Public Tech for Nextcloud" to "Public Tech for Nextcloud" (still gets " | Conduction" appended). Trim meta description from 180 to ~157 chars so Google stops truncating in SERP. - /apps/<slug> pages left as-is: "OpenRegister, Conduction" reads as branding (made-by signal), not a typo, so the appended duplicate is acceptable. Preset 3.6.0 - Bump @conduction/docusaurus-preset to ^3.6.0 (companion preset PR ships sitemap lastmod, drops priority/changefreq, adds searchConsoleVerification opt, ships absolute www.conduction.nl defaults for footer legal links). - package-lock.json regenerated with --min-release-age=0 per .npmrc cooldown override. legalLinks override - conduction-website hosts /privacy, /terms, /iso itself, so we override the preset's new absolute defaults back to relative routes. Per-app subdomain sites inherit the absolute defaults (they don't have /privacy etc.) so those 645 sitewide broken internal links get fixed automatically on their next deploy. searchConsoleVerification scaffold - Commented-out placeholder in docusaurus.config.js. Once ops claims the property in Google Search Console / Bing Webmaster Tools, the tokens go here and the preset emits a meta tag per token.
4 tasks
This was referenced May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes conduction.nl AI-crawler-friendly across three layers, then locks the contract with a CI gate.
robots.txtallows every AI bot Conduction wants (citation and training), points at both locale sitemaps.llms.txtlists the 15 shipping apps with one-line descriptions for AI dev-tools. Both per-locale sitemaps emit clean URL sets./apps/<slug>page adds a SoftwareApplication block emitted by<DetailHero>with category-mappedapplicationCategoryandoperatingSystem: Nextcloud./support,/install,/isoeach ship a<FAQ>that auto-emits FAQPage JSON-LD.<DetailHero>on every shipping app page so AI fetchers extract a clean "what is this app" answer in plain text, not from a hero component. New OG card (1200x630, cobalt + point-up hex) so LinkedIn / Slack / AI previews don't render a 404.scripts/validate-ai-baseline.mjsruns as apostbuildstep on every build. 15 checks, hard-fail. Any future PR that drops the baseline gets blocked at CI time.Posture is open: we allow both citation and training. Documented at the top of
static/robots.txt; flipping any subset to Disallow is a one-line edit.What's in here
static/robots.txt,static/llms.txt,static/img/og-conduction.png(new files)docusaurus.config.js(PR 55 commit 1 wrapped with site-local JSON-LD; later commit drops the wrap once preset 3.4.0 ships the same defaults viaheadTags+themeConfig.image+themeConfig.metadata)@conduction/docusaurus-presetbumped to^3.4.0src/pages/apps/*.mdx(15 files): Wikipedia-style lede injected under<DetailHero>src/pages/install.mdx: new 7-question FAQ blocksrc/pages/iso.mdx: new 6-question FAQ blocksrc/pages/support.mdx: untouched; its existing 6-question<FAQ>now auto-emits FAQPage JSON-LD via preset 3.4.0scripts/validate-ai-baseline.mjs: 15-check hard-fail validator, wired aspostbuildCI gate (15 checks, all hard-fail)
Adding a check: append to the CHECKS list in
scripts/validate-ai-baseline.mjs. Keep the failure message specific so a CI annotation tells the reader exactly what regressed.Notes
appinfo/info.xmlor README only because the Nextcloud app store does not include EUPL in its license picker, so AGPL is the closest copyleft option there. Not a contradiction; both the marketing copy and the schema.orglicensefield carry EUPL-1.2.Test plan
/robots.txt,/llms.txt, view-source of/,/apps/openregister,/support,/install,/isoto confirm JSON-LD blockshttps://search.google.com/test/rich-resultsvalidates Organization + WebSite on/https://validator.schema.org/validates SoftwareApplication on/apps/openregisterhttps://validator.schema.org/validates FAQPage on/support,/install,/iso