Add a FAQs section to a ProstDev post
FAQs are an OPTIONAL faqs frontmatter array on a post's .mdx, rendered as a ## FAQs
disclosure section (by Faqs.astro), mirrored in the .md/llms endpoint, AND emitted as
FAQPage JSON-LD — a machine-readable answer-engine signal (for ChatGPT / Perplexity /
Copilot-style crawlers + the .md/llms.txt surface). NOTE: Google fully deprecated the FAQ rich
result in May 2026, and its AI experiences (AI Overviews / AI Mode / Gemini) read the visible page
text from the regular index, NOT the JSON-LD — so for Google/Gemini the win is the rendered ## FAQs section, and the JSON-LD is the bonus for non-Google engines. Blog posts are the site's AEO
surface, so explicit, well-phrased Q&A in the visible text is a direct AEO win. Same plumbing shape as reader notes
(optional array → component OUTSIDE .prose → .md block), but EDITORIAL, not preserved Wix
content. Full detail → .claude/docs/content-authoring.md (the FAQs convention). See [[add-post]]
for the full post schema and [[add-comment]] for the sibling per-post editor (reader notes).
Steps
Identify the post + READ IT. src/content/blog/<slug>.mdx. You must read the body — every
answer has to be grounded in what the post ACTUALLY says (next step). Append to an existing
faqs: block or create one after tags: (placement in frontmatter doesn't matter; convention is
after readerNotes/tags, before draft).
HARD RULE — answers are GROUNDED IN THE POST BODY, never fabricated. Ask the question a real
reader would ask about this post, and answer it from what the post already states. Do NOT add
outside facts, version numbers, or claims the post doesn't make. If the post doesn't answer a
question you'd like to include, drop the question — don't invent an answer. 3–6 Q&A is plenty.
Phrase questions naturally ("How do I…", "What's the difference between…", "Why does…") — that's
what AEO matches against.
Add the entries (schema in src/content.config.ts):
faqs:
- question: "What is the difference between On-Error Propagate and On-Error Continue?"
answer: "On-Error Propagate re-throws the error to the parent flow; On-Error Continue handles it and lets the flow finish. The `try` scope examples above show each behavior."
- question: "Where can I read the official reference?"
answer: "See the MuleSoft docs at https://docs.mulesoft.com for the full error-handling reference."
- Both
question and answer are required strings.
answer is INLINE PROSE ONLY — it may contain `code` chips and bare https://… URLs
(autolinked by the component, new tab + external icon, same as reader notes), but NO block
elements: no bulleted lists, no fenced code blocks, no headings. A clean single paragraph
keeps the FAQPage JSON-LD acceptedAnswer.text valid. Need to enumerate? Write it as a
sentence ("first X, then Y, finally Z"), not a list.
YAML safety. question:/answer: are quoted YAML strings, so quote the value ("…") and
escape an inner " as \". A literal : mid-sentence is fine inside quotes. A raw < is fine
INSIDE a YAML string, but write XML/config tag names in backticks (`<provider>`) so they
render as a code chip rather than plain text.
- Escape only the INNER quotes, never the OUTER pair.
answer: "… \"STRICT\" …" is correct;
answer: \"…\" (outer pair escaped) is the trap — YAML reads it as a PLAIN scalar starting with
a literal \, the build PASSES, and the page/JSON-LD render visible \"…\" backslashes. Grep
grep -rn ': \\"' src/content/blog/*.mdx to catch it (an outer escape always follows : ).
Verify with a build. npm run build from the repo root — a YAML/schema error names the file.
The build does NOT catch a render-quality defect that's still valid YAML (e.g. the outer-escape
trap above, or a stray block element) — so after a BATCH pass also grep the source: outer escapes
(: \\"), and confirm every question ends in ?. Then optionally npm run preview and open
/post/<slug>:
- the
## FAQs disclosures render after the body / reader notes, before the tags (both themes,
keyboard-operable, focus ring visible);
- view source → a
<script type="application/ld+json"> with "@type":"FAQPage" and a
"@type":"Question" per pair;
curl -s localhost:4321/post/<slug>.md → the trailing ## FAQs block (### question + answer).
Notes
- The EDIT here is to a SITE file (
src/content/blog/<slug>.mdx) — a one-commit change in the
PUBLIC repo, and only when the user explicitly asks. (Editing THIS skill is the internal
two-commit submodule case.)
- A post with no
faqs renders nothing — the section, JSON-LD, and .md block are all guarded on
faqs.length, so adding the field to one post never touches the others.
- Infra shipped June 2026 with ZERO posts seeded — FAQs are added per-post on demand via this skill,
not batch-generated.
1---2name: add-faqs3description: Add a FAQs section to the end of a ProstDev blog post for AEO. Use when the user wants to add or update frequently-asked questions / Q&A on a post (the "add FAQs", "FAQ section", "AEO Q&A" ask). Writes an optional `faqs` frontmatter array — answers GROUNDED in the post body, never fabricated — that renders a `## FAQs` section, mirrors into the `.md` endpoint, and emits FAQPage JSON-LD. Verifies with a build.4---56# Add a FAQs section to a ProstDev post78FAQs are an OPTIONAL `faqs` frontmatter array on a post's `.mdx`, rendered as a `## FAQs`9disclosure section (by `Faqs.astro`), mirrored in the `.md`/llms endpoint, AND emitted as10**`FAQPage` JSON-LD** — a machine-readable answer-engine signal (for ChatGPT / Perplexity /11Copilot-style crawlers + the `.md`/`llms.txt` surface). NOTE: Google fully deprecated the FAQ rich12result in May 2026, and its AI experiences (AI Overviews / AI Mode / Gemini) read the *visible page13text* from the regular index, NOT the JSON-LD — so for Google/Gemini the win is the rendered `##14FAQs` section, and the JSON-LD is the bonus for non-Google engines. Blog posts are the site's AEO15surface, so explicit, well-phrased Q&A in the visible text is a direct AEO win. Same plumbing shape as reader notes16(optional array → component OUTSIDE `.prose` → `.md` block), but EDITORIAL, not preserved Wix17content. Full detail → `.claude/docs/content-authoring.md` (the FAQs convention). See [[add-post]]18for the full post schema and [[add-comment]] for the sibling per-post editor (reader notes).1920## Steps21221. **Identify the post + READ IT.** `src/content/blog/<slug>.mdx`. You must read the body — every23 answer has to be grounded in what the post ACTUALLY says (next step). Append to an existing24 `faqs:` block or create one after `tags:` (placement in frontmatter doesn't matter; convention is25 after `readerNotes`/`tags`, before `draft`).26272. **HARD RULE — answers are GROUNDED IN THE POST BODY, never fabricated.** Ask the question a real28 reader would ask about this post, and answer it from what the post already states. Do NOT add29 outside facts, version numbers, or claims the post doesn't make. If the post doesn't answer a30 question you'd like to include, drop the question — don't invent an answer. **3–6 Q&A is plenty.**31 Phrase questions naturally ("How do I…", "What's the difference between…", "Why does…") — that's32 what AEO matches against.33343. **Add the entries** (schema in `src/content.config.ts`):3536 ```yaml37 faqs:38 - question: "What is the difference between On-Error Propagate and On-Error Continue?"39 answer: "On-Error Propagate re-throws the error to the parent flow; On-Error Continue handles it and lets the flow finish. The `try` scope examples above show each behavior."40 - question: "Where can I read the official reference?"41 answer: "See the MuleSoft docs at https://docs.mulesoft.com for the full error-handling reference."42 ```4344 - Both `question` and `answer` are required strings.45 - **`answer` is INLINE PROSE ONLY** — it may contain `` `code` `` chips and bare `https://…` URLs46 (autolinked by the component, new tab + external icon, same as reader notes), but **NO block47 elements**: no bulleted lists, no fenced code blocks, no headings. A clean single paragraph48 keeps the `FAQPage` JSON-LD `acceptedAnswer.text` valid. Need to enumerate? Write it as a49 sentence ("first X, then Y, finally Z"), not a list.50514. **YAML safety.** `question:`/`answer:` are quoted YAML strings, so quote the value (`"…"`) and52 escape an inner `"` as `\"`. A literal `:` mid-sentence is fine inside quotes. A raw `<` is fine53 INSIDE a YAML string, but write XML/config tag names in backticks (`` `<provider>` ``) so they54 render as a code chip rather than plain text.55 - **Escape only the INNER quotes, never the OUTER pair.** `answer: "… \"STRICT\" …"` is correct;56 `answer: \"…\"` (outer pair escaped) is the trap — YAML reads it as a PLAIN scalar starting with57 a literal `\`, the build PASSES, and the page/JSON-LD render visible `\"…\"` backslashes. Grep58 `grep -rn ': \\"' src/content/blog/*.mdx` to catch it (an outer escape always follows `: `).59605. **Verify with a build.** `npm run build` from the repo root — a YAML/schema error names the file.61 The build does NOT catch a render-quality defect that's still valid YAML (e.g. the outer-escape62 trap above, or a stray block element) — so after a BATCH pass also grep the source: outer escapes63 (`: \\"`), and confirm every question ends in `?`. Then optionally `npm run preview` and open64 `/post/<slug>`:65 - the `## FAQs` disclosures render after the body / reader notes, before the tags (both themes,66 keyboard-operable, focus ring visible);67 - view source → a `<script type="application/ld+json">` with `"@type":"FAQPage"` and a68 `"@type":"Question"` per pair;69 - `curl -s localhost:4321/post/<slug>.md` → the trailing `## FAQs` block (`### question` + answer).7071## Notes7273- The EDIT here is to a SITE file (`src/content/blog/<slug>.mdx`) — a one-commit change in the74 PUBLIC repo, and only when the user explicitly asks. (Editing THIS skill is the internal75 two-commit submodule case.)76- A post with no `faqs` renders nothing — the section, JSON-LD, and `.md` block are all guarded on77 `faqs.length`, so adding the field to one post never touches the others.78- Infra shipped June 2026 with ZERO posts seeded — FAQs are added per-post on demand via this skill,79 not batch-generated.