Docs Frontmatter
Shoehorn parses an optional YAML frontmatter block at the top of every Markdown document it ingests. Frontmatter lets you tag a doc with a category, override the title and description shown in the Docs Hub, and link the doc to specific catalog entities.
If a doc has no frontmatter, it is still indexed and searchable. It just won’t appear in the Docs Hub category filters.
Format
Section titled “Format”A frontmatter block is fenced by --- lines and must be the very first thing in the file:
---category: runbooktitle: "Payment Service: Failed Charge Recovery"description: "How to recover stuck charges when Stripe webhooks fail."related_entities: - payments-api - billing-worker---
When a webhook delivery from Stripe fails...Rules:
- The opening
---must be on the first line of the file. - The closing
---must be on its own line. - Body content begins on the line after the closing fence.
- All fields are optional. A missing or empty field is simply ignored.
- A malformed YAML block is logged and treated as “no frontmatter”. Your doc still gets indexed, it just won’t have frontmatter-driven metadata.
Supported Fields
Section titled “Supported Fields”| Field | Type | Purpose |
|---|---|---|
category | string | Groups the doc under a chip in the Docs Hub category strip. |
title | string | Overrides the auto-detected title (otherwise the first # H1 is used). |
description | string | Card subtitle in the Docs Hub and search snippets. |
related_entities | string list | Links the doc to one or more catalog entities. |
category
Section titled “category”The category becomes a filterable chip in the Docs Hub. Categories are dynamic: any value you write becomes a chip, you don’t need to pre-register it.
Categories are normalized before indexing:
- Trimmed and lowercased (so
Runbook,runbook, andRUNBOOKall collapse torunbook). - Allowed characters: ASCII letters, digits, and
. _ / -. - Maximum length: 64 characters.
- Values starting with
_are reserved (used internally for the “Other” overflow chip) and will be dropped.
If a category fails normalization (e.g. contains spaces, emoji, or non-ASCII characters), the doc is indexed without a category and won’t appear in any category filter.
Reserved category labels
Section titled “Reserved category labels”These slugs ship with built-in translated labels and reserved colors. You can still use any other slug you like. It just won’t get a curated label.
| Slug | Label |
|---|---|
onboarding | Onboarding |
runbook | Runbooks |
architecture | Architecture |
api | API |
security | Security |
Sets the document title in the Docs Hub card, search results, and entity Documentation tab. If omitted, Shoehorn falls back to the first # H1 in the body.
description
Section titled “description”A short blurb shown as the card subtitle in the Docs Hub and as the snippet in search results. Aim for one sentence (under ~160 characters).
If omitted, Shoehorn auto-generates a summary from the first paragraph of the body.
related_entities
Section titled “related_entities”A list of catalog entity names that the doc relates to. Use the entity’s slug (the same name shown in the catalog), one per line. Inline list form ([payments-api, billing-worker]) also works.
Related entities are surfaced:
- On the doc card in the Docs Hub (as small entity chips)
- In the entity’s Documentation tab (so the doc appears even if it lives in another repository)
Where Frontmatter Is Parsed
Section titled “Where Frontmatter Is Parsed”Frontmatter is extracted from Markdown sources Shoehorn ingests:
- READMEs discovered in repositories
- Runbook files referenced from manifests or annotations
- Changelogs
- Doc-site Markdown crawled by the docs crawler
After extraction, the frontmatter block is stripped from the body before rendering, so it never appears as raw text in the rendered doc.
Examples
Section titled “Examples”Onboarding doc with explicit title
Section titled “Onboarding doc with explicit title”---category: onboardingtitle: "New-Hire Setup: Local Dev Environment"description: "Get a local checkout building and tests passing in under 30 minutes."---Runbook linked to multiple services
Section titled “Runbook linked to multiple services”---category: runbooktitle: "Recover from Redis Eviction Storm"description: "Steps for the on-call to clear runaway Redis evictions."related_entities: - cart-api - session-store - checkout---Custom category
Section titled “Custom category”---category: post-mortemtitle: "2026-03-14 Checkout Outage"description: "Root-cause analysis for the 47-minute checkout outage on Pi Day."---The post-mortem chip will appear in the Docs Hub alongside the built-in chips.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause |
|---|---|
| Doc isn’t filtered under your category chip | Category contains disallowed characters (spaces, emoji, non-ASCII), normalize to ASCII slug. |
| Frontmatter rendered as text in the doc body | Opening --- isn’t on the very first line, or the closing fence is missing. |
| Doc has no description / wrong title in the Hub | YAML parse error, Shoehorn logged a warning and fell back to body-only. Validate the YAML block. |
| Related entities don’t show up | Entity reference doesn’t match a catalog entity, or the kind/name pair is wrong. |
Security Notes
Section titled “Security Notes”The category slug is used in downstream search filters, so the parser enforces a strict ASCII allowlist as defense-in-depth against filter injection. This is why category values are limited to letters, digits, and . _ / -, it is intentional and won’t be loosened.