@shoalrun/cli 0.0.0-stage → 0.1.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORING.md +269 -0
- package/CHANGELOG.md +82 -0
- package/LICENSE +202 -0
- package/README.md +189 -2
- package/agent-docs/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt +33 -0
- package/agent-docs/.well-known/shoalrun/navigation/docs-50f26fe22670.txt +24 -0
- package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +9 -0
- package/agent-docs/SNAPSHOT.json +9 -0
- package/agent-docs/about.md +49 -0
- package/agent-docs/api-docs/focused-contracts.md +68 -0
- package/agent-docs/api-docs/generate.md +189 -0
- package/agent-docs/api-docs/generate.sections/add-useful-examples.md +47 -0
- package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +50 -0
- package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +52 -0
- package/agent-docs/api-docs/generate.sections/generate-many-pages-selectively.md +71 -0
- package/agent-docs/api-docs/generate.sections/link-guides-to-api-references.md +48 -0
- package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +52 -0
- package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +60 -0
- package/agent-docs/api-docs/generate.sections/related-reading.md +38 -0
- package/agent-docs/api-docs/generate.sections/use-a-template-for-editorial-context.md +45 -0
- package/agent-docs/api-docs/support.md +97 -0
- package/agent-docs/author/add-page.md +124 -0
- package/agent-docs/author/agent-overview.md +59 -0
- package/agent-docs/author/agent-workflow.md +65 -0
- package/agent-docs/author/agents.md +53 -0
- package/agent-docs/author/analytics.md +286 -0
- package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +51 -0
- package/agent-docs/author/analytics.sections/built-in-events.md +52 -0
- package/agent-docs/author/analytics.sections/configure-an-adapter.md +51 -0
- package/agent-docs/author/analytics.sections/custom-interactions.md +57 -0
- package/agent-docs/author/analytics.sections/event-format.md +59 -0
- package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +42 -0
- package/agent-docs/author/analytics.sections/inspect-events-locally.md +36 -0
- package/agent-docs/author/analytics.sections/map-events-to-your-service.md +42 -0
- package/agent-docs/author/analytics.sections/posthog-example.md +126 -0
- package/agent-docs/author/analytics.sections/related-reading.md +42 -0
- package/agent-docs/author/authoring-agent.md +102 -0
- package/agent-docs/author/coding-agent.md +90 -0
- package/agent-docs/author/components/action-link.md +41 -0
- package/agent-docs/author/components/api-embeds.md +263 -0
- package/agent-docs/author/components/api-embeds.sections/apiexample.md +117 -0
- package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +37 -0
- package/agent-docs/author/components/api-embeds.sections/related-reading.md +37 -0
- package/agent-docs/author/components/badge.md +76 -0
- package/agent-docs/author/components/breadcrumbs.md +57 -0
- package/agent-docs/author/components/callout.md +131 -0
- package/agent-docs/author/components/cards.md +168 -0
- package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +50 -0
- package/agent-docs/author/components/cards.sections/build-a-collection.md +69 -0
- package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +66 -0
- package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +37 -0
- package/agent-docs/author/components/cards.sections/link-to-one-document.md +45 -0
- package/agent-docs/author/components/cards.sections/override-card-text.md +58 -0
- package/agent-docs/author/components/cards.sections/related-reading.md +43 -0
- package/agent-docs/author/components/code-blocks.md +117 -0
- package/agent-docs/author/components/collapsible.md +99 -0
- package/agent-docs/author/components/cookbook-chooser.md +86 -0
- package/agent-docs/author/components/custom/react.md +190 -0
- package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +36 -0
- package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +88 -0
- package/agent-docs/author/components/custom/react.sections/registration.md +41 -0
- package/agent-docs/author/components/custom/react.sections/related-reading.md +30 -0
- package/agent-docs/author/components/custom/react.sections/share-the-model-with-the-browser.md +47 -0
- package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +100 -0
- package/agent-docs/author/components/custom.md +183 -0
- package/agent-docs/author/components/definition-list.md +54 -0
- package/agent-docs/author/components/diagrams/d2-gallery.md +861 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/basic-shapes.md +163 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/flows-and-structures.md +375 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md +33 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/layout-engines.md +169 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/related-reading.md +37 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md +123 -0
- package/agent-docs/author/components/diagrams/d2-gallery.sections/styles-and-code.md +125 -0
- package/agent-docs/author/components/diagrams/pele-gallery.md +1317 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/charts-and-planning.md +341 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md +269 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md +273 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md +31 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/related-reading.md +35 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md +229 -0
- package/agent-docs/author/components/diagrams/pele-gallery.sections/systems-and-structures.md +291 -0
- package/agent-docs/author/components/diagrams.md +155 -0
- package/agent-docs/author/components/doc-link.md +58 -0
- package/agent-docs/author/components/fields.md +121 -0
- package/agent-docs/author/components/file-tree.md +84 -0
- package/agent-docs/author/components/images.md +103 -0
- package/agent-docs/author/components/info-hint.md +61 -0
- package/agent-docs/author/components/kbd.md +45 -0
- package/agent-docs/author/components/math.md +39 -0
- package/agent-docs/author/components/only.md +65 -0
- package/agent-docs/author/components/progress.md +53 -0
- package/agent-docs/author/components/related-reading.md +48 -0
- package/agent-docs/author/components/steps.md +121 -0
- package/agent-docs/author/components/tables.md +64 -0
- package/agent-docs/author/components/tabs.md +129 -0
- package/agent-docs/author/components/timeline.md +74 -0
- package/agent-docs/author/components/tooltips.md +58 -0
- package/agent-docs/author/components/walkthroughs.md +390 -0
- package/agent-docs/author/components/walkthroughs.sections/attributes.md +45 -0
- package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +133 -0
- package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +141 -0
- package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +126 -0
- package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +38 -0
- package/agent-docs/author/components/walkthroughs.sections/related-reading.md +36 -0
- package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +53 -0
- package/agent-docs/author/components.md +78 -0
- package/agent-docs/author/content.md +74 -0
- package/agent-docs/author/cookbooks.md +119 -0
- package/agent-docs/author/css.md +238 -0
- package/agent-docs/author/css.sections/borders-fields-and-navigation-tokens.md +70 -0
- package/agent-docs/author/css.sections/core-color-tokens.md +71 -0
- package/agent-docs/author/css.sections/page-attributes.md +69 -0
- package/agent-docs/author/css.sections/page-transitions.md +60 -0
- package/agent-docs/author/css.sections/responsive-behavior.md +58 -0
- package/agent-docs/author/css.sections/status-code-and-callout-tokens.md +89 -0
- package/agent-docs/author/css.sections/typography-shape-and-width-tokens.md +71 -0
- package/agent-docs/author/custom-metadata.md +177 -0
- package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +68 -0
- package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +54 -0
- package/agent-docs/author/custom-metadata.sections/preview-changes-to-metadata-providers.md +33 -0
- package/agent-docs/author/custom-metadata.sections/read-metadata-from-a-project-module.md +57 -0
- package/agent-docs/author/custom-metadata.sections/related-reading.md +29 -0
- package/agent-docs/author/design-templates.md +49 -0
- package/agent-docs/author/design-writing-guides.md +73 -0
- package/agent-docs/author/frontmatter-reference.md +146 -0
- package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +44 -0
- package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +41 -0
- package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +31 -0
- package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +40 -0
- package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +37 -0
- package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +41 -0
- package/agent-docs/author/frontmatter-reference.sections/related-reading.md +35 -0
- package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +33 -0
- package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +31 -0
- package/agent-docs/author/frontmatter.md +255 -0
- package/agent-docs/author/frontmatter.sections/audience-badges.md +66 -0
- package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +88 -0
- package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +75 -0
- package/agent-docs/author/frontmatter.sections/optional-native-fields.md +90 -0
- package/agent-docs/author/frontmatter.sections/publication-fields.md +85 -0
- package/agent-docs/author/frontmatter.sections/publishing-policy.md +71 -0
- package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +72 -0
- package/agent-docs/author/frontmatter.sections/related-reading.md +72 -0
- package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +84 -0
- package/agent-docs/author/frontmatter.sections/seo-fields.md +79 -0
- package/agent-docs/author/frontmatter.sections/validation-rules.md +75 -0
- package/agent-docs/author/markdown-metadata.md +207 -0
- package/agent-docs/author/navigation.md +269 -0
- package/agent-docs/author/navigation.sections/arrange-authored-pages.md +58 -0
- package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +48 -0
- package/agent-docs/author/navigation.sections/hide-group-page-counts.md +45 -0
- package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +40 -0
- package/agent-docs/author/navigation.sections/local-api-preview.md +47 -0
- package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +65 -0
- package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +97 -0
- package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +38 -0
- package/agent-docs/author/navigation.sections/related-reading.md +44 -0
- package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +67 -0
- package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +42 -0
- package/agent-docs/author/reader-views.md +200 -0
- package/agent-docs/author/reader-views.sections/configure-the-choices.md +65 -0
- package/agent-docs/author/reader-views.sections/connect-your-own-control.md +59 -0
- package/agent-docs/author/reader-views.sections/how-it-works-for-agents.md +41 -0
- package/agent-docs/author/reader-views.sections/mark-pages.md +49 -0
- package/agent-docs/author/reader-views.sections/mark-sections-and-add-an-entry-choice.md +49 -0
- package/agent-docs/author/reader-views.sections/place-filter-controls.md +43 -0
- package/agent-docs/author/reader-views.sections/try-the-controls-here.md +64 -0
- package/agent-docs/author/recipe-drafts.md +181 -0
- package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +82 -0
- package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +60 -0
- package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +55 -0
- package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +66 -0
- package/agent-docs/author/recipe-drafts.sections/related-reading.md +45 -0
- package/agent-docs/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md +50 -0
- package/agent-docs/author/recipes.md +127 -0
- package/agent-docs/author/recipes.sections/how-agents-use-this.md +50 -0
- package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +64 -0
- package/agent-docs/author/recipes.sections/related-reading.md +36 -0
- package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +42 -0
- package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +52 -0
- package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +44 -0
- package/agent-docs/author/recipes.sections/what-each-file-does.md +48 -0
- package/agent-docs/author/recipes.sections/what-happens-and-when.md +45 -0
- package/agent-docs/author/related-reading.md +143 -0
- package/agent-docs/author/related-reading.sections/automatic-footers.md +35 -0
- package/agent-docs/author/related-reading.sections/declare-relationships.md +68 -0
- package/agent-docs/author/related-reading.sections/display-related-documents.md +54 -0
- package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +32 -0
- package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +32 -0
- package/agent-docs/author/related-reading.sections/related-reading.md +34 -0
- package/agent-docs/author/related-reading.sections/where-relationship-explanations-come-from.md +34 -0
- package/agent-docs/author/release-notes.md +153 -0
- package/agent-docs/author/search.md +299 -0
- package/agent-docs/author/search.sections/choose-a-provider.md +52 -0
- package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +49 -0
- package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +55 -0
- package/agent-docs/author/search.sections/html-markdown-and-agents.md +37 -0
- package/agent-docs/author/search.sections/lexical-search.md +78 -0
- package/agent-docs/author/search.sections/local-semantic-preview.md +43 -0
- package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +41 -0
- package/agent-docs/author/search.sections/related-reading.md +45 -0
- package/agent-docs/author/search.sections/reuse-the-lexical-index.md +81 -0
- package/agent-docs/author/search.sections/turn-search-off.md +46 -0
- package/agent-docs/author/search.sections/use-the-search-box.md +39 -0
- package/agent-docs/author/search.sections/write-a-custom-provider.md +98 -0
- package/agent-docs/author/snippets.md +118 -0
- package/agent-docs/author/taxonomy.md +121 -0
- package/agent-docs/author/templates.md +231 -0
- package/agent-docs/author/templates.sections/built-in-feature-templates.md +52 -0
- package/agent-docs/author/templates.sections/built-in-templates.md +48 -0
- package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +69 -0
- package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +76 -0
- package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +46 -0
- package/agent-docs/author/templates.sections/project-added-templates.md +39 -0
- package/agent-docs/author/templates.sections/related-reading.md +47 -0
- package/agent-docs/author/templates.sections/scaffold-a-page.md +53 -0
- package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +56 -0
- package/agent-docs/author/templates.sections/what-every-template-gives-you.md +44 -0
- package/agent-docs/author/workspace/commands.md +92 -0
- package/agent-docs/author/workspace.md +104 -0
- package/agent-docs/author/writing-style.md +137 -0
- package/agent-docs/author/writing-style.sections/adapt-this-example.md +28 -0
- package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +42 -0
- package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +32 -0
- package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +28 -0
- package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +36 -0
- package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +41 -0
- package/agent-docs/author/writing-style.sections/procedures-and-examples.md +32 -0
- package/agent-docs/author/writing-style.sections/related-reading.md +32 -0
- package/agent-docs/author/writing-style.sections/review-a-draft.md +30 -0
- package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +39 -0
- package/agent-docs/author/writing-style.sections/voice-and-explanations.md +39 -0
- package/agent-docs/changelog/2026-10-14-agent-readiness.md +29 -0
- package/agent-docs/changelog/2026-10-15-evaluation-builds.md +84 -0
- package/agent-docs/changelog/2026-10-16-navigation-layouts.md +72 -0
- package/agent-docs/changelog/2026-10-17-mcp-hosting.md +60 -0
- package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +46 -0
- package/agent-docs/changelog/2026-10-19-visual-navigation.md +44 -0
- package/agent-docs/changelog/2026-10-25.md +45 -0
- package/agent-docs/changelog/2026-10-26.md +66 -0
- package/agent-docs/changelog/2026-10-27.md +85 -0
- package/agent-docs/changelog/authoring-preview.md +40 -0
- package/agent-docs/changelog/authoring-search.md +39 -0
- package/agent-docs/changelog/authoring-tools.md +34 -0
- package/agent-docs/changelog/working-tree-skill.md +38 -0
- package/agent-docs/changelog.md +115 -0
- package/agent-docs/chat/checks.md +175 -0
- package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +38 -0
- package/agent-docs/chat/checks.sections/answer-for-one-audience.md +66 -0
- package/agent-docs/chat/checks.sections/answer-without-a-model.md +54 -0
- package/agent-docs/chat/checks.sections/follow-up-questions.md +54 -0
- package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +67 -0
- package/agent-docs/chat/checks.sections/questions-with-several-parts.md +44 -0
- package/agent-docs/chat/checks.sections/related-reading.md +42 -0
- package/agent-docs/chat/checks.sections/reuse-answers.md +50 -0
- package/agent-docs/chat/host.md +222 -0
- package/agent-docs/chat/host.sections/cap-the-daily-spend.md +78 -0
- package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +64 -0
- package/agent-docs/chat/host.sections/related-reading.md +43 -0
- package/agent-docs/chat/passage-index.md +228 -0
- package/agent-docs/chat/passage-index.sections/build-the-index.md +72 -0
- package/agent-docs/chat/passage-index.sections/embed-passages.md +103 -0
- package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +53 -0
- package/agent-docs/chat/passage-index.sections/limits.md +45 -0
- package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +52 -0
- package/agent-docs/chat/passage-index.sections/related-reading.md +42 -0
- package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +91 -0
- package/agent-docs/chat/prepared-answers.md +116 -0
- package/agent-docs/chat/settings.md +213 -0
- package/agent-docs/chat/settings.sections/choose-the-scorer.md +63 -0
- package/agent-docs/chat/settings.sections/configure-chat.md +80 -0
- package/agent-docs/chat/settings.sections/configure-retrieval.md +62 -0
- package/agent-docs/chat/settings.sections/related-reading.md +32 -0
- package/agent-docs/chat/settings.sections/send-extra-request-fields.md +42 -0
- package/agent-docs/chat/settings.sections/use-more-than-one-model.md +62 -0
- package/agent-docs/chat/settings.sections/when-the-scorer-is-down.md +42 -0
- package/agent-docs/chat/setup.md +97 -0
- package/agent-docs/chat.md +102 -0
- package/agent-docs/cli.md +445 -0
- package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +102 -0
- package/agent-docs/cli.sections/author-pages.md +94 -0
- package/agent-docs/cli.sections/build-and-serve.md +144 -0
- package/agent-docs/cli.sections/inspect-config-and-operations.md +41 -0
- package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +45 -0
- package/agent-docs/cli.sections/related-reading.md +33 -0
- package/agent-docs/cli.sections/search-and-chat.md +132 -0
- package/agent-docs/cli.sections/start-a-project.md +37 -0
- package/agent-docs/cli.sections/working-tree-authoring-tools.md +35 -0
- package/agent-docs/concepts.md +133 -0
- package/agent-docs/config/apis.md +136 -0
- package/agent-docs/config/content.md +264 -0
- package/agent-docs/config/content.sections/authoring.md +58 -0
- package/agent-docs/config/content.sections/badges.md +34 -0
- package/agent-docs/config/content.sections/callouts.md +34 -0
- package/agent-docs/config/content.sections/cookbooks.md +38 -0
- package/agent-docs/config/content.sections/frontmatter.md +75 -0
- package/agent-docs/config/content.sections/readerfilters.md +44 -0
- package/agent-docs/config/content.sections/related-reading.md +34 -0
- package/agent-docs/config/content.sections/relationships.md +76 -0
- package/agent-docs/config/content.sections/snippets.md +61 -0
- package/agent-docs/config/content.sections/templates.md +57 -0
- package/agent-docs/config/content.sections/variables.md +55 -0
- package/agent-docs/config/examples.md +354 -0
- package/agent-docs/config/examples.sections/feature-showcase.md +55 -0
- package/agent-docs/config/examples.sections/minimal-site.md +80 -0
- package/agent-docs/config/examples.sections/multilingual-help-center.md +110 -0
- package/agent-docs/config/examples.sections/parcel-api-documentation.md +153 -0
- package/agent-docs/config/examples.sections/related-reading.md +50 -0
- package/agent-docs/config/examples.sections/shared-company-preset.md +118 -0
- package/agent-docs/config/integrations.md +76 -0
- package/agent-docs/config/outputs.md +160 -0
- package/agent-docs/config/outputs.sections/exports.md +57 -0
- package/agent-docs/config/outputs.sections/metadata.md +42 -0
- package/agent-docs/config/outputs.sections/related-reading.md +34 -0
- package/agent-docs/config/publishing.md +219 -0
- package/agent-docs/config/publishing.sections/navigation.md +92 -0
- package/agent-docs/config/publishing.sections/redirects.md +79 -0
- package/agent-docs/config/publishing.sections/related-reading.md +33 -0
- package/agent-docs/config/site.md +193 -0
- package/agent-docs/config/site.sections/related-reading.md +33 -0
- package/agent-docs/config/site.sections/theme.md +74 -0
- package/agent-docs/config.md +195 -0
- package/agent-docs/configuration.md +384 -0
- package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +36 -0
- package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +76 -0
- package/agent-docs/configuration.sections/extract-a-section-with-include.md +75 -0
- package/agent-docs/configuration.sections/inspect-and-validate-changes.md +77 -0
- package/agent-docs/configuration.sections/related-reading.md +42 -0
- package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +54 -0
- package/agent-docs/configuration.sections/share-defaults-through-extends.md +121 -0
- package/agent-docs/configuration.sections/start-with-one-working-file.md +81 -0
- package/agent-docs/configuration.sections/understand-the-three-stages.md +59 -0
- package/agent-docs/configuration.sections/understand-where-paths-point.md +53 -0
- package/agent-docs/connect/mcp.md +85 -0
- package/agent-docs/contribute/agent-skills.md +72 -0
- package/agent-docs/cookbooks/authoring.md +68 -0
- package/agent-docs/cookbooks/site-workflows.md +59 -0
- package/agent-docs/cookbooks/welcome-email.md +55 -0
- package/agent-docs/documents.json +20058 -0
- package/agent-docs/example-api/cedar/create-enrollment-7af3e5d2.md +594 -0
- package/agent-docs/example-api/cedar/get-legacy-parcel-6758d051.md +122 -0
- package/agent-docs/example-api/cedar/get-parcel-edee10e6.md +122 -0
- package/agent-docs/example-api/cedar/list-parcels-0345fb5f.md +271 -0
- package/agent-docs/example-api/cedar/parcel-delivered-7d1ba6db.md +122 -0
- package/agent-docs/example-api/cedar/upload-manifest-1af17891.md +101 -0
- package/agent-docs/example-api/cedar.md +39 -0
- package/agent-docs/example-api/create-note.md +344 -0
- package/agent-docs/example-api/generated/get-note-cbedb319.md +165 -0
- package/agent-docs/example-api/write-note.md +55 -0
- package/agent-docs/explore.md +54 -0
- package/agent-docs/glossary.md +827 -0
- package/agent-docs/index.md +249 -0
- package/agent-docs/ingredients/audit-site.md +27 -0
- package/agent-docs/ingredients/build-site.md +29 -0
- package/agent-docs/ingredients/compile-framework.md +28 -0
- package/agent-docs/ingredients/complete-page.md +30 -0
- package/agent-docs/ingredients/inspect-agent-bundle.md +28 -0
- package/agent-docs/ingredients/inspect-build.md +41 -0
- package/agent-docs/ingredients/preview-site.md +31 -0
- package/agent-docs/ingredients/refresh-agent-bundle.md +29 -0
- package/agent-docs/ingredients/scaffold-page.md +28 -0
- package/agent-docs/non-goals.md +58 -0
- package/agent-docs/provenance.json +10 -0
- package/agent-docs/publish/agent-discovery.md +79 -0
- package/agent-docs/publish/agent-friendliness.md +201 -0
- package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +61 -0
- package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +48 -0
- package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +46 -0
- package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +48 -0
- package/agent-docs/publish/agent-friendliness.sections/related-reading.md +52 -0
- package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +50 -0
- package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +62 -0
- package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +50 -0
- package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +58 -0
- package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +68 -0
- package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +60 -0
- package/agent-docs/publish/api-references.md +217 -0
- package/agent-docs/publish/api-references.sections/add-useful-examples.md +36 -0
- package/agent-docs/publish/api-references.sections/author-the-reference-page.md +65 -0
- package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +48 -0
- package/agent-docs/publish/api-references.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +36 -0
- package/agent-docs/publish/api-references.sections/generate-many-pages-selectively.md +36 -0
- package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +36 -0
- package/agent-docs/publish/api-references.sections/link-guides-to-api-references.md +36 -0
- package/agent-docs/publish/api-references.sections/map-extension-values-to-shoalrun-status.md +36 -0
- package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +38 -0
- package/agent-docs/publish/api-references.sections/publish-several-versions.md +36 -0
- package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +62 -0
- package/agent-docs/publish/api-references.sections/register-the-operation.md +64 -0
- package/agent-docs/publish/api-references.sections/related-reading.md +42 -0
- package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +54 -0
- package/agent-docs/publish/api-references.sections/use-a-template-for-editorial-context.md +36 -0
- package/agent-docs/publish/api-references.sections/what-readers-get.md +38 -0
- package/agent-docs/publish/audit.md +160 -0
- package/agent-docs/publish/audit.sections/add-project-tests.md +57 -0
- package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +52 -0
- package/agent-docs/publish/audit.sections/check-before-pushing.md +80 -0
- package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +54 -0
- package/agent-docs/publish/audit.sections/read-the-report.md +67 -0
- package/agent-docs/publish/audit.sections/related-reading.md +47 -0
- package/agent-docs/publish/content-export.md +208 -0
- package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +40 -0
- package/agent-docs/publish/content-export.sections/check-the-result.md +27 -0
- package/agent-docs/publish/content-export.sections/export-selected-pages.md +113 -0
- package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +29 -0
- package/agent-docs/publish/content-export.sections/prerequisites.md +29 -0
- package/agent-docs/publish/content-export.sections/related-reading.md +35 -0
- package/agent-docs/publish/content-export.sections/review-exported-api-material.md +44 -0
- package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +34 -0
- package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +43 -0
- package/agent-docs/publish/content-negotiation.md +121 -0
- package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +60 -0
- package/agent-docs/publish/content-negotiation.sections/missing-pages.md +51 -0
- package/agent-docs/publish/content-negotiation.sections/related-reading.md +45 -0
- package/agent-docs/publish/content-negotiation.sections/validators-and-manifest-links.md +49 -0
- package/agent-docs/publish/content-negotiation.sections/verify-the-deployed-url.md +62 -0
- package/agent-docs/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md +47 -0
- package/agent-docs/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md +49 -0
- package/agent-docs/publish/content-negotiation.sections/why-this-matters.md +47 -0
- package/agent-docs/publish/deployment-check.md +72 -0
- package/agent-docs/publish/evals.md +175 -0
- package/agent-docs/publish/evals.sections/add-the-audit-hook.md +63 -0
- package/agent-docs/publish/evals.sections/check-the-report.md +36 -0
- package/agent-docs/publish/evals.sections/define-a-task-file.md +47 -0
- package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +42 -0
- package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +39 -0
- package/agent-docs/publish/evals.sections/related-reading.md +36 -0
- package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +54 -0
- package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +42 -0
- package/agent-docs/publish/host-adapters.md +60 -0
- package/agent-docs/publish/manni.md +227 -0
- package/agent-docs/publish/manni.sections/check-the-result.md +40 -0
- package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +83 -0
- package/agent-docs/publish/manni.sections/optional-custom-policies.md +42 -0
- package/agent-docs/publish/manni.sections/prerequisites.md +40 -0
- package/agent-docs/publish/mcp-analytics.md +356 -0
- package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +50 -0
- package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +45 -0
- package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +53 -0
- package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +62 -0
- package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +54 -0
- package/agent-docs/publish/mcp-analytics.sections/related-reading.md +36 -0
- package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +46 -0
- package/agent-docs/publish/mcp.md +190 -0
- package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +52 -0
- package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +51 -0
- package/agent-docs/publish/mcp.sections/configure-the-client.md +55 -0
- package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +50 -0
- package/agent-docs/publish/mcp.sections/related-reading.md +42 -0
- package/agent-docs/publish/mcp.sections/search-then-read.md +53 -0
- package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +79 -0
- package/agent-docs/publish/mcp.sections/verify-the-connection.md +40 -0
- package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +42 -0
- package/agent-docs/publish/openapi-extension-mappings.md +84 -0
- package/agent-docs/publish/output.md +220 -0
- package/agent-docs/publish/output.sections/api-contracts.md +48 -0
- package/agent-docs/publish/output.sections/code-highlighting.md +38 -0
- package/agent-docs/publish/output.sections/current-limits.md +40 -0
- package/agent-docs/publish/output.sections/incremental-sync.md +69 -0
- package/agent-docs/publish/output.sections/manifest-records-and-sections.md +46 -0
- package/agent-docs/publish/output.sections/navigation-section-indexes.md +42 -0
- package/agent-docs/publish/output.sections/page-formats.md +46 -0
- package/agent-docs/publish/output.sections/published-output-contract.md +58 -0
- package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +44 -0
- package/agent-docs/publish/output.sections/related-reading.md +34 -0
- package/agent-docs/publish/output.sections/response-identity.md +38 -0
- package/agent-docs/publish/output.sections/site-files.md +64 -0
- package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +48 -0
- package/agent-docs/publish/output.sections/where-files-go.md +49 -0
- package/agent-docs/publish/publications.md +153 -0
- package/agent-docs/publish/revisions.md +104 -0
- package/agent-docs/publish/seo.md +119 -0
- package/agent-docs/publish/single-source-sites.md +168 -0
- package/agent-docs/publish/troubleshooting.md +112 -0
- package/agent-docs/publish/vercel.md +130 -0
- package/agent-docs/publish/vercel.sections/check-the-deployment.md +54 -0
- package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +38 -0
- package/agent-docs/publish/vercel.sections/prepare-your-project.md +52 -0
- package/agent-docs/publish/vercel.sections/related-reading.md +38 -0
- package/agent-docs/publish.md +95 -0
- package/agent-docs/recipes/add-page.md +194 -0
- package/agent-docs/recipes/add-page.sections/audit-the-shoalrun-docs-project.md +40 -0
- package/agent-docs/recipes/add-page.sections/before-you-start.md +33 -0
- package/agent-docs/recipes/add-page.sections/build-the-shoalrun-docs-site.md +42 -0
- package/agent-docs/recipes/add-page.sections/check-agent-search-and-page-lookup.md +42 -0
- package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +54 -0
- package/agent-docs/recipes/add-page.sections/check-the-outcome.md +28 -0
- package/agent-docs/recipes/add-page.sections/complete-the-guide-and-add-navigation.md +42 -0
- package/agent-docs/recipes/add-page.sections/install-the-site-dependencies.md +41 -0
- package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +42 -0
- package/agent-docs/recipes/add-page.sections/related-reading.md +30 -0
- package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +42 -0
- package/agent-docs/recipes/audit-docs.md +122 -0
- package/agent-docs/recipes/build-docs.md +105 -0
- package/agent-docs/recipes/preview-hybrid-search.md +84 -0
- package/agent-docs/recipes/preview-page.md +124 -0
- package/agent-docs/recipes/queue-email.md +49 -0
- package/agent-docs/recipes/refresh-agent-docs.md +109 -0
- package/agent-docs/recipes/send-welcome-email.md +92 -0
- package/agent-docs/reference/agent-skills.md +73 -0
- package/agent-docs/search-and-chat.md +87 -0
- package/agent-docs/search-index.json +1 -0
- package/agent-docs/start.md +197 -0
- package/agent-docs/start.sections/add-the-page-to-navigation.md +50 -0
- package/agent-docs/start.sections/build-and-check-both-outputs.md +50 -0
- package/agent-docs/start.sections/build-this-site.md +35 -0
- package/agent-docs/start.sections/check-writing-style.md +35 -0
- package/agent-docs/start.sections/create-a-page.md +105 -0
- package/agent-docs/start.sections/make-it-yours.md +37 -0
- package/agent-docs/start.sections/prerequisites.md +37 -0
- package/agent-docs/start.sections/related-reading.md +45 -0
- package/agent-docs/start.sections/start-your-own-project.md +53 -0
- package/agent-docs/status.md +75 -0
- package/agent-docs/styling/color-modes.md +85 -0
- package/agent-docs/styling/footer.md +67 -0
- package/agent-docs/styling/header.md +65 -0
- package/agent-docs/styling/layouts.md +193 -0
- package/agent-docs/styling/layouts.sections/build-a-landing-page.md +61 -0
- package/agent-docs/styling/layouts.sections/build-a-splash-page.md +88 -0
- package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +51 -0
- package/agent-docs/styling/layouts.sections/customize-the-hero.md +50 -0
- package/agent-docs/styling/layouts.sections/hero.md +83 -0
- package/agent-docs/styling/layouts.sections/related-reading.md +42 -0
- package/agent-docs/styling/palettes.md +140 -0
- package/agent-docs/styling/share-images.md +105 -0
- package/agent-docs/styling/themes.md +125 -0
- package/agent-docs/styling/try.md +106 -0
- package/agent-docs/what-is-shoalrun.md +56 -0
- package/assets/analytics.js +72 -0
- package/assets/ask-widget.js +320 -0
- package/assets/code-samples.js +28 -0
- package/assets/components.js +32 -0
- package/assets/cookbook-chooser.js +170 -0
- package/assets/copy-markdown.js +24 -0
- package/assets/example-panel.js +77 -0
- package/assets/file-tree.js +49 -0
- package/assets/image-viewer.js +41 -0
- package/assets/mode.js +26 -0
- package/assets/navigation.js +233 -0
- package/assets/reader-filters.js +305 -0
- package/assets/reader.js +111 -0
- package/assets/search-highlight.js +32 -0
- package/assets/search-lexical.js +66 -0
- package/assets/search.js +150 -0
- package/assets/table-filter.js +63 -0
- package/assets/tabs.js +80 -0
- package/assets/theme-preview.css +17 -0
- package/assets/theme-preview.js +135 -0
- package/assets/theme-switcher.js +113 -0
- package/assets/tooltips.js +81 -0
- package/assets/walkthrough.js +233 -0
- package/dist/agent-discovery.d.ts +11 -0
- package/dist/agent-discovery.js +37 -0
- package/dist/analytics.d.ts +2 -0
- package/dist/analytics.js +13 -0
- package/dist/answer-cache.d.ts +24 -0
- package/dist/answer-cache.js +55 -0
- package/dist/answer-cards.d.ts +71 -0
- package/dist/answer-cards.js +148 -0
- package/dist/api-embeds.d.ts +22 -0
- package/dist/api-embeds.js +84 -0
- package/dist/api-identity.d.ts +6 -0
- package/dist/api-identity.js +7 -0
- package/dist/api-materialize.d.ts +12 -0
- package/dist/api-materialize.js +120 -0
- package/dist/api-publication-plan.d.ts +86 -0
- package/dist/api-publication-plan.js +187 -0
- package/dist/api-publication-review.d.ts +23 -0
- package/dist/api-publication-review.js +58 -0
- package/dist/api-selection.d.ts +21 -0
- package/dist/api-selection.js +84 -0
- package/dist/api.d.ts +74 -0
- package/dist/api.js +782 -0
- package/dist/artifact-bundle.d.ts +96 -0
- package/dist/artifact-bundle.js +306 -0
- package/dist/ask-function.d.ts +19 -0
- package/dist/ask-function.js +139 -0
- package/dist/ask-handler.d.ts +38 -0
- package/dist/ask-handler.js +157 -0
- package/dist/ask-log-kv.d.ts +14 -0
- package/dist/ask-log-kv.js +69 -0
- package/dist/ask-log.d.ts +106 -0
- package/dist/ask-log.js +159 -0
- package/dist/ask-setup.d.ts +43 -0
- package/dist/ask-setup.js +99 -0
- package/dist/ask.d.ts +152 -0
- package/dist/ask.js +532 -0
- package/dist/audit.d.ts +29 -0
- package/dist/audit.js +171 -0
- package/dist/authored-change.d.ts +22 -0
- package/dist/authored-change.js +47 -0
- package/dist/authoring-api.d.ts +18 -0
- package/dist/authoring-api.js +15 -0
- package/dist/authoring-findings.d.ts +31 -0
- package/dist/authoring-findings.js +104 -0
- package/dist/authoring-guidance.d.ts +15 -0
- package/dist/authoring-guidance.js +57 -0
- package/dist/authoring-preview.d.ts +24 -0
- package/dist/authoring-preview.js +160 -0
- package/dist/authoring-project-command.d.ts +7 -0
- package/dist/authoring-project-command.js +52 -0
- package/dist/authoring-project.d.ts +104 -0
- package/dist/authoring-project.js +287 -0
- package/dist/authoring-review-command.d.ts +1 -0
- package/dist/authoring-review-command.js +68 -0
- package/dist/authoring-review.d.ts +72 -0
- package/dist/authoring-review.js +71 -0
- package/dist/authoring-snapshot.d.ts +66 -0
- package/dist/authoring-snapshot.js +293 -0
- package/dist/authoring-validation-command.d.ts +1 -0
- package/dist/authoring-validation-command.js +54 -0
- package/dist/authoring-validation.d.ts +101 -0
- package/dist/authoring-validation.js +348 -0
- package/dist/badges.d.ts +16 -0
- package/dist/badges.js +57 -0
- package/dist/budget-store.d.ts +21 -0
- package/dist/budget-store.js +90 -0
- package/dist/budget.d.ts +45 -0
- package/dist/budget.js +128 -0
- package/dist/build-info.d.ts +10 -0
- package/dist/build-info.js +15 -0
- package/dist/callouts.d.ts +18 -0
- package/dist/callouts.js +63 -0
- package/dist/cards.d.ts +35 -0
- package/dist/cards.js +237 -0
- package/dist/chat-config.d.ts +117 -0
- package/dist/chat-config.js +400 -0
- package/dist/chat-pause.d.ts +1 -0
- package/dist/chat-pause.js +3 -0
- package/dist/chat.d.ts +46 -0
- package/dist/chat.js +78 -0
- package/dist/cli-discovery.d.ts +4 -0
- package/dist/cli-discovery.js +86 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +750 -0
- package/dist/code-samples.d.ts +50 -0
- package/dist/code-samples.js +181 -0
- package/dist/compact-discovery.d.ts +15 -0
- package/dist/compact-discovery.js +78 -0
- package/dist/compiler-config.d.ts +67 -0
- package/dist/compiler-config.js +66 -0
- package/dist/compiler.d.ts +208 -0
- package/dist/compiler.js +524 -0
- package/dist/component-bundle.d.ts +4 -0
- package/dist/component-bundle.js +32 -0
- package/dist/component-content.d.ts +78 -0
- package/dist/component-content.js +47 -0
- package/dist/component-manifest.d.ts +15 -0
- package/dist/component-manifest.js +84 -0
- package/dist/component-names.d.ts +1 -0
- package/dist/component-names.js +1 -0
- package/dist/component-plugins.d.ts +28 -0
- package/dist/component-plugins.js +141 -0
- package/dist/component-transform.d.ts +10 -0
- package/dist/component-transform.js +697 -0
- package/dist/components.d.ts +2 -0
- package/dist/components.js +1 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.js +149 -0
- package/dist/content-export-assets.d.ts +23 -0
- package/dist/content-export-assets.js +103 -0
- package/dist/content-export-command.d.ts +20 -0
- package/dist/content-export-command.js +57 -0
- package/dist/content-export-config.d.ts +16 -0
- package/dist/content-export-config.js +50 -0
- package/dist/content-export-render.d.ts +12 -0
- package/dist/content-export-render.js +132 -0
- package/dist/content-export.d.ts +30 -0
- package/dist/content-export.js +307 -0
- package/dist/content-filter.d.ts +4 -0
- package/dist/content-filter.js +16 -0
- package/dist/content-source.d.ts +100 -0
- package/dist/content-source.js +42 -0
- package/dist/content-workspace.d.ts +293 -0
- package/dist/content-workspace.js +69 -0
- package/dist/content.d.ts +41 -0
- package/dist/content.js +176 -0
- package/dist/cookbook-chooser.d.ts +19 -0
- package/dist/cookbook-chooser.js +56 -0
- package/dist/dev.d.ts +2 -0
- package/dist/dev.js +113 -0
- package/dist/diagram-svg.d.ts +1 -0
- package/dist/diagram-svg.js +44 -0
- package/dist/diagrams.d.ts +7 -0
- package/dist/diagrams.js +102 -0
- package/dist/docs-author.d.ts +86 -0
- package/dist/docs-author.js +380 -0
- package/dist/docs-command.d.ts +8 -0
- package/dist/docs-command.js +62 -0
- package/dist/docs-eval.d.ts +146 -0
- package/dist/docs-eval.js +231 -0
- package/dist/docs-mcp.d.ts +12 -0
- package/dist/docs-mcp.js +82 -0
- package/dist/docs-tool.d.ts +81 -0
- package/dist/docs-tool.js +7 -0
- package/dist/document-sync.d.ts +36 -0
- package/dist/document-sync.js +58 -0
- package/dist/documentation-core.d.ts +148 -0
- package/dist/documentation-core.js +160 -0
- package/dist/embeddings.d.ts +68 -0
- package/dist/embeddings.js +198 -0
- package/dist/focused-audit.d.ts +10 -0
- package/dist/focused-audit.js +69 -0
- package/dist/focused-openapi.d.ts +2 -0
- package/dist/focused-openapi.js +140 -0
- package/dist/fonts.d.ts +54 -0
- package/dist/fonts.js +92 -0
- package/dist/freshness.d.ts +7 -0
- package/dist/freshness.js +58 -0
- package/dist/frontmatter.d.ts +24 -0
- package/dist/frontmatter.js +342 -0
- package/dist/function-package.d.ts +1 -0
- package/dist/function-package.js +58 -0
- package/dist/highlight.d.ts +14 -0
- package/dist/highlight.js +114 -0
- package/dist/html-renderer.d.ts +10 -0
- package/dist/html-renderer.js +63 -0
- package/dist/icons.d.ts +8 -0
- package/dist/icons.js +40 -0
- package/dist/index-build.d.ts +55 -0
- package/dist/index-build.js +227 -0
- package/dist/ingredient-draft.d.ts +17 -0
- package/dist/ingredient-draft.js +94 -0
- package/dist/ingredient-workflow.d.ts +8 -0
- package/dist/ingredient-workflow.js +25 -0
- package/dist/init.d.ts +8 -0
- package/dist/init.js +66 -0
- package/dist/jev.d.ts +62 -0
- package/dist/jev.js +190 -0
- package/dist/link-audit.d.ts +12 -0
- package/dist/link-audit.js +146 -0
- package/dist/llms-discovery.d.ts +11 -0
- package/dist/llms-discovery.js +23 -0
- package/dist/markdown-sections.d.ts +15 -0
- package/dist/markdown-sections.js +60 -0
- package/dist/markdown-size.d.ts +7 -0
- package/dist/markdown-size.js +6 -0
- package/dist/mcp-analytics.d.ts +38 -0
- package/dist/mcp-analytics.js +35 -0
- package/dist/mcp-artifacts.d.ts +2 -0
- package/dist/mcp-artifacts.js +78 -0
- package/dist/mcp-client-metadata.d.ts +18 -0
- package/dist/mcp-client-metadata.js +69 -0
- package/dist/mcp-config.d.ts +23 -0
- package/dist/mcp-config.js +56 -0
- package/dist/mcp-http.d.ts +19 -0
- package/dist/mcp-http.js +157 -0
- package/dist/mcp-integrity.d.ts +3 -0
- package/dist/mcp-integrity.js +4 -0
- package/dist/mcp-node.d.ts +4 -0
- package/dist/mcp-node.js +68 -0
- package/dist/mcp-vercel-runtime.d.ts +3 -0
- package/dist/mcp-vercel-runtime.js +36 -0
- package/dist/mcp-vercel.d.ts +15 -0
- package/dist/mcp-vercel.js +65 -0
- package/dist/metadata-provider.d.ts +19 -0
- package/dist/metadata-provider.js +38 -0
- package/dist/negotiation.d.ts +10 -0
- package/dist/negotiation.js +35 -0
- package/dist/not-found.d.ts +16 -0
- package/dist/not-found.js +25 -0
- package/dist/output-commit.d.ts +1 -0
- package/dist/output-commit.js +133 -0
- package/dist/output-location.d.ts +3 -0
- package/dist/output-location.js +30 -0
- package/dist/page-materialization.d.ts +78 -0
- package/dist/page-materialization.js +132 -0
- package/dist/page-renderer.d.ts +71 -0
- package/dist/page-renderer.js +177 -0
- package/dist/palettes.d.ts +41 -0
- package/dist/palettes.js +160 -0
- package/dist/procedure-components.d.ts +2 -0
- package/dist/procedure-components.js +94 -0
- package/dist/project-navigation.d.ts +41 -0
- package/dist/project-navigation.js +190 -0
- package/dist/provider-http.d.ts +10 -0
- package/dist/provider-http.js +60 -0
- package/dist/publication-manifest.d.ts +229 -0
- package/dist/publication-manifest.js +53 -0
- package/dist/publication-plan.d.ts +34 -0
- package/dist/publication-plan.js +85 -0
- package/dist/publication-render.d.ts +71 -0
- package/dist/publication-render.js +92 -0
- package/dist/reader-filters.d.ts +30 -0
- package/dist/reader-filters.js +105 -0
- package/dist/recipe-draft.d.ts +17 -0
- package/dist/recipe-draft.js +147 -0
- package/dist/reference-audit.d.ts +18 -0
- package/dist/reference-audit.js +169 -0
- package/dist/remote-import.d.ts +62 -0
- package/dist/remote-import.js +292 -0
- package/dist/representation-tree.d.ts +3 -0
- package/dist/representation-tree.js +320 -0
- package/dist/retrieval-config.d.ts +30 -0
- package/dist/retrieval-config.js +83 -0
- package/dist/retrieval.d.ts +60 -0
- package/dist/retrieval.js +228 -0
- package/dist/scaffold.d.ts +39 -0
- package/dist/scaffold.js +167 -0
- package/dist/search-config.d.ts +8 -0
- package/dist/search-config.js +26 -0
- package/dist/search-handler.d.ts +16 -0
- package/dist/search-handler.js +111 -0
- package/dist/search-identifier.d.ts +3 -0
- package/dist/search-identifier.js +25 -0
- package/dist/search-literal.d.ts +1 -0
- package/dist/search-literal.js +28 -0
- package/dist/search-query.d.ts +54 -0
- package/dist/search-query.js +120 -0
- package/dist/search-results.d.ts +6 -0
- package/dist/search-results.js +45 -0
- package/dist/search-snippet.d.ts +11 -0
- package/dist/search-snippet.js +93 -0
- package/dist/search-synonyms.d.ts +8 -0
- package/dist/search-synonyms.js +46 -0
- package/dist/semantic-markdown.d.ts +10 -0
- package/dist/semantic-markdown.js +39 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +223 -0
- package/dist/share-images.d.ts +24 -0
- package/dist/share-images.js +187 -0
- package/dist/site-path.d.ts +2 -0
- package/dist/site-path.js +15 -0
- package/dist/sitemap.d.ts +8 -0
- package/dist/sitemap.js +58 -0
- package/dist/snippets.d.ts +19 -0
- package/dist/snippets.js +84 -0
- package/dist/structured-model-output.d.ts +6 -0
- package/dist/structured-model-output.js +21 -0
- package/dist/subject-deprecation.d.ts +21 -0
- package/dist/subject-deprecation.js +57 -0
- package/dist/surface-text.d.ts +4 -0
- package/dist/surface-text.js +42 -0
- package/dist/taxonomy.d.ts +14 -0
- package/dist/taxonomy.js +88 -0
- package/dist/turnstile.d.ts +21 -0
- package/dist/turnstile.js +52 -0
- package/dist/vale.d.ts +28 -0
- package/dist/vale.js +103 -0
- package/dist/vercel-function.d.ts +21 -0
- package/dist/vercel-function.js +108 -0
- package/dist/vercel.d.ts +11 -0
- package/dist/vercel.js +103 -0
- package/dist/walkthrough.d.ts +25 -0
- package/dist/walkthrough.js +336 -0
- package/dist/yaml-value.d.ts +2 -0
- package/dist/yaml-value.js +36 -0
- package/example-configs/api-docs/README.md +59 -0
- package/example-configs/api-docs/apis/cedar-parcel.yaml +413 -0
- package/example-configs/api-docs/content/create-enrollment.mdx +11 -0
- package/example-configs/api-docs/content/overview.mdx +36 -0
- package/example-configs/api-docs/content/quickstart.mdx +52 -0
- package/example-configs/api-docs/docs.config.yaml +104 -0
- package/example-configs/faceted-sites/README.md +31 -0
- package/example-configs/faceted-sites/base.yaml +30 -0
- package/example-configs/faceted-sites/content/api.md +12 -0
- package/example-configs/faceted-sites/content/home.md +10 -0
- package/example-configs/faceted-sites/content/operations.md +12 -0
- package/example-configs/faceted-sites/developers.config.yaml +8 -0
- package/example-configs/faceted-sites/docs.config.yaml +7 -0
- package/example-configs/faceted-sites/europe.config.yaml +9 -0
- package/example-configs/minimal/content/install.mdx +12 -0
- package/example-configs/minimal/content/welcome.mdx +8 -0
- package/example-configs/minimal/docs.config.yaml +31 -0
- package/example-configs/multilingual/content/de/home.mdx +9 -0
- package/example-configs/multilingual/content/de/reset-password.mdx +9 -0
- package/example-configs/multilingual/content/home.mdx +10 -0
- package/example-configs/multilingual/content/reset-password.mdx +12 -0
- package/example-configs/multilingual/docs.config.yaml +61 -0
- package/example-configs/multilingual/snippets/contact.mdx +1 -0
- package/example-configs/notifications/apis/notifications.yaml +132 -0
- package/example-configs/notifications/content/cookbook.mdx +17 -0
- package/example-configs/notifications/content/get-message.mdx +14 -0
- package/example-configs/notifications/content/queue-email.mdx +42 -0
- package/example-configs/notifications/content/queue-push.mdx +33 -0
- package/example-configs/notifications/content/queue-sms.mdx +33 -0
- package/example-configs/notifications/content/send-email.mdx +14 -0
- package/example-configs/notifications/content/send-push.mdx +14 -0
- package/example-configs/notifications/content/send-sms.mdx +14 -0
- package/example-configs/notifications/content/start.mdx +13 -0
- package/example-configs/notifications/content/welcome-cookbook.mdx +21 -0
- package/example-configs/notifications/content/welcome-email.mdx +82 -0
- package/example-configs/notifications/demo.mjs +43 -0
- package/example-configs/notifications/docs.config.yaml +88 -0
- package/example-configs/notifications/ingredient-drafts/README.md +41 -0
- package/example-configs/notifications/ingredient-drafts/check-delivery.mdx +13 -0
- package/example-configs/notifications/ingredient-drafts/queue-welcome-email.mdx +48 -0
- package/example-configs/notifications/ingredient-specs/queue-welcome-email.yaml +7 -0
- package/example-configs/notifications/ingredients/check-delivery.mdx +42 -0
- package/example-configs/notifications/ingredients/queue-welcome-email.mdx +37 -0
- package/example-configs/notifications/recipe-drafts/send-welcome-email.mdx +91 -0
- package/example-configs/notifications/recipe-specs/send-welcome-email.yaml +11 -0
- package/example-configs/reference-stress/README.md +32 -0
- package/example-configs/reference-stress/apis/cedar-parcel.yaml +413 -0
- package/example-configs/reference-stress/content/enrollment-shapes.mdx +16 -0
- package/example-configs/reference-stress/content/overview.mdx +14 -0
- package/example-configs/reference-stress/docs.config.yaml +55 -0
- package/example-configs/shared-preset/shared/company-docs.yaml +46 -0
- package/example-configs/shared-preset/shared/runbook.mdx +7 -0
- package/example-configs/shared-preset/site/content/failed-invoices.mdx +15 -0
- package/example-configs/shared-preset/site/content/start.mdx +9 -0
- package/example-configs/shared-preset/site/docs.config.yaml +18 -0
- package/example-configs/showcase/README.md +20 -0
- package/example-configs/showcase/apis/cedar-parcel.yaml +413 -0
- package/example-configs/showcase/content/assets/collection.svg +1 -0
- package/example-configs/showcase/content/code.mdx +100 -0
- package/example-configs/showcase/content/create-enrollment.mdx +11 -0
- package/example-configs/showcase/content/features.mdx +39 -0
- package/example-configs/showcase/content/landing.mdx +36 -0
- package/example-configs/showcase/content/overview.mdx +42 -0
- package/example-configs/showcase/content/personalization.mdx +38 -0
- package/example-configs/showcase/content/preview.mdx +35 -0
- package/example-configs/showcase/content/procedures.mdx +88 -0
- package/example-configs/showcase/content/quickstart.mdx +64 -0
- package/example-configs/showcase/content/reading.mdx +99 -0
- package/example-configs/showcase/content/verify.mdx +27 -0
- package/example-configs/showcase/content/visuals.mdx +47 -0
- package/example-configs/showcase/content/workflows.mdx +12 -0
- package/example-configs/showcase/docs.config.yaml +149 -0
- package/example-configs/showcase/snippets/sandbox.mdx +1 -0
- package/examples/analytics/README.md +56 -0
- package/examples/analytics/inspector.js +25 -0
- package/examples/analytics/posthog.js +36 -0
- package/examples/components/comparison.mjs +8 -0
- package/examples/components/components.json +6 -0
- package/examples/components/copy-text/LICENSE.react-dom.txt +21 -0
- package/examples/components/copy-text/LICENSE.react.txt +21 -0
- package/examples/components/copy-text/LICENSE.scheduler.txt +21 -0
- package/examples/components/copy-text/browser.jsx +21 -0
- package/examples/components/copy-text/components.json +6 -0
- package/examples/components/copy-text/package-lock.json +41 -0
- package/examples/components/copy-text/package.json +9 -0
- package/examples/components/copy-text/plugin.mjs +5 -0
- package/examples/components/retry-budget/LICENSE.react-dom.txt +21 -0
- package/examples/components/retry-budget/LICENSE.react.txt +21 -0
- package/examples/components/retry-budget/LICENSE.scheduler.txt +21 -0
- package/examples/components/retry-budget/browser.jsx +50 -0
- package/examples/components/retry-budget/components.json +6 -0
- package/examples/components/retry-budget/model.js +22 -0
- package/examples/components/retry-budget/package-lock.json +41 -0
- package/examples/components/retry-budget/package.json +9 -0
- package/examples/components/retry-budget/plugin.mjs +31 -0
- package/examples/components/retry-budget/policy.json +9 -0
- package/examples/components/retry-budget/style.css +25 -0
- package/examples/diagrams/d2-gallery.json +138 -0
- package/examples/diagrams/gallery.json +236 -0
- package/examples/help-drawer/README.md +44 -0
- package/examples/help-drawer/app.js +53 -0
- package/examples/help-drawer/components/components.json +1 -0
- package/examples/help-drawer/components/support.mjs +10 -0
- package/examples/help-drawer/content/account.md +8 -0
- package/examples/help-drawer/content/billing.mdx +29 -0
- package/examples/help-drawer/content/keys.mdx +46 -0
- package/examples/help-drawer/content/settings.svg +1 -0
- package/examples/help-drawer/docs.config.yaml +30 -0
- package/examples/help-drawer/index.html +26 -0
- package/examples/help-drawer/preview.mjs +33 -0
- package/examples/mcp-analytics/README.md +59 -0
- package/examples/mcp-analytics/posthog.mjs +159 -0
- package/package.json +100 -4
- package/schemas/content-export.schema.json +55 -0
- package/skills/shoalrun-author/SKILL.md +52 -0
- package/skills/shoalrun-component-author/SKILL.md +24 -0
- package/skills/shoalrun-recipes/SKILL.md +25 -0
- package/skills/shoalrun-setup/SKILL.md +34 -0
- package/skills/shoalrun-walkthrough/SKILL.md +18 -0
- package/styles/fonts/figtree-LICENSE.txt +93 -0
- package/styles/fonts/figtree-italic.woff2 +0 -0
- package/styles/fonts/figtree.woff2 +0 -0
- package/styles/fonts/inter-LICENSE.txt +93 -0
- package/styles/fonts/inter-italic.woff2 +0 -0
- package/styles/fonts/inter.woff2 +0 -0
- package/styles/fonts/jetbrains-mono-LICENSE.txt +93 -0
- package/styles/fonts/jetbrains-mono.woff2 +0 -0
- package/styles/fonts/jost-LICENSE.txt +93 -0
- package/styles/fonts/jost-italic.woff2 +0 -0
- package/styles/fonts/jost.woff2 +0 -0
- package/styles/fonts/share/figtree-400.ttf +0 -0
- package/styles/fonts/share/figtree-700.ttf +0 -0
- package/styles/fonts/share/inter-400.ttf +0 -0
- package/styles/fonts/share/inter-700.ttf +0 -0
- package/styles/fonts/share/jetbrains-mono-700.ttf +0 -0
- package/styles/fonts/share/jost-italic-800.ttf +0 -0
- package/styles/fonts/share/metrics.json +1 -0
- package/styles/fonts/share/source-serif-4-400.ttf +0 -0
- package/styles/fonts/source-serif-4-LICENSE.txt +93 -0
- package/styles/fonts/source-serif-4-italic.woff2 +0 -0
- package/styles/fonts/source-serif-4.woff2 +0 -0
- package/styles/header.css +56 -0
- package/styles/site.css +825 -0
- package/styles/themes/ledger.css +93 -0
- package/styles/themes/palettes/amethyst.yaml +127 -0
- package/styles/themes/palettes/coral.yaml +127 -0
- package/styles/themes/palettes/harbor.yaml +127 -0
- package/styles/themes/palettes/ink.yaml +127 -0
- package/styles/themes/palettes/kelp.yaml +127 -0
- package/styles/themes/palettes/vice.yaml +127 -0
- package/styles/themes/reef.css +68 -0
- package/styles/themes/vice.css +56 -0
- package/styles/tokens.css +91 -0
- package/templates/api-reference.mdx +133 -0
- package/templates/cookbook.mdx +38 -0
- package/templates/explanation.mdx +76 -0
- package/templates/guide.mdx +175 -0
- package/templates/how-to.mdx +171 -0
- package/templates/ingredient.mdx +53 -0
- package/templates/recipe.mdx +76 -0
- package/templates/reference.mdx +171 -0
- package/templates/troubleshooting.mdx +159 -0
- package/templates/tutorial.mdx +165 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"schemaVersion":1,"synonyms":[["walkthrough","walk through","code tutorial","tutorial"]],"documents":[{"id":"guide.about","demo":false,"url":"/about","markdownUrl":"/about.md","title":"About Shoalrun","summary":"Learn what Shoalrun is exploring and where the alpha stands.","type":"overview","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"what-makes-shoalrun-special","title":"What makes Shoalrun special"}],"text":"I'm CT Smith, and I'm building Shoalrun cause there's no such thing as a perfect doc tool. I have opinions, undirected rage, and curiosity about doc-building tools. I built my first documentation generator back in 2015. It was based on Jekyll and relied heavily (probably too heavily) on general templating and... you guessed it... page metadata . Shoalrun is part art project, part portfolio piece, and part laboratory. I use it to push the limits of content and tooling in whatever domain I'm working in. I had a lot of sources of inspiration (both negative and positive) from my years as a tech writer and tooling lover. I wanted to build something maximally flexible that also could keep things on the rails. I wanted something that uses frontmatter for deterministic features that feel like AI. I also wanted to play with what a BYO search and chat hookup could look like. And also leave room for others to use as much AI as they want. I wanted to chew on how to give human and AI readers content that works for them without cognitive—or contextual???—overload. No, I'm not saying AI has true cognition; stick with me here. I want flashy interactive components that help humans understand a concept. I also want agents to get the useful information without the extra junk—and WITHOUT extra authoring work. I centered the design with this project around making everything for two audiences: humans and agents. Not one above the other because it's honestly trivial to give them both what they need. I guess the more polished marketing-friendly summary is: One source can serve different readers without fuss. Shoalrun lets authors shape the browser experience and choose what enters agent-facing Markdown. Authors can add content for one format when readers need different explanations. The framework also provides settings and extension points for the rest of a documentation site. What makes Shoalrun special What interests me most is the interconnectedness that comes from treating information as a first-class object. Each doc has its own identity, metadata, and relationships. Its stable ID connects links, navigation, cards, and related reading, so I can move the source file without breaking those connections. See how Shoalrun works . I want config to be composable, too. I can keep navigation, API sources, templates, and other settings in small YAML files. Includes and presets combine them; I can trace each value's source. The project can grow without forcing every concern into one config file. See configuration composition . Presenting and linking content for humans and agents are first-class features. A rich component has an explicit form in both the browser and the page's Markdown twin. The build can turn one accepted source into interactive HTML, agent-readable Markdown, /llms.txt , and a document manifest. It rejects unsupported dynamic MDX instead of silently dropping content. Authors can still write a section for just one output when that reader needs a different explanation. See agent-friendly output . This structure also makes workflows easier to connect. An ingredient can be reused in a complete recipe, and a cookbook can assemble the reviewed recipes a reader selects into one path. See recipes and cookbooks . API content follows the same approach. Local OpenAPI files can supply reference pages, examples, and focused contracts for individual operations. A public build requires a review digest for imported API content, so a changed source returns to review before publication. See API review . I'm building Shoalrun for tinkerers like me, who will never be fully satisfied with a mass market docs tool. Docs are never one-size-fits-all, on any level. You can try the alpha CLI from npm: Getting started walks through installation and your first page. The project status describes what works and what still needs work. yee haw forever, CT","readerFilters":{},"readerSegments":[{"filters":{},"text":"I'm CT Smith, and I'm building Shoalrun cause there's no such thing as a perfect doc tool. I have opinions, undirected rage, and curiosity about doc-building tools. I built my first documentation generator back in 2015. It was based on Jekyll and relied heavily (probably too heavily) on general templating and... you guessed it... page metadata . Shoalrun is part art project, part portfolio piece, and part laboratory. I use it to push the limits of content and tooling in whatever domain I'm working in. I had a lot of sources of inspiration (both negative and positive) from my years as a tech writer and tooling lover. I wanted to build something maximally flexible that also could keep things on the rails. I wanted something that uses frontmatter for deterministic features that feel like AI. I also wanted to play with what a BYO search and chat hookup could look like. And also leave room for others to use as much AI as they want. I wanted to chew on how to give human and AI readers content that works for them without cognitive—or contextual???—overload. No, I'm not saying AI has true cognition; stick with me here. I want flashy interactive components that help humans understand a concept. I also want agents to get the useful information without the extra junk—and WITHOUT extra authoring work. I centered the design with this project around making everything for two audiences: humans and agents. Not one above the other because it's honestly trivial to give them both what they need. I guess the more polished marketing-friendly summary is: One source can serve different readers without fuss. Shoalrun lets authors shape the browser experience and choose what enters agent-facing Markdown. Authors can add content for one format when readers need different explanations. The framework also provides settings and extension points for the rest of a documentation site. What makes Shoalrun special What interests me most is the interconnectedness that comes from treating information as a first-class object. Each doc has its own identity, metadata, and relationships. Its stable ID connects links, navigation, cards, and related reading, so I can move the source file without breaking those connections. See how Shoalrun works . I want config to be composable, too. I can keep navigation, API sources, templates, and other settings in small YAML files. Includes and presets combine them; I can trace each value's source. The project can grow without forcing every concern into one config file. See configuration composition . Presenting and linking content for humans and agents are first-class features. A rich component has an explicit form in both the browser and the page's Markdown twin. The build can turn one accepted source into interactive HTML, agent-readable Markdown, /llms.txt , and a document manifest. It rejects unsupported dynamic MDX instead of silently dropping content. Authors can still write a section for just one output when that reader needs a different explanation. See agent-friendly output . This structure also makes workflows easier to connect. An ingredient can be reused in a complete recipe, and a cookbook can assemble the reviewed recipes a reader selects into one path. See recipes and cookbooks . API content follows the same approach. Local OpenAPI files can supply reference pages, examples, and focused contracts for individual operations. A public build requires a review digest for imported API content, so a changed source returns to review before publication. See API review . I'm building Shoalrun for tinkerers like me, who will never be fully satisfied with a mass market docs tool. Docs are never one-size-fits-all, on any level. You can try the alpha CLI from npm: Getting started walks through installation and your first page. The project status describes what works and what still needs work. yee haw forever, CT"}],"markdownBytes":4618,"markdownTokens":988,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.add-page","demo":false,"url":"/author/add-page","markdownUrl":"/author/add-page.md","title":"Create a page","summary":"Create a page from a template, complete its scaffolded draft, and publish it in navigation.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-pages","headings":[{"id":"choose-a-template","title":"Choose a template"},{"id":"scaffold-the-draft","title":"Scaffold the draft"},{"id":"complete-the-template","title":"Complete the template"},{"id":"publish-the-page","title":"Publish the page"},{"id":"put-it-in-navigation","title":"Put it in navigation"},{"id":"verify-html-and-markdown","title":"Verify HTML and Markdown"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Create a page from a template with scaffold . Templates prompt you for the page's frontmatter, an introduction, the main content, and related pages before you publish. This is the recommended authoring workflow for new pages. This guide assumes you have completed getting started and are working in my-docs/ . Keep SHOALRUN_CLI pointing to the checkout's framework/dist/cli.js . Choose a template Choose the template that matches what the reader needs to accomplish. Template Use it for tutorial A reliable guided exercise for learning by doing. how-to A specific task, with practical actions and a success check. reference Exact syntax, fields, options, examples, errors, and limits. explanation Concepts, context, reasons, and tradeoffs. api-reference Editorial context above generated operation details; requires one known operation ID. recipe A complete task used by recipe and cookbook workflows. ingredient One reusable action or check used in recipes. cookbook A page that helps readers choose complete recipes. These templates ship with the CLI. guide and troubleshooting remain available for compatibility. Projects can register additional templates or override built-ins. The CLI includes a recipe template for a complete customer task, written directly or assembled from ingredients. Built-in ingredient and cookbook templates support reusable steps and workflow selection. The ingredient draft command can start one ingredient from an API example; recipe draft assembles an ordered set of ingredient files for review. Use the project's template for the document type when one exists. Project templates can also override the built-in names. See templates to register or change one. Scaffold the draft From the project directory: node \"$SHOALRUN_CLI\" scaffold how-to -n content/track-parcel.mdx \\ --id how-to.track-parcel --title 'Track a parcel' The command finds docs.config.yaml , creates the file, and adds the template body and draft frontmatter. It refuses to overwrite an existing file. This example sets the stable ID and title explicitly; the CLI derives the slug /track-parcel from the target path. Without overrides, this path would produce ID how-to.track-parcel and title Track Parcel . The generated summary starts with Draft guide for and must be replaced before publication. Publication fields come from your project configuration. Complete the template Open content/track-parcel.mdx and work through its prompts: Read the comments in the frontmatter, fill in the placeholder fields, and delete the comment lines. Set updated to today's date in YYYY-MM-DD format. Write an introduction of 150 words or fewer and remove irrelevant optional sections. Follow the chosen shape. Write a guided exercise, practical task actions, organized reference facts, or conceptual discussion. For this how-to, write actions and checks. Keep the HTML, Markdown, and agents section when the page uses a component or behavior that changes either output or what an agent reads. Otherwise delete it. Add relationships for the page, or delete Related reading. Verify technical claims before you publish. Replace every TODO prompt enclosed in double square brackets. Adapt the sections to the task rather than leaving irrelevant prompts behind. Templates provide a starting structure; editing a template later does not rewrite this page. The quickstart shows a completed example. Keep the generated access.policy: draft while writing. Drafts are validated but omitted from the published site, even if the starter defaults to public access. Headings in the body begin at level 2 because Shoalrun renders the page title separately. Publish the page After reviewing the content, change the generated access value to: access : { policy : public } Keep the ID how-to.track-parcel and slug /track-parcel for this example. Check the channel, version, and language match an enabled publication. The build rejects public pages with unresolved template prompts or the generated draft summary. See page metadata for shared defaults and publication rules. The generated frontmatter reference lists native fields and this site's project declarations. Put it in navigation Append this item to the existing navigation list in docs.config.yaml : - id : track-parcel doc : how-to.track-parcel Use the page's frontmatter ID for doc ; the navigation item's own id identifies that menu entry. You can nest the item under a group's items list instead. Navigation uses the page title as its label unless you supply label . A public page can have a working URL without appearing in the sidebar. Adding this entry makes it discoverable there. See organize navigation for groups, includes, and links. Verify HTML and Markdown From the project directory: node \"$SHOALRUN_CLI\" build docs.config.yaml site-dist node \"$SHOALRUN_CLI\" serve site-dist --port 8765 Open http://127.0.0.1:8765/track-parcel and confirm that the page appears in navigation and that its links work. Then open http://127.0.0.1:8765/track-parcel.md and c","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Create a page from a template with scaffold . Templates prompt you for the page's frontmatter, an introduction, the main content, and related pages before you publish. This is the recommended authoring workflow for new pages. This guide assumes you have completed getting started and are working in my-docs/ . Keep SHOALRUN_CLI pointing to the checkout's framework/dist/cli.js . Choose a template Choose the template that matches what the reader needs to accomplish. Template Use it for tutorial A reliable guided exercise for learning by doing. how-to A specific task, with practical actions and a success check. reference Exact syntax, fields, options, examples, errors, and limits. explanation Concepts, context, reasons, and tradeoffs. api-reference Editorial context above generated operation details; requires one known operation ID. recipe A complete task used by recipe and cookbook workflows. ingredient One reusable action or check used in recipes. cookbook A page that helps readers choose complete recipes. These templates ship with the CLI. guide and troubleshooting remain available for compatibility. Projects can register additional templates or override built-ins. The CLI includes a recipe template for a complete customer task, written directly or assembled from ingredients. Built-in ingredient and cookbook templates support reusable steps and workflow selection. The ingredient draft command can start one ingredient from an API example; recipe draft assembles an ordered set of ingredient files for review. Use the project's template for the document type when one exists. Project templates can also override the built-in names. See templates to register or change one. Scaffold the draft From the project directory: node \"$SHOALRUN_CLI\" scaffold how-to -n content/track-parcel.mdx \\ --id how-to.track-parcel --title 'Track a parcel' The command finds docs.config.yaml , creates the file, and adds the template body and draft frontmatter. It refuses to overwrite an existing file. This example sets the stable ID and title explicitly; the CLI derives the slug /track-parcel from the target path. Without overrides, this path would produce ID how-to.track-parcel and title Track Parcel . The generated summary starts with Draft guide for and must be replaced before publication. Publication fields come from your project configuration. Complete the template Open content/track-parcel.mdx and work through its prompts: Read the comments in the frontmatter, fill in the placeholder fields, and delete the comment lines. Set updated to today's date in YYYY-MM-DD format. Write an introduction of 150 words or fewer and remove irrelevant optional sections. Follow the chosen shape. Write a guided exercise, practical task actions, organized reference facts, or conceptual discussion. For this how-to, write actions and checks. Keep the HTML, Markdown, and agents section when the page uses a component or behavior that changes either output or what an agent reads. Otherwise delete it. Add relationships for the page, or delete Related reading. Verify technical claims before you publish. Replace every TODO prompt enclosed in double square brackets. Adapt the sections to the task rather than leaving irrelevant prompts behind. Templates provide a starting structure; editing a template later does not rewrite this page. The quickstart shows a completed example. Keep the generated access.policy: draft while writing. Drafts are validated but omitted from the published site, even if the starter defaults to public access. Headings in the body begin at level 2 because Shoalrun renders the page title separately. Publish the page After reviewing the content, change the generated access value to: access: { policy: public } Keep the ID how-to.track-parcel and slug /track-parcel for this example. Check the channel, version, and language match an enabled publication. The build rejects public pages with unresolved template prompts or the generated draft summary. See page metadata for shared defaults and publication rules. The generated frontmatter reference lists native fields and this site's project declarations. Put it in navigation Append this item to the existing navigation list in docs.config.yaml : - id: track-parcel doc: how-to.track-parcel Use the page's frontmatter ID for doc ; the navigation item's own id identifies that menu entry. You can nest the item under a group's items list instead. Navigation uses the page title as its label unless you supply label . A public page can have a working URL without appearing in the sidebar. Adding this entry makes it discoverable there. See organize navigation for groups, includes, and links. Verify HTML and Markdown From the project directory: node \"$SHOALRUN_CLI\" build docs.config.yaml site-dist node \"$SHOALRUN_CLI\" serve site-dist --port 8765 Open http://127.0.0.1:8765/track-parcel and confirm that the page appears in navigation and that its links work. Then open http://127.0.0.1:8765/track-parcel.md and confi"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates — Adapt the starting template for your team's next pages."},{"filters":{"focus":["write"],"audience":["authors","maintainers"]},"text":"Page metadata — Check the scaffolded page's publication and metadata fields."},{"filters":{"focus":["configure"]},"text":"Troubleshooting — Find why a page is missing or a build fails."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":7649,"markdownTokens":1680,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.agent-discovery","demo":false,"url":"/publish/agent-discovery","markdownUrl":"/publish/agent-discovery.md","title":"Configure the agent discovery block","summary":"Choose how early HTML guidance appears, customize its wording, and verify its links.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[{"id":"choose-the-presentation","title":"Choose the presentation"},{"id":"set-the-message-and-link-labels","title":"Set the message and link labels"},{"id":"build-and-check-the-result","title":"Build and check the result"},{"id":"copy-the-page-as-markdown","title":"Copy the page as Markdown"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Configure the early HTML guidance so readers and agents can find the article, Markdown twin, and documentation index. Work in an existing Shoalrun project with a working local build. Choose the presentation Set site.agentDiscovery to change the early HTML instruction. The default mode: focus hides it visually until keyboard focus enters its links. Choose visible for an always-shown banner, or disclosure for a compact For agents toggle in the header that starts closed. All three modes include the guidance links in the HTML source. Choose off to omit the block from HTML entirely. The mode controls visual presentation and whether the block is included. Screen readers and agents parsing raw HTML can encounter the guidance in both focus and visible modes. The disclosure uses native HTML details and summary , so it works without JavaScript. Agents using screenshots see the same visual presentation as humans and need to open the disclosure to see its links. Some HTML extraction tools discard visually hidden elements; the document head also provides discovery links. This setting does not control access to documentation or make the guidance private. Set the message and link labels docs.config.yaml site : title : Cedar Parcel documentation agentDiscovery : mode : disclosure label : For agents message : Use Markdown for complete examples and nested schemas. links : article : Jump to the article index : Browse documentation markdown : Read Markdown The message and labels are plain text. Shoalrun generates the article, index, and Markdown destinations, including the site's base path. The standard Skip to content link stays first, even with the agent block disabled. The index destination is the compact text index, /llms.min.txt . It links to full Markdown pages and author-declared standalone sections with sizes and full-page fallbacks. The HTML head’s rel=\"describedby\" link and each Markdown page’s index backlink use the same compact index, including when the visible block is off. The detailed /llms.txt index remains linked from the compact index. These settings affect HTML only; the Markdown index link and discovery files remain available. See the configuration reference for defaults and validation rules. Build and check the result Run these commands from the directory containing docs.config.yaml : shoalrun check docs.config.yaml shoalrun build docs.config.yaml site-dist shoalrun serve site-dist --port 8765 Open a documentation page at http://127.0.0.1:8765/ . With focus , press Tab until the guidance links receive focus and the block appears. With visible , confirm the block appears before focusing it. With disclosure , confirm the header toggle starts closed, opens with Enter or a click, and exposes working links. With off , confirm the block is absent and Skip to content still works. Follow the article, index, and Markdown links. The article link should move focus to the main content; the index should open /llms.min.txt , and the Markdown link should open the current page's .md twin. A configured base path prefixes the generated resource URLs. View the HTML source to confirm that all three enabled modes include the links. The Markdown twin and discovery files should remain available in all three modes. If labels or destinations look wrong, check site.agentDiscovery in the resolved config and rebuild. Stop the server with Ctrl+C when finished. Copy the page as Markdown Use Copy as Markdown beside Read as Markdown to copy the current page's published Markdown twin. The button fetches the full file, including metadata and all reader-labeled sections, regardless of the selected HTML reader view. It uses the page's publication and base path. Activate the button with Enter, Space, or a tap. A visible status announces success or failure to screen readers. If fetching or clipboard access fails, use Read as Markdown to open and copy the file manually. The plain link also works without JavaScript; the copy button appears when its script loads. Browser clipboard access requires a secure context and permission. Related reading Reference while working Configuration reference — Look up discovery modes, defaults, labels, and validation rules. Related topics Agent-friendly documentation — Understand how HTML guidance, Markdown, and discovery files serve different readers.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure the early HTML guidance so readers and agents can find the article, Markdown twin, and documentation index. Work in an existing Shoalrun project with a working local build. Choose the presentation Set site.agentDiscovery to change the early HTML instruction. The default mode: focus hides it visually until keyboard focus enters its links. Choose visible for an always-shown banner, or disclosure for a compact For agents toggle in the header that starts closed. All three modes include the guidance links in the HTML source. Choose off to omit the block from HTML entirely. The mode controls visual presentation and whether the block is included. Screen readers and agents parsing raw HTML can encounter the guidance in both focus and visible modes. The disclosure uses native HTML details and summary , so it works without JavaScript. Agents using screenshots see the same visual presentation as humans and need to open the disclosure to see its links. Some HTML extraction tools discard visually hidden elements; the document head also provides discovery links. This setting does not control access to documentation or make the guidance private. Set the message and link labels site: title: Cedar Parcel documentation agentDiscovery: mode: disclosure label: For agents message: Use Markdown for complete examples and nested schemas. links: article: Jump to the article index: Browse documentation markdown: Read Markdown The message and labels are plain text. Shoalrun generates the article, index, and Markdown destinations, including the site's base path. The standard Skip to content link stays first, even with the agent block disabled. The index destination is the compact text index, /llms.min.txt . It links to full Markdown pages and author-declared standalone sections with sizes and full-page fallbacks. The HTML head’s rel=\"describedby\" link and each Markdown page’s index backlink use the same compact index, including when the visible block is off. The detailed /llms.txt index remains linked from the compact index. These settings affect HTML only; the Markdown index link and discovery files remain available. See the configuration reference for defaults and validation rules. Build and check the result Run these commands from the directory containing docs.config.yaml : shoalrun check docs.config.yaml shoalrun build docs.config.yaml site-dist shoalrun serve site-dist --port 8765 Open a documentation page at http://127.0.0.1:8765/ . With focus , press Tab until the guidance links receive focus and the block appears. With visible , confirm the block appears before focusing it. With disclosure , confirm the header toggle starts closed, opens with Enter or a click, and exposes working links. With off , confirm the block is absent and Skip to content still works. Follow the article, index, and Markdown links. The article link should move focus to the main content; the index should open /llms.min.txt , and the Markdown link should open the current page's .md twin. A configured base path prefixes the generated resource URLs. View the HTML source to confirm that all three enabled modes include the links. The Markdown twin and discovery files should remain available in all three modes. If labels or destinations look wrong, check site.agentDiscovery in the resolved config and rebuild. Stop the server with Ctrl+C when finished. Copy the page as Markdown Use Copy as Markdown beside Read as Markdown to copy the current page's published Markdown twin. The button fetches the full file, including metadata and all reader-labeled sections, regardless of the selected HTML reader view. It uses the page's publication and base path. Activate the button with Enter, Space, or a tap. A visible status announces success or failure to screen readers. If fetching or clipboard access fails, use Read as Markdown to open and copy the file manually. The plain link also works without JavaScript; the copy button appears when its script loads. Browser clipboard access requires a secure context and permission. Related reading Reference while working Related topics"},{"filters":{"focus":["configure"]},"text":"Configuration reference — Look up discovery modes, defaults, labels, and validation rules. Agent-friendly documentation — Understand how HTML guidance, Markdown, and discovery files serve different readers."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5423,"markdownTokens":1169,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.agent-friendliness","demo":false,"url":"/publish/agent-friendliness","markdownUrl":"/publish/agent-friendliness.md","title":"Agent-friendly documentation","summary":"See how interactive docs become readable Markdown, then discover pages and verify their contents.","type":"explanation","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[{"id":"try-the-page-controls","title":"Try the page controls"},{"id":"what-an-agent-reads","title":"What an agent reads"},{"id":"what-happens-to-an-unsupported-component","title":"What happens to an unsupported component?"},{"id":"discover-a-page-with-a-small-context-budget","title":"Discover a page with a small context budget"},{"id":"verify-the-page-and-detect-changes","title":"Verify the page and detect changes"},{"id":"keep-shared-instructions-complete","title":"Keep shared instructions complete"},{"id":"distinguish-examples-from-a-real-service","title":"Distinguish examples from a real service"},{"id":"use-the-transport-your-client-supports","title":"Use the transport your client supports"},{"id":"evidence-has-a-scope","title":"Evidence has a scope"},{"id":"secret-handshake","title":"Secret handshake"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun lets people use an interactive documentation page while agents read a Markdown copy of the same instructions. Tabs, closed disclosures, and reader choices should not make essential content disappear from that copy. The build checks that it knows how to turn each component into readable Markdown. If it does not, it stops with an error. Each generated Markdown page also has a SHA-256 digest, a fingerprint of its bytes. An agent can compare it with the fetched file to verify that the bytes match the published manifest. Try the example below. Switch the client tab, open Retry detail , and choose a reader. Then compare what is visible with the Markdown underneath, which retains both clients, the retry advice, and both reader sections. You can also open this page's actual Markdown . Try the page controls Command line Application Command line Send the request from a terminal. Application Send the request from application code. Retry detail Retry only after checking whether the first request succeeded. Open the activity screen to inspect the result. Inspect the response status and returned identifier. What an agent reads Here is the Markdown generated from the example above. An agent does not need to click the tabs, expand the disclosure, or choose a reader to get these instructions. ### Command line Send the request from a terminal. ### Application Send the request from application code. ### Retry detail Retry only after checking whether the first request succeeded. **For Reader: UI reader.** Open the activity screen to inspect the result. **For Reader: Developer.** Inspect the response status and returned identifier. The labels become headings or ordinary text. The controls themselves are omitted. This site's test compares the example's generated Markdown with the text shown here so they cannot drift apart unnoticed. The reader views reference explains how authors configure those choices. What happens to an unsupported component? A component needs rendering support for both HTML and Markdown. The compiler calls that support an adapter . If a page uses an unknown component such as the one below, Shoalrun stops rather than publishing a Markdown file that silently loses its contents. < UnregisteredPanel > This instruction must not disappear. </ UnregisteredPanel > Running shoalrun check docs.config.yaml reports a diagnostic containing: <UnregisteredPanel> has no semantic/Markdown adapter The example is displayed as code here so you can read it. A test also runs it as an actual component, checks that compilation fails, and verifies that the previous successful output remains intact. This check establishes how unsupported components are handled; it does not prove that every supported component or authored instruction is correct. Discover a page with a small context budget An agent does not need to download every discovery artifact. Start with /llms.min.txt , follow a matching topic index when present, and fetch the supplied Markdown page URL. Small indexes list pages directly. Larger indexes group pages by publication and primary taxonomy area, or page type when no area is declared. Topics split into narrower indexes as they grow. Each compact or navigation-section index is limited to 2,000 cl100k_base tokens. This is a limit per response, not a fixed total for every reading task. Page entries retain IDs, titles, summaries, publication labels, and Markdown links. Author-declared standalone sections retain exact sizes and a Full page fallback. Default to the full page for setup or broader questions. Every published page remains reachable, including pages outside navigation. Choose another artifact only when the task needs it: Resource When to use it llms.min.txt Follow topic indexes to full pages and declared standalone sections. search-index.min.json Inspect page headings as well as summaries, without article text. llms.txt Browse grouped page links, API downloads, and discovery resources. documents.json Read complete page metadata, digests, relationships, and contract links. documents.sync.json Compare a saved inventory with the current build. build-info.json Check whether the assembled build has changed. Both search indexes are generated when search indexing is enabled. The full /search-index.json includes bounded article text for browser search, CLI search, and custom lexical fallbacks. It remains available, but it is not needed to find a page through the compact list. These files are downloadable indexes, not query endpoints. Shoalrun does not produce llms-full.txt . HTML pages provide a visible Read as Markdown link, a rel=\"alternate\" link, and optional early agent guidance. The guidance links to the article, the compact index, and the current twin. The HTML head’s rel=\"describedby\" link and Markdown index backlinks also point to /llms.min.txt , so entering through either format leads to the same starting list. Follow those supplied links when a fetch tool rejects guessed URLs. Compact-lis","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Shoalrun lets people use an interactive documentation page while agents read a Markdown copy of the same instructions. Tabs, closed disclosures, and reader choices should not make essential content disappear from that copy. The build checks that it knows how to turn each component into readable Markdown. If it does not, it stops with an error. Each generated Markdown page also has a SHA-256 digest, a fingerprint of its bytes. An agent can compare it with the fetched file to verify that the bytes match the published manifest. Try the example below. Switch the client tab, open Retry detail , and choose a reader. Then compare what is visible with the Markdown underneath, which retains both clients, the retry advice, and both reader sections. You can also open this page's actual Markdown . Try the page controls Command line Application Command line Send the request from a terminal. Application Send the request from application code. Retry detail Retry only after checking whether the first request succeeded. What an agent reads Here is the Markdown generated from the example above. An agent does not need to click the tabs, expand the disclosure, or choose a reader to get these instructions. ### Command line Send the request from a terminal. ### Application Send the request from application code. ### Retry detail Retry only after checking whether the first request succeeded. **For Reader: UI reader.** Open the activity screen to inspect the result. **For Reader: Developer.** Inspect the response status and returned identifier. The labels become headings or ordinary text. The controls themselves are omitted. This site's test compares the example's generated Markdown with the text shown here so they cannot drift apart unnoticed. The reader views reference explains how authors configure those choices. What happens to an unsupported component? A component needs rendering support for both HTML and Markdown. The compiler calls that support an adapter . If a page uses an unknown component such as the one below, Shoalrun stops rather than publishing a Markdown file that silently loses its contents. <UnregisteredPanel> This instruction must not disappear. </UnregisteredPanel> Running shoalrun check docs.config.yaml reports a diagnostic containing: <UnregisteredPanel> has no semantic/Markdown adapter The example is displayed as code here so you can read it. A test also runs it as an actual component, checks that compilation fails, and verifies that the previous successful output remains intact. This check establishes how unsupported components are handled; it does not prove that every supported component or authored instruction is correct. Discover a page with a small context budget An agent does not need to download every discovery artifact. Start with /llms.min.txt , follow a matching topic index when present, and fetch the supplied Markdown page URL. Small indexes list pages directly. Larger indexes group pages by publication and primary taxonomy area, or page type when no area is declared. Topics split into narrower indexes as they grow. Each compact or navigation-section index is limited to 2,000 cl100k_base tokens. This is a limit per response, not a fixed total for every reading task. Page entries retain IDs, titles, summaries, publication labels, and Markdown links. Author-declared standalone sections retain exact sizes and a Full page fallback. Default to the full page for setup or broader questions. Every published page remains reachable, including pages outside navigation. Choose another artifact only when the task needs it: Resource When to use it llms.min.txt Follow topic indexes to full pages and declared standalone sections. search-index.min.json Inspect page headings as well as summaries, without article text. llms.txt Browse grouped page links, API downloads, and discovery resources. documents.json Read complete page metadata, digests, relationships, and contract links. documents.sync.json Compare a saved inventory with the current build. build-info.json Check whether the assembled build has changed. Both search indexes are generated when search indexing is enabled. The full /search-index.json includes bounded article text for browser search, CLI search, and custom lexical fallbacks. It remains available, but it is not needed to find a page through the compact list. These files are downloadable indexes, not query endpoints. Shoalrun does not produce llms-full.txt . HTML pages provide a visible Read as Markdown link, a rel=\"alternate\" link, and optional early agent guidance. The guidance links to the article, the compact index, and the current twin. The HTML head’s rel=\"describedby\" link and Markdown index backlinks also point to /llms.min.txt , so entering through either format leads to the same starting list. Follow those supplied links when a fetch tool rejects guessed URLs. Compact-list links are site-relative; resolve them against the fetched index's origin. Markdown page links use the configured publi"},{"filters":{"persona":["ui"]},"text":"Open the activity screen to inspect the result."},{"filters":{"persona":["developer"]},"text":"Inspect the response status and returned identifier."},{"filters":{"focus":["configure"]},"text":"Publishing and agent representations — Know which HTML, Markdown, and manifest files the build writes. Connect an MCP client — Connect a tool-capable client to bundled or built documentation. Content negotiation — Serve the Markdown twin when an agent asks for it. Configure the agent discovery block — Understand how HTML guidance, Markdown, and discovery files serve different readers. Connect an MCP client — Understand the published Markdown and discovery surfaces alongside MCP."},{"filters":{"focus":["write"]},"text":"Focused OpenAPI contracts — Focused contracts are how agents find exact API details without the full spec."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14705,"markdownTokens":2958,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"try-the-page-controls","title":"Try the page controls","markdownUrl":"/publish/agent-friendliness.sections/try-the-page-controls.md","markdownBytes":2621,"markdownTokens":598,"standalone":true},{"id":"what-an-agent-reads","title":"What an agent reads","markdownUrl":"/publish/agent-friendliness.sections/what-an-agent-reads.md","markdownBytes":3125,"markdownTokens":701},{"id":"what-happens-to-an-unsupported-component","title":"What happens to an unsupported component?","markdownUrl":"/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md","markdownBytes":3130,"markdownTokens":699},{"id":"discover-a-page-with-a-small-context-budget","title":"Discover a page with a small context budget","markdownUrl":"/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md","markdownBytes":5399,"markdownTokens":1132},{"id":"verify-the-page-and-detect-changes","title":"Verify the page and detect changes","markdownUrl":"/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md","markdownBytes":4180,"markdownTokens":861},{"id":"keep-shared-instructions-complete","title":"Keep shared instructions complete","markdownUrl":"/publish/agent-friendliness.sections/keep-shared-instructions-complete.md","markdownBytes":3337,"markdownTokens":728},{"id":"distinguish-examples-from-a-real-service","title":"Distinguish examples from a real service","markdownUrl":"/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md","markdownBytes":3257,"markdownTokens":724},{"id":"use-the-transport-your-client-supports","title":"Use the transport your client supports","markdownUrl":"/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md","markdownBytes":3755,"markdownTokens":850},{"id":"evidence-has-a-scope","title":"Evidence has a scope","markdownUrl":"/publish/agent-friendliness.sections/evidence-has-a-scope.md","markdownBytes":2966,"markdownTokens":660},{"id":"secret-handshake","title":"Secret handshake","markdownUrl":"/publish/agent-friendliness.sections/secret-handshake.md","markdownBytes":2451,"markdownTokens":577},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/agent-friendliness.sections/related-reading.md","markdownBytes":2981,"markdownTokens":695}]},{"id":"reference.agent-skills","demo":false,"url":"/reference/agent-skills","markdownUrl":"/reference/agent-skills.md","title":"Bundled agent skills","summary":"Skill names, locations, workflow behavior, offline documentation, and validation limits.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"skill-inventory","title":"Skill inventory"},{"id":"workflow-behavior","title":"Workflow behavior"},{"id":"component-authoring-skill","title":"Component-authoring skill"},{"id":"offline-documentation","title":"Offline documentation"},{"id":"limits","title":"Limits"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun ships five portable skill folders under framework/skills/ . Each folder contains a SKILL.md with instructions for an agent that can read files and run the Shoalrun CLI. A skill supplies guidance; it does not run a separate authoring service. These are authoring skills for Shoalrun. The build does not create a reader-side skill for each published site. Agents reading a generated site use its Markdown twins, /llms.txt , and /documents.json . A non-interactive skill builder is a non-goal : skill creation and maintenance need guidance from a human expert. Skill inventory Each skill supplies instructions for a specific part of the authoring workflow. Skill Use it for shoalrun-setup Start a docs project, choose a working example config, build it, and inspect its first HTML and Markdown pages. shoalrun-author Add or revise pages, navigation, API links, snippets, and project tests with the agent's own model and Shoalrun CLI. It uses normal file edits, project discovery, isolated validation, and snapshot review/preview tools. shoalrun-recipes Write task-oriented how-tos as complete recipes, reuse ingredients where helpful, and configure cookbook choices. shoalrun-component-author Create trusted custom components , validate their schemas and shared content, and review HTML/Markdown parity. shoalrun-walkthrough Turn notes, a tutorial, or project code into a walkthrough that explains code step by step. Each folder name matches its skill name. For example, the author skill's entry file is framework/skills/shoalrun-author/SKILL.md . Installation locations depend on the agent. Use the bundled agent skills describes choosing and invoking one. Workflow behavior The setup skill uses shoalrun init to create a project from the bundled minimal or api-docs starter, then uses config validate , build , and dev to check the result. The author skill uses stable IDs and project config provenance so edits stay attached to the intended publication. The walkthrough skill chooses a mode and layout, prefers code taken from project files, and checks each step's highlight. The recipes skill starts from a reader goal and success check, reuses ingredient source when useful, and distinguishes authoring from browser selection. All five ask the agent to inspect generated HTML and Markdown. They leave deployment decisions with the site owner. The author skill starts with project-wide discovery and policy reads, captures a task baseline, and edits ordinary working-tree files. It validates a separate capture and opens the matching snapshot review/preview. Required companions come from project policy; compiler success does not waive them. Existing local edits are included in the baseline rather than attributed to the new task. No extra authoring model key is needed. Explicit checked-plan clients can still use Apply a checked edit plan . Component-authoring skill shoalrun-component-author guides a coding agent through creating or repairing a trusted component plugin. It asks the agent to inventory essential content and decide what belongs in MDX and data. The agent then writes validation and shared content, adds browser controls where needed, and tests both representations. The agent produces project files, fixtures, usage examples, check results, and a local preview for review. The skill is an instruction file, not a compiler feature or an automatic React-to-Markdown converter. The component author and agent must write the complete static explanation. A passing build does not establish that every interactive choice or warning is represented faithfully. Custom components shows a small copy button with content in MDX, generated Markdown, and a sample agent request. Data-driven React components adds a local policy file and generated explanations. Offline documentation All five skills can consult Shoalrun's bundled docs through a local, agent-neutral tool: shoalrun docs search \"API reference navigation\" shoalrun docs read guide.api-references Search returns JSON with document IDs and excerpts. Read returns the complete generated Markdown page. The commands work offline and do not require a docs site to be running. They are useful to any agent that can run a CLI, even when it cannot discover SKILL.md files automatically. Limits Skills guide the agent's actions. They cannot establish whether a technical claim is true. Shoalrun's audit checks implemented build and representation rules and any configured external tests. Human review and behavior tests establish whether the instructions work. The recipes skill prefers complete task pages, adds ingredients when instructions are shared, and uses cookbooks when readers need help choosing tasks. It respects an explicitly requested format. Ingredients, recipes, and cookbooks explains those distinctions. Related reading Related topics Non-goals — Understand why a non-interactive skill builder is outside the tool's scope.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Shoalrun ships five portable skill folders under framework/skills/ . Each folder contains a SKILL.md with instructions for an agent that can read files and run the Shoalrun CLI. A skill supplies guidance; it does not run a separate authoring service. These are authoring skills for Shoalrun. The build does not create a reader-side skill for each published site. Agents reading a generated site use its Markdown twins, /llms.txt , and /documents.json . A non-interactive skill builder is a non-goal : skill creation and maintenance need guidance from a human expert. Skill inventory Each skill supplies instructions for a specific part of the authoring workflow. Skill Use it for shoalrun-setup Start a docs project, choose a working example config, build it, and inspect its first HTML and Markdown pages. shoalrun-author Add or revise pages, navigation, API links, snippets, and project tests with the agent's own model and Shoalrun CLI. It uses normal file edits, project discovery, isolated validation, and snapshot review/preview tools. shoalrun-recipes Write task-oriented how-tos as complete recipes, reuse ingredients where helpful, and configure cookbook choices. shoalrun-component-author Create trusted custom components , validate their schemas and shared content, and review HTML/Markdown parity. shoalrun-walkthrough Turn notes, a tutorial, or project code into a walkthrough that explains code step by step. Each folder name matches its skill name. For example, the author skill's entry file is framework/skills/shoalrun-author/SKILL.md . Installation locations depend on the agent. Use the bundled agent skills describes choosing and invoking one. Workflow behavior The setup skill uses shoalrun init to create a project from the bundled minimal or api-docs starter, then uses config validate , build , and dev to check the result. The author skill uses stable IDs and project config provenance so edits stay attached to the intended publication. The walkthrough skill chooses a mode and layout, prefers code taken from project files, and checks each step's highlight. The recipes skill starts from a reader goal and success check, reuses ingredient source when useful, and distinguishes authoring from browser selection. All five ask the agent to inspect generated HTML and Markdown. They leave deployment decisions with the site owner. The author skill starts with project-wide discovery and policy reads, captures a task baseline, and edits ordinary working-tree files. It validates a separate capture and opens the matching snapshot review/preview. Required companions come from project policy; compiler success does not waive them. Existing local edits are included in the baseline rather than attributed to the new task. No extra authoring model key is needed. Explicit checked-plan clients can still use Apply a checked edit plan . Component-authoring skill shoalrun-component-author guides a coding agent through creating or repairing a trusted component plugin. It asks the agent to inventory essential content and decide what belongs in MDX and data. The agent then writes validation and shared content, adds browser controls where needed, and tests both representations. The agent produces project files, fixtures, usage examples, check results, and a local preview for review. The skill is an instruction file, not a compiler feature or an automatic React-to-Markdown converter. The component author and agent must write the complete static explanation. A passing build does not establish that every interactive choice or warning is represented faithfully. Custom components shows a small copy button with content in MDX, generated Markdown, and a sample agent request. Data-driven React components adds a local policy file and generated explanations. Offline documentation All five skills can consult Shoalrun's bundled docs through a local, agent-neutral tool: shoalrun docs search \"API reference navigation\" shoalrun docs read guide.api-references Search returns JSON with document IDs and excerpts. Read returns the complete generated Markdown page. The commands work offline and do not require a docs site to be running. They are useful to any agent that can run a CLI, even when it cannot discover SKILL.md files automatically. Limits Skills guide the agent's actions. They cannot establish whether a technical claim is true. Shoalrun's audit checks implemented build and representation rules and any configured external tests. Human review and behavior tests establish whether the instructions work. The recipes skill prefers complete task pages, adds ingredients when instructions are shared, and uses cookbooks when readers need help choosing tasks. It respects an explicitly requested format. Ingredients, recipes, and cookbooks explains those distinctions. Related reading Related topics Non-goals — Understand why a non-interactive skill builder is outside the tool's scope."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":7163,"markdownTokens":1407,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.agent-skills","demo":false,"url":"/contribute/agent-skills","markdownUrl":"/contribute/agent-skills.md","title":"Use the bundled agent skills","summary":"Give an agent the setup and authoring workflows that ship with Shoalrun.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"choose-the-skill-for-your-task","title":"Choose the skill for your task"},{"id":"make-the-instructions-available","title":"Make the instructions available"},{"id":"give-the-agent-a-bounded-request","title":"Give the agent a bounded request"},{"id":"check-the-result","title":"Check the result"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Give an agent a bundled skill when you want it to follow Shoalrun's setup, authoring, recipe, component, or walkthrough workflow. You need an agent that can read the skill file and run commands, plus a Shoalrun checkout or installed CLI. Choose the skill for your task Use shoalrun-setup to start a site, shoalrun-author to add or revise pages, shoalrun-recipes to write a complete task recipe, or shoalrun-walkthrough to explain code in steps. Use shoalrun-component-author to create trusted custom components. The skill reference lists their locations and behavior. Make the instructions available Install the complete folder in your agent's skill directory using that agent's installation process. If it supports reading repository files directly, point it at the entry file instead. For a recipe task, use framework/skills/shoalrun-recipes/SKILL.md . In an installed package, skill folders live under node_modules/@shoalrun/cli/skills/ . These files are portable instructions; the CLI does not install them into your agent automatically. Give your agent the installed shoalrun-author/SKILL.md path and the consumer project's docs.config.yaml path. Use the existing harness's file, terminal, and browser tools. No separate authoring service or model configuration is required. Ask the agent to read the skill before beginning. If it cannot discover installed skills, include the file path. If it cannot read files or run a CLI, follow the page creation workflow yourself. Give the agent a bounded request Name the task, documentation project, relevant source files, and result to check. For example: Read framework/skills/shoalrun-recipes/SKILL.md and use its workflow. Write a complete recipe for previewing a Shoalrun documentation change. Work in this checkout's docs project. Include setup, commands, failure guidance, and a final success check. Reuse existing ingredients where instructions are shared. Preserve IDs and routes when updating pages, and set updated to today's date. Show the diff and verification results. For a page edit, name the stable document ID and the facts that must stay unchanged. Use a coding agent with Shoalrun explains native editing and checks. Check working-tree documentation edits covers baselines, validation, and matching previews. Check the result Ask the agent to show the changed files, rendered HTML and Markdown, and results from the project's checks. Read the diff and verify technical claims against the source or API contract. For an existing page, confirm its ID and route are preserved and updated records the edit date. If the agent lacks product guidance, have it run shoalrun docs search and shoalrun docs read using the offline documentation commands . If a build or audit fails, ask it to fix the reported issue and rerun the check. A passing check covers the implemented rules; review the task instructions and factual claims before committing or publishing. Related reading Reference while working Bundled agent skills — Look up shipped skill names, locations, workflows, and offline documentation behavior. Related topics Frontmatter field reference — Point agents at the local inventory of page fields this project accepts. Apply a checked edit plan — Let an agent run the same draft, check, and apply loop. (Status: experimental.) Getting started — Give an agent the same setup and authoring workflow as a bundled skill. Use your coding agent — Give your coding agent the bundled Shoalrun workflow instructions.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Give an agent a bundled skill when you want it to follow Shoalrun's setup, authoring, recipe, component, or walkthrough workflow. You need an agent that can read the skill file and run commands, plus a Shoalrun checkout or installed CLI. Choose the skill for your task Use shoalrun-setup to start a site, shoalrun-author to add or revise pages, shoalrun-recipes to write a complete task recipe, or shoalrun-walkthrough to explain code in steps. Use shoalrun-component-author to create trusted custom components. The skill reference lists their locations and behavior. Make the instructions available Install the complete folder in your agent's skill directory using that agent's installation process. If it supports reading repository files directly, point it at the entry file instead. For a recipe task, use framework/skills/shoalrun-recipes/SKILL.md . In an installed package, skill folders live under node_modules/@shoalrun/cli/skills/ . These files are portable instructions; the CLI does not install them into your agent automatically. Give your agent the installed shoalrun-author/SKILL.md path and the consumer project's docs.config.yaml path. Use the existing harness's file, terminal, and browser tools. No separate authoring service or model configuration is required. Ask the agent to read the skill before beginning. If it cannot discover installed skills, include the file path. If it cannot read files or run a CLI, follow the page creation workflow yourself. Give the agent a bounded request Name the task, documentation project, relevant source files, and result to check. For example: Read framework/skills/shoalrun-recipes/SKILL.md and use its workflow. Write a complete recipe for previewing a Shoalrun documentation change. Work in this checkout's docs project. Include setup, commands, failure guidance, and a final success check. Reuse existing ingredients where instructions are shared. Preserve IDs and routes when updating pages, and set updated to today's date. Show the diff and verification results. For a page edit, name the stable document ID and the facts that must stay unchanged. Use a coding agent with Shoalrun explains native editing and checks. Check working-tree documentation edits covers baselines, validation, and matching previews. Check the result Ask the agent to show the changed files, rendered HTML and Markdown, and results from the project's checks. Read the diff and verify technical claims against the source or API contract. For an existing page, confirm its ID and route are preserved and updated records the edit date. If the agent lacks product guidance, have it run shoalrun docs search and shoalrun docs read using the offline documentation commands . If a build or audit fails, ask it to fix the reported issue and rerun the check. A passing check covers the implemented rules; review the task instructions and factual claims before committing or publishing. Related reading Reference while working Related topics Getting started — Give an agent the same setup and authoring workflow as a bundled skill."},{"filters":{"focus":["write"]},"text":"Bundled agent skills — Look up shipped skill names, locations, workflows, and offline documentation behavior. Frontmatter field reference — Point agents at the local inventory of page fields this project accepts."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Apply a checked edit plan — Let an agent run the same draft, check, and apply loop. (Status: experimental.) Use your coding agent — Give your coding agent the bundled Shoalrun workflow instructions."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4845,"markdownTokens":1133,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.analytics","demo":false,"url":"/author/analytics","markdownUrl":"/author/analytics.md","title":"Bring your own analytics","summary":"Send documentation interaction events to your analytics service through an optional browser adapter.","type":"reference","variant":"production|current|en","area":"quality","subarea":"quality-analytics","headings":[{"id":"configure-an-adapter","title":"Configure an adapter"},{"id":"adapter-exports-and-consent","title":"Adapter exports and consent"},{"id":"event-format","title":"Event format"},{"id":"built-in-events","title":"Built-in events"},{"id":"map-events-to-your-service","title":"Map events to your service"},{"id":"custom-interactions","title":"Custom interactions"},{"id":"inspect-events-locally","title":"Inspect events locally"},{"id":"posthog-example","title":"PostHog example"},{"id":"install-the-sdk-and-bundler","title":"Install the SDK and bundler"},{"id":"create-the-adapter","title":"Create the adapter"},{"id":"bundle-and-configure-the-module","title":"Bundle and configure the module"},{"id":"verify-events-on-localhost","title":"Verify events on localhost"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun sends documentation interactions to an analytics service through an adapter : a browser module you supply to initialize the service and deliver events. Analytics is off by default. Shoalrun includes no service SDK, storage, visitor identity, or delivery queue. Configure an adapter Point analytics.module at a local .js or .mjs file: docs.config.yaml analytics : module : ./analytics.js Paths resolve relative to the declaring config file, including included files. The build copies the module to /assets/analytics-adapter.js without executing or bundling it. Supply a self-contained module or use browser-resolvable imports; relative imports resolve from the copied asset directory. The file becomes public browser code. For example, if your page already initializes a client named myAnalytics , forward events to its capture method: analytics.js export function track (event) { globalThis . myAnalytics .capture ( event .name , event .properties); } Replace the client and method with your service’s API. Set analytics: false , or omit the setting, to exclude the runtime, adapter, and page context. Unknown settings, unsupported extensions, and missing files fail the build. Adapter exports and consent Implement these exports in your browser module: Export Required Contract track(event) Yes Receive an event; may return a promise. The adapter owns delivery, batching, retries, and flushing before navigation. init(context) No Initialize the service or await consent; may return a promise. Events start after it resolves. The read-only context provides page properties, setEnabled(boolean) , and track(name, properties, element?) . Import or initialization failures disable analytics for the page. Thrown or rejected track calls are caught without interrupting controls or navigation; Shoalrun does not retry them. Events are discarded while initialization is pending or delivery is disabled. After initialization, Shoalrun sends page_view if enabled. To delay collection, await consent in init , or call setEnabled(false) and enable delivery from your consent callback. In the latter case, call track('page_view') after enabling to count the current page. You can also disable delivery through the public hook: globalThis . shoalrunAnalytics ?.setEnabled ( false ); Connect consent changes to your SDK too. Disabling Shoalrun does not stop SDK-generated events, unload the SDK, or revoke data already sent. Event format Each event has schemaVersion , name , and properties . For example: { \"schemaVersion\" : 1 , \"name\" : \"content_tab_change\" , \"properties\" : { \"pageId\" : \"guide.example\" , \"pageUrl\" : \"/example\" , \"documentType\" : \"reference\" , \"channel\" : \"production\" , \"version\" : \"current\" , \"language\" : \"en\" , \"navigationSectionId\" : \"docs\" , \"componentId\" : \"clients:tabs:1\" , \"componentType\" : \"tabs\" , \"headingId\" : \"clients\" , \"tabIndex\" : 1 , \"tabId\" : \"clients-2\" } } Every event includes page identity and publication properties; navigationSectionId appears only for pages in a navigation tab. pageUrl is the published path without query or fragment. Custom properties cannot replace page identity. Events associated with an element add component context. componentId uses data-analytics-id , then the element’s HTML ID, then its heading, kind, and position. Generated IDs can change when content moves. componentType is tabs , walkthrough , disclosure , code , or control ; headingId identifies the preceding article heading when available. Built-in events Use these events to measure browser interactions. Each includes the page properties above. Event Additional properties Trigger page_view None Once after adapter initialization, when delivery is enabled. navigation_click region , targetPath , external A section, sidebar, outline, breadcrumb, related-reading, card, hero, footer, header, article, or Markdown-action link is activated. content_tab_change tabIndex , tabId A different content tab is selected by click or keyboard. Initial selection and hash reveals are excluded. disclosure_toggle open A reader opens or closes a Collapsible or article InfoHint through its summary. Programmatic initialization is excluded. walkthrough_step_change stepIndex , stepCount , layout , trigger A different walkthrough step becomes active through click, keyboard, or step scrolling. Initial selection and layout changes are excluded. code_copy language , optional stepIndex A code example or walkthrough pane is successfully written to the clipboard. markdown_copy None The full Markdown twin is successfully written to the clipboard. section_link_copy targetHeadingId A heading's link is successfully written to the clipboard. search_results queryLength , resultCount , status A completed search settles for 300 ms. Status is results , empty , or error ; the count is the displayed result count. search_result_click queryLength , resultIndex , targetPath A search result is activated, including through the keyboard. reader_filter_change scope , filter_<facet> , opti","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Shoalrun sends documentation interactions to an analytics service through an adapter : a browser module you supply to initialize the service and deliver events. Analytics is off by default. Shoalrun includes no service SDK, storage, visitor identity, or delivery queue. Configure an adapter Point analytics.module at a local .js or .mjs file: analytics: module: ./analytics.js Paths resolve relative to the declaring config file, including included files. The build copies the module to /assets/analytics-adapter.js without executing or bundling it. Supply a self-contained module or use browser-resolvable imports; relative imports resolve from the copied asset directory. The file becomes public browser code. For example, if your page already initializes a client named myAnalytics , forward events to its capture method: export function track(event) { globalThis.myAnalytics.capture(event.name, event.properties); } Replace the client and method with your service’s API. Set analytics: false , or omit the setting, to exclude the runtime, adapter, and page context. Unknown settings, unsupported extensions, and missing files fail the build. Adapter exports and consent Implement these exports in your browser module: Export Required Contract track(event) Yes Receive an event; may return a promise. The adapter owns delivery, batching, retries, and flushing before navigation. init(context) No Initialize the service or await consent; may return a promise. Events start after it resolves. The read-only context provides page properties, setEnabled(boolean) , and track(name, properties, element?) . Import or initialization failures disable analytics for the page. Thrown or rejected track calls are caught without interrupting controls or navigation; Shoalrun does not retry them. Events are discarded while initialization is pending or delivery is disabled. After initialization, Shoalrun sends page_view if enabled. To delay collection, await consent in init , or call setEnabled(false) and enable delivery from your consent callback. In the latter case, call track('page_view') after enabling to count the current page. You can also disable delivery through the public hook: globalThis.shoalrunAnalytics?.setEnabled(false); Connect consent changes to your SDK too. Disabling Shoalrun does not stop SDK-generated events, unload the SDK, or revoke data already sent. Event format Each event has schemaVersion , name , and properties . For example: { \"schemaVersion\": 1, \"name\": \"content_tab_change\", \"properties\": { \"pageId\": \"guide.example\", \"pageUrl\": \"/example\", \"documentType\": \"reference\", \"channel\": \"production\", \"version\": \"current\", \"language\": \"en\", \"navigationSectionId\": \"docs\", \"componentId\": \"clients:tabs:1\", \"componentType\": \"tabs\", \"headingId\": \"clients\", \"tabIndex\": 1, \"tabId\": \"clients-2\" } } Every event includes page identity and publication properties; navigationSectionId appears only for pages in a navigation tab. pageUrl is the published path without query or fragment. Custom properties cannot replace page identity. Events associated with an element add component context. componentId uses data-analytics-id , then the element’s HTML ID, then its heading, kind, and position. Generated IDs can change when content moves. componentType is tabs , walkthrough , disclosure , code , or control ; headingId identifies the preceding article heading when available. Built-in events Use these events to measure browser interactions. Each includes the page properties above. Event Additional properties Trigger page_view None Once after adapter initialization, when delivery is enabled. navigation_click region , targetPath , external A section, sidebar, outline, breadcrumb, related-reading, card, hero, footer, header, article, or Markdown-action link is activated. content_tab_change tabIndex , tabId A different content tab is selected by click or keyboard. Initial selection and hash reveals are excluded. disclosure_toggle open A reader opens or closes a Collapsible or article InfoHint through its summary. Programmatic initialization is excluded. walkthrough_step_change stepIndex , stepCount , layout , trigger A different walkthrough step becomes active through click, keyboard, or step scrolling. Initial selection and layout changes are excluded. code_copy language , optional stepIndex A code example or walkthrough pane is successfully written to the clipboard. markdown_copy None The full Markdown twin is successfully written to the clipboard. section_link_copy targetHeadingId A heading's link is successfully written to the clipboard. search_results queryLength , resultCount , status A completed search settles for 300 ms. Status is results , empty , or error ; the count is the displayed result count. search_result_click queryLength , resultIndex , targetPath A search result is activated, including through the keyboard. reader_filter_change scope , filter_<facet> , optional inherit A site or page reader selection changes through the controls or rea"},{"filters":{"focus":["configure"]},"text":"Measure MCP tool usage — Measure documentation tool calls separately from browser interactions. Site search — Configure the search provider whose displayed outcomes analytics records. Configuration reference — Find the project-level analytics module setting. Measure MCP tool usage — Collect browser interactions through the separate browser adapter."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":18753,"markdownTokens":3673,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"configure-an-adapter","title":"Configure an adapter","markdownUrl":"/author/analytics.sections/configure-an-adapter.md","markdownBytes":2281,"markdownTokens":517},{"id":"adapter-exports-and-consent","title":"Adapter exports and consent","markdownUrl":"/author/analytics.sections/adapter-exports-and-consent.md","markdownBytes":2903,"markdownTokens":598},{"id":"event-format","title":"Event format","markdownUrl":"/author/analytics.sections/event-format.md","markdownBytes":2427,"markdownTokens":589},{"id":"built-in-events","title":"Built-in events","markdownUrl":"/author/analytics.sections/built-in-events.md","markdownBytes":5327,"markdownTokens":905},{"id":"map-events-to-your-service","title":"Map events to your service","markdownUrl":"/author/analytics.sections/map-events-to-your-service.md","markdownBytes":2422,"markdownTokens":519},{"id":"custom-interactions","title":"Custom interactions","markdownUrl":"/author/analytics.sections/custom-interactions.md","markdownBytes":2860,"markdownTokens":641},{"id":"inspect-events-locally","title":"Inspect events locally","markdownUrl":"/author/analytics.sections/inspect-events-locally.md","markdownBytes":1755,"markdownTokens":409},{"id":"posthog-example","title":"PostHog example","markdownUrl":"/author/analytics.sections/posthog-example.md","markdownBytes":5996,"markdownTokens":1321},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/analytics.sections/html-markdown-and-agents.md","markdownBytes":2764,"markdownTokens":592},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/analytics.sections/related-reading.md","markdownBytes":1856,"markdownTokens":431}]},{"id":"guide.api-generation","demo":false,"url":"/api-docs/generate","markdownUrl":"/api-docs/generate.md","title":"Generate and select API pages","summary":"Choose operations, generate reference pages, and add editorial context to an API reference.","type":"how-to","variant":"production|current|en","area":"api","subarea":"api-generation","headings":[{"id":"choose-generated-references-or-mdx","title":"Choose generated references or MDX"},{"id":"generate-many-pages-selectively","title":"Generate many pages selectively"},{"id":"override-generated-reference-order-in-navigation","title":"Override generated reference order in navigation"},{"id":"use-a-template-for-editorial-context","title":"Use a template for editorial context"},{"id":"add-useful-examples","title":"Add useful examples"},{"id":"link-guides-to-api-references","title":"Link guides to API references"},{"id":"map-extension-values-to-shoalrun-status","title":"Map extension values to Shoalrun status"},{"id":"describe-filters-that-do-not-use-their-openapi-parameter-name","title":"Describe filters that do not use their OpenAPI parameter name"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Start with a registered local API from Add an OpenAPI API . Use generation when you want references for many operations without writing an MDX page for each one. The commands below run in your documentation project with SHOALRUN_CLI set as in the quickstart. Choose generated references or MDX Use build-time generated references when the OpenAPI contract already gives readers the method, path, parameters, schemas, and examples they need. The pages update whenever the reviewed source changes, and there are no MDX files to maintain. Use an authored MDX reference when an endpoint needs a reviewed introduction, prerequisites, limitations, or task-specific context that the contract cannot express. The compiler still appends the contract details from OpenAPI, so do not copy field tables and example payloads into MDX. Use a guide for a task spanning several endpoints; link its reference pages with relatedApiReferences . The one-time api materialize command creates draft MDX references for every endpoint or selected source operation IDs or method/path routes. It does not change config or navigation and never rewrites an existing page. For example: node \"$SHOALRUN_CLI\" api materialize notes docs.config.yaml --all node \"$SHOALRUN_CLI\" api materialize notes docs.config.yaml --operation getNote node \"$SHOALRUN_CLI\" api materialize notes docs.config.yaml --route 'GET /notes/{id}' The default destination is content/api/<api-id>/ ; use --output for another directory inside the configured content tree. Selectors use the OpenAPI operationId or exact uppercase method and path. Repeating a command reports the existing matching page as skipped. A file with a conflicting identity stops the job before it writes anything. Existing authored references also count as skipped. Each new page has a stable document ID, slug, operation binding, and access.policy: draft . The draft contains an editorial prompt. While it remains a draft, any already selected build-time reference continues to publish. Review the text, replace the prompt, then set access to public ; that MDX page takes the generated page's place for its publication. This also works when generateReferences is off: the authored page binds to the registered API's local OpenAPI source. The command never enables build-time generation, changes the public review digest, or chooses navigation order for you. Run api review before publishing changed API content, and place the reference with operation: or doc: in navigation if it is not already covered by a generator. Generate many pages selectively For a large API, set generateReferences on its API config. This avoids writing one MDX file and registry entry for every operation. The build scans the local spec and creates HTML and Markdown reference pages for selected operations. An explicit operations entry and authored page take precedence for that operation. The example Create a note page is authored, while its Get a note page is generated. The example below uses this site's two-operation Notes source , which contains createNote and getNote . To try it after the tutorial, replace your one-operation apis/notes/openapi.yaml with that source first. Keep the authored Create a note page and its binding. Store the generation choices in a separate config file: config/api.yaml notes : publicReview : digest : <digest-from-your-api-review> source : { kind : file , path : ../apis/notes/openapi.yaml , publish : true } operations : - { id : notes.create , sourceOperationId : createNote , reference : reference.create-note } generateReferences : { $include : ./notes-pages.yaml } config/notes-pages.yaml pathPrefix : /example-api/generated include : [ getNote ] include lists source operationId values to generate; an empty list generates none. You can use exclude instead to generate all but named operations, or set generateReferences: true to generate every operation without an authored binding. The build rejects unknown selection IDs. Generated IDs and URLs derive from the API ID and source operationId , not the operation summary, so editing a title does not move the page. If an operationId changes, add an authored binding when the old public identity must remain stable. For an API notes and operationId: getNote , the generator creates: Value Pattern Example Stable operation ID <apiId>.<operationId> notes.getNote Page ID reference.<apiId>.<operationId> reference.notes.getNote Slug <pathPrefix>/<kebab-case operationId>-<8-character hash> /example-api/generated/get-note-cbedb319 pathPrefix defaults to /reference/<apiId> . An operationId with characters outside letters, digits, . , _ , and - uses the kebab-case name plus the hash in place of the raw ID. Use the page ID in relatedApiReferences and the stable operation ID in navigation operation: entries. Generated pages pass through global frontmatter defaults and enforced values, so an enforced value or a required custom field applies to them too. The pag","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Start with a registered local API from Add an OpenAPI API . Use generation when you want references for many operations without writing an MDX page for each one. The commands below run in your documentation project with SHOALRUN_CLI set as in the quickstart. Choose generated references or MDX Use build-time generated references when the OpenAPI contract already gives readers the method, path, parameters, schemas, and examples they need. The pages update whenever the reviewed source changes, and there are no MDX files to maintain. Use an authored MDX reference when an endpoint needs a reviewed introduction, prerequisites, limitations, or task-specific context that the contract cannot express. The compiler still appends the contract details from OpenAPI, so do not copy field tables and example payloads into MDX. Use a guide for a task spanning several endpoints; link its reference pages with relatedApiReferences . The one-time api materialize command creates draft MDX references for every endpoint or selected source operation IDs or method/path routes. It does not change config or navigation and never rewrites an existing page. For example: node \"$SHOALRUN_CLI\" api materialize notes docs.config.yaml --all node \"$SHOALRUN_CLI\" api materialize notes docs.config.yaml --operation getNote node \"$SHOALRUN_CLI\" api materialize notes docs.config.yaml --route 'GET /notes/{id}' The default destination is content/api/<api-id>/ ; use --output for another directory inside the configured content tree. Selectors use the OpenAPI operationId or exact uppercase method and path. Repeating a command reports the existing matching page as skipped. A file with a conflicting identity stops the job before it writes anything. Existing authored references also count as skipped. Each new page has a stable document ID, slug, operation binding, and access.policy: draft . The draft contains an editorial prompt. While it remains a draft, any already selected build-time reference continues to publish. Review the text, replace the prompt, then set access to public ; that MDX page takes the generated page's place for its publication. This also works when generateReferences is off: the authored page binds to the registered API's local OpenAPI source. The command never enables build-time generation, changes the public review digest, or chooses navigation order for you. Run api review before publishing changed API content, and place the reference with operation: or doc: in navigation if it is not already covered by a generator. Generate many pages selectively For a large API, set generateReferences on its API config. This avoids writing one MDX file and registry entry for every operation. The build scans the local spec and creates HTML and Markdown reference pages for selected operations. An explicit operations entry and authored page take precedence for that operation. The example Create a note page is authored, while its Get a note page is generated. The example below uses this site's two-operation Notes source , which contains createNote and getNote . To try it after the tutorial, replace your one-operation apis/notes/openapi.yaml with that source first. Keep the authored Create a note page and its binding. Store the generation choices in a separate config file: notes: publicReview: digest: <digest-from-your-api-review> source: { kind: file, path: ../apis/notes/openapi.yaml, publish: true } operations: - { id: notes.create, sourceOperationId: createNote, reference: reference.create-note } generateReferences: { $include: ./notes-pages.yaml } pathPrefix: /example-api/generated include: [getNote] include lists source operationId values to generate; an empty list generates none. You can use exclude instead to generate all but named operations, or set generateReferences: true to generate every operation without an authored binding. The build rejects unknown selection IDs. Generated IDs and URLs derive from the API ID and source operationId , not the operation summary, so editing a title does not move the page. If an operationId changes, add an authored binding when the old public identity must remain stable. For an API notes and operationId: getNote , the generator creates: Value Pattern Example Stable operation ID <apiId>.<operationId> notes.getNote Page ID reference.<apiId>.<operationId> reference.notes.getNote Slug <pathPrefix>/<kebab-case operationId>-<8-character hash> /example-api/generated/get-note-cbedb319 pathPrefix defaults to /reference/<apiId> . An operationId with characters outside letters, digits, . , _ , and - uses the kebab-case name plus the hash in place of the raw ID. Use the page ID in relatedApiReferences and the stable operation ID in navigation operation: entries. Generated pages pass through global frontmatter defaults and enforced values, so an enforced value or a required custom field applies to them too. The page title is the operation summary , or the method and path when there is no summary. OpenAPI 3.1 webhooks can us"},{"filters":{"focus":["write"]},"text":"Add an OpenAPI API — Register and review an API source before generating its pages. Organize site navigation — Arrange selected operations in the site menu. Organize site navigation — Generate the API reference pages that fill a tag group in the menu."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":17360,"markdownTokens":3736,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"choose-generated-references-or-mdx","title":"Choose generated references or MDX","markdownUrl":"/api-docs/generate.sections/choose-generated-references-or-mdx.md","markdownBytes":3818,"markdownTokens":856},{"id":"generate-many-pages-selectively","title":"Generate many pages selectively","markdownUrl":"/api-docs/generate.sections/generate-many-pages-selectively.md","markdownBytes":5368,"markdownTokens":1199},{"id":"override-generated-reference-order-in-navigation","title":"Override generated reference order in navigation","markdownUrl":"/api-docs/generate.sections/override-generated-reference-order-in-navigation.md","markdownBytes":4169,"markdownTokens":968},{"id":"use-a-template-for-editorial-context","title":"Use a template for editorial context","markdownUrl":"/api-docs/generate.sections/use-a-template-for-editorial-context.md","markdownBytes":2444,"markdownTokens":576},{"id":"add-useful-examples","title":"Add useful examples","markdownUrl":"/api-docs/generate.sections/add-useful-examples.md","markdownBytes":4662,"markdownTokens":1045},{"id":"link-guides-to-api-references","title":"Link guides to API references","markdownUrl":"/api-docs/generate.sections/link-guides-to-api-references.md","markdownBytes":2545,"markdownTokens":613},{"id":"map-extension-values-to-shoalrun-status","title":"Map extension values to Shoalrun status","markdownUrl":"/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md","markdownBytes":2386,"markdownTokens":579},{"id":"describe-filters-that-do-not-use-their-openapi-parameter-name","title":"Describe filters that do not use their OpenAPI parameter name","markdownUrl":"/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md","markdownBytes":2442,"markdownTokens":589},{"id":"related-reading","title":"Related reading","markdownUrl":"/api-docs/generate.sections/related-reading.md","markdownBytes":1632,"markdownTokens":415}]},{"id":"guide.api-references","demo":false,"url":"/publish/api-references","markdownUrl":"/publish/api-references.md","title":"Add an OpenAPI API","summary":"Import a local OpenAPI file, author an operation page, review its public content, and build HTML and Markdown.","type":"how-to","variant":"production|current|en","area":"api","subarea":"api-contracts","headings":[{"id":"put-the-spec-in-your-project","title":"Put the spec in your project"},{"id":"register-the-operation","title":"Register the operation"},{"id":"author-the-reference-page","title":"Author the reference page"},{"id":"review-imported-content-before-publishing","title":"Review imported content before publishing"},{"id":"build-and-verify-the-output","title":"Build and verify the output"},{"id":"what-readers-get","title":"What readers get"},{"id":"publish-several-versions","title":"Publish several versions"},{"id":"map-extension-values-to-shoalrun-status","title":"Map extension values to Shoalrun status"},{"id":"describe-filters-that-do-not-use-their-openapi-parameter-name","title":"Describe filters that do not use their OpenAPI parameter name"},{"id":"generate-many-pages-selectively","title":"Generate many pages selectively"},{"id":"use-a-template-for-editorial-context","title":"Use a template for editorial context"},{"id":"add-useful-examples","title":"Add useful examples"},{"id":"link-guides-to-api-references","title":"Link guides to API references"},{"id":"inspect-the-machine-readable-contract","title":"Inspect the machine-readable contract"},{"id":"preview-a-small-api-reference","title":"Preview a small API reference"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Add one authored API reference to the project created in the quickstart . This walkthrough uses a fictional Notes API as its example. You will register an operation, write its introduction, add it to navigation, review the imported content, and verify its published files. Run commands from the documentation project directory created in the quickstart, where @shoalrun/cli is installed. The commands use that local package. Check OpenAPI support and limits before importing a larger specification. Put the spec in your project Create apis/notes/openapi.yaml with this complete fictional API. It documents a response without calling a live service: apis/notes/openapi.yaml openapi : 3.1.0 info : { title : Example Notes API , version : 1.0.0 } paths : /notes : post : operationId : createNote summary : Create a note responses : '201' : description : The note was created. content : application/json : schema : type : object required : [ id ] properties : id : { type : string , description : The new note identifier. } examples : created : summary : A created note value : { id : note_123 } OpenAPI 3.0 or 3.1 YAML and JSON files are accepted. There is no required directory name; a spec can also reference other local files. Register the operation Add this top-level entry to your existing docs.config.yaml : docs.config.yaml apis : { $include : ./config/api.yaml } Create the config directory if needed and add config/api.yaml : config/api.yaml notes : source : kind : file path : ../apis/notes/openapi.yaml focused : true operations : - id : notes.create sourceOperationId : createNote reference : reference.create-note source.path is relative to the config fragment that declares it. notes names this API, and sourceOperationId selects the spec's operationId . The stable operation ID notes.create connects the operation to authored pages; reference names the page that will present it. focused: true publishes a one-operation contract . For your own API, if the source lives at a public HTTPS URL, import it into a local snapshot first. Replace the example URL below with your actual OpenAPI URL: npx --no-install shoalrun api import https://api.example.com/openapi.yaml --output apis/remote Point source.path at ../apis/remote/openapi.yaml from config/api.yaml . Commit the snapshot and its source-lock.json . Normal builds use those local files and make no network request. To check for upstream changes, run api refresh apis/remote --output apis/remote-next . If the source changed, the command reports the changed hashes and writes a complete new snapshot while keeping apis/remote intact. Point source.path to ../apis/remote-next/openapi.yaml , inspect a new api review candidate, and pin its digest before building. The CLI reference lists import limits. Author the reference page Create content/create-note.mdx : content/create-note.mdx --- id : reference.create-note title : Create a note summary : Create a note in the fictional Notes API. type : api-reference slug : /example-api/create-note channel : production version : current language : en operations : [ notes.create ] access : { policy : public } --- This fictional operation returns the identifier of a new note. Its response schema and named example are generated from the local OpenAPI file. The page ID must match the registry's reference value. An api-reference page lists exactly one operation. The compiler appends the method, path, parameters, authentication, schemas, and examples to your authored introduction. Append this entry to the existing navigation array in docs.config.yaml : - id : notes-create doc : reference.create-note If your project includes navigation from another file, add the entry there. Save the page and navigation before the review so the candidate contains the page you intend to publish. Review imported content before publishing Shoalrun requires publicReview.digest for every API whose content appears in a public page, embed, or focused contract. A missing or stale digest stops a normal build. Generate a local candidate in a fresh temporary directory: API_REVIEW_DIR = \"$( mktemp -d /tmp/shoalrun-api-review.XXXXXX )\" npx --no-install shoalrun api review docs.config.yaml --output \"$API_REVIEW_DIR\" The command builds the candidate and reports each API's digest, page URLs, focused contracts, full-source downloads, and input hashes. Inspect the candidate files for private operations, fields, descriptions, examples, and credentials. For this example, check the Create a note HTML and Markdown page and its linked focused contract. Copy the reported digest for notes into config/api.yaml alongside source and operations : notes : publicReview : digest : <paste-the-reported-notes-digest> # Keep source and operations here. Replace the angle-bracket placeholder with the actual digest. Keep the candidate local and remove it after review. The digest records what you reviewed; it does not determine whether content is safe. Changing source bytes, selected operations or embeds, focu","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Add one authored API reference to the project created in the quickstart . This walkthrough uses a fictional Notes API as its example. You will register an operation, write its introduction, add it to navigation, review the imported content, and verify its published files. Run commands from the documentation project directory created in the quickstart, where @shoalrun/cli is installed. The commands use that local package. Check OpenAPI support and limits before importing a larger specification. Put the spec in your project Create apis/notes/openapi.yaml with this complete fictional API. It documents a response without calling a live service: openapi: 3.1.0 info: { title: Example Notes API, version: 1.0.0 } paths: /notes: post: operationId: createNote summary: Create a note responses: '201': description: The note was created. content: application/json: schema: type: object required: [id] properties: id: { type: string, description: The new note identifier. } examples: created: summary: A created note value: { id: note_123 } OpenAPI 3.0 or 3.1 YAML and JSON files are accepted. There is no required directory name; a spec can also reference other local files. Register the operation Add this top-level entry to your existing docs.config.yaml : apis: { $include: ./config/api.yaml } Create the config directory if needed and add config/api.yaml : notes: source: kind: file path: ../apis/notes/openapi.yaml focused: true operations: - id: notes.create sourceOperationId: createNote reference: reference.create-note source.path is relative to the config fragment that declares it. notes names this API, and sourceOperationId selects the spec's operationId . The stable operation ID notes.create connects the operation to authored pages; reference names the page that will present it. focused: true publishes a one-operation contract . For your own API, if the source lives at a public HTTPS URL, import it into a local snapshot first. Replace the example URL below with your actual OpenAPI URL: npx --no-install shoalrun api import https://api.example.com/openapi.yaml --output apis/remote Point source.path at ../apis/remote/openapi.yaml from config/api.yaml . Commit the snapshot and its source-lock.json . Normal builds use those local files and make no network request. To check for upstream changes, run api refresh apis/remote --output apis/remote-next . If the source changed, the command reports the changed hashes and writes a complete new snapshot while keeping apis/remote intact. Point source.path to ../apis/remote-next/openapi.yaml , inspect a new api review candidate, and pin its digest before building. The CLI reference lists import limits. Author the reference page Create content/create-note.mdx : --- id: reference.create-note title: Create a note summary: Create a note in the fictional Notes API. type: api-reference slug: /example-api/create-note channel: production version: current language: en operations: [notes.create] access: { policy: public } --- This fictional operation returns the identifier of a new note. Its response schema and named example are generated from the local OpenAPI file. The page ID must match the registry's reference value. An api-reference page lists exactly one operation. The compiler appends the method, path, parameters, authentication, schemas, and examples to your authored introduction. Append this entry to the existing navigation array in docs.config.yaml : - id: notes-create doc: reference.create-note If your project includes navigation from another file, add the entry there. Save the page and navigation before the review so the candidate contains the page you intend to publish. Review imported content before publishing Shoalrun requires publicReview.digest for every API whose content appears in a public page, embed, or focused contract. A missing or stale digest stops a normal build. Generate a local candidate in a fresh temporary directory: API_REVIEW_DIR=\"$(mktemp -d /tmp/shoalrun-api-review.XXXXXX)\" npx --no-install shoalrun api review docs.config.yaml --output \"$API_REVIEW_DIR\" The command builds the candidate and reports each API's digest, page URLs, focused contracts, full-source downloads, and input hashes. Inspect the candidate files for private operations, fields, descriptions, examples, and credentials. For this example, check the Create a note HTML and Markdown page and its linked focused contract. Copy the reported digest for notes into config/api.yaml alongside source and operations : notes: publicReview: digest: <paste-the-reported-notes-digest> # Keep source and operations here. Replace the angle-bracket placeholder with the actual digest. Keep the candidate local and remove it after review. The digest records what you reviewed; it does not determine whether content is safe. Changing source bytes, selected operations or embeds, focused contracts, or full-source publication requires another review. Changing only authored page copy does not. Build and verify the output npx --no-in"},{"filters":{"focus":["write"]},"text":"ApiExample and ApiSchema — Include named examples and selected schemas in your guides. Focused OpenAPI contracts — Give tools one operation and its required schemas. Create a note — A finished operation page built from a small, fictional OpenAPI file. Compose and maintain recipes — Configure the stable operation ID and review the OpenAPI source used by an API ingredient draft."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":11689,"markdownTokens":2640,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"put-the-spec-in-your-project","title":"Put the spec in your project","markdownUrl":"/publish/api-references.sections/put-the-spec-in-your-project.md","markdownBytes":2576,"markdownTokens":622},{"id":"register-the-operation","title":"Register the operation","markdownUrl":"/publish/api-references.sections/register-the-operation.md","markdownBytes":3385,"markdownTokens":825},{"id":"author-the-reference-page","title":"Author the reference page","markdownUrl":"/publish/api-references.sections/author-the-reference-page.md","markdownBytes":2709,"markdownTokens":646},{"id":"review-imported-content-before-publishing","title":"Review imported content before publishing","markdownUrl":"/publish/api-references.sections/review-imported-content-before-publishing.md","markdownBytes":2990,"markdownTokens":696},{"id":"build-and-verify-the-output","title":"Build and verify the output","markdownUrl":"/publish/api-references.sections/build-and-verify-the-output.md","markdownBytes":3042,"markdownTokens":738},{"id":"what-readers-get","title":"What readers get","markdownUrl":"/publish/api-references.sections/what-readers-get.md","markdownBytes":2426,"markdownTokens":565},{"id":"publish-several-versions","title":"Publish several versions","markdownUrl":"/publish/api-references.sections/publish-several-versions.md","markdownBytes":1840,"markdownTokens":452},{"id":"map-extension-values-to-shoalrun-status","title":"Map extension values to Shoalrun status","markdownUrl":"/publish/api-references.sections/map-extension-values-to-shoalrun-status.md","markdownBytes":1832,"markdownTokens":459},{"id":"describe-filters-that-do-not-use-their-openapi-parameter-name","title":"Describe filters that do not use their OpenAPI parameter name","markdownUrl":"/publish/api-references.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md","markdownBytes":1836,"markdownTokens":457},{"id":"generate-many-pages-selectively","title":"Generate many pages selectively","markdownUrl":"/publish/api-references.sections/generate-many-pages-selectively.md","markdownBytes":1860,"markdownTokens":461},{"id":"use-a-template-for-editorial-context","title":"Use a template for editorial context","markdownUrl":"/publish/api-references.sections/use-a-template-for-editorial-context.md","markdownBytes":1813,"markdownTokens":450},{"id":"add-useful-examples","title":"Add useful examples","markdownUrl":"/publish/api-references.sections/add-useful-examples.md","markdownBytes":1811,"markdownTokens":452},{"id":"link-guides-to-api-references","title":"Link guides to API references","markdownUrl":"/publish/api-references.sections/link-guides-to-api-references.md","markdownBytes":1819,"markdownTokens":452},{"id":"inspect-the-machine-readable-contract","title":"Inspect the machine-readable contract","markdownUrl":"/publish/api-references.sections/inspect-the-machine-readable-contract.md","markdownBytes":2054,"markdownTokens":503},{"id":"preview-a-small-api-reference","title":"Preview a small API reference","markdownUrl":"/publish/api-references.sections/preview-a-small-api-reference.md","markdownBytes":2226,"markdownTokens":548},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/api-references.sections/related-reading.md","markdownBytes":2118,"markdownTokens":524}]},{"id":"guide.audit","demo":false,"url":"/publish/audit","markdownUrl":"/publish/audit.md","title":"Audit a docs project","summary":"Run project tests and local API representation checks with one CI command.","type":"how-to","variant":"production|current|en","area":"quality","subarea":"quality-audits","headings":[{"id":"check-before-pushing","title":"Check before pushing"},{"id":"add-project-tests","title":"Add project tests"},{"id":"connect-a-documentation-test-suite","title":"Connect a documentation test suite"},{"id":"check-agent-evaluation-reports","title":"Check agent evaluation reports"},{"id":"read-the-report","title":"Read the report"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"often-confused-with","title":"Often confused with"}],"text":"Run shoalrun audit from a project directory before publishing. The command combines tests that your project configures with Shoalrun's build and API representation checks. It reports each result as JSON and exits with code 1 if any result fails. From framework/ , this example needs no extra setup after npm run build : node dist/cli.js audit example/docs.config.yaml With no audit setting, Shoalrun runs the API source and focused-contract audits and builds the site. No project test commands run until you configure them. Check before pushing Run this from your docs project: shoalrun check shoalrun check docs.config.yaml --json The first command discovers docs.config.yaml in the current directory or a parent and prints PASS/FAIL results. Use --json for a structured report in CI. A failed check exits with code 1. shoalrun audit runs the same checks and retains its JSON output. Checks include configured test commands, local OpenAPI sources, a complete temporary build, focused contracts, and local links. The build validates config, frontmatter, and supported MDX. YAML duplicate keys, excessive alias expansion, and cyclic aliases fail with a source-file diagnostic. OpenAPI inputs must declare a supported 3.0 or 3.1 version, an info title and version, and mapping-shaped paths. Link checks inspect generated HTML and Markdown. They verify local destinations and HTML fragments, including same-origin absolute links. Markdown fragments are not checked because heading rules vary between readers. Links in code samples are ignored. Built-in checks need no browser or running server and do not fetch external URLs. Existing site output is preserved; normal generated metadata can still be written under .shoalrun/ . Add a package script to make the check easy to run: { \"scripts\" : { \"docs:check\" : \"shoalrun check docs.config.yaml\" } } An optional Git pre-push hook can run that script. Put these lines in .git/hooks/pre-push and make it executable with chmod +x .git/hooks/pre-push : #!/bin/sh exec npm run docs:check The CLI does not install hooks. Configured test commands can perform their own network requests or writes. To include a dependency check for a project with a package lock, configure: audit : tests : - id : dependencies run : [ npm , audit , --omit=dev ] This optional command contacts the npm registry. Omit --omit=dev to include development dependencies. Commands run beside the docs config; use npm's --prefix option when the package lives elsewhere. Add project tests Add audit to docs.config.yaml . This example assumes your project has a scripts/docs.test.mjs file that Node's test runner can execute: docs.config.yaml audit : tests : - id : project-tests run : [ node , --test , scripts/docs.test.mjs ] api : true focusedContracts : true links : true Each test has a unique lowercase id (letters, digits, and hyphens) and a nonempty run list of strings. Shoalrun starts the executable in the first item and passes the rest as arguments. It does not invoke a shell, so shell operators, pipes, and redirection do not work in run . Tests run in list order from the directory containing the config file. They run before API audits and the build. A failing test does not stop the other tests or audits. Each test has a two minute timeout. Shoalrun captures its output and includes the last 16,000 characters in a failure finding. Successful test output is omitted from the report. Because the commands are executable code, review test entries before running an unfamiliar project. Set audit.api: false to skip local OpenAPI source audits, or audit.focusedContracts: false to skip focused-contract checks. Set audit.links: false to skip local link checks. All three default to true ; the build always runs. Connect a documentation test suite audit.tests is the hookup for an external test suite. We recommend Doc Detective for testing documentation behavior, but you can run any installed command that exits nonzero on failure. Shoalrun passes the arguments and records the process exit status; the tool owns its test specifications, fixtures, assertions, and detailed results. For a project with Doc Detective installed locally and its configuration in .doc-detective.json beside docs.config.yaml : docs.config.yaml audit : tests : - id : doc-detective run : [ npx , --no-install , doc-detective , --config , .doc-detective.json , --exit-on-fail ] The --exit-on-fail flag matters: Doc Detective's standalone CLI otherwise can exit successfully when a test fails . npx --no-install uses the locally installed package without downloading one during the audit. Configure tests and report artifacts with Doc Detective. Shoalrun's audit report only records the command's success or failure and the end of its output on failure. To use another suite, replace the run list with its command and failure-exit option. Configured test commands run before Shoalrun's temporary site build. If a tool needs a built or deployed site, run it as a separate step after building or deployin","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Run shoalrun audit from a project directory before publishing. The command combines tests that your project configures with Shoalrun's build and API representation checks. It reports each result as JSON and exits with code 1 if any result fails. From framework/ , this example needs no extra setup after npm run build : node dist/cli.js audit example/docs.config.yaml With no audit setting, Shoalrun runs the API source and focused-contract audits and builds the site. No project test commands run until you configure them. Check before pushing Run this from your docs project: shoalrun check shoalrun check docs.config.yaml --json The first command discovers docs.config.yaml in the current directory or a parent and prints PASS/FAIL results. Use --json for a structured report in CI. A failed check exits with code 1. shoalrun audit runs the same checks and retains its JSON output. Checks include configured test commands, local OpenAPI sources, a complete temporary build, focused contracts, and local links. The build validates config, frontmatter, and supported MDX. YAML duplicate keys, excessive alias expansion, and cyclic aliases fail with a source-file diagnostic. OpenAPI inputs must declare a supported 3.0 or 3.1 version, an info title and version, and mapping-shaped paths. Link checks inspect generated HTML and Markdown. They verify local destinations and HTML fragments, including same-origin absolute links. Markdown fragments are not checked because heading rules vary between readers. Links in code samples are ignored. Built-in checks need no browser or running server and do not fetch external URLs. Existing site output is preserved; normal generated metadata can still be written under .shoalrun/ . Add a package script to make the check easy to run: { \"scripts\": { \"docs:check\": \"shoalrun check docs.config.yaml\" } } An optional Git pre-push hook can run that script. Put these lines in .git/hooks/pre-push and make it executable with chmod +x .git/hooks/pre-push : #!/bin/sh exec npm run docs:check The CLI does not install hooks. Configured test commands can perform their own network requests or writes. To include a dependency check for a project with a package lock, configure: audit: tests: - id: dependencies run: [npm, audit, --omit=dev] This optional command contacts the npm registry. Omit --omit=dev to include development dependencies. Commands run beside the docs config; use npm's --prefix option when the package lives elsewhere. Add project tests Add audit to docs.config.yaml . This example assumes your project has a scripts/docs.test.mjs file that Node's test runner can execute: audit: tests: - id: project-tests run: [node, --test, scripts/docs.test.mjs] api: true focusedContracts: true links: true Each test has a unique lowercase id (letters, digits, and hyphens) and a nonempty run list of strings. Shoalrun starts the executable in the first item and passes the rest as arguments. It does not invoke a shell, so shell operators, pipes, and redirection do not work in run . Tests run in list order from the directory containing the config file. They run before API audits and the build. A failing test does not stop the other tests or audits. Each test has a two minute timeout. Shoalrun captures its output and includes the last 16,000 characters in a failure finding. Successful test output is omitted from the report. Because the commands are executable code, review test entries before running an unfamiliar project. Set audit.api: false to skip local OpenAPI source audits, or audit.focusedContracts: false to skip focused-contract checks. Set audit.links: false to skip local link checks. All three default to true ; the build always runs. Connect a documentation test suite audit.tests is the hookup for an external test suite. We recommend Doc Detective for testing documentation behavior, but you can run any installed command that exits nonzero on failure. Shoalrun passes the arguments and records the process exit status; the tool owns its test specifications, fixtures, assertions, and detailed results. For a project with Doc Detective installed locally and its configuration in .doc-detective.json beside docs.config.yaml : audit: tests: - id: doc-detective run: [npx, --no-install, doc-detective, --config, .doc-detective.json, --exit-on-fail] The --exit-on-fail flag matters: Doc Detective's standalone CLI otherwise can exit successfully when a test fails . npx --no-install uses the locally installed package without downloading one during the audit. Configure tests and report artifacts with Doc Detective. Shoalrun's audit report only records the command's success or failure and the end of its output on failure. To use another suite, replace the run list with its command and failure-exit option. Configured test commands run before Shoalrun's temporary site build. If a tool needs a built or deployed site, run it as a separate step after building or deploying. Shoalrun does not define a competing documentation assertion fo"},{"filters":{"focus":["configure"]},"text":"Evaluate agent tasks against your docs — Add task definitions and reviewed result reports to the audit. Use Manni with Shoalrun — Add conditional editorial metadata checks through an audit hook. Check a deployed site — The audit checks project sources in CI; the deployment check tests the published site over HTTP."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9884,"markdownTokens":2287,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"check-before-pushing","title":"Check before pushing","markdownUrl":"/publish/audit.sections/check-before-pushing.md","markdownBytes":3713,"markdownTokens":880},{"id":"add-project-tests","title":"Add project tests","markdownUrl":"/publish/audit.sections/add-project-tests.md","markdownBytes":2985,"markdownTokens":729},{"id":"connect-a-documentation-test-suite","title":"Connect a documentation test suite","markdownUrl":"/publish/audit.sections/connect-a-documentation-test-suite.md","markdownBytes":3227,"markdownTokens":767},{"id":"check-agent-evaluation-reports","title":"Check agent evaluation reports","markdownUrl":"/publish/audit.sections/check-agent-evaluation-reports.md","markdownBytes":2693,"markdownTokens":643},{"id":"read-the-report","title":"Read the report","markdownUrl":"/publish/audit.sections/read-the-report.md","markdownBytes":3745,"markdownTokens":919},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/audit.sections/related-reading.md","markdownBytes":1970,"markdownTokens":493}]},{"id":"guide.authoring-agent-overview","demo":false,"url":"/author/agent-overview","markdownUrl":"/author/agent-overview.md","title":"Authoring tools for your coding agent","summary":"Understand project discovery, working-tree editing, snapshot validation, and human review.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"discover-before-editing","title":"Discover before editing"},{"id":"edit-and-check","title":"Edit and check"},{"id":"review-and-release","title":"Review and release"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"go-deeper","title":"Go deeper"}],"text":"Shoalrun supplies documentation tools for existing coding agents. Your agent supplies its model, file editing, repository exploration, and execution permissions. Shoalrun supplies canonical writing guidance, templates, project discovery, and checks. The tools make no authoring provider calls. Discover before editing Project discovery works without selecting a page. It lists pages, configured guidance, templates, navigation, relationships, and findings. Topic searches help your agent find candidates across the project. Source reads return bounded passages and file digests. Bundled documentation search and reads explain framework behavior; your project's guidance governs local conventions. Edit and check The default is to edit ordinary working-tree files using your agent's file tools. A baseline records the current files, including earlier local changes. Snapshot validation captures those files and compiles a separate copy, so checking a draft does not rewrite the project. Results identify affected pages, findings, skipped checks, and retained artifacts. A freshness check tells you whether those results still apply after further edits. Existing checked plan/apply commands remain available for clients that need them. Their digest checks and application protections are preserved. Review and release Compiler checks establish structural validity. They do not establish factual accuracy, clear writing, or a successful reader task. Review the diff, supporting evidence, and rendered documentation before using your project's release process. Local previews serve the exact captured build and show its freshness. Review reports list task scope, affected HTML/Markdown, findings, checks, and dependencies. The portable authoring skill guides this working-tree workflow. Independent author trials remain separate from these checks. Install the alpha CLI through Getting started . Related reading Next steps Check working-tree documentation edits — Discover the project and check a working-tree edit. (Status: experimental.) Reference while working Authoring tools commands — Look up discovery, baseline, validation, and freshness commands. (Status: experimental.) Design a writing guide — Give both people and models useful project writing guidance. Go deeper How snapshot validation works — Understand capture coverage, checks, artifacts, and freshness. (Status: experimental.)","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"Shoalrun supplies documentation tools for existing coding agents. Your agent supplies its model, file editing, repository exploration, and execution permissions. Shoalrun supplies canonical writing guidance, templates, project discovery, and checks. The tools make no authoring provider calls. Discover before editing Project discovery works without selecting a page. It lists pages, configured guidance, templates, navigation, relationships, and findings. Topic searches help your agent find candidates across the project. Source reads return bounded passages and file digests. Bundled documentation search and reads explain framework behavior; your project's guidance governs local conventions. Edit and check The default is to edit ordinary working-tree files using your agent's file tools. A baseline records the current files, including earlier local changes. Snapshot validation captures those files and compiles a separate copy, so checking a draft does not rewrite the project. Results identify affected pages, findings, skipped checks, and retained artifacts. A freshness check tells you whether those results still apply after further edits. Existing checked plan/apply commands remain available for clients that need them. Their digest checks and application protections are preserved. Review and release Compiler checks establish structural validity. They do not establish factual accuracy, clear writing, or a successful reader task. Review the diff, supporting evidence, and rendered documentation before using your project's release process. Local previews serve the exact captured build and show its freshness. Review reports list task scope, affected HTML/Markdown, findings, checks, and dependencies. The portable authoring skill guides this working-tree workflow. Independent author trials remain separate from these checks. Install the alpha CLI through Getting started . Related reading Next steps Reference while working Go deeper"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Check working-tree documentation edits — Discover the project and check a working-tree edit. (Status: experimental.) Authoring tools commands — Look up discovery, baseline, validation, and freshness commands. (Status: experimental.) Design a writing guide — Give both people and models useful project writing guidance. How snapshot validation works — Understand capture coverage, checks, artifacts, and freshness. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3627,"markdownTokens":754,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.authoring-agent-workflow","demo":false,"url":"/author/agent-workflow","markdownUrl":"/author/agent-workflow.md","title":"How snapshot validation works","summary":"Understand captured files, affected-page coverage, freshness, and validation limits.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"baselines-and-captures","title":"Baselines and captures"},{"id":"checks-and-artifacts","title":"Checks and artifacts"},{"id":"freshness-and-scope","title":"Freshness and scope"},{"id":"matching-previews-and-review-reports","title":"Matching previews and review reports"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Snapshot validation checks a captured working tree. Your existing coding agent edits files; Shoalrun records and checks the resulting state. Baselines and captures A baseline records source paths, modes, and digests before a task. It includes preexisting dirty and untracked files. Validation compares with that baseline, or uses explicit file and page selectors, to identify affected pages. Configuration, dependency, and deletion changes can expand coverage to all authored pages. The capture excludes generated output, dependencies, repository metadata, credentials, and private archives. Files must fit capture limits. Symlinks and absolute dependency references are rejected. Declared sibling dependencies can be captured within the project's parent directory. Capture races produce a failure rather than an apparently current result. Checks and artifacts The compiler renders affected drafts in the captured project while preserving their publication access metadata. It checks metadata, identities, routes, components, navigation, relationships, and document links. Local HTML and Markdown links and configured API contracts are checked in the captured output. External URLs are not requested. Configured shell checks are skipped by default. With --run-checks , trusted project commands run inside the capture under the harness's permissions. This is not an operating-system sandbox; scripts can still access absolute paths or services. Model evaluators are skipped. Executable metadata and highlighting extensions are currently unavailable to snapshot validation. The result retains the captured project, built site, and JSON report. Remove the reported artifact directory when finished. Compiler success does not replace factual and editorial review. Freshness and scope The report identifies the snapshot and source digests. docs validation-status compares current inputs with the report and returns stale when they differ. A report only applies to its recorded coverage and checks. Review skipped and unavailable checks before accepting a result. Snapshot validation does not apply edits, start a preview server, commit, or publish. Existing checked plan/apply clients retain their own review and freshness protections. Matching previews and review reports docs review reads a retained validation report as JSON or Markdown. It associates changed-file operations and digests with the declared baseline and exposes findings, check status, affected routes, dependencies, and artifacts. Baselines retain digests rather than earlier contents, so your harness must retain the task diff. Evidence, semantic review, and author decisions are not inferred by these tools. docs preview makes a separate private copy of the validated site and starts a foreground loopback server. Every affected rendered page has HTML and Markdown URLs. HTML pages link to a browser review and display freshness; the original Markdown output remains unchanged. Replacing source files does not replace the preview's content. Replacing the report makes its pinned preview stale. Artifact changes prevent startup or stop page serving. After editing, validate again and restart from the new report. Ctrl-C or SIGTERM closes the server and removes only its serving copy. Retained validation artifacts have a separate lifecycle. The preview starts no source watcher or provider requests. Related reading Next steps Check working-tree documentation edits — Capture a baseline and validate a working-tree edit. (Status: experimental.) Reference while working Authoring tools commands — Find commands for discovery and snapshot validation. (Status: experimental.)","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"Snapshot validation checks a captured working tree. Your existing coding agent edits files; Shoalrun records and checks the resulting state. Baselines and captures A baseline records source paths, modes, and digests before a task. It includes preexisting dirty and untracked files. Validation compares with that baseline, or uses explicit file and page selectors, to identify affected pages. Configuration, dependency, and deletion changes can expand coverage to all authored pages. The capture excludes generated output, dependencies, repository metadata, credentials, and private archives. Files must fit capture limits. Symlinks and absolute dependency references are rejected. Declared sibling dependencies can be captured within the project's parent directory. Capture races produce a failure rather than an apparently current result. Checks and artifacts The compiler renders affected drafts in the captured project while preserving their publication access metadata. It checks metadata, identities, routes, components, navigation, relationships, and document links. Local HTML and Markdown links and configured API contracts are checked in the captured output. External URLs are not requested. Configured shell checks are skipped by default. With --run-checks , trusted project commands run inside the capture under the harness's permissions. This is not an operating-system sandbox; scripts can still access absolute paths or services. Model evaluators are skipped. Executable metadata and highlighting extensions are currently unavailable to snapshot validation. The result retains the captured project, built site, and JSON report. Remove the reported artifact directory when finished. Compiler success does not replace factual and editorial review. Freshness and scope The report identifies the snapshot and source digests. docs validation-status compares current inputs with the report and returns stale when they differ. A report only applies to its recorded coverage and checks. Review skipped and unavailable checks before accepting a result. Snapshot validation does not apply edits, start a preview server, commit, or publish. Existing checked plan/apply clients retain their own review and freshness protections. Matching previews and review reports docs review reads a retained validation report as JSON or Markdown. It associates changed-file operations and digests with the declared baseline and exposes findings, check status, affected routes, dependencies, and artifacts. Baselines retain digests rather than earlier contents, so your harness must retain the task diff. Evidence, semantic review, and author decisions are not inferred by these tools. docs preview makes a separate private copy of the validated site and starts a foreground loopback server. Every affected rendered page has HTML and Markdown URLs. HTML pages link to a browser review and display freshness; the original Markdown output remains unchanged. Replacing source files does not replace the preview's content. Replacing the report makes its pinned preview stale. Artifact changes prevent startup or stop page serving. After editing, validate again and restart from the new report. Ctrl-C or SIGTERM closes the server and removes only its serving copy. Retained validation artifacts have a separate lifecycle. The preview starts no source watcher or provider requests. Related reading Next steps Reference while working"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Check working-tree documentation edits — Capture a baseline and validate a working-tree edit. (Status: experimental.) Authoring tools commands — Find commands for discovery and snapshot validation. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4709,"markdownTokens":923,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.authoring-agent","demo":false,"url":"/author/authoring-agent","markdownUrl":"/author/authoring-agent.md","title":"Apply a checked edit plan","summary":"Find a page's sources, review an edit, and apply it through Shoalrun checks.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"prepare-and-apply-an-update","title":"Prepare and apply an update"},{"id":"read-the-page-and-its-owners","title":"Read the page and its owners"},{"id":"write-and-review-a-candidate","title":"Write and review a candidate"},{"id":"create-an-exact-edit-plan","title":"Create an exact edit plan"},{"id":"apply-the-reviewed-plan","title":"Apply the reviewed plan"},{"id":"what-checks-establish","title":"What checks establish"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Use this optional workflow when your agent needs a digest-checked replacement plan before writing files. Your agent gathers evidence and writes the candidate; Shoalrun validates and applies the exact plan. For ordinary working-tree editing, follow Check working-tree documentation edits instead. Prepare and apply an update Read the page and its owners shoalrun docs context guide.welcome --config docs.config.yaml Read the returned source files and the project's writing guide. Capture the source digest before drafting. Give your agent the requested change and supporting sources; those can include other repositories, specifications, or links it can inspect with its own tools. Write and review a candidate Have the agent save a complete replacement file separately from the source. Preserve stable IDs, routes, publication fields, and access policy. Update the edit date. Ask for a diff, the evidence supporting changed claims, and any unresolved questions. Run the project's Vale rules and verify code examples. Create an exact edit plan Create edit-request.json with full replacement text and the digest of the source used to draft it: { \"edits\" : [ { \"file\" : \"content/welcome.mdx\" , \"baseDigest\" : \"<SHA-256 digest of the original source>\" , \"content\" : \"<complete replacement file>\" } ] } The placeholders above must be replaced with actual values. Paths are relative to the project configuration directory. shoalrun docs plan --request-file edit-request.json --out edit-plan.json --config docs.config.yaml shoalrun docs apply edit-plan.json --config docs.config.yaml --check The check builds a temporary copy and leaves source files unchanged. A stale source or failed build stops the edit. Plans support existing authored Markdown files and YAML files loaded by the configuration; use scaffolding for new files. Apply the reviewed plan shoalrun docs apply edit-plan.json --config docs.config.yaml shoalrun audit docs.config.yaml Applying repeats freshness and build checks before writing. Inspect the resulting HTML and Markdown. The plan does not run configured audit tests, commit changes, or deploy; those are separate steps. What checks establish Compiler checks catch problems such as broken document links and invalid components. Vale checks the rules your team configures. Neither establishes factual accuracy or whether a procedure works. Ask your agent to explain what it verified and what still needs review. Ordinary public builds exclude draft pages. Use the separate working-tree docs validate interface to render affected drafts in isolation without changing their authored access policy. This does not change the checked plan/apply contract described above. Related reading Read first Templates — Scaffold a draft page before an agent writes its content. Reference while working Add an OpenAPI API — Review a drafted API page against its operation and contract. Example writing guide — Review this site's example editorial guidance. Related topics Use the bundled agent skills — Let an agent run the same draft, check, and apply loop. Write with agents — Start with the agent authoring workflow. Check working-tree documentation edits — Use the checked edit commands with your existing coding agent. (Status: experimental.) Use your coding agent — Prepare a checked edit to an existing page.","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"Use this optional workflow when your agent needs a digest-checked replacement plan before writing files. Your agent gathers evidence and writes the candidate; Shoalrun validates and applies the exact plan. For ordinary working-tree editing, follow Check working-tree documentation edits instead. Prepare and apply an update Read the page and its owners shoalrun docs context guide.welcome --config docs.config.yaml Read the returned source files and the project's writing guide. Capture the source digest before drafting. Give your agent the requested change and supporting sources; those can include other repositories, specifications, or links it can inspect with its own tools. Write and review a candidate Have the agent save a complete replacement file separately from the source. Preserve stable IDs, routes, publication fields, and access policy. Update the edit date. Ask for a diff, the evidence supporting changed claims, and any unresolved questions. Run the project's Vale rules and verify code examples. Create an exact edit plan Create edit-request.json with full replacement text and the digest of the source used to draft it: { \"edits\": [ { \"file\": \"content/welcome.mdx\", \"baseDigest\": \"<SHA-256 digest of the original source>\", \"content\": \"<complete replacement file>\" } ] } The placeholders above must be replaced with actual values. Paths are relative to the project configuration directory. shoalrun docs plan --request-file edit-request.json --out edit-plan.json --config docs.config.yaml shoalrun docs apply edit-plan.json --config docs.config.yaml --check The check builds a temporary copy and leaves source files unchanged. A stale source or failed build stops the edit. Plans support existing authored Markdown files and YAML files loaded by the configuration; use scaffolding for new files. Apply the reviewed plan shoalrun docs apply edit-plan.json --config docs.config.yaml shoalrun audit docs.config.yaml Applying repeats freshness and build checks before writing. Inspect the resulting HTML and Markdown. The plan does not run configured audit tests, commit changes, or deploy; those are separate steps. What checks establish Compiler checks catch problems such as broken document links and invalid components. Vale checks the rules your team configures. Neither establishes factual accuracy or whether a procedure works. Ask your agent to explain what it verified and what still needs review. Ordinary public builds exclude draft pages. Use the separate working-tree docs validate interface to render affected drafts in isolation without changing their authored access policy. This does not change the checked plan/apply contract described above. Related reading Read first Reference while working Related topics"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates — Scaffold a draft page before an agent writes its content. Write with agents — Start with the agent authoring workflow. Check working-tree documentation edits — Use the checked edit commands with your existing coding agent. (Status: experimental.) Use your coding agent — Prepare a checked edit to an existing page."},{"filters":{"focus":["write"]},"text":"Add an OpenAPI API — Review a drafted API page against its operation and contract. Example writing guide — Review this site's example editorial guidance. Use the bundled agent skills — Let an agent run the same draft, check, and apply loop."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4853,"markdownTokens":1082,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.authoring-workspace","demo":false,"url":"/author/workspace/commands","markdownUrl":"/author/workspace/commands.md","title":"Authoring tools commands","summary":"Look up provider-free project discovery, reference reads, baselines, and snapshot validation.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"discovery-and-references","title":"Discovery and references"},{"id":"validation","title":"Validation"},{"id":"review-and-preview","title":"Review and preview"},{"id":"existing-checked-edits","title":"Existing checked edits"},{"id":"related-reading","title":"Related reading"}],"text":"These commands are available through the Shoalrun CLI. Follow Getting started to install it from npm. They make no authoring provider calls. Discovery and references Use these commands to find the project and retrieve the references needed for an edit. Command Result docs project Project-wide JSON discovery, without requiring a page selector. docs source FILE Bounded project-relative source passage with a whole-file digest. docs search QUERY --json Search bundled framework documentation. docs read ID --json Read a bundled reference by stable ID. Project commands accept --config FILE ; otherwise they find the nearest docs.config.yaml in the current directory or its ancestors. Project sections are pages , guidance , configuration , navigation , relationships , templates , and findings . Choose a section with --section . Pages, navigation, and relationships accept one of --id , --file , or --query . Project pagination uses --offset and --limit (default 20, maximum 100). Follow the returned pagination.nextOffset . --max-tokens bounds the response (default 8192). Source reads use Unicode code-point offsets and default to 4096 tokens; follow nextOffset and verify the digest between reads. Paths must resolve inside the project. Use your harness's tools and permissions for external implementation sources. Validation Use these checks to find source and publication problems before reviewing the result. Command Result docs baseline --out FILE Record the current working tree without running checks. The destination must be new. docs validate --baseline FILE Validate changes since a task baseline in a separate capture. docs validate --file FILE Validate declared file changes; repeat the selector for more files. docs validate --id ID Validate declared pages; repeat the selector for more IDs. docs validation-status REPORT Check whether a retained report still applies to current inputs. Baselines and validation artifacts must be outside the project or inside its excluded .shoalrun directory. --artifacts DIRECTORY selects a new artifact directory; otherwise validation retains a temporary directory. Results contain actual report, capture, and site locations. --run-checks opts into configured trusted shell checks under the harness's permissions; evaluator hooks remain skipped. Declare sibling files and directories needed by a configured check in audit.tests[].inputs . Paths are relative to the project configuration directory and must remain within its parent. Snapshot builds resolve revision dates without writing freshness history. A configured check that changes captured source or history still fails validation. Configured Node checks receive Shoalrun's installed dependency search paths through NODE_PATH for CommonJS resolution. Consumer dependencies are not copied into the snapshot; missing modules produce an unavailable check. ESM imports do not use NODE_PATH . Validation statuses include ok , failed , incomplete , unavailable , and stale . Read findings and coverage alongside status. These commands always return JSON. Snapshot validation requires affected page IDs to match [A-Za-z0-9][A-Za-z0-9._-]* . Review and preview Use these commands to inspect proposed changes and their rendered output. Command Result docs review REPORT JSON review for a retained validation report. docs review REPORT --format markdown A readable report for the same snapshot and task scope. docs preview REPORT --port PORT Foreground local preview of that exact build, with a browser review page. REPORT is the validation report path returned by docs validate . Review accepts --format json or --format markdown ; JSON is the default. It exits 0 only for a current ok result. An error returns the existing JSON failure envelope, even when Markdown was requested. Preview binds only to 127.0.0.1 ; the default port is 8771. Use port 0 to allocate a free port. Its JSON startup record contains the snapshot ID, origin, and review/status URLs. It also includes affected HTML/Markdown URLs, serving-copy directory, validation review, and lifecycle instructions. The process stays running. Ctrl-C or SIGTERM closes it, removes its private copy, and emits a stopped record. Validation artifacts remain. No browser is opened automatically. The review identifies the baseline, changed-file operations and digests, dependencies, and current freshness. It includes checks, findings and source/reference locations, coverage, and affected-page artifacts. Earlier file contents are not retained in a baseline; the report explains why it cannot generate a task diff. Evidence gathering remains with the harness. Reviewer results and author dispositions are explicitly empty; no semantic reviewer ran. Configuration, dependency, and deletion changes conservatively list every rendered page, including generated API operations. Authored-only changes list their affected pages. Each page reports its authored or generated origin. A stale working tree can still be previewed as a clearly labelled his","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"These commands are available through the Shoalrun CLI. Follow Getting started to install it from npm. They make no authoring provider calls. Discovery and references Use these commands to find the project and retrieve the references needed for an edit. Command Result docs project Project-wide JSON discovery, without requiring a page selector. docs source FILE Bounded project-relative source passage with a whole-file digest. docs search QUERY --json Search bundled framework documentation. docs read ID --json Read a bundled reference by stable ID. Project commands accept --config FILE ; otherwise they find the nearest docs.config.yaml in the current directory or its ancestors. Project sections are pages , guidance , configuration , navigation , relationships , templates , and findings . Choose a section with --section . Pages, navigation, and relationships accept one of --id , --file , or --query . Project pagination uses --offset and --limit (default 20, maximum 100). Follow the returned pagination.nextOffset . --max-tokens bounds the response (default 8192). Source reads use Unicode code-point offsets and default to 4096 tokens; follow nextOffset and verify the digest between reads. Paths must resolve inside the project. Use your harness's tools and permissions for external implementation sources. Validation Use these checks to find source and publication problems before reviewing the result. Command Result docs baseline --out FILE Record the current working tree without running checks. The destination must be new. docs validate --baseline FILE Validate changes since a task baseline in a separate capture. docs validate --file FILE Validate declared file changes; repeat the selector for more files. docs validate --id ID Validate declared pages; repeat the selector for more IDs. docs validation-status REPORT Check whether a retained report still applies to current inputs. Baselines and validation artifacts must be outside the project or inside its excluded .shoalrun directory. --artifacts DIRECTORY selects a new artifact directory; otherwise validation retains a temporary directory. Results contain actual report, capture, and site locations. --run-checks opts into configured trusted shell checks under the harness's permissions; evaluator hooks remain skipped. Declare sibling files and directories needed by a configured check in audit.tests[].inputs . Paths are relative to the project configuration directory and must remain within its parent. Snapshot builds resolve revision dates without writing freshness history. A configured check that changes captured source or history still fails validation. Configured Node checks receive Shoalrun's installed dependency search paths through NODE_PATH for CommonJS resolution. Consumer dependencies are not copied into the snapshot; missing modules produce an unavailable check. ESM imports do not use NODE_PATH . Validation statuses include ok , failed , incomplete , unavailable , and stale . Read findings and coverage alongside status. These commands always return JSON. Snapshot validation requires affected page IDs to match [A-Za-z0-9][A-Za-z0-9._-]* . Review and preview Use these commands to inspect proposed changes and their rendered output. Command Result docs review REPORT JSON review for a retained validation report. docs review REPORT --format markdown A readable report for the same snapshot and task scope. docs preview REPORT --port PORT Foreground local preview of that exact build, with a browser review page. REPORT is the validation report path returned by docs validate . Review accepts --format json or --format markdown ; JSON is the default. It exits 0 only for a current ok result. An error returns the existing JSON failure envelope, even when Markdown was requested. Preview binds only to 127.0.0.1 ; the default port is 8771. Use port 0 to allocate a free port. Its JSON startup record contains the snapshot ID, origin, and review/status URLs. It also includes affected HTML/Markdown URLs, serving-copy directory, validation review, and lifecycle instructions. The process stays running. Ctrl-C or SIGTERM closes it, removes its private copy, and emits a stopped record. Validation artifacts remain. No browser is opened automatically. The review identifies the baseline, changed-file operations and digests, dependencies, and current freshness. It includes checks, findings and source/reference locations, coverage, and affected-page artifacts. Earlier file contents are not retained in a baseline; the report explains why it cannot generate a task diff. Evidence gathering remains with the harness. Reviewer results and author dispositions are explicitly empty; no semantic reviewer ran. Configuration, dependency, and deletion changes conservatively list every rendered page, including generated API operations. Authored-only changes list their affected pages. Each page reports its authored or generated origin. A stale working tree can still be previewed as a clearly labelled his"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":8340,"markdownTokens":1613,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.authoring-workspace","demo":false,"url":"/author/workspace","markdownUrl":"/author/workspace.md","title":"Check working-tree documentation edits","summary":"Discover a project, capture a baseline, edit files, and validate an isolated copy.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"read-project-guidance","title":"Read project guidance"},{"id":"record-the-starting-files","title":"Record the starting files"},{"id":"edit-and-validate","title":"Edit and validate"},{"id":"confirm-the-result-still-applies","title":"Confirm the result still applies"},{"id":"review-and-preview-the-snapshot","title":"Review and preview the snapshot"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Use this procedure from your documentation project directory, containing docs.config.yaml , with @shoalrun/cli installed. Getting started explains how to install the alpha package from npm. You need Node.js 22.12 or newer; a framework source checkout and a separate authoring provider key are not required. Your coding agent uses its own model and file tools. Replace the example page path with your project's path. Framework contributors can instead build the source checkout and run node framework/dist/cli.js <command> from its root. The examples below use the installed package. Read project guidance npx --no-install shoalrun docs project --section guidance --config docs.config.yaml npx --no-install shoalrun docs project --query \"installation\" --config docs.config.yaml npx --no-install shoalrun docs source AGENTS.md --config docs.config.yaml npx --no-install shoalrun docs search \"page metadata\" --json npx --no-install shoalrun docs read guide.frontmatter --json Read applicable instructions and reviewed examples before editing. Discovery works without a selected page. Inspect the findings section when discovery reports findings; follow pagination when a section exceeds its response budget. Record the starting files npx --no-install shoalrun docs baseline --out .shoalrun/task-baseline.json --config docs.config.yaml Choose a new baseline filename for each task. The baseline includes earlier local edits and untracked files; it compares later changes with this starting state rather than Git HEAD. It runs no checks. Edit and validate Edit ordinary MDX and configuration files using your agent's file tools. Preserve unrelated edits and review changes to identity, navigation, relationships, and publication metadata. npx --no-install shoalrun docs validate --baseline .shoalrun/task-baseline.json --config docs.config.yaml For an existing edit without a baseline, declare its scope explicitly: npx --no-install shoalrun docs validate --file content/install.mdx --config docs.config.yaml Validation compiles a separate capture. Read the returned status, coverage, findings, skipped checks, and artifact paths. A failure needs correction and another validation. An incomplete or unavailable result needs investigation; it is not a passing result. Configured shell checks require explicit --run-checks and your harness's execution authorization. Confirm the result still applies npx --no-install shoalrun docs validation-status /path/from/result/report.json Use the actual report path returned by validation. A stale result requires another validation. Review and preview the snapshot npx --no-install shoalrun docs review /path/from/result/report.json --format markdown npx --no-install shoalrun docs preview /path/from/result/report.json --port 8771 The preview command stays running and returns a local review URL plus HTML and Markdown URLs for every affected page that rendered. Open the review URL in your browser. It shows the task baseline, changed files, checks, findings, dependencies, and artifacts. Previewing a failed or incomplete result does not make it pass. A failed compile can leave no site to preview; read its findings with docs review first. The server uses a private copy of the captured build. Each HTML page shows the snapshot status and a link back to the review. Source changes make that preview stale; the displayed content remains the captured version. A baseline contains digests rather than earlier file contents, so retain the task diff with your harness. The report does not attribute all dirty files to your task. After a revision, stop the preview with Ctrl-C, validate again, and start a preview using the new report path. The server never watches or rebuilds source. Ctrl-C or SIGTERM removes its private serving copy; the validation artifacts remain. Remove only the reported validation artifact directory when finished. A forced process kill can leave the serving copy behind; its path is in the startup result. Review facts, examples, supporting sources, and the task diff before accepting the edit. Use your normal review and publication process afterward. Related reading Read first Authoring tools for your coding agent — Understand how your coding agent uses Shoalrun tools and human review. (Status: experimental.) Reference while working Authoring tools commands — Look up discovery and snapshot validation commands. (Status: experimental.) Example writing guide — Review the example guidance before approving a writing plan. Related topics Apply a checked edit plan — Use the checked edit commands with your existing coding agent. (Status: experimental.)","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"Use this procedure from your documentation project directory, containing docs.config.yaml , with @shoalrun/cli installed. Getting started explains how to install the alpha package from npm. You need Node.js 22.12 or newer; a framework source checkout and a separate authoring provider key are not required. Your coding agent uses its own model and file tools. Replace the example page path with your project's path. Framework contributors can instead build the source checkout and run node framework/dist/cli.js <command> from its root. The examples below use the installed package. Read project guidance npx --no-install shoalrun docs project --section guidance --config docs.config.yaml npx --no-install shoalrun docs project --query \"installation\" --config docs.config.yaml npx --no-install shoalrun docs source AGENTS.md --config docs.config.yaml npx --no-install shoalrun docs search \"page metadata\" --json npx --no-install shoalrun docs read guide.frontmatter --json Read applicable instructions and reviewed examples before editing. Discovery works without a selected page. Inspect the findings section when discovery reports findings; follow pagination when a section exceeds its response budget. Record the starting files npx --no-install shoalrun docs baseline --out .shoalrun/task-baseline.json --config docs.config.yaml Choose a new baseline filename for each task. The baseline includes earlier local edits and untracked files; it compares later changes with this starting state rather than Git HEAD. It runs no checks. Edit and validate Edit ordinary MDX and configuration files using your agent's file tools. Preserve unrelated edits and review changes to identity, navigation, relationships, and publication metadata. npx --no-install shoalrun docs validate --baseline .shoalrun/task-baseline.json --config docs.config.yaml For an existing edit without a baseline, declare its scope explicitly: npx --no-install shoalrun docs validate --file content/install.mdx --config docs.config.yaml Validation compiles a separate capture. Read the returned status, coverage, findings, skipped checks, and artifact paths. A failure needs correction and another validation. An incomplete or unavailable result needs investigation; it is not a passing result. Configured shell checks require explicit --run-checks and your harness's execution authorization. Confirm the result still applies npx --no-install shoalrun docs validation-status /path/from/result/report.json Use the actual report path returned by validation. A stale result requires another validation. Review and preview the snapshot npx --no-install shoalrun docs review /path/from/result/report.json --format markdown npx --no-install shoalrun docs preview /path/from/result/report.json --port 8771 The preview command stays running and returns a local review URL plus HTML and Markdown URLs for every affected page that rendered. Open the review URL in your browser. It shows the task baseline, changed files, checks, findings, dependencies, and artifacts. Previewing a failed or incomplete result does not make it pass. A failed compile can leave no site to preview; read its findings with docs review first. The server uses a private copy of the captured build. Each HTML page shows the snapshot status and a link back to the review. Source changes make that preview stale; the displayed content remains the captured version. A baseline contains digests rather than earlier file contents, so retain the task diff with your harness. The report does not attribute all dirty files to your task. After a revision, stop the preview with Ctrl-C, validate again, and start a preview using the new report path. The server never watches or rebuilds source. Ctrl-C or SIGTERM removes its private serving copy; the validation artifacts remain. Remove only the reported validation artifact directory when finished. A forced process kill can leave the serving copy behind; its path is in the startup result. Review facts, examples, supporting sources, and the task diff before accepting the edit. Use your normal review and publication process afterward. Related reading Read first Reference while working Related topics"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Authoring tools for your coding agent — Understand how your coding agent uses Shoalrun tools and human review. (Status: experimental.) Authoring tools commands — Look up discovery and snapshot validation commands. (Status: experimental.) Apply a checked edit plan — Use the checked edit commands with your existing coding agent. (Status: experimental.)"},{"filters":{"focus":["write"]},"text":"Example writing guide — Review the example guidance before approving a writing plan."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5916,"markdownTokens":1286,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.cards","demo":false,"url":"/author/components/cards","markdownUrl":"/author/components/cards.md","title":"Cards and collections","summary":"Link to documents by stable ID and build filtered card collections.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-navigation","headings":[{"id":"link-to-one-document","title":"Link to one document"},{"id":"curate-a-reading-list","title":"Curate a reading list"},{"id":"override-card-text","title":"Override card text"},{"id":"add-a-lucide-icon","title":"Add a Lucide icon"},{"id":"build-a-collection","title":"Build a collection"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"A card is a linked preview of another documentation page: it shows a title and short preview so readers can decide where to go next. Cards use the target page's title, the project's configured outputs.text.card field, and its current URL. The target is the page the reader will open when they select the card. Authors maintain those details in the target page's frontmatter, the YAML metadata at the top of the file. A card references the page's stable id , so renaming its file or changing its URL does not break the card. HTML displays a card layout; Markdown displays the same links, descriptions, subject lifecycle status, and relationship reasons as a readable list. Use these components as standalone, empty blocks in .md or .mdx pages or registered snippets. Literal attributes are accepted; arbitrary JavaScript expressions are not evaluated. Link to one document < DocCard doc = \"guide.frontmatter\" /> Page metadata Set page identity, publication, and presentation fields before publishing. The target must be public and available in the current publication: the channel, API version, and language of the page displaying the card. An unknown, draft, or unavailable target stops the build with a diagnostic. There is no automatic fallback to another publication. Curate a reading list Use a curated list when you want to choose exactly which pages readers see and in what order. DocCards displays one card for each document ID you supply. For example, this list offers the content guide followed by the templates guide: < DocCards docs = {[ \"guide.content-identity\" , \"guide.templates\" ]} /> Content and stable IDs Give each page a durable identity and publish explicit variants. Templates Create and edit page starting points, then scaffold drafts from them. The array controls the order. Duplicate IDs fail validation. An empty array renders “No matching documents.” Set empty=\"Your message\" to replace that text. Add an ordinary Markdown heading before a card group when it needs a section title. Cards themselves use list and link semantics rather than inserting heading levels. DocCards can also show cards from a declared relationship. Supply either docs or relation : < DocCards relation = \"next-step\" relatedTo = \"guide.cards\" /> Attribute Required Meaning docs For a curated list Literal array of unique document IDs in display order. relation For relationship cards One declared relationship type; cannot be combined with docs . relatedTo No Source document for relation ; defaults to this page. empty No Message for no results; default is “No matching documents.” Use RelatedReading when a plain link list grouped by purpose fits better than cards. Override card text By default, a card shows the target page's title and summary . These are the resolved values after global defaults, page frontmatter, and enforced values have been applied. Add an optional card object to the target page's frontmatter when its card needs different wording. An eyebrow is a short label above the card title, such as “Integration guide” or “Tutorial.” It helps readers recognize the kind of content before reading the title. It is optional display text; it does not set the document's type, add a tag, or affect collection filters. In this example, “Integration guide” appears above “Send your first payment”: title : Create a payment summary : Submit a payment and understand the result. card : icon : credit-card title : Send your first payment description : Prepare the request and inspect the response. eyebrow : Integration guide Field What it displays When omitted card.title The linked heading inside the card. Uses the document title . card.description A short explanation of what the reader will find. Uses outputs.text.card , which defaults to the document summary . card.eyebrow A small label above the title. No label. card.icon A decorative Lucide symbol above the text. No icon, unless inherited from global frontmatter. These overrides affect cards only. The page heading, SEO, and navigation keep their existing values. A card's destination always comes from the stable ID; href overrides are not supported. Values must be nonempty strings. Images, arbitrary badges, and other card fields are not implemented and fail with a diagnostic. Subject lifecycle status comes from the target document, including authoritative OpenAPI deprecation. Add a Lucide icon Choose an icon from the Lucide icon browser and put its lowercase name on the target page: card : icon : book-open Names use hyphens, such as book-open , credit-card , terminal , or sliders-horizontal . The pinned Lucide package supplies the icons at build time. An unknown name or URL fails with a file-specific diagnostic, so typos never silently produce an empty icon. New icons from a later Lucide release need a dependency update first. The icon appears in every card for that page, including curated lists, collections, and relationship views. It does not change the page heading or sidebar. Omit card.ico","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A card is a linked preview of another documentation page: it shows a title and short preview so readers can decide where to go next. Cards use the target page's title, the project's configured outputs.text.card field, and its current URL. The target is the page the reader will open when they select the card. Authors maintain those details in the target page's frontmatter, the YAML metadata at the top of the file. A card references the page's stable id , so renaming its file or changing its URL does not break the card. HTML displays a card layout; Markdown displays the same links, descriptions, subject lifecycle status, and relationship reasons as a readable list. Use these components as standalone, empty blocks in .md or .mdx pages or registered snippets. Literal attributes are accepted; arbitrary JavaScript expressions are not evaluated. Link to one document <DocCard doc=\"guide.frontmatter\" /> The target must be public and available in the current publication: the channel, API version, and language of the page displaying the card. An unknown, draft, or unavailable target stops the build with a diagnostic. There is no automatic fallback to another publication. Curate a reading list Use a curated list when you want to choose exactly which pages readers see and in what order. DocCards displays one card for each document ID you supply. For example, this list offers the content guide followed by the templates guide: <DocCards docs={[\"guide.content-identity\", \"guide.templates\"]} /> The array controls the order. Duplicate IDs fail validation. An empty array renders “No matching documents.” Set empty=\"Your message\" to replace that text. Add an ordinary Markdown heading before a card group when it needs a section title. Cards themselves use list and link semantics rather than inserting heading levels. DocCards can also show cards from a declared relationship. Supply either docs or relation : <DocCards relation=\"next-step\" relatedTo=\"guide.cards\" /> Attribute Required Meaning docs For a curated list Literal array of unique document IDs in display order. relation For relationship cards One declared relationship type; cannot be combined with docs . relatedTo No Source document for relation ; defaults to this page. empty No Message for no results; default is “No matching documents.” Use RelatedReading when a plain link list grouped by purpose fits better than cards. Override card text By default, a card shows the target page's title and summary . These are the resolved values after global defaults, page frontmatter, and enforced values have been applied. Add an optional card object to the target page's frontmatter when its card needs different wording. An eyebrow is a short label above the card title, such as “Integration guide” or “Tutorial.” It helps readers recognize the kind of content before reading the title. It is optional display text; it does not set the document's type, add a tag, or affect collection filters. In this example, “Integration guide” appears above “Send your first payment”: title: Create a payment summary: Submit a payment and understand the result. card: icon: credit-card title: Send your first payment description: Prepare the request and inspect the response. eyebrow: Integration guide Field What it displays When omitted card.title The linked heading inside the card. Uses the document title . card.description A short explanation of what the reader will find. Uses outputs.text.card , which defaults to the document summary . card.eyebrow A small label above the title. No label. card.icon A decorative Lucide symbol above the text. No icon, unless inherited from global frontmatter. These overrides affect cards only. The page heading, SEO, and navigation keep their existing values. A card's destination always comes from the stable ID; href overrides are not supported. Values must be nonempty strings. Images, arbitrary badges, and other card fields are not implemented and fail with a diagnostic. Subject lifecycle status comes from the target document, including authoritative OpenAPI deprecation. Add a Lucide icon Choose an icon from the Lucide icon browser and put its lowercase name on the target page: card: icon: book-open Names use hyphens, such as book-open , credit-card , terminal , or sliders-horizontal . The pinned Lucide package supplies the icons at build time. An unknown name or URL fails with a file-specific diagnostic, so typos never silently produce an empty icon. New icons from a later Lucide release need a dependency update first. The icon appears in every card for that page, including curated lists, collections, and relationship views. It does not change the page heading or sidebar. Omit card.icon for a text-only card. Global frontmatter.defaults.card.icon and frontmatter.enforced.card.icon use the same precedence rules as other card metadata; a page can override a default with another icon name. Icons are inline SVGs with aria-hidden=\"true\" and focusable=\"false\" . The visible card tit"},{"filters":{"focus":["write"],"audience":["authors","maintainers"]},"text":"Page metadata Set page identity, publication, and presentation fields before publishing. Page metadata — Configure shared metadata and optional card text overrides."},{"filters":{"focus":["write"]},"text":"Content and stable IDs Give each page a durable identity and publish explicit variants. DocLink — Link to a page inline, or show it as a card with its summary. Related reading — Related reading follows authored relationships with reasons; cards and collections show pages you pick by ID or filter by metadata."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates Create and edit page starting points, then scaffold drafts from them."},{"filters":{"focus":["configure"]},"text":"Publishing and agent representations — Inspect the HTML, Markdown, and manifests produced by the build."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":12368,"markdownTokens":2419,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"link-to-one-document","title":"Link to one document","markdownUrl":"/author/components/cards.sections/link-to-one-document.md","markdownBytes":2398,"markdownTokens":543},{"id":"curate-a-reading-list","title":"Curate a reading list","markdownUrl":"/author/components/cards.sections/curate-a-reading-list.md","markdownBytes":3820,"markdownTokens":829},{"id":"override-card-text","title":"Override card text","markdownUrl":"/author/components/cards.sections/override-card-text.md","markdownBytes":4115,"markdownTokens":846},{"id":"add-a-lucide-icon","title":"Add a Lucide icon","markdownUrl":"/author/components/cards.sections/add-a-lucide-icon.md","markdownBytes":3398,"markdownTokens":769},{"id":"build-a-collection","title":"Build a collection","markdownUrl":"/author/components/cards.sections/build-a-collection.md","markdownBytes":5444,"markdownTokens":1018},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/components/cards.sections/html-markdown-and-agents.md","markdownBytes":2320,"markdownTokens":509},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/components/cards.sections/related-reading.md","markdownBytes":2385,"markdownTokens":547}]},{"id":"guide.cedar-parcel","demo":true,"url":"/example-api/cedar","markdownUrl":"/example-api/cedar.md","title":"API reference styling lab","summary":"Inspect a synthetic API with complex schemas, filters, response formats, and webhooks.","type":"overview","variant":"production|current|en","area":"api","subarea":"api-examples","headings":[{"id":"how-it-works-for-agents","title":"How it works for agents"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. The Cedar Parcel API is fictional. Its .example hosts do not accept requests, and its OpenAPI examples have not been executed. We keep it in the Shoalrun docs to check API reference layouts alongside other pages. It uses the same navigation, search, themes, and Markdown output. Use these pages to inspect the hardest layouts: Create a parcel enrollment shows four named request shapes with overlapping nested objects and required fields. In Bulk dispatch , monthlyParcelEstimate demonstrates an exclusive lower bound and schema-level examples, while customMetadata accepts any JSON value. List parcel records shows direct query filters, three response formats, and the new object, array, and number constraints: minProperties , maxProperties , uniqueItems , and multipleOf . Get a parcel uses a path-specific server and no authentication. Upload a manifest requires two binary upload fields. Get a parcel through the old route shows OpenAPI deprecation overriding an extension value. Parcel delivered event shows an inbound OpenAPI 3.1 webhook with a nested oneOf proof. The source and standalone test project live at framework/example-configs/reference-stress/ in the repository. The source is not copied into the built site; each operation publishes only its focused contract. How it works for agents Every operation has a complete .md page and a focused OpenAPI contract. Schema fields remain in Markdown even when their HTML disclosure is closed. The site manifest and search index include these pages, and the reader's theme choice does not change what an agent can read.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. The Cedar Parcel API is fictional. Its .example hosts do not accept requests, and its OpenAPI examples have not been executed. We keep it in the Shoalrun docs to check API reference layouts alongside other pages. It uses the same navigation, search, themes, and Markdown output. Use these pages to inspect the hardest layouts: Create a parcel enrollment shows four named request shapes with overlapping nested objects and required fields. In Bulk dispatch , monthlyParcelEstimate demonstrates an exclusive lower bound and schema-level examples, while customMetadata accepts any JSON value. List parcel records shows direct query filters, three response formats, and the new object, array, and number constraints: minProperties , maxProperties , uniqueItems , and multipleOf . Get a parcel uses a path-specific server and no authentication. Upload a manifest requires two binary upload fields. Get a parcel through the old route shows OpenAPI deprecation overriding an extension value. Parcel delivered event shows an inbound OpenAPI 3.1 webhook with a nested oneOf proof. The source and standalone test project live at framework/example-configs/reference-stress/ in the repository. The source is not copied into the built site; each operation publishes only its focused contract. How it works for agents Every operation has a complete .md page and a focused OpenAPI contract. Schema fields remain in Markdown even when their HTML disclosure is closed. The site manifest and search index include these pages, and the reader's theme choice does not change what an agent can read."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2973,"markdownTokens":727,"markdownTokenEncoding":"cl100k_base"},{"id":"change.agent-readiness","demo":false,"url":"/changelog/2026-10-14-agent-readiness","markdownUrl":"/changelog/2026-10-14-agent-readiness.md","title":"Agent discovery, verified Markdown, and incremental sync","summary":"Compact discovery, content verification, and incremental fetching.","type":"changelog-entry","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[],"text":"Agents can now find pages through smaller indexes, check which build they are reading, and compare saved page inventories before fetching updates. Smaller discovery files. llms.min.txt lists page IDs, titles, summaries, and Markdown links. search-index.min.json adds headings without article text. Markdown 404 responses point to these compact files. Incremental sync. Clients can check build-info.json for a new build, then compare documents.sync.json with their saved snapshot to find added, changed, and removed pages. They can fetch only the pages that need updating instead of downloading the full manifest and every page again. shoalrun docs changes CURRENT-SNAPSHOT --since PREVIOUS-SNAPSHOT performs the comparison locally. Verifiable responses. Markdown responses include a fingerprint that lets clients check whether a page changed without downloading it again, plus a link to its manifest record. Focused API contracts now use their actual content digest in the URL, allowing a one-year immutable cache policy. Clearer examples. Fictional pages carry a machine-readable demo flag. The refreshed agent-friendly guide puts working tabs, a disclosure, and reader choices beside the Markdown an agent receives. Try the example and see what an agent reads . The output reference covers the files, digests, and sync workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Agents can now find pages through smaller indexes, check which build they are reading, and compare saved page inventories before fetching updates. Smaller discovery files. llms.min.txt lists page IDs, titles, summaries, and Markdown links. search-index.min.json adds headings without article text. Markdown 404 responses point to these compact files. Incremental sync. Clients can check build-info.json for a new build, then compare documents.sync.json with their saved snapshot to find added, changed, and removed pages. They can fetch only the pages that need updating instead of downloading the full manifest and every page again. shoalrun docs changes CURRENT-SNAPSHOT --since PREVIOUS-SNAPSHOT performs the comparison locally. Verifiable responses. Markdown responses include a fingerprint that lets clients check whether a page changed without downloading it again, plus a link to its manifest record. Focused API contracts now use their actual content digest in the URL, allowing a one-year immutable cache policy. Clearer examples. Fictional pages carry a machine-readable demo flag. The refreshed agent-friendly guide puts working tabs, a disclosure, and reader choices beside the Markdown an agent receives. Try the example and see what an agent reads . The output reference covers the files, digests, and sync workflow."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":2367,"markdownTokens":549,"markdownTokenEncoding":"cl100k_base"},{"id":"change.evaluation-builds","demo":false,"url":"/changelog/2026-10-15-evaluation-builds","markdownUrl":"/changelog/2026-10-15-evaluation-builds.md","title":"Agent reading and evaluation","summary":"Smaller reads, lifecycle guidance, and reproducible evaluations.","type":"changelog-entry","variant":"production|current|en","area":"quality","subarea":"quality-evaluations","headings":[{"id":"compare-evaluation-builds","title":"Compare evaluation builds"},{"id":"find-and-read-markdown","title":"Find and read Markdown"},{"id":"follow-deprecation-and-migration-guidance","title":"Follow deprecation and migration guidance"},{"id":"keep-reading-paths-in-section-markdown","title":"Keep reading paths in section Markdown"},{"id":"understand-authored-change-meaning","title":"Understand authored change meaning"},{"id":"check-the-published-output-contract","title":"Check the published-output contract"}],"text":"This entry combines the October 15 changes to the private prototype. It does not announce a package release or a verified deployment. Compare evaluation builds Evaluation reports can now identify which published files changed. New report templates include a file inventory; eval check lists additions, edits, and removals when the evaluated build differs from the current output. Use shoalrun eval snapshot to save an inventory and shoalrun eval compare to compare builds. The check still requires the exact evaluated output. Copying a build to another machine preserves its identity; rebuilding it may produce different bytes. The repository can also capture hosted builds with their tasks and an ungraded report template for later review. Capturing a build does not run the tasks or award a passing grade. The packaged Markdown bundle also stops carrying a whole-site build ID for assets it does not include. Its page digests and metadata remain intact. Evaluate agent tasks against your docs explains the workflow and its limits. Find and read Markdown The manifest and compact search index now expose exact published Markdown byte counts and cl100k_base token counts. Copy as Markdown copies the full published twin, with an accessible status and a plain link fallback. See Markdown metadata and agent discovery . Pages now publish complete Markdown resources for top-level sections, with outlines, exact sizes, and parent/section digests. Use docs outline and docs section , or MCP get_outline and get_section , to retrieve them. Nested reader content stays together. Generated section IDs can change when headings change; see section identity and citations . Search now returns the exact next read call and a direct Markdown URL, with a full-page fallback. Section files are limited to longer pages and must halve both bytes and tokens; short pages no longer produce redundant section files. Compact search records expose eligible section URLs without requiring the full manifest. Search now recommends a smaller section only when the author explicitly lists its heading in standaloneSections ; otherwise the next read fetches the full page. This addresses an observed case where a matching section omitted prerequisite configuration. Declarations are author judgments, not compiler verification of completeness. CLI/MCP search now allows a stronger match missing one meaningful query term to outrank complete matches found only in body text. Complete matches with relevant titles, summaries, or headings keep their preference. Page-title matching also accepts simple final- s query plurals against singular titles. These changes fix an observed discovery miss without project-specific synonyms; browser search is unchanged. See search ranking . For partial CLI/MCP matches, a focused subject match can now outrank a result with one extra incidental term. Only candidates within one meaningful term of the best coverage and at least two matched terms receive this ordering. Sparse matches stay below that group. This corrects an observed MCP client setup query while preserving full-page reads for setup and budget instructions. Fetch-only agents can now reach approved section resources from the small text index. The HTML discovery block opens /llms.min.txt , which lists full pages and author-declared standalone sections with exact sizes and explicit full-page fallbacks. Publication labels distinguish editions. No JSON parsing, CLI or MCP is needed for that reading path; the detailed index remains available. HTML metadata and Markdown page backlinks now point to the same compact index as the visible agent guidance. The full index remains available from that list. The diagram reference also includes complete D2 and Mermaid authoring examples with intact nested code fences. These small private-prototype changes address discovery detours and missing copyable syntax observed during fetch-only evaluations. Follow deprecation and migration guidance This private prototype update adds subjectDeprecation to page metadata. Authors can supply deprecation and sunset dates, a replacement document ID, and a migration guide ID for a deprecated API or feature. Readers see the same guidance in HTML, full-page Markdown, and published section resources. Fetch-only agents can follow the Markdown links directly. The document manifest also exposes the dates and resolved targets. Builds reject invalid dates and references outside the current publication. The guidance describes the documented subject. It does not remove the documentation page or emit HTTP retirement headers. Dates are author declarations, not evidence that a service has retired. See page metadata for syntax and validation rules. Keep reading paths in section Markdown This private prototype update preserves reading guidance when an agent fetches one section of a longer page. Prerequisites and next steps from top-level, current-page RelatedReading views now travel with the section, including the reason to follow each","readerFilters":{},"readerSegments":[{"filters":{},"text":"This entry combines the October 15 changes to the private prototype. It does not announce a package release or a verified deployment. Compare evaluation builds Evaluation reports can now identify which published files changed. New report templates include a file inventory; eval check lists additions, edits, and removals when the evaluated build differs from the current output. Use shoalrun eval snapshot to save an inventory and shoalrun eval compare to compare builds. The check still requires the exact evaluated output. Copying a build to another machine preserves its identity; rebuilding it may produce different bytes. The repository can also capture hosted builds with their tasks and an ungraded report template for later review. Capturing a build does not run the tasks or award a passing grade. The packaged Markdown bundle also stops carrying a whole-site build ID for assets it does not include. Its page digests and metadata remain intact. Evaluate agent tasks against your docs explains the workflow and its limits. Find and read Markdown The manifest and compact search index now expose exact published Markdown byte counts and cl100k_base token counts. Copy as Markdown copies the full published twin, with an accessible status and a plain link fallback. See Markdown metadata and agent discovery . Pages now publish complete Markdown resources for top-level sections, with outlines, exact sizes, and parent/section digests. Use docs outline and docs section , or MCP get_outline and get_section , to retrieve them. Nested reader content stays together. Generated section IDs can change when headings change; see section identity and citations . Search now returns the exact next read call and a direct Markdown URL, with a full-page fallback. Section files are limited to longer pages and must halve both bytes and tokens; short pages no longer produce redundant section files. Compact search records expose eligible section URLs without requiring the full manifest. Search now recommends a smaller section only when the author explicitly lists its heading in standaloneSections ; otherwise the next read fetches the full page. This addresses an observed case where a matching section omitted prerequisite configuration. Declarations are author judgments, not compiler verification of completeness. CLI/MCP search now allows a stronger match missing one meaningful query term to outrank complete matches found only in body text. Complete matches with relevant titles, summaries, or headings keep their preference. Page-title matching also accepts simple final- s query plurals against singular titles. These changes fix an observed discovery miss without project-specific synonyms; browser search is unchanged. See search ranking . For partial CLI/MCP matches, a focused subject match can now outrank a result with one extra incidental term. Only candidates within one meaningful term of the best coverage and at least two matched terms receive this ordering. Sparse matches stay below that group. This corrects an observed MCP client setup query while preserving full-page reads for setup and budget instructions. Fetch-only agents can now reach approved section resources from the small text index. The HTML discovery block opens /llms.min.txt , which lists full pages and author-declared standalone sections with exact sizes and explicit full-page fallbacks. Publication labels distinguish editions. No JSON parsing, CLI or MCP is needed for that reading path; the detailed index remains available. HTML metadata and Markdown page backlinks now point to the same compact index as the visible agent guidance. The full index remains available from that list. The diagram reference also includes complete D2 and Mermaid authoring examples with intact nested code fences. These small private-prototype changes address discovery detours and missing copyable syntax observed during fetch-only evaluations. Follow deprecation and migration guidance This private prototype update adds subjectDeprecation to page metadata. Authors can supply deprecation and sunset dates, a replacement document ID, and a migration guide ID for a deprecated API or feature. Readers see the same guidance in HTML, full-page Markdown, and published section resources. Fetch-only agents can follow the Markdown links directly. The document manifest also exposes the dates and resolved targets. Builds reject invalid dates and references outside the current publication. The guidance describes the documented subject. It does not remove the documentation page or emit HTTP retirement headers. Dates are author declarations, not evidence that a service has retired. See page metadata for syntax and validation rules. Keep reading paths in section Markdown This private prototype update preserves reading guidance when an agent fetches one section of a longer page. Prerequisites and next steps from top-level, current-page RelatedReading views now travel with the section, including the reason to follow each"}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":8595,"markdownTokens":1699,"markdownTokenEncoding":"cl100k_base"},{"id":"change.2026-10-25","demo":false,"url":"/changelog/2026-10-25","markdownUrl":"/changelog/2026-10-25.md","title":"Content exports and documentation checks","summary":"Content exports and documentation checks.","type":"changelog-entry","variant":"production|current|en","area":"project","subarea":"project-releases","headings":[{"id":"reuse-documentation-inside-an-application","title":"Reuse documentation inside an application"},{"id":"check-documentation-with-manni","title":"Check documentation with Manni"},{"id":"planned-work","title":"Planned work"}],"text":"These October 25 changes group content exports in CLI 0.1.0-alpha.6 and optional documentation checks in our docs project. Reuse documentation inside an application The content export command builds shared pages into Markdown, static HTML fragments, assets, and a manifest. Applications can use those files in help drawers, onboarding screens, or other interfaces without loading Shoalrun in the browser. Named export targets select a publication and eligible pages independently of the website's navigation. Facet selection is optional. Reader-specific sections remain visible with labels; tabs and walkthroughs retain every panel and step. Document links identify their destinations for application routing, with eligible website links used for pages outside the bundle. Exports retain referenced local assets, notices, and API review requirements. A plain JavaScript help-drawer example demonstrates loading the bundle from an unrelated application route. Its /help/ URL is an example; the configured path must match where the application serves the files. Check documentation with Manni The Manni integration provides access to the project's installed Manni tools through a small launcher and existing Shoalrun audit hooks. Manni remains an optional project dependency; its configuration and built-in tools stay with Manni. Our documentation project uses glossary references and structure rules for selected guides. A procedure test runs the quickstart's initialization, scaffolding, and build instructions in a disposable project, then verifies HTML, Markdown, navigation, and links. A separate accessibility check uses the built document list to inspect every published HTML page, including pages outside navigation. A source citation connects one metadata explanation to its framework implementation and flags changes for review. This check needs a source checkout and runs separately from ordinary builds and isolated validation. Planned work Project status also records optional vector-store connections as planned work. They are not required for content exports or the existing file-based retrieval path.","readerFilters":{},"readerSegments":[{"filters":{},"text":"These October 25 changes group content exports in CLI 0.1.0-alpha.6 and optional documentation checks in our docs project. Reuse documentation inside an application The content export command builds shared pages into Markdown, static HTML fragments, assets, and a manifest. Applications can use those files in help drawers, onboarding screens, or other interfaces without loading Shoalrun in the browser. Named export targets select a publication and eligible pages independently of the website's navigation. Facet selection is optional. Reader-specific sections remain visible with labels; tabs and walkthroughs retain every panel and step. Document links identify their destinations for application routing, with eligible website links used for pages outside the bundle. Exports retain referenced local assets, notices, and API review requirements. A plain JavaScript help-drawer example demonstrates loading the bundle from an unrelated application route. Its /help/ URL is an example; the configured path must match where the application serves the files. Check documentation with Manni The Manni integration provides access to the project's installed Manni tools through a small launcher and existing Shoalrun audit hooks. Manni remains an optional project dependency; its configuration and built-in tools stay with Manni. Our documentation project uses glossary references and structure rules for selected guides. A procedure test runs the quickstart's initialization, scaffolding, and build instructions in a disposable project, then verifies HTML, Markdown, navigation, and links. A separate accessibility check uses the built document list to inspect every published HTML page, including pages outside navigation. A source citation connects one metadata explanation to its framework implementation and flags changes for review. This check needs a source checkout and runs separately from ordinary builds and isolated validation. Planned work Project status also records optional vector-store connections as planned work. They are not required for content exports or the existing file-based retrieval path."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":3133,"markdownTokens":671,"markdownTokenEncoding":"cl100k_base"},{"id":"change.2026-10-26","demo":false,"url":"/changelog/2026-10-26","markdownUrl":"/changelog/2026-10-26.md","title":"Safer exports and easier discovery for AI assistants","summary":"Keep exported images and links with their pages, and help AI assistants find docs by topic.","type":"changelog-entry","variant":"production|current|en","area":["project","discovery"],"subarea":["project-releases","discovery-agents"],"headings":[{"id":"find-documentation-by-topic","title":"Find documentation by topic"},{"id":"keep-exported-images-and-links-with-their-pages","title":"Keep exported images and links with their pages"},{"id":"check-your-output-destination","title":"Check your output destination"},{"id":"technical-details-and-validation","title":"Technical details and validation"}],"text":"Today's two private-alpha releases make documentation safer to reuse and easier for AI assistants to find. Alpha.7 keeps exported images and links attached to the right document. Alpha.8 lets assistants choose a topic before reading a directory of every page. Both versions are published in the private package registry. Upgrade to CLI 0.1.0-alpha.8 and rebuild your site to receive both sets of changes. Find documentation by topic Previously, the starting directory listed every published page. Each new page made that directory longer, so an assistant had to read more text before choosing what to open. Now, larger sites link to smaller topic directories. An assistant looking for deployment instructions can choose Publishing , then open the relevant page. Topic names come from your project's categories, or page types when categories are absent. If a directory grows too large, Shoalrun divides it again. Small sites can still list their pages directly. Every published page remains reachable, including pages outside the website's navigation. On Shoalrun's own site, the starting directory shrank from roughly 6,000 tokens to 400. Tokens are the pieces of text an AI model reads. Larger sites may require more directory steps, but each step stays small. Assistants still start at /llms.min.txt . If you maintain a script that reads this file, update it to follow topic-directory links instead of expecting every page in the first response. The complete catalog remains at /llms.txt . Independently readable sections retain their sizes and links to the full page. Keep exported images and links with their pages Two documents can share a website route while needing different images or links in an exported bundle. Alpha.7 keeps each document's own assets and link destinations in exported HTML and Markdown. This also covers cards, related reading, cookbook choices, deprecation notices, and changelog notices. The help-drawer example now moves keyboard focus into opened content and follows links to specific headings. Closing the drawer with Escape returns focus to its launcher. Check your output destination Use a real directory as the build or export destination. A destination that is itself a symbolic link is now rejected; symbolic links in its parent directories remain supported. Shoalrun also rejects paths that escape the output directory, empty path segments, unsafe export mount paths, and duplicate output aliases before writing. Different paths to the same parent directory share one output lock, preventing competing builds from writing there at the same time. The export manifest remains at schema version 1. Technical details and validation Compact directories have a 2,000-token limit, measured with cl100k_base . This limits each response, not the total reading needed for a question. A title or summary that cannot fit in one entry still needs shortening. Tests cover 160 to 1,600 pages, large topics, hundreds of topics, and reachability of every published page and declared standalone section. The MCP server and client packages move to version 2.3.0 . Zod moves to 4.6.6 , and KaTeX to 0.18.2 . MCP tool arguments are limited to 1,024 elements before schema validation. HTTP requests retain the 64 KiB body limit and a separate server instance for each request. These updates address advisories for MCP connection isolation , MCP input validation , MCP bearer-token audience checks , Zod collection validation , and KaTeX inherited settings . Alpha.7 validation passed 723 framework tests, all five packaged skill checks, and clean installations of the minimal and API-documentation starters. Its dependency audit reported no vulnerabilities at validation time. Package checks also inspect the file inventory and exercise the installed help drawer in a browser. Test runs limit concurrency to four files, rebuild tests wait for complete server events, and skill validation reports missing Python prerequisites with setup instructions. This remains an alpha release. Publishing the CLI does not automatically upgrade or deploy an existing site. See Agent-friendly documentation for the reading workflow and portable content exports for reuse in another application.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Today's two private-alpha releases make documentation safer to reuse and easier for AI assistants to find. Alpha.7 keeps exported images and links attached to the right document. Alpha.8 lets assistants choose a topic before reading a directory of every page. Both versions are published in the private package registry. Upgrade to CLI 0.1.0-alpha.8 and rebuild your site to receive both sets of changes. Find documentation by topic Previously, the starting directory listed every published page. Each new page made that directory longer, so an assistant had to read more text before choosing what to open. Now, larger sites link to smaller topic directories. An assistant looking for deployment instructions can choose Publishing , then open the relevant page. Topic names come from your project's categories, or page types when categories are absent. If a directory grows too large, Shoalrun divides it again. Small sites can still list their pages directly. Every published page remains reachable, including pages outside the website's navigation. On Shoalrun's own site, the starting directory shrank from roughly 6,000 tokens to 400. Tokens are the pieces of text an AI model reads. Larger sites may require more directory steps, but each step stays small. Assistants still start at /llms.min.txt . If you maintain a script that reads this file, update it to follow topic-directory links instead of expecting every page in the first response. The complete catalog remains at /llms.txt . Independently readable sections retain their sizes and links to the full page. Keep exported images and links with their pages Two documents can share a website route while needing different images or links in an exported bundle. Alpha.7 keeps each document's own assets and link destinations in exported HTML and Markdown. This also covers cards, related reading, cookbook choices, deprecation notices, and changelog notices. The help-drawer example now moves keyboard focus into opened content and follows links to specific headings. Closing the drawer with Escape returns focus to its launcher. Check your output destination Use a real directory as the build or export destination. A destination that is itself a symbolic link is now rejected; symbolic links in its parent directories remain supported. Shoalrun also rejects paths that escape the output directory, empty path segments, unsafe export mount paths, and duplicate output aliases before writing. Different paths to the same parent directory share one output lock, preventing competing builds from writing there at the same time. The export manifest remains at schema version 1. Technical details and validation Compact directories have a 2,000-token limit, measured with cl100k_base . This limits each response, not the total reading needed for a question. A title or summary that cannot fit in one entry still needs shortening. Tests cover 160 to 1,600 pages, large topics, hundreds of topics, and reachability of every published page and declared standalone section. The MCP server and client packages move to version 2.3.0 . Zod moves to 4.6.6 , and KaTeX to 0.18.2 . MCP tool arguments are limited to 1,024 elements before schema validation. HTTP requests retain the 64 KiB body limit and a separate server instance for each request. These updates address advisories for MCP connection isolation , MCP input validation , MCP bearer-token audience checks , Zod collection validation , and KaTeX inherited settings . Alpha.7 validation passed 723 framework tests, all five packaged skill checks, and clean installations of the minimal and API-documentation starters. Its dependency audit reported no vulnerabilities at validation time. Package checks also inspect the file inventory and exercise the installed help drawer in a browser. Test runs limit concurrency to four files, rebuild tests wait for complete server events, and skill validation reports missing Python prerequisites with setup instructions. This remains an alpha release. Publishing the CLI does not automatically upgrade or deploy an existing site. See Agent-friendly documentation for the reading workflow and portable content exports for reuse in another application."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":5694,"markdownTokens":1291,"markdownTokenEncoding":"cl100k_base"},{"id":"change.2026-10-27","demo":false,"url":"/changelog/2026-10-27","markdownUrl":"/changelog/2026-10-27.md","title":"Clearer defaults, a feature showcase, and easier navigation","summary":"Explore a complete starter, read clearer controls, and find focused configuration references alongside the new mobile navigation.","type":"changelog-entry","variant":"production|current|en","area":["appearance","authoring","publishing","project"],"subarea":["appearance-navigation","authoring-pages","publishing-configuration","project-releases"],"headings":[{"id":"install-from-public-npm","title":"Install from public npm"},{"id":"explore-a-complete-starter","title":"Explore a complete starter"},{"id":"read-controls-and-prose-comfortably","title":"Read controls and prose comfortably"},{"id":"choose-a-page-before-fetching-it","title":"Choose a page before fetching it"},{"id":"find-configuration-settings-by-topic","title":"Find configuration settings by topic"},{"id":"keep-your-place-on-a-phone","title":"Keep your place on a phone"},{"id":"reach-the-article-sooner","title":"Reach the article sooner"}],"text":"The October 27 releases improve reading and navigation, add a complete feature-showcase starter, and give agents page types and sizes before they fetch content. The documentation site also gets a refreshed logo and smaller configuration references. Upgrade to CLI 0.1.0-alpha.11 and rebuild your site to receive the framework changes from alpha.9 and alpha.10. Existing navigation configuration continues to work. The logo and reorganized reference are updates to this documentation site. Install from public npm Alpha.11 moves the CLI to the public npm registry. Installation no longer needs an invitation, GitHub package access, or a package token. Follow Getting started for an exact-version install. If you used the earlier private alpha, remove or replace the old @shoalrun registry override and update the manifest and lockfile together. The package README now leads with the showcase. Starter instructions explain how to replace the fictional API and its connected operation bindings. Alpha.11 keeps the site configuration and output contracts from alpha.10. Explore a complete starter Alpha.10 adds a fictional Cedar Parcel handbook with 18 pages. It includes component examples, code walkthroughs, Mermaid and D2 diagrams, reader views, a landing page, a local-workflow cookbook, and generated API references. Explore the starter is the first page in its navigation and maps the working examples. shoalrun init my-handbook --starter showcase cd my-handbook shoalrun build docs.config.yaml site-dist shoalrun serve site-dist The starter builds without provider credentials. Hosted chat, analytics, and remote services need your own configuration. The minimal and api-docs starters remain available. See example projects . Read controls and prose comfortably Alpha.10 increases small reader, code, and API control labels. Ordinary lists use the same reading measure as paragraphs, while tables, code, and file trees retain their available width. Mobile header tools share a row when space permits, and search results fit within the header width. Choose a page before fetching it Compact discovery and navigation indexes now include each page's content type and full-page token count. An agent can compare a short how-to with a longer reference before opening either. The existing 2,000-token limit per compact index still applies; larger catalogs split into linked topic indexes without losing pages. Find configuration settings by topic The configuration reference is now an overview linking to six focused references. The former combined page was about 11,454 tokens; each focused reference is about 1,300–2,600 tokens in the reviewed build. Existing section bookmarks remain available on the overview and link to the new destinations. The site also has a refreshed logo and favicon. The header mark follows the selected theme, with a text fallback in forced-color mode. Keep your place on a phone Alpha.9 brought section links and page navigation into one mobile Menu . Previously, section choices, the page menu, and the outline competed for space above the article. On smaller screens, Menu now opens a drawer containing section choices and the current section's pages. You can filter the page list, follow a link, or close the drawer to resume reading. On this page stays with the article as a compact disclosure below its introduction. Choosing a heading closes the disclosure and moves focus to that heading. Pages without an outline omit the control. Reach the article sooner The HTML now places the article before the full site navigation. Readers and tools that process HTML in document order can reach the page content without first passing through the entire menu. Desktop styling still places navigation on the left and the outline on the right. Keyboard skip links appear when focused without moving the page layout. The mobile drawer keeps focus inside while open; Escape closes it and returns focus to its launcher. If the navigation filter contains text, the first Escape clears the filter and the next closes the drawer. Resizing preserves access to the focused control. Without JavaScript, Menu remains a link to the navigation below the article, and native disclosures remain usable. Markdown pages and documentation indexes remain available. See navigation configuration for section and sidebar settings.","readerFilters":{},"readerSegments":[{"filters":{},"text":"The October 27 releases improve reading and navigation, add a complete feature-showcase starter, and give agents page types and sizes before they fetch content. The documentation site also gets a refreshed logo and smaller configuration references. Upgrade to CLI 0.1.0-alpha.11 and rebuild your site to receive the framework changes from alpha.9 and alpha.10. Existing navigation configuration continues to work. The logo and reorganized reference are updates to this documentation site. Install from public npm Alpha.11 moves the CLI to the public npm registry. Installation no longer needs an invitation, GitHub package access, or a package token. Follow Getting started for an exact-version install. If you used the earlier private alpha, remove or replace the old @shoalrun registry override and update the manifest and lockfile together. The package README now leads with the showcase. Starter instructions explain how to replace the fictional API and its connected operation bindings. Alpha.11 keeps the site configuration and output contracts from alpha.10. Explore a complete starter Alpha.10 adds a fictional Cedar Parcel handbook with 18 pages. It includes component examples, code walkthroughs, Mermaid and D2 diagrams, reader views, a landing page, a local-workflow cookbook, and generated API references. Explore the starter is the first page in its navigation and maps the working examples. shoalrun init my-handbook --starter showcase cd my-handbook shoalrun build docs.config.yaml site-dist shoalrun serve site-dist The starter builds without provider credentials. Hosted chat, analytics, and remote services need your own configuration. The minimal and api-docs starters remain available. See example projects . Read controls and prose comfortably Alpha.10 increases small reader, code, and API control labels. Ordinary lists use the same reading measure as paragraphs, while tables, code, and file trees retain their available width. Mobile header tools share a row when space permits, and search results fit within the header width. Choose a page before fetching it Compact discovery and navigation indexes now include each page's content type and full-page token count. An agent can compare a short how-to with a longer reference before opening either. The existing 2,000-token limit per compact index still applies; larger catalogs split into linked topic indexes without losing pages. Find configuration settings by topic The configuration reference is now an overview linking to six focused references. The former combined page was about 11,454 tokens; each focused reference is about 1,300–2,600 tokens in the reviewed build. Existing section bookmarks remain available on the overview and link to the new destinations. The site also has a refreshed logo and favicon. The header mark follows the selected theme, with a text fallback in forced-color mode. Keep your place on a phone Alpha.9 brought section links and page navigation into one mobile Menu . Previously, section choices, the page menu, and the outline competed for space above the article. On smaller screens, Menu now opens a drawer containing section choices and the current section's pages. You can filter the page list, follow a link, or close the drawer to resume reading. On this page stays with the article as a compact disclosure below its introduction. Choosing a heading closes the disclosure and moves focus to that heading. Pages without an outline omit the control. Reach the article sooner The HTML now places the article before the full site navigation. Readers and tools that process HTML in document order can reach the page content without first passing through the entire menu. Desktop styling still places navigation on the left and the outline on the right. Keyboard skip links appear when focused without moving the page layout. The mobile drawer keeps focus inside while open; Escape closes it and returns focus to its launcher. If the navigation filter contains text, the first Escape clears the filter and the next closes the drawer. Resizing preserves access to the focused control. Without JavaScript, Menu remains a link to the navigation below the article, and native disclosures remain usable. Markdown pages and documentation indexes remain available. See navigation configuration for section and sidebar settings."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":5717,"markdownTokens":1226,"markdownTokenEncoding":"cl100k_base"},{"id":"change.authoring-preview","demo":false,"url":"/changelog/authoring-preview","markdownUrl":"/changelog/authoring-preview.md","title":"Authoring snapshot previews and review reports","summary":"Snapshot previews with coverage and freshness reports.","type":"changelog-entry","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"}],"text":"This change concerns the private prototype; no package release or deployment is claimed. docs review REPORT presents a validated snapshot as JSON or Markdown. It identifies the task baseline, changed files and dependencies, findings, check coverage, and affected HTML/Markdown artifacts. Baselines contain digests rather than earlier contents; retain the task diff with your existing harness. docs preview REPORT serves a private copy of that exact build on a loopback address. It returns a browser review URL and routes for every affected page that rendered. HTML pages display freshness and a review link. Source edits make the preview stale rather than replacing its content; validate again and restart from the new report. Changed artifacts prevent startup or serving. Ctrl-C or SIGTERM closes the foreground server and removes its serving copy. Validation artifacts remain available separately. Failed or skipped checks retain their actual status while previewing. The tools make no authoring provider calls and do not apply edits, commit, or publish. Snapshot builds preserve captured freshness history. Configured checks can declare sibling files and directories with audit.tests[].inputs ; validation captures those inputs and tracks their changes. Compiler checks do not replace factual or editorial review. Related reading Next steps Check working-tree documentation edits — Validate working-tree edits and open the matching snapshot review. (Status: experimental.) Reference while working Authoring tools commands — Look up review formats, preview lifecycle, statuses, and limits. (Status: experimental.)","readerFilters":{},"readerSegments":[{"filters":{},"text":"This change concerns the private prototype; no package release or deployment is claimed. docs review REPORT presents a validated snapshot as JSON or Markdown. It identifies the task baseline, changed files and dependencies, findings, check coverage, and affected HTML/Markdown artifacts. Baselines contain digests rather than earlier contents; retain the task diff with your existing harness. docs preview REPORT serves a private copy of that exact build on a loopback address. It returns a browser review URL and routes for every affected page that rendered. HTML pages display freshness and a review link. Source edits make the preview stale rather than replacing its content; validate again and restart from the new report. Changed artifacts prevent startup or serving. Ctrl-C or SIGTERM closes the foreground server and removes its serving copy. Validation artifacts remain available separately. Failed or skipped checks retain their actual status while previewing. The tools make no authoring provider calls and do not apply edits, commit, or publish. Snapshot builds preserve captured freshness history. Configured checks can declare sibling files and directories with audit.tests[].inputs ; validation captures those inputs and tracks their changes. Compiler checks do not replace factual or editorial review. Related reading Next steps Reference while working"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Check working-tree documentation edits — Validate working-tree edits and open the matching snapshot review. (Status: experimental.) Authoring tools commands — Look up review formats, preview lifecycle, statuses, and limits. (Status: experimental.)"}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":2609,"markdownTokens":554,"markdownTokenEncoding":"cl100k_base"},{"id":"change.authoring-search","demo":false,"url":"/changelog/authoring-search","markdownUrl":"/changelog/authoring-search.md","title":"Agent authoring, search, and documentation answers","summary":"Reviewed agent drafts, search improvements, and answer context.","type":"changelog-entry","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Prepared for the next prototype release: Agent authoring: Skills, templates, project directives, source context, and checked edit plans help your existing agent draft and update documentation. Writing guidance: Design templates and project writing guides, with a complete example to adapt. Search: Semantic ranking, exact-key assistance, and clearer snippets. Word matching provides fallback results when embeddings fail or exceed the three-second deadline. Ask: Follow-ups keep their topic, and explicit multi-part questions get evidence for each part. Citation and claim checks remain; multi-topic answers are experimental. Related reading Next steps Apply a checked edit plan — Prepare and review a page update with your own model key. (Status: experimental.) Related topics Site search — Configure semantic search and lexical fallback. Check and speed up answers — Understand documentation answer checks and their limits. (Status: experimental.)","readerFilters":{},"readerSegments":[{"filters":{},"text":"Prepared for the next prototype release: Agent authoring: Skills, templates, project directives, source context, and checked edit plans help your existing agent draft and update documentation. Writing guidance: Design templates and project writing guides, with a complete example to adapt. Search: Semantic ranking, exact-key assistance, and clearer snippets. Word matching provides fallback results when embeddings fail or exceed the three-second deadline. Ask: Follow-ups keep their topic, and explicit multi-part questions get evidence for each part. Citation and claim checks remain; multi-topic answers are experimental. Related reading Next steps Related topics"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Apply a checked edit plan — Prepare and review a page update with your own model key. (Status: experimental.)"},{"filters":{"focus":["configure"]},"text":"Site search — Configure semantic search and lexical fallback. Check and speed up answers — Understand documentation answer checks and their limits. (Status: experimental.)"}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":2020,"markdownTokens":469,"markdownTokenEncoding":"cl100k_base"},{"id":"change.authoring-tools","demo":false,"url":"/changelog/authoring-tools","markdownUrl":"/changelog/authoring-tools.md","title":"Working-tree authoring tools","summary":"Project discovery and captured working-tree validation.","type":"changelog-entry","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"}],"text":"This change concerns the private prototype; no package release is claimed. Project-wide discovery and bounded source reads work without selecting a page or configuring an authoring provider. Existing coding agents edit ordinary working-tree files. Baselines record the starting state; validation checks a separate capture and retains findings and build artifacts. Freshness checks detect later source changes. Checked plan/apply commands retain their existing protections. Snapshot preview serving, consolidated review reports, and the portable skill's complete working-tree workflow remain planned. Compiler checks do not replace factual or editorial review. Related reading Next steps Authoring tools for your coding agent — Understand project discovery and snapshot validation for existing agents. (Status: experimental.)","readerFilters":{},"readerSegments":[{"filters":{},"text":"This change concerns the private prototype; no package release is claimed. Project-wide discovery and bounded source reads work without selecting a page or configuring an authoring provider. Existing coding agents edit ordinary working-tree files. Baselines record the starting state; validation checks a separate capture and retains findings and build artifacts. Freshness checks detect later source changes. Checked plan/apply commands retain their existing protections. Snapshot preview serving, consolidated review reports, and the portable skill's complete working-tree workflow remain planned. Compiler checks do not replace factual or editorial review. Related reading Next steps"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Authoring tools for your coding agent — Understand project discovery and snapshot validation for existing agents. (Status: experimental.)"}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":1698,"markdownTokens":381,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.changelog","demo":false,"url":"/changelog","markdownUrl":"/changelog.md","title":"Changelog","summary":"Compiler, CLI, and reader changes.","type":"reference","variant":"production|current|en","area":"project","subarea":"project-releases","headings":[{"id":"latest-changes","title":"Latest changes"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Updates to Shoalrun and its documentation. Each entry identifies the affected versions and any upgrade steps. Earlier entries retain their private-prototype release context. Latest changes 2026-10-27 Version 0.1.0-alpha.11 Clearer defaults, a feature showcase, and easier navigation Explore a complete starter, read clearer controls, and find focused configuration references alongside the new mobile navigation. 2026-10-26 Version 0.1.0-alpha.7 and 0.1.0-alpha.8 Safer exports and easier discovery for AI assistants Keep exported images and links with their pages, and help AI assistants find docs by topic. 2026-10-25 Version 0.1.0-alpha.6 Content exports and documentation checks Content exports and documentation checks. 2026-10-19 Experimental visual navigation and taxonomy enforcement Visual navigation and taxonomy validation. 2026-10-18 Search results and tooltips Indexed search and hover and focus tooltips. 2026-10-17 MCP hosting, analytics, and component improvements MCP hosting, analytics, and shared component content. 2026-10-16 Navigation, page layouts, and browser analytics Navigation sections, reader controls, layouts, and browser analytics. 2026-10-15 Agent reading and evaluation Smaller reads, lifecycle guidance, and reproducible evaluations. 2026-10-14 Agent discovery, verified Markdown, and incremental sync Compact discovery, content verification, and incremental fetching. 2026-10-13 Authoring snapshot previews and review reports Snapshot previews with coverage and freshness reports. 2026-10-13 Working-tree authoring tools Project discovery and captured working-tree validation. 2026-10-13 Portable working-tree authoring workflow Agent discovery, native editing, validation, and snapshot review. 2026-10-03 Agent authoring, search, and documentation answers Reviewed agent drafts, search improvements, and answer context. Related reading Related topics Project status — Check implemented capabilities and the remaining release work. Write release notes and changelog entries — Write dated entries and collect them with the built-in components.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Updates to Shoalrun and its documentation. Each entry identifies the affected versions and any upgrade steps. Earlier entries retain their private-prototype release context. Latest changes 2026-10-27 Version 0.1.0-alpha.11 Clearer defaults, a feature showcase, and easier navigation Explore a complete starter, read clearer controls, and find focused configuration references alongside the new mobile navigation. 2026-10-26 Version 0.1.0-alpha.7 and 0.1.0-alpha.8 Safer exports and easier discovery for AI assistants Keep exported images and links with their pages, and help AI assistants find docs by topic. 2026-10-25 Version 0.1.0-alpha.6 Content exports and documentation checks Content exports and documentation checks. 2026-10-19 Experimental visual navigation and taxonomy enforcement Visual navigation and taxonomy validation. 2026-10-18 Search results and tooltips Indexed search and hover and focus tooltips. 2026-10-17 MCP hosting, analytics, and component improvements MCP hosting, analytics, and shared component content. 2026-10-16 Navigation, page layouts, and browser analytics Navigation sections, reader controls, layouts, and browser analytics. 2026-10-15 Agent reading and evaluation Smaller reads, lifecycle guidance, and reproducible evaluations. 2026-10-14 Agent discovery, verified Markdown, and incremental sync Compact discovery, content verification, and incremental fetching. 2026-10-13 Authoring snapshot previews and review reports Snapshot previews with coverage and freshness reports. 2026-10-13 Working-tree authoring tools Project discovery and captured working-tree validation. 2026-10-13 Portable working-tree authoring workflow Agent discovery, native editing, validation, and snapshot review. 2026-10-03 Agent authoring, search, and documentation answers Reviewed agent drafts, search improvements, and answer context. Related reading Related topics Project status — Check implemented capabilities and the remaining release work."},{"filters":{"focus":["write"]},"text":"Write release notes and changelog entries — Write dated entries and collect them with the built-in components."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":3790,"markdownTokens":1002,"markdownTokenEncoding":"cl100k_base"},{"id":"change.mcp-hosting","demo":false,"url":"/changelog/2026-10-17-mcp-hosting","markdownUrl":"/changelog/2026-10-17-mcp-hosting.md","title":"MCP hosting, analytics, and component improvements","summary":"MCP hosting, analytics, and shared component content.","type":"changelog-entry","variant":"production|current|en","area":"discovery","subarea":"discovery-mcp","headings":[{"id":"serve-documentation-tools-over-http","title":"Serve documentation tools over HTTP"},{"id":"measure-mcp-tool-calls","title":"Measure MCP tool calls"},{"id":"render-mermaid-syntax-with-pele","title":"Render Mermaid syntax with Pele"},{"id":"more-interactive-documentation-components","title":"More interactive documentation components"},{"id":"build-custom-components","title":"Build custom components"}],"text":"This entry groups the October 17 changes to Shoalrun’s private prototype. It does not announce a package release. Serve documentation tools over HTTP Projects can enable an MCP endpoint for one explicitly public publication. It exposes the existing read-only search, page, outline, and section tools through the Node server. The Vercel build can package an independent function without Ask, embeddings, or a model key. Read-only SDK calls have also been verified on this site’s production Vercel endpoint. The endpoint uses a scoped, byte-verified copy of published Markdown and indexes. Search works independently of browser search settings. Host and origin checks, request limits, deadlines, and publication checks apply before serving documentation. Stdio remains available. See connect an MCP client for configuration, limits, and when MCP helps alongside public Markdown. Measure MCP tool calls An optional mcp.analytics.module server adapter receives tool outcomes, duration, build/publication identity, and published page or section IDs. Analytics is off by default. The adapter is separate from browser analytics and runs on the serving host. The PostHog example emits native MCP events and flushes before the HTTP response completes. Separate opt-ins add supported client/model labels, agent intent, and conversation grouping. Labels are unverified. Intent is limited to fixed categories; free text is replaced before delivery. Unknown model labels are omitted. The example excludes raw queries, complete arguments, results, headers, and exception bodies from outbound events. GeoIP enrichment and person profiles are disabled; session grouping remains pseudonymous. See measure MCP tool usage for the adapter contract, privacy limits, and setup steps. Other services can use the same server adapter interface. Render Mermaid syntax with Pele Pele replaces Mermaid CLI for Mermaid-syntax diagrams. Diagram builds no longer launch Chrome, and production package installs no longer include Puppeteer. Browser development tests still use it. Inline diagrams follow the site’s palette and color mode, support per-diagram width caps, and retain source and summaries in Markdown. Use native Pele CSS variables to override the default theme mapping. The Pele gallery shows the built-in families and 48 flowchart shapes. The D2 gallery adds 17 examples covering shapes, containers, sequence diagrams, tables, classes, and layout engines. Both galleries include source examples you can copy. More interactive documentation components File trees now have expandable folders, keyboard navigation, and optional expand-all controls. Collapsible groups keep related disclosures in one compact stack while allowing multiple items to stay open. Tabs can synchronize matching choices across related examples on a page. Images support captions and an optional expanded viewer; width is optional. The viewer supports keyboard dismissal and returns focus to the image link. Markdown retains all tree nodes, disclosure bodies, tab alternatives, image descriptions, and captions. Native disclosures and original-image links remain useful without JavaScript. Build custom components Projects can register trusted custom components from local files or installed packages through one component manifest. Each component implements a required content() function using shared content helpers. Shoalrun renders that content as HTML and Markdown, including links, search content, and section resources. Attribute and child validation report authoring errors during the build. Optional browser modules add interactive controls, including React, with explicit data from the same content function. Shoalrun bundles imports and JSX, publishes browser assets, and tracks dependencies for rebuilds and isolated authoring validation. Shared documentation remains readable without JavaScript. Configured component code is trusted; arbitrary MDX imports and React page rendering remain outside this API. The bundled shoalrun-component-author skill guides agents through the component contract, implementation, and focused validation.","readerFilters":{},"readerSegments":[{"filters":{},"text":"This entry groups the October 17 changes to Shoalrun’s private prototype. It does not announce a package release. Serve documentation tools over HTTP Projects can enable an MCP endpoint for one explicitly public publication. It exposes the existing read-only search, page, outline, and section tools through the Node server. The Vercel build can package an independent function without Ask, embeddings, or a model key. Read-only SDK calls have also been verified on this site’s production Vercel endpoint. The endpoint uses a scoped, byte-verified copy of published Markdown and indexes. Search works independently of browser search settings. Host and origin checks, request limits, deadlines, and publication checks apply before serving documentation. Stdio remains available. See connect an MCP client for configuration, limits, and when MCP helps alongside public Markdown. Measure MCP tool calls An optional mcp.analytics.module server adapter receives tool outcomes, duration, build/publication identity, and published page or section IDs. Analytics is off by default. The adapter is separate from browser analytics and runs on the serving host. The PostHog example emits native MCP events and flushes before the HTTP response completes. Separate opt-ins add supported client/model labels, agent intent, and conversation grouping. Labels are unverified. Intent is limited to fixed categories; free text is replaced before delivery. Unknown model labels are omitted. The example excludes raw queries, complete arguments, results, headers, and exception bodies from outbound events. GeoIP enrichment and person profiles are disabled; session grouping remains pseudonymous. See measure MCP tool usage for the adapter contract, privacy limits, and setup steps. Other services can use the same server adapter interface. Render Mermaid syntax with Pele Pele replaces Mermaid CLI for Mermaid-syntax diagrams. Diagram builds no longer launch Chrome, and production package installs no longer include Puppeteer. Browser development tests still use it. Inline diagrams follow the site’s palette and color mode, support per-diagram width caps, and retain source and summaries in Markdown. Use native Pele CSS variables to override the default theme mapping. The Pele gallery shows the built-in families and 48 flowchart shapes. The D2 gallery adds 17 examples covering shapes, containers, sequence diagrams, tables, classes, and layout engines. Both galleries include source examples you can copy. More interactive documentation components File trees now have expandable folders, keyboard navigation, and optional expand-all controls. Collapsible groups keep related disclosures in one compact stack while allowing multiple items to stay open. Tabs can synchronize matching choices across related examples on a page. Images support captions and an optional expanded viewer; width is optional. The viewer supports keyboard dismissal and returns focus to the image link. Markdown retains all tree nodes, disclosure bodies, tab alternatives, image descriptions, and captions. Native disclosures and original-image links remain useful without JavaScript. Build custom components Projects can register trusted custom components from local files or installed packages through one component manifest. Each component implements a required content() function using shared content helpers. Shoalrun renders that content as HTML and Markdown, including links, search content, and section resources. Attribute and child validation report authoring errors during the build. Optional browser modules add interactive controls, including React, with explicit data from the same content function. Shoalrun bundles imports and JSX, publishes browser assets, and tracks dependencies for rebuilds and isolated authoring validation. Shared documentation remains readable without JavaScript. Configured component code is trusted; arbitrary MDX imports and React page rendering remain outside this API. The bundled shoalrun-component-author skill guides agents through the component contract, implementation, and focused validation."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":5546,"markdownTokens":1148,"markdownTokenEncoding":"cl100k_base"},{"id":"change.navigation-layouts","demo":false,"url":"/changelog/2026-10-16-navigation-layouts","markdownUrl":"/changelog/2026-10-16-navigation-layouts.md","title":"Navigation, page layouts, and browser analytics","summary":"Navigation sections, reader controls, layouts, and browser analytics.","type":"changelog-entry","variant":"production|current|en","area":"appearance","subarea":"appearance-layouts","headings":[{"id":"navigate-between-sections","title":"Navigate between sections"},{"id":"give-readers-more-room","title":"Give readers more room"},{"id":"keep-entry-pages-focused","title":"Keep entry pages focused"},{"id":"measure-browser-interactions","title":"Measure browser interactions"},{"id":"add-contributor-documentation","title":"Add contributor documentation"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"This entry groups the October 16 changes to Shoalrun's private prototype and documentation. It does not announce a package release or a verified deployment. Navigate between sections Top-level navigation groups can now become tabs, each with its own landing page and sidebar. This site uses Docs , Project updates , and Changelog . API documentation and recipes remain in Docs. Tabs use ordinary page links. Direct links select the correct section without a saved browser choice, and navigation works without JavaScript. On smaller screens, a Sections disclosure holds the links. Existing navigation lists continue to work without tabs. Agents receive the same structure through explicit section membership in Markdown, the document manifest, and both search indexes. Each tab has a scoped text index that links to its member pages and back to the global index. The global indexes still list every published page, including shared pages and pages omitted from navigation. The offline agent documentation bundle includes the scoped indexes. See navigation configuration and the published-output contract . Give readers more room Documentation pages keep their table of contents visible at laptop widths. Readers can hide it to widen the article, including paragraphs and code examples, without moving the article's left edge. Restoring the contents restores the original width, and the browser remembers the choice across pages. The navigation uses aligned chevrons, lighter group headings, quieter selection styling, and consistent spacing. Projects can omit group page counts with outputs.html.navigation.showCounts: false ; counts remain visible by default, and filtering works with either setting. Header spacing and title sizing are tighter. The Reef theme keeps equal padding around text and examples, and its Contents control follows the panel's inset. Wide pages retain their wider content area. The reading and navigation changes work across all four themes. Keep entry pages focused Navigation tabs show by default on docs and wide pages and stay hidden on landing and splash pages. Page frontmatter can override that choice with showNavigationTabs: true or false . This site's splash homepage hides the tab bar. Pages led by a Hero omit the page-level Markdown action row. Markdown twins and discovery links remain available. Hiding the tab bar changes only its HTML presentation; section membership and agent indexes remain intact. See page layouts . Measure browser interactions Projects can now connect browser analytics through the top-level analytics.module setting. Shoalrun supplies versioned events for navigation, content tabs, disclosures, clipboard successes, search outcomes, and reader selections. Events include stable page IDs and publication context. Site scripts can emit additional events through the same hook. The browser adapter owns service initialization, consent, and delivery. Analytics is off by default, and disabled builds omit its runtime and adapter. SDK failures do not interrupt the site. Browser instrumentation leaves Markdown and agent discovery unchanged; agent request measurements belong at the host or server. See bring your own analytics . Add contributor documentation Repository contributors now have a separate maintainer guide covering architecture, development, validation, hosting, and release work. It is separate from the public documentation and packaged agent bundle. Related reading Reference while working Organize site navigation — Configure navigation tabs, landing pages, and optional group counts. Publishing and agent representations — Inspect section membership and scoped text indexes for agents. Page layouts, landing pages, and splash pages — Choose a page layout and control whether its tab bar appears. Bring your own analytics — Connect your analytics service to documented browser interaction events. Related topics Project status — Check the alpha's capabilities and current limits.","readerFilters":{},"readerSegments":[{"filters":{},"text":"This entry groups the October 16 changes to Shoalrun's private prototype and documentation. It does not announce a package release or a verified deployment. Navigate between sections Top-level navigation groups can now become tabs, each with its own landing page and sidebar. This site uses Docs , Project updates , and Changelog . API documentation and recipes remain in Docs. Tabs use ordinary page links. Direct links select the correct section without a saved browser choice, and navigation works without JavaScript. On smaller screens, a Sections disclosure holds the links. Existing navigation lists continue to work without tabs. Agents receive the same structure through explicit section membership in Markdown, the document manifest, and both search indexes. Each tab has a scoped text index that links to its member pages and back to the global index. The global indexes still list every published page, including shared pages and pages omitted from navigation. The offline agent documentation bundle includes the scoped indexes. See navigation configuration and the published-output contract . Give readers more room Documentation pages keep their table of contents visible at laptop widths. Readers can hide it to widen the article, including paragraphs and code examples, without moving the article's left edge. Restoring the contents restores the original width, and the browser remembers the choice across pages. The navigation uses aligned chevrons, lighter group headings, quieter selection styling, and consistent spacing. Projects can omit group page counts with outputs.html.navigation.showCounts: false ; counts remain visible by default, and filtering works with either setting. Header spacing and title sizing are tighter. The Reef theme keeps equal padding around text and examples, and its Contents control follows the panel's inset. Wide pages retain their wider content area. The reading and navigation changes work across all four themes. Keep entry pages focused Navigation tabs show by default on docs and wide pages and stay hidden on landing and splash pages. Page frontmatter can override that choice with showNavigationTabs: true or false . This site's splash homepage hides the tab bar. Pages led by a Hero omit the page-level Markdown action row. Markdown twins and discovery links remain available. Hiding the tab bar changes only its HTML presentation; section membership and agent indexes remain intact. See page layouts . Measure browser interactions Projects can now connect browser analytics through the top-level analytics.module setting. Shoalrun supplies versioned events for navigation, content tabs, disclosures, clipboard successes, search outcomes, and reader selections. Events include stable page IDs and publication context. Site scripts can emit additional events through the same hook. The browser adapter owns service initialization, consent, and delivery. Analytics is off by default, and disabled builds omit its runtime and adapter. SDK failures do not interrupt the site. Browser instrumentation leaves Markdown and agent discovery unchanged; agent request measurements belong at the host or server. See bring your own analytics . Add contributor documentation Repository contributors now have a separate maintainer guide covering architecture, development, validation, hosting, and release work. It is separate from the public documentation and packaged agent bundle. Related reading Reference while working Related topics Project status — Check the alpha's capabilities and current limits."},{"filters":{"focus":["write"]},"text":"Organize site navigation — Configure navigation tabs, landing pages, and optional group counts."},{"filters":{"focus":["configure"]},"text":"Publishing and agent representations — Inspect section membership and scoped text indexes for agents. Page layouts, landing pages, and splash pages — Choose a page layout and control whether its tab bar appears. Bring your own analytics — Connect your analytics service to documented browser interaction events."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":5348,"markdownTokens":1095,"markdownTokenEncoding":"cl100k_base"},{"id":"change.search-and-tooltips","demo":false,"url":"/changelog/2026-10-18-search-and-tooltips","markdownUrl":"/changelog/2026-10-18-search-and-tooltips.md","title":"Search results and tooltips","summary":"Indexed search and hover and focus tooltips.","type":"changelog-entry","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"find-useful-search-results","title":"Find useful search results"},{"id":"distinguish-short-definitions-from-tooltips","title":"Distinguish short definitions from tooltips"},{"id":"show-supporting-text-on-hover-or-focus","title":"Show supporting text on hover or focus"}],"text":"These October 18 changes improve search and supporting explanations in Shoalrun’s private prototype. This entry does not announce a package release. Find useful search results Search results now select substantive passages instead of generated related-reading lists or source-only fragments. An exact page-title query opens that page’s introduction. Large galleries no longer crowd other pages out of the search candidates. Explicit identifiers and commands remain searchable in code and tables. Matching pages keep their retrieved order. They open the passage containing the exact match, and the result description shows its code line or table row. The passage index prepares result paragraphs, code lines, and table rows during indexing. Search requests no longer parse the Markdown passages to prepare these results. Preparing this data does not change the embedding input, so unchanged passages reuse their existing vectors. Queries such as “charts” and “graphs” lead to chart and diagram examples with readable descriptions. Searching “diagrams” opens the Diagrams guide . Semantic search retains its keyword fallback when embeddings are unavailable; Ask passage retrieval is unchanged. Distinguish short definitions from tooltips The former Tooltips reference is now Short definitions . <InfoHint> keeps its native click-to-expand disclosure, including keyboard and touch support without JavaScript. <Tooltip> previously named the same disclosure. If you used it for click-to-expand definitions, replace it with <InfoHint> to retain that behavior. Show supporting text on hover or focus The separate Tooltip component now shows brief supporting text when readers hover over or focus its label. It works inline or as a standalone block. Readers can move the pointer onto the popup, dismiss it with Escape, or tap the label to open and close it on touch screens. Without JavaScript, the label and explanation remain visible together. Markdown includes the full label and explanation, so agents can read both without interaction. Keep essential warnings and instructions in visible page content.","readerFilters":{},"readerSegments":[{"filters":{},"text":"These October 18 changes improve search and supporting explanations in Shoalrun’s private prototype. This entry does not announce a package release. Find useful search results Search results now select substantive passages instead of generated related-reading lists or source-only fragments. An exact page-title query opens that page’s introduction. Large galleries no longer crowd other pages out of the search candidates. Explicit identifiers and commands remain searchable in code and tables. Matching pages keep their retrieved order. They open the passage containing the exact match, and the result description shows its code line or table row. The passage index prepares result paragraphs, code lines, and table rows during indexing. Search requests no longer parse the Markdown passages to prepare these results. Preparing this data does not change the embedding input, so unchanged passages reuse their existing vectors. Queries such as “charts” and “graphs” lead to chart and diagram examples with readable descriptions. Searching “diagrams” opens the Diagrams guide . Semantic search retains its keyword fallback when embeddings are unavailable; Ask passage retrieval is unchanged. Distinguish short definitions from tooltips The former Tooltips reference is now Short definitions . <InfoHint> keeps its native click-to-expand disclosure, including keyboard and touch support without JavaScript. <Tooltip> previously named the same disclosure. If you used it for click-to-expand definitions, replace it with <InfoHint> to retain that behavior. Show supporting text on hover or focus The separate Tooltip component now shows brief supporting text when readers hover over or focus its label. It works inline or as a standalone block. Readers can move the pointer onto the popup, dismiss it with Escape, or tap the label to open and close it on touch screens. Without JavaScript, the label and explanation remain visible together. Markdown includes the full label and explanation, so agents can read both without interaction. Keep essential warnings and instructions in visible page content."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":3159,"markdownTokens":671,"markdownTokenEncoding":"cl100k_base"},{"id":"change.visual-navigation","demo":false,"url":"/changelog/2026-10-19-visual-navigation","markdownUrl":"/changelog/2026-10-19-visual-navigation.md","title":"Experimental visual navigation and taxonomy enforcement","summary":"Visual navigation and taxonomy validation.","type":"changelog-entry","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"explore-documentation-visually","title":"Explore documentation visually"},{"id":"classify-pages-explicitly","title":"Classify pages explicitly"},{"id":"continue-improving-the-explorer","title":"Continue improving the explorer"}],"text":"These October 19 changes cover the documentation site's experimental explorer and taxonomy enforcement in CLI 0.1.0-alpha.3 . This entry does not announce a package release or a verified deployment. Explore documentation visually The site's experimental explorer provides five ways to navigate the same documentation: packed circles, expandable branches, connection arcs, a relationship matrix, and a force layout. Filter by declared area, subarea, page type, relationship, or configured reader facets. Demo pages are excluded from the explorer. Views support zoom and pan, with native browser fullscreen where supported. Fullscreen keeps layout controls visible and makes filters and the relationship key available in expandable panels. The matrix distinguishes source rows from destination columns and offers readable sizing alongside the full overview. Relationship arrows show direction. Related topics and comparisons apply in both directions. Line patterns, matrix symbols, labels, and a monochrome option supplement color. The sidebar identifies incoming, outgoing, and two-way relationships, their page endpoints, and why they are connected. Those explanations come from authored reason fields in the relationship configuration. The build publishes them in documents.json ; the explorer makes no model calls and infers no new connections. Related reading documents the authoring and validation rules. The Markdown twin retains the explorer guide and topic links. Agents can read the full page catalog and declared relationships directly from the document manifest. The visualization remains experimental; further sizing, density, interaction, and accessibility improvements are planned. Classify pages explicitly This site's pages now declare areas and subareas rather than deriving subjects from navigation groups. MCP pages belong to Search & discovery. Breadcrumbs belongs to built-in site navigation, while API example and schema components belong to Content components. CLI 0.1.0-alpha.3 adds configurable taxonomy enforcement to the build, including allowed definitions, required fields, explicit authored values, and valid area/subarea pairs. Sites can choose whether to allow multiple areas or subareas on a page; the default permits a single value. These built-in options require CLI 0.1.0-alpha.3 or later. This site enables enforcement through frontmatter.taxonomy . Continue improving the explorer The project update tracks further work on layout sizing, dense views, filtering, relationship presentation, and accessibility.","readerFilters":{},"readerSegments":[{"filters":{},"text":"These October 19 changes cover the documentation site's experimental explorer and taxonomy enforcement in CLI 0.1.0-alpha.3 . This entry does not announce a package release or a verified deployment. Explore documentation visually The site's experimental explorer provides five ways to navigate the same documentation: packed circles, expandable branches, connection arcs, a relationship matrix, and a force layout. Filter by declared area, subarea, page type, relationship, or configured reader facets. Demo pages are excluded from the explorer. Views support zoom and pan, with native browser fullscreen where supported. Fullscreen keeps layout controls visible and makes filters and the relationship key available in expandable panels. The matrix distinguishes source rows from destination columns and offers readable sizing alongside the full overview. Relationship arrows show direction. Related topics and comparisons apply in both directions. Line patterns, matrix symbols, labels, and a monochrome option supplement color. The sidebar identifies incoming, outgoing, and two-way relationships, their page endpoints, and why they are connected. Those explanations come from authored reason fields in the relationship configuration. The build publishes them in documents.json ; the explorer makes no model calls and infers no new connections. Related reading documents the authoring and validation rules. The Markdown twin retains the explorer guide and topic links. Agents can read the full page catalog and declared relationships directly from the document manifest. The visualization remains experimental; further sizing, density, interaction, and accessibility improvements are planned. Classify pages explicitly This site's pages now declare areas and subareas rather than deriving subjects from navigation groups. MCP pages belong to Search & discovery. Breadcrumbs belongs to built-in site navigation, while API example and schema components belong to Content components. CLI 0.1.0-alpha.3 adds configurable taxonomy enforcement to the build, including allowed definitions, required fields, explicit authored values, and valid area/subarea pairs. Sites can choose whether to allow multiple areas or subareas on a page; the default permits a single value. These built-in options require CLI 0.1.0-alpha.3 or later. This site enables enforcement through frontmatter.taxonomy . Continue improving the explorer The project update tracks further work on layout sizing, dense views, filtering, relationship presentation, and accessibility."}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":3624,"markdownTokens":749,"markdownTokenEncoding":"cl100k_base"},{"id":"change.working-tree-skill","demo":false,"url":"/changelog/working-tree-skill","markdownUrl":"/changelog/working-tree-skill.md","title":"Portable working-tree authoring workflow","summary":"Agent discovery, native editing, validation, and snapshot review.","type":"changelog-entry","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"}],"text":"This change concerns the private prototype; no package release or deployment is claimed. The shoalrun-author skill now uses ordinary working-tree edits by default. It guides project discovery, policy and evidence reads, baseline capture, native edits, and required companions. The agent then validates a separate capture and presents its matching HTML/Markdown preview for review. It preserves earlier local edits and keeps task-diff attribution with the harness. Affected drafts render in snapshot validation without changing their access policy. Existing checked plan/apply clients can still choose that workflow explicitly. The authoring guides now distinguish these two paths and remove obsolete instructions to change draft access for a review copy. Give your coding agent the installed skill file and use the public CLI alongside its usual editing tools. No separate authoring service or model configuration is required. Related reading Next steps Use the bundled agent skills — Load the portable authoring skill in your existing coding agent. Reference while working Check working-tree documentation edits — Follow the baseline, validation, and matching-preview procedure. (Status: experimental.)","readerFilters":{},"readerSegments":[{"filters":{},"text":"This change concerns the private prototype; no package release or deployment is claimed. The shoalrun-author skill now uses ordinary working-tree edits by default. It guides project discovery, policy and evidence reads, baseline capture, native edits, and required companions. The agent then validates a separate capture and presents its matching HTML/Markdown preview for review. It preserves earlier local edits and keeps task-diff attribution with the harness. Affected drafts render in snapshot validation without changing their access policy. Existing checked plan/apply clients can still choose that workflow explicitly. The authoring guides now distinguish these two paths and remove obsolete instructions to change draft access for a review copy. Give your coding agent the installed skill file and use the public CLI alongside its usual editing tools. No separate authoring service or model configuration is required. Related reading Next steps Reference while working"},{"filters":{"focus":["write"]},"text":"Use the bundled agent skills — Load the portable authoring skill in your existing coding agent."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Check working-tree documentation edits — Follow the baseline, validation, and matching-preview procedure. (Status: experimental.)"}],"navigationTab":{"id":"changelog-tab","label":"Changelog","variant":{"channel":"production","version":"current","language":"en"},"url":"/changelog","markdownUrl":"/changelog.md","indexUrl":"/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt"},"markdownBytes":2186,"markdownTokens":481,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.chat-checks","demo":false,"url":"/chat/checks","markdownUrl":"/chat/checks.md","title":"Check and speed up answers","summary":"Understand answer checks, direct excerpts, caching, and the limits of each.","type":"explanation","variant":"production|current|en","area":"discovery","subarea":"discovery-chat","headings":[{"id":"how-an-answer-is-checked","title":"How an answer is checked"},{"id":"citations","title":"Citations"},{"id":"code","title":"Code"},{"id":"claims","title":"Claims"},{"id":"answer-without-a-model","title":"Answer without a model"},{"id":"answer-ahead-of-time","title":"Answer ahead of time"},{"id":"reuse-answers","title":"Reuse answers"},{"id":"follow-up-questions","title":"Follow-up questions"},{"id":"recognize-a-standalone-question","title":"Recognize a standalone question"},{"id":"rewrite-a-follow-up-for-search","title":"Rewrite a follow-up for search"},{"id":"questions-with-several-parts","title":"Questions with several parts"},{"id":"answer-for-one-audience","title":"Answer for one audience"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Use this page after local chat setup to understand which checks run, which need a scorer, and when Shoalrun can reuse an answer. The settings reference defines the corresponding fields. Citations and code are checked by default. Coverage gating, claim verification, direct excerpts, cards, and caching need their own configuration. None of these checks proves an answer is correct. How an answer is checked The coverage gate runs before generation. The other checks inspect the generated answer. Check What it catches Needs Gate A question the docs don't cover. The model is never called. rerank: jev and gate Citations A citation to a passage the model wasn't given. Always on Code A command or config that isn't in the passages. Always on Claims A sentence that its cited passage doesn't support. rerank: jev and verify Citations The model sees numbered passages and cites them as [1] , [2] . A citation to a number it wasn't given is removed. The rest are renumbered in order of first appearance, so a reader sees [1] , [2] , [3] . An answer with no citation is flagged. Code A line of code must appear in the passages word for word, or every word in it must appear there. That allows a shorter form of a documented example, such as <Table filter> for <Table filter sticky> . It catches an invented flag, subcommand, or config key, and a glued path such as docs.config.yaml.vercel/output , where the model dropped a space. Some differences are allowed. Sample content in a language that illustrates, such as a Mermaid diagram or plain output, isn't checked. A path or file name that a reader would choose, such as content/my-page.mdx , is accepted even when the docs never use it. Inline code may flatten a nested example. Numbers and comments are ignored. The check can't catch the right words in the wrong order. Claims Jev reads each sentence that carries a citation, together with the passage it cites. It scores from 0 to 1 how well the passage supports the sentence. A sentence with no citation of its own uses the citations on its line. Fenced code, lead-ins that end in a colon, and statements that the docs lack something are skipped, because no passage can support an absence. That covers phrasings such as \"the docs don't specifically describe\", \"no other information is given\", and \"it only shows\". A sentence below verify.threshold is flagged in the notes, or removed when onUnsupported is remove . If removal leaves no supported sentence, the answer becomes \"The documentation does not cover that.\" The check costs one more Jev call for each answer. Start with flagging while you review the results. Choose a threshold using questions and source passages from your own project; scores and useful thresholds vary by scorer. Removing sentences can leave an answer incomplete. The claims check can't catch a wrong sentence that a passage loosely supports, or a passage that is itself wrong. It reads only the passage a sentence cites. Answer without a model For a question answered by one passage, chat.direct can show the source text instead of generating an answer. This avoids a chat-model call, but the excerpt is only as accurate as the documentation behind it. docs.config.yaml chat : rerank : jev direct : { threshold : 0.9 , margin : 0.1 , others : 1 } A passage is shown only when all of these are true: Jev scores the best passage at threshold or higher. At most others other passages score within margin of the best. A broad question has many strong passages and needs a model to combine them. It is a question that stands on its own. A follow-up, which needs the conversation to make sense, always goes to the model. Every other question goes to the model as usual. A passage longer than maxChars (default 1,200) is cut to the block that answers the question. The cut keeps the sentence that introduces a code example, or the example that a sentence introduces. If trimming fails, the whole passage is shown. The answer begins with From the docs and the page and section, and the result's decision is excerpt . --no-direct on ask turns the mode off for one run. A higher threshold , a smaller margin , or fewer allowed others produces fewer excerpts and sends more questions to the model. Test both narrow questions and broad how-to questions; one relevant passage may answer only part of a request. Answer ahead of time Some questions are asked so often that they deserve a reviewed answer. An answer card is generated and reviewed ahead of time, then served without a new chat-model answer. Matching still needs a query embedding and scorer confirmation. A card is used only while the passages behind it are unchanged. See Prepared answers to make them. Reuse answers People ask the same questions. With chat.cache , serve --ask keeps recent answers in memory and returns a stored one when the same question comes back, with no model call. The question is compared after ignoring case, extra spaces, and closing punctuation, and separately for each publication a","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Use this page after local chat setup to understand which checks run, which need a scorer, and when Shoalrun can reuse an answer. The settings reference defines the corresponding fields. Citations and code are checked by default. Coverage gating, claim verification, direct excerpts, cards, and caching need their own configuration. None of these checks proves an answer is correct. How an answer is checked The coverage gate runs before generation. The other checks inspect the generated answer. Check What it catches Needs Gate A question the docs don't cover. The model is never called. rerank: jev and gate Citations A citation to a passage the model wasn't given. Always on Code A command or config that isn't in the passages. Always on Claims A sentence that its cited passage doesn't support. rerank: jev and verify Citations The model sees numbered passages and cites them as [1] , [2] . A citation to a number it wasn't given is removed. The rest are renumbered in order of first appearance, so a reader sees [1] , [2] , [3] . An answer with no citation is flagged. Code A line of code must appear in the passages word for word, or every word in it must appear there. That allows a shorter form of a documented example, such as <Table filter> for <Table filter sticky> . It catches an invented flag, subcommand, or config key, and a glued path such as docs.config.yaml.vercel/output , where the model dropped a space. Some differences are allowed. Sample content in a language that illustrates, such as a Mermaid diagram or plain output, isn't checked. A path or file name that a reader would choose, such as content/my-page.mdx , is accepted even when the docs never use it. Inline code may flatten a nested example. Numbers and comments are ignored. The check can't catch the right words in the wrong order. Claims Jev reads each sentence that carries a citation, together with the passage it cites. It scores from 0 to 1 how well the passage supports the sentence. A sentence with no citation of its own uses the citations on its line. Fenced code, lead-ins that end in a colon, and statements that the docs lack something are skipped, because no passage can support an absence. That covers phrasings such as \"the docs don't specifically describe\", \"no other information is given\", and \"it only shows\". A sentence below verify.threshold is flagged in the notes, or removed when onUnsupported is remove . If removal leaves no supported sentence, the answer becomes \"The documentation does not cover that.\" The check costs one more Jev call for each answer. Start with flagging while you review the results. Choose a threshold using questions and source passages from your own project; scores and useful thresholds vary by scorer. Removing sentences can leave an answer incomplete. The claims check can't catch a wrong sentence that a passage loosely supports, or a passage that is itself wrong. It reads only the passage a sentence cites. Answer without a model For a question answered by one passage, chat.direct can show the source text instead of generating an answer. This avoids a chat-model call, but the excerpt is only as accurate as the documentation behind it. chat: rerank: jev direct: { threshold: 0.9, margin: 0.1, others: 1 } A passage is shown only when all of these are true: Jev scores the best passage at threshold or higher. At most others other passages score within margin of the best. A broad question has many strong passages and needs a model to combine them. It is a question that stands on its own. A follow-up, which needs the conversation to make sense, always goes to the model. Every other question goes to the model as usual. A passage longer than maxChars (default 1,200) is cut to the block that answers the question. The cut keeps the sentence that introduces a code example, or the example that a sentence introduces. If trimming fails, the whole passage is shown. The answer begins with From the docs and the page and section, and the result's decision is excerpt . --no-direct on ask turns the mode off for one run. A higher threshold , a smaller margin , or fewer allowed others produces fewer excerpts and sends more questions to the model. Test both narrow questions and broad how-to questions; one relevant passage may answer only part of a request. Answer ahead of time Some questions are asked so often that they deserve a reviewed answer. An answer card is generated and reviewed ahead of time, then served without a new chat-model answer. Matching still needs a query embedding and scorer confirmation. A card is used only while the passages behind it are unchanged. See Prepared answers to make them. Reuse answers People ask the same questions. With chat.cache , serve --ask keeps recent answers in memory and returns a stored one when the same question comes back, with no model call. The question is compared after ignoring case, extra spaces, and closing punctuation, and separately for each publication and reader view. Only an answer that"},{"filters":{"focus":["configure"]},"text":"Generate and refresh answer cards — Write reviewed answers to common questions so the chat serves them with no model call. (Status: experimental.) Retrieval and chat settings — Look up the settings that turn each check on. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":12373,"markdownTokens":2681,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"how-an-answer-is-checked","title":"How an answer is checked","markdownUrl":"/chat/checks.sections/how-an-answer-is-checked.md","markdownBytes":4541,"markdownTokens":1013},{"id":"answer-without-a-model","title":"Answer without a model","markdownUrl":"/chat/checks.sections/answer-without-a-model.md","markdownBytes":3058,"markdownTokens":730},{"id":"answer-ahead-of-time","title":"Answer ahead of time","markdownUrl":"/chat/checks.sections/answer-ahead-of-time.md","markdownBytes":2040,"markdownTokens":486},{"id":"reuse-answers","title":"Reuse answers","markdownUrl":"/chat/checks.sections/reuse-answers.md","markdownBytes":2648,"markdownTokens":616},{"id":"follow-up-questions","title":"Follow-up questions","markdownUrl":"/chat/checks.sections/follow-up-questions.md","markdownBytes":3300,"markdownTokens":755},{"id":"questions-with-several-parts","title":"Questions with several parts","markdownUrl":"/chat/checks.sections/questions-with-several-parts.md","markdownBytes":3236,"markdownTokens":696},{"id":"answer-for-one-audience","title":"Answer for one audience","markdownUrl":"/chat/checks.sections/answer-for-one-audience.md","markdownBytes":3029,"markdownTokens":720},{"id":"related-reading","title":"Related reading","markdownUrl":"/chat/checks.sections/related-reading.md","markdownBytes":1955,"markdownTokens":472}]},{"id":"reference.chat-config","demo":false,"url":"/chat/settings","markdownUrl":"/chat/settings.md","title":"Retrieval and chat settings","summary":"Look up embedding, chat-model, scoring, and answer-reuse configuration.","type":"reference","variant":"production|current|en","area":"discovery","subarea":"discovery-chat","headings":[{"id":"configure-retrieval","title":"Configure retrieval"},{"id":"configure-chat","title":"Configure chat"},{"id":"optional-layers","title":"Optional layers"},{"id":"send-extra-request-fields","title":"Send extra request fields"},{"id":"choose-the-scorer","title":"Choose the scorer"},{"id":"when-the-scorer-is-down","title":"When the scorer is down"},{"id":"use-more-than-one-model","title":"Use more than one model"},{"id":"fallback","title":"Fallback"},{"id":"escalation","title":"Escalation"},{"id":"related-reading","title":"Related reading"}],"text":"Use this reference to look up fields after choosing a setup. For a working sequence, start with local chat setup . retrieval configures embeddings; chat configures answer generation and optional checks. Both sections are optional. A normal site build validates them without calling these providers. Configure retrieval retrieval.embeddings supplies embeddings for passage indexing, semantic queries, and hosted chat builds. Choose a provider and model when you need meaning-based retrieval. docs.config.yaml retrieval : embeddings : provider : voyage model : voyage-4-large dimension : 1024 queryModel : voyage-4-lite To use OpenAI's embeddings, or a server that copies its API, such as Ollama, vLLM, or a LiteLLM proxy, name the openai provider: docs.config.yaml retrieval : embeddings : provider : openai model : text-embedding-3-small keyEnv : OPENAI_API_KEY Key Meaning provider Required. voyage or openai . model Required. The embedding model ID. dimension The vector size. Voyage accepts 256, 512, 1024, or 2048. Other models need it unless Shoalrun knows the model's size. queryModel The model that embeds queries. It must share an embedding space with model , as the Voyage 4 models do. Without it, queries use model . baseUrl openai only. An OpenAI-style server, such as http://localhost:11434/v1 for Ollama. keyEnv The name of the environment variable that holds the key. It defaults to VOYAGE_API_KEY or OPENAI_API_KEY . The config never holds a key. A key setting fails validation, and keyEnv fails if its value isn't a variable name. Command-line flags on shoalrun index override these settings. See Passage index for the files that --embed writes. Configure chat chat configures the OpenAI-compatible service that writes answers. Choose a provider and model; there is no default model. Start with these fields, then add optional checks or reuse settings as needed. docs.config.yaml chat : provider : openai model : deepseek/deepseek-v4-flash baseUrl : https://openrouter.ai/api/v1 keyEnv : OPENROUTER_API_KEY These fields configure the service and answer limits: Key Meaning provider Required. openai , which covers any OpenAI-style service. model Required. The model ID that your service uses. baseUrl The service's API address. It defaults to https://api.openai.com/v1 . keyEnv The name of the environment variable that holds the key. It defaults to OPENAI_API_KEY . Services on localhost need no key. body Extra fields to send with every request, such as OpenRouter's reasoning . See Send extra request fields . passages How many passages the model sees, from 1 to 20. maxTokens The longest answer the model may write. Reasoning models need a larger value. temperature A number from 0 to 2. Without it, the service's default applies. Optional layers Add these fields to chat when the corresponding capability is needed. Scorer-dependent fields require rerank: jev or an equivalent scorer mapping. Key Meaning readerView Whose questions the chat answers, as reader filter choices. See Answer for one audience . rerank jev reorders the top 24 results with a relevance scorer. It needs JEV_API_KEY . To use a different service, give a mapping instead. See Choose the scorer . gate Needs rerank: jev . decline and hedge are Jev scores from 0 to 1, and decline must be lower. verify Needs rerank: jev . threshold is a Jev score above 0 and below 1. onUnsupported is flag (the default) or remove . See How an answer is checked . direct Needs rerank: jev . Shows a passage word for word instead of calling the model. See Answer without a model . fallback A list of one to five other models to try, in order, when the main one fails. See Use more than one model . escalate A second model to ask when the checks flag an answer, with an optional when list. See Use more than one model . budget Daily caps on questions that reach the model. See Cap the daily spend . challenge A Turnstile check for a hosted chat. See Host the chat on Vercel . log Records questions on a hosted chat. See Host the chat on Vercel . cache Keeps clean answers so a repeated question costs nothing. maxEntries (default 500) and ttlMinutes (default 1,440) set the size and the age. See Reuse answers . cards Needs rerank: jev . Serves answers written ahead of time. threshold (default 0.75) shortlists a card by similarity, and confirm (default 0.9) is the Jev score that must confirm it. See Prepared answers . The gate uses the best passage score: Below decline : return a not-covered response without a chat-model call. Between decline and hedge : generate an answer with a partial-coverage warning. At or above hedge : generate an answer normally. The config never holds a key. A key setting fails validation, and keyEnv fails if its value isn't a variable name. The --model flag on shoalrun ask overrides model , so you can try another model without editing the config. Send extra request fields Some services accept request fields that Shoalrun doesn't know about. chat.body adds them to every request. On Open","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Use this reference to look up fields after choosing a setup. For a working sequence, start with local chat setup . retrieval configures embeddings; chat configures answer generation and optional checks. Both sections are optional. A normal site build validates them without calling these providers. Configure retrieval retrieval.embeddings supplies embeddings for passage indexing, semantic queries, and hosted chat builds. Choose a provider and model when you need meaning-based retrieval. retrieval: embeddings: provider: voyage model: voyage-4-large dimension: 1024 queryModel: voyage-4-lite To use OpenAI's embeddings, or a server that copies its API, such as Ollama, vLLM, or a LiteLLM proxy, name the openai provider: retrieval: embeddings: provider: openai model: text-embedding-3-small keyEnv: OPENAI_API_KEY Key Meaning provider Required. voyage or openai . model Required. The embedding model ID. dimension The vector size. Voyage accepts 256, 512, 1024, or 2048. Other models need it unless Shoalrun knows the model's size. queryModel The model that embeds queries. It must share an embedding space with model , as the Voyage 4 models do. Without it, queries use model . baseUrl openai only. An OpenAI-style server, such as http://localhost:11434/v1 for Ollama. keyEnv The name of the environment variable that holds the key. It defaults to VOYAGE_API_KEY or OPENAI_API_KEY . The config never holds a key. A key setting fails validation, and keyEnv fails if its value isn't a variable name. Command-line flags on shoalrun index override these settings. See Passage index for the files that --embed writes. Configure chat chat configures the OpenAI-compatible service that writes answers. Choose a provider and model; there is no default model. Start with these fields, then add optional checks or reuse settings as needed. chat: provider: openai model: deepseek/deepseek-v4-flash baseUrl: https://openrouter.ai/api/v1 keyEnv: OPENROUTER_API_KEY These fields configure the service and answer limits: Key Meaning provider Required. openai , which covers any OpenAI-style service. model Required. The model ID that your service uses. baseUrl The service's API address. It defaults to https://api.openai.com/v1 . keyEnv The name of the environment variable that holds the key. It defaults to OPENAI_API_KEY . Services on localhost need no key. body Extra fields to send with every request, such as OpenRouter's reasoning . See Send extra request fields . passages How many passages the model sees, from 1 to 20. maxTokens The longest answer the model may write. Reasoning models need a larger value. temperature A number from 0 to 2. Without it, the service's default applies. Optional layers Add these fields to chat when the corresponding capability is needed. Scorer-dependent fields require rerank: jev or an equivalent scorer mapping. Key Meaning readerView Whose questions the chat answers, as reader filter choices. See Answer for one audience . rerank jev reorders the top 24 results with a relevance scorer. It needs JEV_API_KEY . To use a different service, give a mapping instead. See Choose the scorer . gate Needs rerank: jev . decline and hedge are Jev scores from 0 to 1, and decline must be lower. verify Needs rerank: jev . threshold is a Jev score above 0 and below 1. onUnsupported is flag (the default) or remove . See How an answer is checked . direct Needs rerank: jev . Shows a passage word for word instead of calling the model. See Answer without a model . fallback A list of one to five other models to try, in order, when the main one fails. See Use more than one model . escalate A second model to ask when the checks flag an answer, with an optional when list. See Use more than one model . budget Daily caps on questions that reach the model. See Cap the daily spend . challenge A Turnstile check for a hosted chat. See Host the chat on Vercel . log Records questions on a hosted chat. See Host the chat on Vercel . cache Keeps clean answers so a repeated question costs nothing. maxEntries (default 500) and ttlMinutes (default 1,440) set the size and the age. See Reuse answers . cards Needs rerank: jev . Serves answers written ahead of time. threshold (default 0.75) shortlists a card by similarity, and confirm (default 0.9) is the Jev score that must confirm it. See Prepared answers . The gate uses the best passage score: Below decline : return a not-covered response without a chat-model call. Between decline and hedge : generate an answer with a partial-coverage warning. At or above hedge : generate an answer normally. The config never holds a key. A key setting fails validation, and keyEnv fails if its value isn't a variable name. The --model flag on shoalrun ask overrides model , so you can try another model without editing the config. Send extra request fields Some services accept request fields that Shoalrun doesn't know about. chat.body adds them to every request. On OpenRouter, the useful ones are reasoning , which controls whether a mo"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":17353,"markdownTokens":3448,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"configure-retrieval","title":"Configure retrieval","markdownUrl":"/chat/settings.sections/configure-retrieval.md","markdownBytes":3396,"markdownTokens":750},{"id":"configure-chat","title":"Configure chat","markdownUrl":"/chat/settings.sections/configure-chat.md","markdownBytes":8212,"markdownTokens":1471},{"id":"send-extra-request-fields","title":"Send extra request fields","markdownUrl":"/chat/settings.sections/send-extra-request-fields.md","markdownBytes":2369,"markdownTokens":569},{"id":"choose-the-scorer","title":"Choose the scorer","markdownUrl":"/chat/settings.sections/choose-the-scorer.md","markdownBytes":4000,"markdownTokens":852},{"id":"when-the-scorer-is-down","title":"When the scorer is down","markdownUrl":"/chat/settings.sections/when-the-scorer-is-down.md","markdownBytes":2307,"markdownTokens":551},{"id":"use-more-than-one-model","title":"Use more than one model","markdownUrl":"/chat/settings.sections/use-more-than-one-model.md","markdownBytes":3569,"markdownTokens":839},{"id":"related-reading","title":"Related reading","markdownUrl":"/chat/settings.sections/related-reading.md","markdownBytes":1260,"markdownTokens":312}]},{"id":"reference.cli","demo":false,"url":"/cli","markdownUrl":"/cli.md","title":"CLI reference","summary":"Commands, arguments, defaults, output, and errors.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-command-line","headings":[{"id":"start-a-project","title":"Start a project"},{"id":"init","title":"init"},{"id":"build-and-serve","title":"Build and serve"},{"id":"build","title":"build"},{"id":"export","title":"export"},{"id":"docs-changes","title":"docs changes"},{"id":"serve","title":"serve"},{"id":"dev","title":"dev"},{"id":"search","title":"search"},{"id":"docs-search-and-docs-read","title":"docs search and docs read"},{"id":"docs-mcp","title":"docs mcp"},{"id":"eval-prepare-eval-check-eval-snapshot-and-eval-compare","title":"eval prepare , eval check , eval snapshot , and eval compare"},{"id":"vercel-build","title":"vercel build"},{"id":"author-pages","title":"Author pages"},{"id":"scaffold","title":"scaffold"},{"id":"docs-context-docs-plan-and-docs-apply","title":"docs context , docs plan , and docs apply"},{"id":"ingredient-draft-and-recipe-draft","title":"ingredient draft and recipe draft"},{"id":"inspect-config-and-operations","title":"Inspect config and operations"},{"id":"audit-a-project-and-api-sources","title":"Audit a project and API sources"},{"id":"check","title":"check"},{"id":"audit","title":"audit"},{"id":"api-audit","title":"api audit"},{"id":"api-import-and-api-refresh","title":"api import and api refresh"},{"id":"api-focused-audit","title":"api focused-audit"},{"id":"api-review","title":"api review"},{"id":"api-materialize","title":"api materialize"},{"id":"api-select","title":"api select"},{"id":"npm-scripts-in-this-repository","title":"npm scripts in this repository"},{"id":"search-and-chat","title":"Search and chat"},{"id":"index","title":"index"},{"id":"serve-search","title":"serve --search"},{"id":"ask","title":"ask"},{"id":"answers","title":"answers"},{"id":"ask-log","title":"ask-log"},{"id":"chat","title":"chat"},{"id":"serve-ask","title":"serve --ask"},{"id":"working-tree-authoring-tools","title":"Working-tree authoring tools"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"The public @shoalrun/cli package supplies the shoalrun command. It needs Node.js 22.12 or newer. Follow Getting started to install it from npm, then run commands as npx --no-install shoalrun <command> . Framework contributors can build the source checkout and run node framework/dist/cli.js <command> from its root. Commands that return data print JSON to standard output. On an error, the CLI prints {\"status\":\"error\",\"message\":\"...\"} to standard error and exits with code 1. A config argument defaults to docs.config.yaml in the current directory unless noted. Diagrams render without a browser: Pele handles Mermaid syntax, and D2 handles D2 source. Development installs include Puppeteer for browser UI tests; production package installs do not need it. Start a project init shoalrun init [directory] [--starter minimal | api-docs | showcase] Copies a bundled starter into directory (default . ). minimal is the default; api-docs includes the fictional Cedar Parcel API, an overview and quickstart, a local OpenAPI file, generated references, search, and a color-mode toggle. The showcase starter adds a component handbook, diagrams, code walkthroughs, reader views, a landing page, and a local-workflow cookbook to that API example. All three build without provider credentials. The API and showcase README files explain customization. Existing unrelated files stay in place, but any destination file collision stops the command before it copies anything. Existing destination directories must be real directories, not symlinks or files. The command prints JSON with the starter, absolute directory, copied files, and the next validate and build commands. Run those commands from the created directory, then replace fixture content and example domains. init does not install packages or deploy the site. Build and serve build shoalrun build [config] [output] [--source-commit SHA] [--release-label LABEL] Compiles the site. output defaults to site-dist . Prints { \"status\": \"ok\", \"documents\": <count>, \"operations\": <count> } . The build writes to a temporary directory, then deletes output and replaces it . Don't point it at a directory with other files. The build stops before deleting anything if output contains the project or content directory, sits inside the content directory, or holds a file the build reads. It also writes the frontmatter reference to .shoalrun/ beside the config; add .shoalrun/ to .gitignore . Every build writes /build-info.json with the build ID and resolved config digest. --source-commit adds a full 40- or 64-character Git commit hash; --release-label adds a short, public release name. The command uses only the values you pass. Neither flag selects a publication or deployment destination. See use Git branches for separate docs sites . export shoalrun export [config] --out DIRECTORY [--target NAME] [--format markdown | html | both] [--document ID] ... [--channel C --version V --language L] [--public-base /help/] [--review] Exports whole public pages from source as resolved Markdown and passive HTML fragments, with a versioned manifest, referenced assets, and notices. No navigation, facets, website theme, or prior website build is required. --out is required. Without --target , the command exports all eligible pages in one enabled publication; select all three publication coordinates when more than one is enabled. --document can be repeated. Command options override the named target's formats, document selection, publication, and public base. Named targets live under exports in the project config. Their optional page-facet filter is independent of site.contentFilter and navigation. Public access, enabled publication, and language still determine eligibility. Invalid selections and missing link or asset dependencies fail before a previous export is replaced. An unrelated nonempty destination or a source directory cannot be replaced. The command prints JSON with status, absolute output directory, publication, formats, document count and IDs, asset count, bundle digest, API review digests, and diagnostics. --review can write a candidate with status: needs-review and exit code 2. Pin the reviewed digests and repeat the normal command before distributing it. See export content into an application for target fields, output contracts, and the help-drawer example. docs changes shoalrun docs changes CURRENT-SNAPSHOT --since PREVIOUS-SNAPSHOT Compares two local documents.sync.json files and prints JSON with build IDs, buildChanged , metadataChanged , and added , changed , and removed page records. Page identity includes its publication variant. The command validates both snapshots and rejects unsupported schema versions, invalid records, and duplicate identities. It reads files only; it does not fetch pages or modify a cache. Keep saved snapshots outside the replaced build directory. See incremental sync . serve shoalrun serve < site-director y > [--host HOST] [--port PORT] Serves a built site. --hos","readerFilters":{},"readerSegments":[{"filters":{},"text":"The public @shoalrun/cli package supplies the shoalrun command. It needs Node.js 22.12 or newer. Follow Getting started to install it from npm, then run commands as npx --no-install shoalrun <command> . Framework contributors can build the source checkout and run node framework/dist/cli.js <command> from its root. Commands that return data print JSON to standard output. On an error, the CLI prints {\"status\":\"error\",\"message\":\"...\"} to standard error and exits with code 1. A config argument defaults to docs.config.yaml in the current directory unless noted. Diagrams render without a browser: Pele handles Mermaid syntax, and D2 handles D2 source. Development installs include Puppeteer for browser UI tests; production package installs do not need it. Start a project init shoalrun init [directory] [--starter minimal|api-docs|showcase] Copies a bundled starter into directory (default . ). minimal is the default; api-docs includes the fictional Cedar Parcel API, an overview and quickstart, a local OpenAPI file, generated references, search, and a color-mode toggle. The showcase starter adds a component handbook, diagrams, code walkthroughs, reader views, a landing page, and a local-workflow cookbook to that API example. All three build without provider credentials. The API and showcase README files explain customization. Existing unrelated files stay in place, but any destination file collision stops the command before it copies anything. Existing destination directories must be real directories, not symlinks or files. The command prints JSON with the starter, absolute directory, copied files, and the next validate and build commands. Run those commands from the created directory, then replace fixture content and example domains. init does not install packages or deploy the site. Build and serve build shoalrun build [config] [output] [--source-commit SHA] [--release-label LABEL] Compiles the site. output defaults to site-dist . Prints { \"status\": \"ok\", \"documents\": <count>, \"operations\": <count> } . The build writes to a temporary directory, then deletes output and replaces it . Don't point it at a directory with other files. The build stops before deleting anything if output contains the project or content directory, sits inside the content directory, or holds a file the build reads. It also writes the frontmatter reference to .shoalrun/ beside the config; add .shoalrun/ to .gitignore . Every build writes /build-info.json with the build ID and resolved config digest. --source-commit adds a full 40- or 64-character Git commit hash; --release-label adds a short, public release name. The command uses only the values you pass. Neither flag selects a publication or deployment destination. See use Git branches for separate docs sites . export shoalrun export [config] --out DIRECTORY [--target NAME] [--format markdown|html|both] [--document ID]... [--channel C --version V --language L] [--public-base /help/] [--review] Exports whole public pages from source as resolved Markdown and passive HTML fragments, with a versioned manifest, referenced assets, and notices. No navigation, facets, website theme, or prior website build is required. --out is required. Without --target , the command exports all eligible pages in one enabled publication; select all three publication coordinates when more than one is enabled. --document can be repeated. Command options override the named target's formats, document selection, publication, and public base. Named targets live under exports in the project config. Their optional page-facet filter is independent of site.contentFilter and navigation. Public access, enabled publication, and language still determine eligibility. Invalid selections and missing link or asset dependencies fail before a previous export is replaced. An unrelated nonempty destination or a source directory cannot be replaced. The command prints JSON with status, absolute output directory, publication, formats, document count and IDs, asset count, bundle digest, API review digests, and diagnostics. --review can write a candidate with status: needs-review and exit code 2. Pin the reviewed digests and repeat the normal command before distributing it. See export content into an application for target fields, output contracts, and the help-drawer example. docs changes shoalrun docs changes CURRENT-SNAPSHOT --since PREVIOUS-SNAPSHOT Compares two local documents.sync.json files and prints JSON with build IDs, buildChanged , metadataChanged , and added , changed , and removed page records. Page identity includes its publication variant. The command validates both snapshots and rejects unsupported schema versions, invalid records, and duplicate identities. It reads files only; it does not fetch pages or modify a cache. Keep saved snapshots outside the replaced build directory. See incremental sync . serve shoalrun serve <site-directory> [--host HOST] [--port PORT] Serves a built site. --host defaults to 127.0.0.1 . The port co"},{"filters":{"focus":["configure"]},"text":"Configuration reference — Build, serve, and inspect a config from the command line."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":40288,"markdownTokens":8648,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"start-a-project","title":"Start a project","markdownUrl":"/cli.sections/start-a-project.md","markdownBytes":2659,"markdownTokens":634},{"id":"build-and-serve","title":"Build and serve","markdownUrl":"/cli.sections/build-and-serve.md","markdownBytes":11363,"markdownTokens":2664},{"id":"author-pages","title":"Author pages","markdownUrl":"/cli.sections/author-pages.md","markdownBytes":7236,"markdownTokens":1565},{"id":"inspect-config-and-operations","title":"Inspect config and operations","markdownUrl":"/cli.sections/inspect-config-and-operations.md","markdownBytes":3968,"markdownTokens":724},{"id":"audit-a-project-and-api-sources","title":"Audit a project and API sources","markdownUrl":"/cli.sections/audit-a-project-and-api-sources.md","markdownBytes":6598,"markdownTokens":1567},{"id":"npm-scripts-in-this-repository","title":"npm scripts in this repository","markdownUrl":"/cli.sections/npm-scripts-in-this-repository.md","markdownBytes":3982,"markdownTokens":842},{"id":"search-and-chat","title":"Search and chat","markdownUrl":"/cli.sections/search-and-chat.md","markdownBytes":12739,"markdownTokens":2867},{"id":"working-tree-authoring-tools","title":"Working-tree authoring tools","markdownUrl":"/cli.sections/working-tree-authoring-tools.md","markdownBytes":2697,"markdownTokens":631},{"id":"related-reading","title":"Related reading","markdownUrl":"/cli.sections/related-reading.md","markdownBytes":1745,"markdownTokens":447}]},{"id":"guide.coding-agent-authoring","demo":false,"url":"/author/coding-agent","markdownUrl":"/author/coding-agent.md","title":"Use your coding agent","summary":"Give your agent project guidance and draft a new documentation page.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-agent-workflows","headings":[{"id":"prepare-your-agent","title":"Prepare your agent"},{"id":"give-a-working-tree-task","title":"Give a working-tree task"},{"id":"draft-a-new-page","title":"Draft a new page"},{"id":"define-the-reader-s-task","title":"Define the reader's task"},{"id":"choose-and-scaffold-a-template","title":"Choose and scaffold a template"},{"id":"check-and-review-the-page","title":"Check and review the page"},{"id":"prepare-publication","title":"Prepare publication"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use an agent that can read project files and run commands. It writes with its own model; Shoalrun requires no additional authoring API key. Prepare your agent Install the portable authoring skill using your agent's supported skill setup. If it cannot load skills, give it the same project instructions and commands directly. Tell it where to find docs.config.yaml , your writing guide, and reviewed examples. The example writing guide is a starting point you can adapt. The CLI's docs search and docs read commands read bundled Shoalrun guidance. The MCP server offers documentation search and reads for agents that support MCP; it does not write project files. Your agent uses its own file tools and the CLI for edits. Give a working-tree task Name the reader outcome and documentation project. Let the agent discover the relevant pages and required supporting changes from project policy. For example: Read the installed shoalrun-author/SKILL.md and work in this documentation project. Revise the authoring procedure so readers can write titled steps and inspect both outputs. Read project policy and supporting evidence first, preserve earlier local edits, capture a task baseline, edit files normally, and show the matching validation report, preview, and task diff. Do not commit or publish. This uses the harness's own writer and execution permissions. Required navigation, relationships, and changelog entries come from the project instructions rather than an automatic compiler rule. If evidence is missing or policies conflict, the agent should identify the question for review. Draft a new page Define the reader's task Give your agent the audience, goal, intended page type, and supporting sources. Let it gather and evaluate evidence using its own tools. Ask it to identify missing facts rather than invent examples or behavior. Choose and scaffold a template Use the project's templates . Record the starting state before scaffolding: shoalrun docs baseline --out .shoalrun/task-baseline.json --config docs.config.yaml shoalrun scaffold how-to -n content/publish-a-site.mdx --config docs.config.yaml The new file is a draft. Replace the prompts, preserve its identity and publication metadata, and add required companions from project policy. Check and review the page Run the project's style checker and configured checks. Read the draft, verify its examples, and review technical claims against the evidence. shoalrun docs validate --baseline .shoalrun/task-baseline.json --config docs.config.yaml shoalrun docs review /path/from/result/report.json --format markdown shoalrun docs preview /path/from/result/report.json --port 0 Use the actual report path returned by validation. It renders affected drafts in a separate capture while preserving their authored access policy. Review findings, coverage, and skipped checks; use --run-checks only for applicable trusted commands under the harness's permissions. A stale, failed, incomplete, or unavailable result is not a pass. After edits, revalidate and restart the preview from the new report. Stop the foreground preview with Ctrl-C when finished. Prepare publication After the author approves publication, change the page's access policy to public and build to a dedicated output directory. Inspect its HTML, Markdown, navigation, and links before committing or deploying. shoalrun build docs.config.yaml preview-output Related reading Related topics Write with agents — Choose the authoring workflow that fits how you work. Use the bundled agent skills — Give your coding agent the bundled Shoalrun workflow instructions. Apply a checked edit plan — Prepare a checked edit to an existing page. (Status: experimental.)","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"Use an agent that can read project files and run commands. It writes with its own model; Shoalrun requires no additional authoring API key. Prepare your agent Install the portable authoring skill using your agent's supported skill setup. If it cannot load skills, give it the same project instructions and commands directly. Tell it where to find docs.config.yaml , your writing guide, and reviewed examples. The example writing guide is a starting point you can adapt. The CLI's docs search and docs read commands read bundled Shoalrun guidance. The MCP server offers documentation search and reads for agents that support MCP; it does not write project files. Your agent uses its own file tools and the CLI for edits. Give a working-tree task Name the reader outcome and documentation project. Let the agent discover the relevant pages and required supporting changes from project policy. For example: Read the installed shoalrun-author/SKILL.md and work in this documentation project. Revise the authoring procedure so readers can write titled steps and inspect both outputs. Read project policy and supporting evidence first, preserve earlier local edits, capture a task baseline, edit files normally, and show the matching validation report, preview, and task diff. Do not commit or publish. This uses the harness's own writer and execution permissions. Required navigation, relationships, and changelog entries come from the project instructions rather than an automatic compiler rule. If evidence is missing or policies conflict, the agent should identify the question for review. Draft a new page Define the reader's task Give your agent the audience, goal, intended page type, and supporting sources. Let it gather and evaluate evidence using its own tools. Ask it to identify missing facts rather than invent examples or behavior. Choose and scaffold a template Use the project's templates . Record the starting state before scaffolding: shoalrun docs baseline --out .shoalrun/task-baseline.json --config docs.config.yaml shoalrun scaffold how-to -n content/publish-a-site.mdx --config docs.config.yaml The new file is a draft. Replace the prompts, preserve its identity and publication metadata, and add required companions from project policy. Check and review the page Run the project's style checker and configured checks. Read the draft, verify its examples, and review technical claims against the evidence. shoalrun docs validate --baseline .shoalrun/task-baseline.json --config docs.config.yaml shoalrun docs review /path/from/result/report.json --format markdown shoalrun docs preview /path/from/result/report.json --port 0 Use the actual report path returned by validation. It renders affected drafts in a separate capture while preserving their authored access policy. Review findings, coverage, and skipped checks; use --run-checks only for applicable trusted commands under the harness's permissions. A stale, failed, incomplete, or unavailable result is not a pass. After edits, revalidate and restart the preview from the new report. Stop the foreground preview with Ctrl-C when finished. Prepare publication After the author approves publication, change the page's access policy to public and build to a dedicated output directory. Inspect its HTML, Markdown, navigation, and links before committing or deploying. shoalrun build docs.config.yaml preview-output Related reading Related topics"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Write with agents — Choose the authoring workflow that fits how you work. Apply a checked edit plan — Prepare a checked edit to an existing page. (Status: experimental.)"},{"filters":{"focus":["write"]},"text":"Use the bundled agent skills — Give your coding agent the bundled Shoalrun workflow instructions."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5012,"markdownTokens":1130,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.color-modes","demo":false,"url":"/styling/color-modes","markdownUrl":"/styling/color-modes.md","title":"Light and dark mode","summary":"Light, dark, and system modes, toggle behavior, storage, and accessibility.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-themes","headings":[{"id":"lock-the-site-to-one-mode","title":"Lock the site to one mode"},{"id":"follow-the-reader-s-setting","title":"Follow the reader's setting"},{"id":"how-it-works","title":"How it works"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Every palette has a light set and a dark set. theme.mode decides which set readers see. Mode Behavior light The default. Readers always see light mode. dark Readers always see dark mode. system Follows the reader's operating system setting. Shows a toggle unless you turn it off. Lock the site to one mode docs.config.yaml theme : mode : dark A locked site writes only the colors for that mode and shows no toggle. The build checks contrast for that mode only. Follow the reader's setting docs.config.yaml theme : mode : system The site starts in the mode the reader's system prefers. A button in the masthead switches between light and dark. The browser stores the choice under the shoalrun-color-mode local storage key on that device, and the choice overrides the system setting. To follow the system setting without a toggle, set toggle: false : docs.config.yaml theme : mode : system toggle : false toggle: true works only with mode: system . The build checks contrast for both modes. Custom callout tones need dark colors before a site can show dark mode. The callout guide explains the dark block. How it works mode: system writes both color sets to /assets/palette.css . The dark set applies inside @media (prefers-color-scheme: dark) . The page sets <meta name=\"color-scheme\"> to light , dark , or light dark , so scrollbars and form controls match. With the toggle on, /assets/mode.js loads in the page head before first paint. It reads the saved choice and sets data-mode=\"light\" or data-mode=\"dark\" on the html element, so the page doesn't flash the wrong colors. The toggle is a button with aria-pressed . Screen readers announce it as \"Dark mode\", pressed or not pressed. Without JavaScript, the toggle stays hidden and the system setting still applies. If the browser blocks storage, the toggle still works for the current page. Target a mode in project CSS with [data-mode=\"dark\"] , or with prefers-color-scheme for readers who have not used the toggle: styles/project.css @media (prefers-color-scheme : dark) { :root:not ([ data-mode = \"light\" ]) .doc-card-icon { opacity : .9 ; } } :root [ data-mode = \"dark\" ] .doc-card-icon { opacity : .9 ; } Code blocks stay dark in both modes. By default, their syntax colors come from the palette's dark set. The code block guide explains how to change it. Related reading Related topics Header links — The dark mode toggle appears in the header beside your links. Color palettes — A palette has one color set for light mode and one for dark mode.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Every palette has a light set and a dark set. theme.mode decides which set readers see. Mode Behavior light The default. Readers always see light mode. dark Readers always see dark mode. system Follows the reader's operating system setting. Shows a toggle unless you turn it off. Lock the site to one mode theme: mode: dark A locked site writes only the colors for that mode and shows no toggle. The build checks contrast for that mode only. Follow the reader's setting theme: mode: system The site starts in the mode the reader's system prefers. A button in the masthead switches between light and dark. The browser stores the choice under the shoalrun-color-mode local storage key on that device, and the choice overrides the system setting. To follow the system setting without a toggle, set toggle: false : theme: mode: system toggle: false toggle: true works only with mode: system . The build checks contrast for both modes. Custom callout tones need dark colors before a site can show dark mode. The callout guide explains the dark block. How it works mode: system writes both color sets to /assets/palette.css . The dark set applies inside @media (prefers-color-scheme: dark) . The page sets <meta name=\"color-scheme\"> to light , dark , or light dark , so scrollbars and form controls match. With the toggle on, /assets/mode.js loads in the page head before first paint. It reads the saved choice and sets data-mode=\"light\" or data-mode=\"dark\" on the html element, so the page doesn't flash the wrong colors. The toggle is a button with aria-pressed . Screen readers announce it as \"Dark mode\", pressed or not pressed. Without JavaScript, the toggle stays hidden and the system setting still applies. If the browser blocks storage, the toggle still works for the current page. Target a mode in project CSS with [data-mode=\"dark\"] , or with prefers-color-scheme for readers who have not used the toggle: @media (prefers-color-scheme: dark) { :root:not([data-mode=\"light\"]) .doc-card-icon { opacity: .9; } } :root[data-mode=\"dark\"] .doc-card-icon { opacity: .9; } Code blocks stay dark in both modes. By default, their syntax colors come from the palette's dark set. The code block guide explains how to change it. Related reading Related topics"},{"filters":{"focus":["configure"]},"text":"Header links — The dark mode toggle appears in the header beside your links. Color palettes — A palette has one color set for light mode and one for dark mode."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3960,"markdownTokens":952,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.action-link","demo":false,"url":"/author/components/action-link","markdownUrl":"/author/components/action-link.md","title":"Action links","summary":"Give a next step a prominent link style while retaining real navigation semantics.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-navigation","headings":[{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"<ActionLink> styles a navigation link as a prominent action. <Button> is an alias for authors migrating button-like links. Both render a real <a> element, so they work with keyboard navigation and without JavaScript. < ActionLink doc = \"guide.add-page\" >Create a page</ ActionLink > < ActionLink href = \"https://example.com/download\" variant = \"secondary\" >Download example</ ActionLink > Create a page Download example Attribute Required Meaning doc or href Yes, one A stable document ID, site path, fragment, HTTP(S) URL, or mailto: link. variant No primary (default) or secondary . The body is nonempty inline text, with optional emphasis or inline code. HTML, Markdown, and agents HTML renders a real link with a visible focus state. Markdown retains its label and destination, resolving doc IDs to the target Markdown page. An agent can follow the destination without interpreting the visual button style.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<ActionLink> styles a navigation link as a prominent action. <Button> is an alias for authors migrating button-like links. Both render a real <a> element, so they work with keyboard navigation and without JavaScript. <ActionLink doc=\"guide.add-page\">Create a page</ActionLink> <ActionLink href=\"https://example.com/download\" variant=\"secondary\">Download example</ActionLink> Create a page Download example Attribute Required Meaning doc or href Yes, one A stable document ID, site path, fragment, HTTP(S) URL, or mailto: link. variant No primary (default) or secondary . The body is nonempty inline text, with optional emphasis or inline code. HTML, Markdown, and agents HTML renders a real link with a visible focus state. Markdown retains its label and destination, resolving doc IDs to the target Markdown page. An agent can follow the destination without interpreting the visual button style."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2033,"markdownTokens":457,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.api-embeds","demo":false,"url":"/author/components/api-embeds","markdownUrl":"/author/components/api-embeds.md","title":"ApiExample and ApiSchema","summary":"Include named OpenAPI examples and selected schemas in authored pages.","type":"reference","variant":"production|current|en","area":["components","api"],"subarea":["components-api","api-contracts"],"headings":[{"id":"apiexample","title":"ApiExample"},{"id":"syntax","title":"Syntax"},{"id":"created-release-note","title":"Created release note"},{"id":"markdown-twin","title":"Markdown twin"},{"id":"apischema","title":"ApiSchema"},{"id":"syntax-2","title":"Syntax"},{"id":"schema-notemetadata","title":"Schema · NoteMetadata"},{"id":"field-source","title":"Field · source"},{"id":"response-201-schema-application-json","title":"Response 201 schema · application/json"},{"id":"markdown-twin-2","title":"Markdown twin"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"related-topics","title":"Related topics"}],"text":"ApiExample and ApiSchema reuse OpenAPI content in authored pages. Examples stay synchronized with named payloads; schemas expose selected field definitions in HTML and Markdown. ApiExample <ApiExample> copies a named example from the OpenAPI source bound to a stable operation ID. Use it in a guide when the full payload should stay synchronized with the reference. Syntax < ApiExample operation = \"notes.create\" kind = \"response\" status = \"201\" mediaType = \"application/json\" example = \"saved\" /> Attribute Required Meaning operation Yes Stable operation ID bound to an API source. kind Yes request or response . mediaType Yes Exact media type in the source. example Yes Key in that media type's OpenAPI examples map. status For responses Response status, such as 201 . The element is standalone and empty, with literal string attributes. It resolves in the page's publication. HTML and Markdown show the example title, original key, context, description when present, provenance, and value. A missing selector fails the build. API includes cannot be nested inside snippets. See API references for source configuration and example presentation in reference pages. The fictional Notes API returns a saved note with its author, labels, and display metadata. The response includes a required but nullable archivedAt field: null means the note is active. Created release note OpenAPI response 201; application/json. Example key: saved. Authored in OpenAPI. An active note with a nested author, two labels, and optional display metadata. { \"id\" : \"note_123\" , \"text\" : \"Review the release candidate.\" , \"createdAt\" : \"2026-10-18T09:30:00Z\" , \"archivedAt\" : null , \"author\" : { \"id\" : \"usr_42\" , \"displayName\" : \"Morgan Lee\" } , \"tags\" : [ \"release\" , \"review\" ] , \"metadata\" : { \"source\" : \"release-checklist\" , \"pinned\" : true } } Markdown twin During the build, Shoalrun selects the named example from the OpenAPI source for this page's publication and replaces <ApiExample> with ordinary content. An agent reading the generated .md page does not need to resolve the component or fetch the OpenAPI file. The example above renders as: ### Created release note OpenAPI response 201; application/json. Example key: saved. Authored in OpenAPI. An active note with a nested author, two labels, and optional display metadata. ```json { \"id\" : \"note_123\" , \"text\" : \"Review the release candidate.\" , \"createdAt\" : \"2026-10-18T09:30:00Z\" , \"archivedAt\" : null , \"author\" : { \"id\" : \"usr_42\" , \"displayName\" : \"Morgan Lee\" } , \"tags\" : [ \"release\" , \"review\" ] , \"metadata\" : { \"source\" : \"release-checklist\" , \"pinned\" : true } } ``` An OpenAPI description appears between the context line and payload when present. JSON-compatible values use a json fence; string values with a text/* media type use a text fence. If the source uses externalValue , the twin shows an External example link instead of an inline payload. A response example's context includes its status, such as response 201; application/json . ApiSchema <ApiSchema> includes a schema from a configured OpenAPI source. It can select a request or response body, a standalone object, or one field. Use it when readers need the exact source definition alongside task instructions. Syntax < ApiSchema operation = \"notes.create\" kind = \"response\" status = \"201\" mediaType = \"application/json\" /> Attribute Required Meaning operation For a body Stable operation ID bound to an API source. api For a standalone schema Configured API ID. kind With operation request or response . mediaType With operation Exact media type. status For response bodies Response status, such as 201 . schema With api Local OpenAPI $ref selector. With operation , omitted uses the selected media type's schema. Use operation , kind , mediaType , and status for a body schema. To select an object that is not a body, use api and schema without the operation attributes. A pointer ending in /properties/<name> selects a single field. Both forms use the API source for the page's publication. < ApiSchema api = \"notes\" schema = \"#/components/schemas/NoteMetadata\" /> < ApiSchema api = \"notes\" schema = \"#/components/schemas/NoteMetadata/properties/source\" /> Schema · NoteMetadata object Optional display information for a note. 2 properties source string optional ⓘ Where the note came from. pinned boolean optional ⓘ Whether the note stays at the top. Field · source string Where the note came from. The element is standalone and empty, with literal string attributes. A missing or invalid selector fails the build. API includes cannot be nested inside snippets. See API references for source setup and focused contracts. Response 201 schema · application/json A saved note with its author, labels, and display metadata. 7 properties id string always present ⓘ The generated note ID. text string always present ⓘ maxLength: 280 The saved text. createdAt string always present ⓘ format: date-time When the note was created. archivedAt s","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"ApiExample and ApiSchema reuse OpenAPI content in authored pages. Examples stay synchronized with named payloads; schemas expose selected field definitions in HTML and Markdown. ApiExample <ApiExample> copies a named example from the OpenAPI source bound to a stable operation ID. Use it in a guide when the full payload should stay synchronized with the reference. Syntax <ApiExample operation=\"notes.create\" kind=\"response\" status=\"201\" mediaType=\"application/json\" example=\"saved\" /> Attribute Required Meaning operation Yes Stable operation ID bound to an API source. kind Yes request or response . mediaType Yes Exact media type in the source. example Yes Key in that media type's OpenAPI examples map. status For responses Response status, such as 201 . The element is standalone and empty, with literal string attributes. It resolves in the page's publication. HTML and Markdown show the example title, original key, context, description when present, provenance, and value. A missing selector fails the build. API includes cannot be nested inside snippets. See API references for source configuration and example presentation in reference pages. The fictional Notes API returns a saved note with its author, labels, and display metadata. The response includes a required but nullable archivedAt field: null means the note is active. Created release note OpenAPI response 201; application/json. Example key: saved. Authored in OpenAPI. An active note with a nested author, two labels, and optional display metadata. { \"id\": \"note_123\", \"text\": \"Review the release candidate.\", \"createdAt\": \"2026-10-18T09:30:00Z\", \"archivedAt\": null, \"author\": { \"id\": \"usr_42\", \"displayName\": \"Morgan Lee\" }, \"tags\": [ \"release\", \"review\" ], \"metadata\": { \"source\": \"release-checklist\", \"pinned\": true } } Markdown twin During the build, Shoalrun selects the named example from the OpenAPI source for this page's publication and replaces <ApiExample> with ordinary content. An agent reading the generated .md page does not need to resolve the component or fetch the OpenAPI file. The example above renders as: ### Created release note OpenAPI response 201; application/json. Example key: saved. Authored in OpenAPI. An active note with a nested author, two labels, and optional display metadata. ```json { \"id\": \"note_123\", \"text\": \"Review the release candidate.\", \"createdAt\": \"2026-10-18T09:30:00Z\", \"archivedAt\": null, \"author\": { \"id\": \"usr_42\", \"displayName\": \"Morgan Lee\" }, \"tags\": [ \"release\", \"review\" ], \"metadata\": { \"source\": \"release-checklist\", \"pinned\": true } } ``` An OpenAPI description appears between the context line and payload when present. JSON-compatible values use a json fence; string values with a text/* media type use a text fence. If the source uses externalValue , the twin shows an External example link instead of an inline payload. A response example's context includes its status, such as response 201; application/json . ApiSchema <ApiSchema> includes a schema from a configured OpenAPI source. It can select a request or response body, a standalone object, or one field. Use it when readers need the exact source definition alongside task instructions. Syntax <ApiSchema operation=\"notes.create\" kind=\"response\" status=\"201\" mediaType=\"application/json\" /> Attribute Required Meaning operation For a body Stable operation ID bound to an API source. api For a standalone schema Configured API ID. kind With operation request or response . mediaType With operation Exact media type. status For response bodies Response status, such as 201 . schema With api Local OpenAPI $ref selector. With operation , omitted uses the selected media type's schema. Use operation , kind , mediaType , and status for a body schema. To select an object that is not a body, use api and schema without the operation attributes. A pointer ending in /properties/<name> selects a single field. Both forms use the API source for the page's publication. <ApiSchema api=\"notes\" schema=\"#/components/schemas/NoteMetadata\" /> <ApiSchema api=\"notes\" schema=\"#/components/schemas/NoteMetadata/properties/source\" /> Schema · NoteMetadata object Optional display information for a note. 2 properties source string optional ⓘ Where the note came from. pinned boolean optional ⓘ Whether the note stays at the top. Field · source string Where the note came from. The element is standalone and empty, with literal string attributes. A missing or invalid selector fails the build. API includes cannot be nested inside snippets. See API references for source setup and focused contracts. Response 201 schema · application/json A saved note with its author, labels, and display metadata. 7 properties id string always present ⓘ The generated note ID. text string always present ⓘ maxLength: 280 The saved text. createdAt string always present ⓘ format: date-time When the note was created. archivedAt string always present nullable ⓘ format: date-time When the note was archived, or null while active. author obj"},{"filters":{"focus":["write"]},"text":"Add an OpenAPI API — Register the OpenAPI source these components read from. Fields — Write field lists by hand in the same format as generated schemas."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10142,"markdownTokens":2303,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"apiexample","title":"ApiExample","markdownUrl":"/author/components/api-embeds.sections/apiexample.md","markdownBytes":4635,"markdownTokens":1133},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/components/api-embeds.sections/html-markdown-and-agents.md","markdownBytes":1682,"markdownTokens":402},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/components/api-embeds.sections/related-reading.md","markdownBytes":1389,"markdownTokens":355}]},{"id":"guide.component.badge","demo":false,"url":"/author/components/badge","markdownUrl":"/author/components/badge.md","title":"Badges","summary":"Put a short, labeled status or platform name inside a sentence.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-prose","headings":[{"id":"built-in-variants","title":"Built-in variants"},{"id":"add-a-custom-color","title":"Add a custom color"},{"id":"attributes-and-output","title":"Attributes and output"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"<Badge> adds a compact label inside prose, a heading, or a table cell. Write the state in its text; color and the optional icon only reinforce it. The API is < Badge variant = \"success\" icon = \"check\" >Stable</ Badge >. The API is Stable . Built-in variants These five variants are available in every Shoalrun project. None has a default icon. Variant Example Color source neutral Platform --color-field-surface , --color-ink , and --color-border from the active palette. info Preview The active palette's callout-note background, text, and line tokens. success Stable The active palette's callout-tip background, text, and line tokens. warning Deprecated The active palette's callout-warning background, text, and line tokens. new New The active palette's purple callout-important background, text, and line tokens. The built-in variants follow the selected palette and color mode. A project can override a built-in variant or add another in badges.variants . Add icon only when it helps the reader. The variant changes presentation only; Markdown keeps the label text. Add a custom color For example, this site registers a teal partner variant. It is a custom example, not one of the built-in variants. Give a custom variant background and text hex colors for light mode, and for dark mode if the site shows dark mode. border is optional and defaults to the text color. The build rejects unknown variant names and checks badge text against its background at 4.5:1 in each shown mode. docs.config.yaml badges : variants : partner : light : { background : '#e5f5f3' , text : '#175b57' , border : '#4c9992' } dark : { background : '#102e2d' , text : '#a6e7df' , border : '#4caaa1' } This feature is < Badge variant = \"partner\" >Partner</ Badge >. This feature is Partner . Projects can put this mapping in a separate file with $include . To change a built-in variant across a site, register that same name with custom colors. For broad palette changes, edit the palette tokens ; for CSS-level overrides, see the CSS reference . Attributes and output Badge attributes control its label, appearance, and representation in the published outputs. Attribute Required Meaning variant No A built-in or registered name. Defaults to neutral . icon No A lowercase Lucide icon name, such as check . Decorative in HTML. The body must be nonempty plain text. HTML, Markdown, and agents HTML renders a styled <span> with the visible label. Markdown keeps the label inline, so an agent receives the status or platform name without relying on color or an icon. There is no JavaScript behavior; the label remains readable without CSS.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<Badge> adds a compact label inside prose, a heading, or a table cell. Write the state in its text; color and the optional icon only reinforce it. The API is <Badge variant=\"success\" icon=\"check\">Stable</Badge>. The API is Stable . Built-in variants These five variants are available in every Shoalrun project. None has a default icon. Variant Example Color source neutral Platform --color-field-surface , --color-ink , and --color-border from the active palette. info Preview The active palette's callout-note background, text, and line tokens. success Stable The active palette's callout-tip background, text, and line tokens. warning Deprecated The active palette's callout-warning background, text, and line tokens. new New The active palette's purple callout-important background, text, and line tokens. The built-in variants follow the selected palette and color mode. A project can override a built-in variant or add another in badges.variants . Add icon only when it helps the reader. The variant changes presentation only; Markdown keeps the label text. Add a custom color For example, this site registers a teal partner variant. It is a custom example, not one of the built-in variants. Give a custom variant background and text hex colors for light mode, and for dark mode if the site shows dark mode. border is optional and defaults to the text color. The build rejects unknown variant names and checks badge text against its background at 4.5:1 in each shown mode. badges: variants: partner: light: { background: '#e5f5f3', text: '#175b57', border: '#4c9992' } dark: { background: '#102e2d', text: '#a6e7df', border: '#4caaa1' } This feature is <Badge variant=\"partner\">Partner</Badge>. This feature is Partner . Projects can put this mapping in a separate file with $include . To change a built-in variant across a site, register that same name with custom colors. For broad palette changes, edit the palette tokens ; for CSS-level overrides, see the CSS reference . Attributes and output Badge attributes control its label, appearance, and representation in the published outputs. Attribute Required Meaning variant No A built-in or registered name. Defaults to neutral . icon No A lowercase Lucide icon name, such as check . Decorative in HTML. The body must be nonempty plain text. HTML, Markdown, and agents HTML renders a styled <span> with the visible label. Markdown keeps the label inline, so an agent receives the status or platform name without relying on color or an icon. There is no JavaScript behavior; the label remains readable without CSS."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4145,"markdownTokens":946,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.breadcrumbs","demo":false,"url":"/author/components/breadcrumbs","markdownUrl":"/author/components/breadcrumbs.md","title":"Breadcrumbs","summary":"Show where a page sits in the configured navigation hierarchy.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-navigation","headings":[{"id":"configuration","title":"Configuration"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Breadcrumbs are built into site navigation. Shoalrun generates them from the navigation tree . Place a page under its intended groups in navigation; there is no <Breadcrumbs> tag to repeat in each MDX file. Configuration This abbreviated navigation puts Breadcrumbs under the Customize and Navigation groups. Those labels become part of its trail: Customize / Navigation / Breadcrumbs . docs/config/nav.yaml - id : styling label : Customize items : - id : navigation label : Navigation items : - id : navigation-overview doc : guide.navigation-lifecycle label : Overview - id : breadcrumbs doc : guide.component.breadcrumbs A group without a document has a plain-text label in the trail. An ancestor with a document becomes a link. The current page is shown as text, never as a link to itself. Top-level pages have no trail. HTML, Markdown, and agents HTML puts a breadcrumb navigation region above the page heading. It uses an ordered list and marks the current page with aria-current=\"page\" . Links remain ordinary keyboard-accessible links, and the trail works without JavaScript. Markdown shows the same path near the title. Ancestors with pages link to their Markdown versions. Each document manifest entry has a breadcrumbs array containing ordered labels and any available URLs. An agent can recover the hierarchy without parsing HTML navigation. Related reading Reference while working Organize site navigation — Place pages in navigation to generate their breadcrumb trails. Related topics Organize site navigation — Understand the breadcrumb trails generated from navigation groups.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Breadcrumbs are built into site navigation. Shoalrun generates them from the navigation tree . Place a page under its intended groups in navigation; there is no <Breadcrumbs> tag to repeat in each MDX file. Configuration This abbreviated navigation puts Breadcrumbs under the Customize and Navigation groups. Those labels become part of its trail: Customize / Navigation / Breadcrumbs . - id: styling label: Customize items: - id: navigation label: Navigation items: - id: navigation-overview doc: guide.navigation-lifecycle label: Overview - id: breadcrumbs doc: guide.component.breadcrumbs A group without a document has a plain-text label in the trail. An ancestor with a document becomes a link. The current page is shown as text, never as a link to itself. Top-level pages have no trail. HTML, Markdown, and agents HTML puts a breadcrumb navigation region above the page heading. It uses an ordered list and marks the current page with aria-current=\"page\" . Links remain ordinary keyboard-accessible links, and the trail works without JavaScript. Markdown shows the same path near the title. Ancestors with pages link to their Markdown versions. Each document manifest entry has a breadcrumbs array containing ordered labels and any available URLs. An agent can recover the hierarchy without parsing HTML navigation. Related reading Reference while working Related topics"},{"filters":{"focus":["write"]},"text":"Organize site navigation — Place pages in navigation to generate their breadcrumb trails. Organize site navigation — Understand the breadcrumb trails generated from navigation groups."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2629,"markdownTokens":594,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.callout","demo":false,"url":"/author/components/callout","markdownUrl":"/author/components/callout.md","title":"Callouts","summary":"Use built-in callouts or register a type with its own label, tone, and icon.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-prose","headings":[{"id":"choose-a-type","title":"Choose a type"},{"id":"attributes-and-defaults","title":"Attributes and defaults"},{"id":"register-a-type","title":"Register a type"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"<Callout> highlights a short message in the reading flow. Use a type that matches the message's purpose. The type sets the HTML color and decorative icon, while a visible label carries the meaning in both HTML and Markdown. Choose a type Choose a callout type that matches the information readers need to notice. Type Use it for note Helpful context or a clarification. tip A practical suggestion that makes a task easier. important Information readers must notice to complete a task correctly. warning A possible problem readers can avoid. caution A higher-risk action or consequence that needs extra care. < Callout type = \"warning\" >Use a fresh idempotency key for a new payment.</ Callout > Note: The example API is fictional. Tip: Keep a copy of the response ID for later checks. Important: Check the selected API version before copying a request. Warning: A changed idempotency key can create a second payment. Caution: Review the target environment before deleting data. Attributes and defaults Use these attributes to set the callout type and its visible title. Attribute Required Meaning type No A built-in or registered type. Omitted with no label defaults to note . label No Nonempty literal text that replaces the visible type name. Set both when the message needs a more specific label: < Callout type = \"warning\" label = \"Before retrying\" >Reuse the original idempotency key.</ Callout > Before retrying: Reuse the original idempotency key. A label without a type retains the neutral style used by earlier pages. Its label remains visible in Markdown: < Callout label = \"Before you begin\" >Use a draft page while checking examples.</ Callout > Before you begin: Use a draft page while checking examples. A bare <Callout> uses the note label and style. Unknown types, unsupported attributes, and empty labels fail the build. Note: This uses the default note style and label. Register a type Add callouts.types to the project config. Each new type needs a label and a tone . The tone can be one of the five built-in values or a name registered in callouts.tones . An optional icon names a Lucide icon in lowercase kebab-case. This site's configuration registers an experiment type with its own laboratory tone: docs.config.yaml callouts : { $include : ./config/callouts.yaml } config/callouts.yaml tones : laboratory : line : '#087f8c' background : '#e9f8f8' text : '#075c66' dark : line : '#3cb9c4' background : '#0e2a2d' text : '#8fe3ea' types : experiment : label : Experiment tone : laboratory icon : flask-conical Use the registered name in MDX: < Callout type = \"experiment\" >Try this flow in a test environment first.</ Callout > Experiment: Try this flow in a test environment first. Each custom tone needs line (left rule), background , and text (label and icon), all as hex colors. Multiple types can share a tone. A tone's dark block sets the same three colors for dark mode . It is optional on a light-only site. When theme.mode is dark or system , every tone in use needs dark , or the build fails. The build checks each tone against the site's palette in every mode the site shows. Body text, links, and the label need 4.5:1 against the tone's background. You can also use callouts.tones to replace a built-in tone's colors. The five built-in types have default labels and Lucide icons; you can override their label , tone , or icon in callouts.types . A registered type without an icon displays its label without an icon. Icons are decorative and hidden from assistive technology; the label stays in HTML and Markdown. Invalid names, colors, icons, and definitions fail the build. HTML, Markdown, and agents The body accepts ordinary Markdown and supported MDX components. HTML renders a styled blockquote with the visible label and optional icon; Markdown renders a labeled blockquote with the full body. Colors and icons never carry the only meaning, and no browser script is needed. Keep the message short. Use a normal section heading for longer instructions. The CSS reference lists the color tokens for each type. See the component index for other supported elements. Related reading Reference while working CSS and theme reference — Restyle callout tones with theme tokens. Related topics Short definitions — Choose a short optional definition or an explanation visible in the reading path.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<Callout> highlights a short message in the reading flow. Use a type that matches the message's purpose. The type sets the HTML color and decorative icon, while a visible label carries the meaning in both HTML and Markdown. Choose a type Choose a callout type that matches the information readers need to notice. Type Use it for note Helpful context or a clarification. tip A practical suggestion that makes a task easier. important Information readers must notice to complete a task correctly. warning A possible problem readers can avoid. caution A higher-risk action or consequence that needs extra care. <Callout type=\"warning\">Use a fresh idempotency key for a new payment.</Callout> Note: The example API is fictional. Tip: Keep a copy of the response ID for later checks. Important: Check the selected API version before copying a request. Warning: A changed idempotency key can create a second payment. Caution: Review the target environment before deleting data. Attributes and defaults Use these attributes to set the callout type and its visible title. Attribute Required Meaning type No A built-in or registered type. Omitted with no label defaults to note . label No Nonempty literal text that replaces the visible type name. Set both when the message needs a more specific label: <Callout type=\"warning\" label=\"Before retrying\">Reuse the original idempotency key.</Callout> Before retrying: Reuse the original idempotency key. A label without a type retains the neutral style used by earlier pages. Its label remains visible in Markdown: <Callout label=\"Before you begin\">Use a draft page while checking examples.</Callout> Before you begin: Use a draft page while checking examples. A bare <Callout> uses the note label and style. Unknown types, unsupported attributes, and empty labels fail the build. Note: This uses the default note style and label. Register a type Add callouts.types to the project config. Each new type needs a label and a tone . The tone can be one of the five built-in values or a name registered in callouts.tones . An optional icon names a Lucide icon in lowercase kebab-case. This site's configuration registers an experiment type with its own laboratory tone: callouts: { $include: ./config/callouts.yaml } tones: laboratory: line: '#087f8c' background: '#e9f8f8' text: '#075c66' dark: line: '#3cb9c4' background: '#0e2a2d' text: '#8fe3ea' types: experiment: label: Experiment tone: laboratory icon: flask-conical Use the registered name in MDX: <Callout type=\"experiment\">Try this flow in a test environment first.</Callout> Experiment: Try this flow in a test environment first. Each custom tone needs line (left rule), background , and text (label and icon), all as hex colors. Multiple types can share a tone. A tone's dark block sets the same three colors for dark mode . It is optional on a light-only site. When theme.mode is dark or system , every tone in use needs dark , or the build fails. The build checks each tone against the site's palette in every mode the site shows. Body text, links, and the label need 4.5:1 against the tone's background. You can also use callouts.tones to replace a built-in tone's colors. The five built-in types have default labels and Lucide icons; you can override their label , tone , or icon in callouts.types . A registered type without an icon displays its label without an icon. Icons are decorative and hidden from assistive technology; the label stays in HTML and Markdown. Invalid names, colors, icons, and definitions fail the build. HTML, Markdown, and agents The body accepts ordinary Markdown and supported MDX components. HTML renders a styled blockquote with the visible label and optional icon; Markdown renders a labeled blockquote with the full body. Colors and icons never carry the only meaning, and no browser script is needed. Keep the message short. Use a normal section heading for longer instructions. The CSS reference lists the color tokens for each type. See the component index for other supported elements. Related reading Reference while working Related topics"},{"filters":{"focus":["configure"]},"text":"CSS and theme reference — Restyle callout tones with theme tokens."},{"filters":{"focus":["write"]},"text":"Short definitions — Choose a short optional definition or an explanation visible in the reading path."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6126,"markdownTokens":1439,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.code-blocks","demo":false,"url":"/author/components/code-blocks","markdownUrl":"/author/components/code-blocks.md","title":"Code blocks","summary":"Write fenced examples and configure Shiki or another highlighter.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-code","headings":[{"id":"syntax","title":"Syntax"},{"id":"highlighting-with-shiki","title":"Highlighting with Shiki"},{"id":"configure-shiki","title":"Configure Shiki"},{"id":"choose-plain-code","title":"Choose plain code"},{"id":"use-a-custom-highlighter","title":"Use a custom highlighter"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Fenced code is ordinary Markdown rather than an MDX component. It belongs in the component reference because authors use it beside components to show commands, configuration, and payloads. Syntax ```yaml title=\"Frontmatter fields\" filename=\"config/frontmatter.yaml\" fields : agent.intent : type : string ``` Frontmatter fields config/frontmatter.yaml fields : agent.intent : type : string Fence option Required Meaning Language, such as yaml No Chooses a build-time highlighting grammar; unknown languages remain plain. title=\"Frontmatter fields\" No Shows a descriptive heading above the HTML block. filename=\"config/frontmatter.yaml\" No Shows a file path beside the title. Use title , filename , both, or neither. Existing fences that use title for a path still display that text. Code, title, and filename are available before browser scripts run. HTML adds a Copy button when clipboard access is available; it copies the original text without syntax markup. Long blocks scroll horizontally. The Markdown twin keeps both options on the original fence. The settings below explain Shiki, themes, plain code, and custom adapters. Highlighting with Shiki Shoalrun highlights fenced code and OpenAPI example panels while building the site. Shiki is the default provider, with the site theme. The HTML already contains the colored code before browser scripts run. The Markdown twin keeps the original fenced text. Language labels, filenames, and copy controls are covered above. Configure Shiki Add this to the root config or an imported outputs fragment: outputs : html : highlighting : provider : shiki theme : site The default is equivalent to that configuration. The site theme takes code colors from the site palette . Keywords use the accent color. Strings, numbers, and functions use the palette's green, amber, and blue. Code colors change with the palette, including in the theme previewer . A color below 4.5:1 contrast on the code background falls back to plain code text. To use a theme you know from your editor, set theme to a bundled Shiki theme name, such as github-dark , dracula , or one-dark-pro . A dark theme sets the syntax colors, and the palette still sets the block background so it matches the toolbar. A light theme, such as github-light , sets both its colors and its background. Shiki's theme list shows available names. Site typography and surrounding colors still come from CSS tokens . An unknown theme fails the build. The built-in grammars are JSON, YAML, shell, JavaScript, TypeScript, Python, HTML, CSS, MDX, Markdown, HTTP, XML, SQL, Go, Java, Ruby, C#, PHP, and Rust. Shiki also recognizes loaded aliases such as sh and js . Unknown or unlabeled code stays plain. JSON-compatible API examples use JSON highlighting; text media currently use plain text. Choose plain code outputs : html : highlighting : provider : none none keeps code readable without syntax colors. Shiki is loaded only when its provider is selected. Code titles, scrolling, and copy behavior still work. Use a custom highlighter outputs : html : highlighting : provider : custom module : ./highlight.mjs The module path is relative to the config fragment that declares it. Export a synchronous function that returns flat text tokens. Each token may have a hexadecimal color: export function highlight (code , language) { // Replace this with tokens from your preferred highlighter. return [{ text : code , color : \"#e4f2e9\" }]; } The adapter may import an installed library and initialize it with top-level await. Its highlight function must be synchronous. Tokens must reproduce the source code exactly, including whitespace, and colors must use #rgb , #rgba , #rrggbb , or #rrggbbaa . The framework validates tokens and escapes HTML; the adapter does not return raw HTML. Invalid tokens or changed text fail the build. The same adapter handles authored fences and API example panels. The entry module appears in the dependency manifest, while its own imports are not tracked individually. HTML, Markdown, and agents Highlighted code remains selectable without JavaScript. Blocks scroll horizontally without widening the page. Keyboard users can focus a long block to scroll it. The Copy button appears when the browser supports clipboard access in a secure context such as HTTPS or localhost. It copies the original code text rather than the colored spans. Without clipboard access, readers can select and copy manually. The Markdown twin keeps the original fenced code, language, title, and filename. An agent reading it receives the complete source text without syntax-color markup or the Copy control. The publishing guide explains where HTML and Markdown outputs are written. Related reading Reference while working CSS and theme reference — Look up the code color tokens and selectors. Related topics Walkthroughs — Walkthroughs build on code blocks to explain an example one step at a time.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fenced code is ordinary Markdown rather than an MDX component. It belongs in the component reference because authors use it beside components to show commands, configuration, and payloads. Syntax ```yaml title=\"Frontmatter fields\" filename=\"config/frontmatter.yaml\" fields: agent.intent: type: string ``` fields: agent.intent: type: string Fence option Required Meaning Language, such as yaml No Chooses a build-time highlighting grammar; unknown languages remain plain. title=\"Frontmatter fields\" No Shows a descriptive heading above the HTML block. filename=\"config/frontmatter.yaml\" No Shows a file path beside the title. Use title , filename , both, or neither. Existing fences that use title for a path still display that text. Code, title, and filename are available before browser scripts run. HTML adds a Copy button when clipboard access is available; it copies the original text without syntax markup. Long blocks scroll horizontally. The Markdown twin keeps both options on the original fence. The settings below explain Shiki, themes, plain code, and custom adapters. Highlighting with Shiki Shoalrun highlights fenced code and OpenAPI example panels while building the site. Shiki is the default provider, with the site theme. The HTML already contains the colored code before browser scripts run. The Markdown twin keeps the original fenced text. Language labels, filenames, and copy controls are covered above. Configure Shiki Add this to the root config or an imported outputs fragment: outputs: html: highlighting: provider: shiki theme: site The default is equivalent to that configuration. The site theme takes code colors from the site palette . Keywords use the accent color. Strings, numbers, and functions use the palette's green, amber, and blue. Code colors change with the palette, including in the theme previewer . A color below 4.5:1 contrast on the code background falls back to plain code text. To use a theme you know from your editor, set theme to a bundled Shiki theme name, such as github-dark , dracula , or one-dark-pro . A dark theme sets the syntax colors, and the palette still sets the block background so it matches the toolbar. A light theme, such as github-light , sets both its colors and its background. Shiki's theme list shows available names. Site typography and surrounding colors still come from CSS tokens . An unknown theme fails the build. The built-in grammars are JSON, YAML, shell, JavaScript, TypeScript, Python, HTML, CSS, MDX, Markdown, HTTP, XML, SQL, Go, Java, Ruby, C#, PHP, and Rust. Shiki also recognizes loaded aliases such as sh and js . Unknown or unlabeled code stays plain. JSON-compatible API examples use JSON highlighting; text media currently use plain text. Choose plain code outputs: html: highlighting: provider: none none keeps code readable without syntax colors. Shiki is loaded only when its provider is selected. Code titles, scrolling, and copy behavior still work. Use a custom highlighter outputs: html: highlighting: provider: custom module: ./highlight.mjs The module path is relative to the config fragment that declares it. Export a synchronous function that returns flat text tokens. Each token may have a hexadecimal color: export function highlight(code, language) { // Replace this with tokens from your preferred highlighter. return [{ text: code, color: \"#e4f2e9\" }]; } The adapter may import an installed library and initialize it with top-level await. Its highlight function must be synchronous. Tokens must reproduce the source code exactly, including whitespace, and colors must use #rgb , #rgba , #rrggbb , or #rrggbbaa . The framework validates tokens and escapes HTML; the adapter does not return raw HTML. Invalid tokens or changed text fail the build. The same adapter handles authored fences and API example panels. The entry module appears in the dependency manifest, while its own imports are not tracked individually. HTML, Markdown, and agents Highlighted code remains selectable without JavaScript. Blocks scroll horizontally without widening the page. Keyboard users can focus a long block to scroll it. The Copy button appears when the browser supports clipboard access in a secure context such as HTTPS or localhost. It copies the original code text rather than the colored spans. Without clipboard access, readers can select and copy manually. The Markdown twin keeps the original fenced code, language, title, and filename. An agent reading it receives the complete source text without syntax-color markup or the Copy control. The publishing guide explains where HTML and Markdown outputs are written. Related reading Reference while working Related topics"},{"filters":{"focus":["configure"]},"text":"CSS and theme reference — Look up the code color tokens and selectors."},{"filters":{"focus":["write"]},"text":"Walkthroughs — Walkthroughs build on code blocks to explain an example one step at a time."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6539,"markdownTokens":1423,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.collapsible","demo":false,"url":"/author/components/collapsible","markdownUrl":"/author/components/collapsible.md","title":"Collapsibles","summary":"Show optional detail in individual disclosures or compact groups, with full Markdown output.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"syntax","title":"Syntax"},{"id":"include-markdown-and-mdx","title":"Include Markdown and MDX"},{"id":"group-related-items","title":"Group related items"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"often-confused-with","title":"Often confused with"}],"text":"<Collapsible> keeps supporting detail near the main instructions. Use it for material readers may need, but do not need to see before taking the next step. Its body is present in the initial HTML even when closed, and fully expanded in the Markdown twin. Syntax < Collapsible title = \"Why is this page a draft?\" > Pages with draft access stay out of the public build. </ Collapsible > Why is this page a draft? Pages with draft access stay out of the public build. Attribute Required Meaning title Yes Nonempty literal text for the disclosure summary. open No Bare boolean attribute that starts the disclosure expanded. The body must contain block content. Dynamic MDX expressions and unknown components fail the build. Include Markdown and MDX The body accepts paragraphs, lists, links, fenced code, and supported MDX components such as Callout and DocLink . These render inside the disclosure in HTML and in reading order in Markdown. < Collapsible title = \"Check the result\" open > - Confirm the response status. - Compare the returned ID. < Callout type = \"tip\" >Keep the response for troubleshooting.</ Callout > </ Collapsible > Use a normal section heading when readers should see the content as part of the main path. See the component index for other supported elements. Group related items Wrap related disclosures in <CollapsibleGroup> to join their borders and remove the gaps between them. Each item opens independently, so readers can compare more than one answer. The wrapper accepts one or more direct Collapsible children and has no attributes. Use each child's title and optional open attribute as usual. < CollapsibleGroup > < Collapsible title = \"What gets published?\" > The build includes public pages in the selected publication. </ Collapsible > < Collapsible title = \"Can I preview first?\" > Yes. Build locally and review the HTML and Markdown before deployment. </ Collapsible > </ CollapsibleGroup > What gets published? The build includes public pages in the selected publication. Can I preview first? Yes. Build locally and review the HTML and Markdown before deployment. Put rich content inside each child. Other direct children fail the build. Groups do not enforce a single open item. HTML, Markdown, and agents Individual disclosures and grouped items use native details and summary , so they work without JavaScript. Every body is present in the initial HTML even when closed. Markdown writes every title as a heading followed by its full body in source order. The group wrapper adds no extra heading or repeated text. An agent can read all details without opening a control. Related reading Often confused with Tabs — A collapsible hides optional detail behind one summary; tabs switch between alternate views of the same content. Short definitions — A short definition contains plain text; a collapsible holds longer rich content.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<Collapsible> keeps supporting detail near the main instructions. Use it for material readers may need, but do not need to see before taking the next step. Its body is present in the initial HTML even when closed, and fully expanded in the Markdown twin. Syntax <Collapsible title=\"Why is this page a draft?\"> Pages with draft access stay out of the public build. </Collapsible> Why is this page a draft? Pages with draft access stay out of the public build. Attribute Required Meaning title Yes Nonempty literal text for the disclosure summary. open No Bare boolean attribute that starts the disclosure expanded. The body must contain block content. Dynamic MDX expressions and unknown components fail the build. Include Markdown and MDX The body accepts paragraphs, lists, links, fenced code, and supported MDX components such as Callout and DocLink . These render inside the disclosure in HTML and in reading order in Markdown. <Collapsible title=\"Check the result\" open> - Confirm the response status. - Compare the returned ID. <Callout type=\"tip\">Keep the response for troubleshooting.</Callout> </Collapsible> Use a normal section heading when readers should see the content as part of the main path. See the component index for other supported elements. Group related items Wrap related disclosures in <CollapsibleGroup> to join their borders and remove the gaps between them. Each item opens independently, so readers can compare more than one answer. The wrapper accepts one or more direct Collapsible children and has no attributes. Use each child's title and optional open attribute as usual. <CollapsibleGroup> <Collapsible title=\"What gets published?\"> The build includes public pages in the selected publication. </Collapsible> <Collapsible title=\"Can I preview first?\"> Yes. Build locally and review the HTML and Markdown before deployment. </Collapsible> </CollapsibleGroup> What gets published? The build includes public pages in the selected publication. Can I preview first? Yes. Build locally and review the HTML and Markdown before deployment. Put rich content inside each child. Other direct children fail the build. Groups do not enforce a single open item. HTML, Markdown, and agents Individual disclosures and grouped items use native details and summary , so they work without JavaScript. Every body is present in the initial HTML even when closed. Markdown writes every title as a heading followed by its full body in source order. The group wrapper adds no extra heading or repeated text. An agent can read all details without opening a control. Related reading Often confused with"},{"filters":{"focus":["write"]},"text":"Tabs — A collapsible hides optional detail behind one summary; tabs switch between alternate views of the same content. Short definitions — A short definition contains plain text; a collapsible holds longer rich content."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4076,"markdownTokens":891,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.cookbook-chooser","demo":false,"url":"/author/components/cookbook-chooser","markdownUrl":"/author/components/cookbook-chooser.md","title":"CookbookChooser","summary":"Let readers select reviewed recipes and assemble them into one reading path.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use <CookbookChooser> to help a reader choose a complete recipe or combine compatible recipes. The author reviews each recipe and sets its place in the choice list. The browser loads the selected published recipe pages and displays their instructions. The component does not read ingredient files, generate a recipe, or execute commands. Start with how recipes and cookbooks work , then configure a cookbook ; this page lists the component's exact syntax. Syntax Map each option to a public recipe in project YAML, then place the chooser on a page in the same publication: config/cookbooks.yaml site-checks : title : How much validation do you need? mode : single options : - { id : build , label : Build , doc : recipe.build-docs } - { id : audit , label : Audit , doc : recipe.audit-docs } docs.config.yaml cookbooks : { $include : ./config/cookbooks.yaml } < CookbookChooser id = \"site-checks\" /> Try the live chooser for this documentation project: How much validation do you need? Build and check page artifacts Use when: You want to confirm a documentation edit compiles into HTML and Markdown. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build and the checked paths for both page formats. Build and run project audits Use when: You are preparing a change for review and need the configured API and project checks too. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build, checked artifacts, and no failed configured audits. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Build and check page artifacts — Build this documentation site Build and run project audits — Build and audit this documentation site Value Rule id Required literal cookbook ID from cookbooks . No child content or other attributes. options Nonempty ordered list of unique lowercase IDs, visible labels, and recipe document IDs. This order controls the assembled path. mode Optional single for alternatives or multiple (default) for compatible recipes. Option descriptions Optional when , needs , and outcome explain the choice in HTML and Markdown. Each is nonempty plain text. Recipe target Must be a public type: recipe page in the chooser's channel, version, and language. The build rejects duplicate IDs, labels, or recipe targets, plus missing, draft, wrong-type, or wrong-publication targets. HTML, Markdown, and agents HTML displays checkboxes, or radio buttons for mode: single , after the page script starts. Selecting options loads the published recipe pages and assembles their instructions in configured order under Your path . Each section links to its source recipe. If a page cannot load, the source link remains available. The recipe list below the controls works without JavaScript. The cookbook page and choice list are compiled at build time. Recipe content is fetched when a reader selects it in the browser. The selected option IDs are stored in the page URL. Link to this path preserves that selection; Download Markdown saves all selected recipe instructions, and Print this path prints the loaded path. Downloads fail as a whole if a recipe cannot be fetched. Printing is disabled while any selected recipe failed to load. Markdown lists every recipe with its choice descriptions and a link to its .md page in the same order. An agent can choose a recipe from those descriptions and read its complete Markdown. The cookbook Markdown does not contain the browser-selected recipe bodies. Give an agent the recipe Markdown or downloaded selection to follow a task. A selection URL does not create a published Markdown endpoint. Related reading Related topics Compose and maintain recipes — Let readers assemble reviewed recipes into a path in a cookbook.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <CookbookChooser> to help a reader choose a complete recipe or combine compatible recipes. The author reviews each recipe and sets its place in the choice list. The browser loads the selected published recipe pages and displays their instructions. The component does not read ingredient files, generate a recipe, or execute commands. Start with how recipes and cookbooks work , then configure a cookbook ; this page lists the component's exact syntax. Syntax Map each option to a public recipe in project YAML, then place the chooser on a page in the same publication: site-checks: title: How much validation do you need? mode: single options: - { id: build, label: Build, doc: recipe.build-docs } - { id: audit, label: Audit, doc: recipe.audit-docs } cookbooks: { $include: ./config/cookbooks.yaml } <CookbookChooser id=\"site-checks\" /> Try the live chooser for this documentation project: How much validation do you need? Build and check page artifacts Use when: You want to confirm a documentation edit compiles into HTML and Markdown. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build and the checked paths for both page formats. Build and run project audits Use when: You are preparing a change for review and need the configured API and project checks too. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build, checked artifacts, and no failed configured audits. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Build and check page artifacts — Build this documentation site Build and run project audits — Build and audit this documentation site Value Rule id Required literal cookbook ID from cookbooks . No child content or other attributes. options Nonempty ordered list of unique lowercase IDs, visible labels, and recipe document IDs. This order controls the assembled path. mode Optional single for alternatives or multiple (default) for compatible recipes. Option descriptions Optional when , needs , and outcome explain the choice in HTML and Markdown. Each is nonempty plain text. Recipe target Must be a public type: recipe page in the chooser's channel, version, and language. The build rejects duplicate IDs, labels, or recipe targets, plus missing, draft, wrong-type, or wrong-publication targets. HTML, Markdown, and agents HTML displays checkboxes, or radio buttons for mode: single , after the page script starts. Selecting options loads the published recipe pages and assembles their instructions in configured order under Your path . Each section links to its source recipe. If a page cannot load, the source link remains available. The recipe list below the controls works without JavaScript. The cookbook page and choice list are compiled at build time. Recipe content is fetched when a reader selects it in the browser. The selected option IDs are stored in the page URL. Link to this path preserves that selection; Download Markdown saves all selected recipe instructions, and Print this path prints the loaded path. Downloads fail as a whole if a recipe cannot be fetched. Printing is disabled while any selected recipe failed to load. Markdown lists every recipe with its choice descriptions and a link to its .md page in the same order. An agent can choose a recipe from those descriptions and read its complete Markdown. The cookbook Markdown does not contain the browser-selected recipe bodies. Give an agent the recipe Markdown or downloaded selection to follow a task. A selection URL does not create a published Markdown endpoint. Related reading Related topics"},{"filters":{"focus":["write"]},"text":"Compose and maintain recipes — Let readers assemble reviewed recipes into a path in a cookbook."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5380,"markdownTokens":1120,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.definition-list","demo":false,"url":"/author/components/definition-list","markdownUrl":"/author/components/definition-list.md","title":"Definition lists","summary":"Pair terms with full explanations in semantic HTML and readable Markdown.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-prose","headings":[{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use <DefinitionList> for a compact glossary or configuration reference. Put alternating <Term> and <Definition> children inside it. Add filter when readers need to search a long list by term or definition text. Syntax < DefinitionList filter > < Term >Publication</ Term > < Definition >A channel, version, and language combination.</ Definition > < Term >Slug</ Term > < Definition >The page's public path. See [ Page metadata ](doc:guide.frontmatter) .</ Definition > </ DefinitionList > Filter terms and definitions Publication A channel, version, and language combination. Slug The page's public path. See Page metadata . filter is an optional bare attribute on <DefinitionList> . The other tags have no attributes. Terms and definitions must have content; definitions can contain links and rich text. See the site glossary for a longer filtered list. HTML, Markdown, and agents HTML uses <dl> , <dt> , and <dd> , with aligned columns on wide screens and stacked pairs on narrow screens. With filter , JavaScript adds a labeled search input and a live count above the list. It searches both terms and definitions, hides or shows each pair together, and Escape clears the query. Without JavaScript, every pair remains visible and the filter control stays hidden. Markdown keeps each term immediately before its full definition in a list, so an agent can read every pair in order. The interactive filter does not appear in Markdown. Related reading Related topics Glossary — See a long, filterable definition list in use.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <DefinitionList> for a compact glossary or configuration reference. Put alternating <Term> and <Definition> children inside it. Add filter when readers need to search a long list by term or definition text. Syntax <DefinitionList filter> <Term>Publication</Term> <Definition>A channel, version, and language combination.</Definition> <Term>Slug</Term> <Definition>The page's public path. See [Page metadata](doc:guide.frontmatter).</Definition> </DefinitionList> Filter terms and definitions Publication A channel, version, and language combination. Slug The page's public path. See Page metadata . filter is an optional bare attribute on <DefinitionList> . The other tags have no attributes. Terms and definitions must have content; definitions can contain links and rich text. See the site glossary for a longer filtered list. HTML, Markdown, and agents HTML uses <dl> , <dt> , and <dd> , with aligned columns on wide screens and stacked pairs on narrow screens. With filter , JavaScript adds a labeled search input and a live count above the list. It searches both terms and definitions, hides or shows each pair together, and Escape clears the query. Without JavaScript, every pair remains visible and the filter control stays hidden. Markdown keeps each term immediately before its full definition in a list, so an agent can read every pair in order. The interactive filter does not appear in Markdown. Related reading Related topics Glossary — See a long, filterable definition list in use."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2439,"markdownTokens":576,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.diagrams","demo":false,"url":"/author/components/diagrams","markdownUrl":"/author/components/diagrams.md","title":"Diagrams","summary":"Render flowcharts, sequence diagrams, charts, and graphs from D2 or Mermaid source as static SVG.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-visuals","headings":[{"id":"d2","title":"D2"},{"id":"mermaid","title":"Mermaid"},{"id":"styling-and-readability","title":"Styling and readability"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Use <Diagram> for flowcharts, sequence diagrams, charts, and other graphs written as text. D2 is the default engine, with TALA as its default layout. Set engine=\"mermaid\" for Mermaid syntax, rendered by Pele . Diagrams render to SVG during the build, so readers do not need a diagram script in their browser. Set a literal pixel width , such as width=\"440\" , to cap the diagram's displayed width while allowing it to shrink on narrow screens. For the diagram languages themselves, use the official D2 tour and Mermaid syntax reference . Shoalrun's component controls how their source is published; those references cover each language's shapes, connections, and diagram types. Every diagram needs a short title and summary . The summary states the point of the diagram; it does not need to repeat every connection. For a complex diagram, add a fuller explanation in nearby prose so readers can understand its meaning without the graphic. D2 Copy the complete component, including its fenced source: < Diagram title = \"Documentation build\" summary = \"One source produces an HTML page and a Markdown page.\" > ``` d2 source: MDX source build: Shoalrun build html: HTML page markdown: Markdown page source -> build build -> html build -> markdown ``` </ Diagram > Documentation build — One source produces an HTML page and a Markdown page. Use layout=\"elk\" or layout=\"dagre\" when a directional flow reads better than TALA's architecture layout. D2 accepts only these three layout values. Browse the D2 gallery for containers, tables, classes, sequences, grids, and basic shapes with copyable source. The official D2 layout guide compares the engines. The D2 style guide and theme guide cover source-level shape styles and theme options. Mermaid Set the engine explicitly and keep the fence language mermaid : < Diagram title = \"Review flow\" summary = \"The author submits a page, then a reviewer approves it.\" engine = \"mermaid\" > ``` mermaid flowchart LR author[Author] --> review[Review] review --> publish[Publish] ``` </ Diagram > Author Review Publish Review flow — The author submits a page, then a reviewer approves it. Attribute Required Meaning title Yes Short literal name for the diagram. summary Yes Literal explanation of the diagram's point. engine No d2 by default; use mermaid for Mermaid source. layout No D2 only: tala by default, or elk or dagre . width No Pixel width from 1 through 4096 as a literal string, such as \"440\" ; the diagram still shrinks on narrow screens. Keep the source in one fenced code block inside the component. When quoting a complete example in Markdown, use four backticks around the outer mdx block so its inner three-backtick fence stays intact. See the diagram gallery for examples of every built-in Pele diagram family and 48 flowchart shapes. Use Mermaid’s syntax reference to write the source and Pele’s compatibility guide to check rendering differences. External Mermaid plugins are not supported. Styling and readability Pele diagrams inherit Shoalrun’s active palette, fonts, and corner radius. They update with light/dark mode and the theme switcher without re-rendering. Shoalrun maps Pele’s native CSS variables to its theme tokens; there is no second set of diagram aliases to learn. Override Pele’s variables in project CSS . For example, adjust the nodes and their text together: styles/project.css .content .doc-diagram .pele { --pele-surface : var (--color-field-surface) ; --pele-fg : var (--color-ink) ; --pele-border : var (--color-accent) ; --pele-radius : 8 px ; } See Pele’s styling guide for all variables, series colors, and element classes. Its examples show more diagram variations. Fixed source-level colors do not follow the palette; check their contrast in both modes. Custom fonts can change label widths, so inspect long labels after overriding fonts. Without width , a diagram fills the available content width. Set width=\"520\" to cap one diagram at 520 pixels; it still shrinks on narrower screens. Use .doc-diagram and .doc-diagram figcaption to style the frame and caption. D2 still renders separate light and dark SVG images using themes 0 and 200. Project CSS can style their frames and dimensions, but cannot reach individual nodes inside those image files. HTML, Markdown, and agents Pele generates inline SVG during the build. It needs no browser or client-side renderer, and the diagram works without JavaScript. Each SVG has an accessible name from title and a visible caption with the summary . Published light/dark SVG files remain available for direct links and Markdown readers. The .md page retains the title, summary, SVG link, and original fenced D2 or Mermaid source. Readers and agents can inspect the structure without running a diagram library. Changing the renderer does not remove the source or explanation. Shoalrun disables diagram links, external images, and JavaScript callbacks. It rejects active SVG content before publication. Arbitrary HTML labels and Mermaid’s named the","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Diagram> for flowcharts, sequence diagrams, charts, and other graphs written as text. D2 is the default engine, with TALA as its default layout. Set engine=\"mermaid\" for Mermaid syntax, rendered by Pele . Diagrams render to SVG during the build, so readers do not need a diagram script in their browser. Set a literal pixel width , such as width=\"440\" , to cap the diagram's displayed width while allowing it to shrink on narrow screens. For the diagram languages themselves, use the official D2 tour and Mermaid syntax reference . Shoalrun's component controls how their source is published; those references cover each language's shapes, connections, and diagram types. Every diagram needs a short title and summary . The summary states the point of the diagram; it does not need to repeat every connection. For a complex diagram, add a fuller explanation in nearby prose so readers can understand its meaning without the graphic. D2 Copy the complete component, including its fenced source: <Diagram title=\"Documentation build\" summary=\"One source produces an HTML page and a Markdown page.\"> ```d2 source: MDX source build: Shoalrun build html: HTML page markdown: Markdown page source -> build build -> html build -> markdown ``` </Diagram> Documentation build — One source produces an HTML page and a Markdown page. Use layout=\"elk\" or layout=\"dagre\" when a directional flow reads better than TALA's architecture layout. D2 accepts only these three layout values. Browse the D2 gallery for containers, tables, classes, sequences, grids, and basic shapes with copyable source. The official D2 layout guide compares the engines. The D2 style guide and theme guide cover source-level shape styles and theme options. Mermaid Set the engine explicitly and keep the fence language mermaid : <Diagram title=\"Review flow\" summary=\"The author submits a page, then a reviewer approves it.\" engine=\"mermaid\"> ```mermaid flowchart LR author[Author] --> review[Review] review --> publish[Publish] ``` </Diagram> Review flow — The author submits a page, then a reviewer approves it. Attribute Required Meaning title Yes Short literal name for the diagram. summary Yes Literal explanation of the diagram's point. engine No d2 by default; use mermaid for Mermaid source. layout No D2 only: tala by default, or elk or dagre . width No Pixel width from 1 through 4096 as a literal string, such as \"440\" ; the diagram still shrinks on narrow screens. Keep the source in one fenced code block inside the component. When quoting a complete example in Markdown, use four backticks around the outer mdx block so its inner three-backtick fence stays intact. See the diagram gallery for examples of every built-in Pele diagram family and 48 flowchart shapes. Use Mermaid’s syntax reference to write the source and Pele’s compatibility guide to check rendering differences. External Mermaid plugins are not supported. Styling and readability Pele diagrams inherit Shoalrun’s active palette, fonts, and corner radius. They update with light/dark mode and the theme switcher without re-rendering. Shoalrun maps Pele’s native CSS variables to its theme tokens; there is no second set of diagram aliases to learn. Override Pele’s variables in project CSS . For example, adjust the nodes and their text together: .content .doc-diagram .pele { --pele-surface: var(--color-field-surface); --pele-fg: var(--color-ink); --pele-border: var(--color-accent); --pele-radius: 8px; } See Pele’s styling guide for all variables, series colors, and element classes. Its examples show more diagram variations. Fixed source-level colors do not follow the palette; check their contrast in both modes. Custom fonts can change label widths, so inspect long labels after overriding fonts. Without width , a diagram fills the available content width. Set width=\"520\" to cap one diagram at 520 pixels; it still shrinks on narrower screens. Use .doc-diagram and .doc-diagram figcaption to style the frame and caption. D2 still renders separate light and dark SVG images using themes 0 and 200. Project CSS can style their frames and dimensions, but cannot reach individual nodes inside those image files. HTML, Markdown, and agents Pele generates inline SVG during the build. It needs no browser or client-side renderer, and the diagram works without JavaScript. Each SVG has an accessible name from title and a visible caption with the summary . Published light/dark SVG files remain available for direct links and Markdown readers. The .md page retains the title, summary, SVG link, and original fenced D2 or Mermaid source. Readers and agents can inspect the structure without running a diagram library. Changing the renderer does not remove the source or explanation. Shoalrun disables diagram links, external images, and JavaScript callbacks. It rejects active SVG content before publication. Arbitrary HTML labels and Mermaid’s named themes are not supported by this renderer. Keep essential instructions in the summary or surrounding "},{"filters":{"focus":["write"]},"text":"D2 gallery — Compare D2 diagrams and shape syntax before writing your own. Pele gallery — Compare diagram families and flowchart shapes before choosing syntax. Images — Render a diagram from source with a caption and responsive width."},{"filters":{"focus":["configure"]},"text":"CSS and theme reference — Look up the diagram frame, color-mode image, and caption selectors."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":8496,"markdownTokens":1941,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.doc-link","demo":false,"url":"/author/components/doc-link","markdownUrl":"/author/components/doc-link.md","title":"DocLink","summary":"Link to a page by stable document ID.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-navigation","headings":[{"id":"which-link-should-i-use","title":"Which link should I use?"},{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"<DocLink> resolves a document ID to its URL in the current publication. It is useful in MDX when the link should use a stable target and optionally inherit the target page's title. Which link should I use? Choose a link form based on whether the destination is a document, a section, or an external resource. Link Use it for What happens [Read the guide](doc:guide.frontmatter) Most links to another Shoalrun page. Resolves the stable document ID in the current publication. <DocLink doc=\"guide.frontmatter\">Read the guide</DocLink> An MDX link by ID, especially when you want the target title as fallback text. Resolves the same target as doc: Markdown. [Open the specification](https://example.test/spec) External sites, downloads, or other URLs without a Shoalrun document ID. Keeps the authored URL. [Jump to fields](#fields) A section on the current page. Keeps the fragment link. Prefer doc: Markdown for ordinary prose. Both ID-based forms survive a target slug change and fail the build if the target is unavailable in this publication. A normal Markdown link to a Shoalrun route can work, but the authored URL must be updated if that route changes. Raw HTML or JSX anchors such as <a href=\"...\"> do not have a semantic adapter in this prototype and fail the build; use Markdown links instead. Syntax < DocLink doc = \"guide.frontmatter\" >Read the frontmatter guide</ DocLink > Attribute Required Meaning doc Yes Stable ID of a page available in the current publication. If the body is empty, the target page title supplies the link text. Keep explicit body text plain. See content and stable IDs . HTML, Markdown, and agents The build keeps only the plain text inside DocLink , so emphasis or code formatting there is dropped. HTML links to the page; the Markdown twin links to its .md URL. An agent following that link receives the target’s Markdown page. Related reading Related topics Content and stable IDs — Link to pages by stable ID so links survive slug changes. Cards and collections — Link to a page inline, or show it as a card with its summary.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<DocLink> resolves a document ID to its URL in the current publication. It is useful in MDX when the link should use a stable target and optionally inherit the target page's title. Which link should I use? Choose a link form based on whether the destination is a document, a section, or an external resource. Link Use it for What happens [Read the guide](doc:guide.frontmatter) Most links to another Shoalrun page. Resolves the stable document ID in the current publication. <DocLink doc=\"guide.frontmatter\">Read the guide</DocLink> An MDX link by ID, especially when you want the target title as fallback text. Resolves the same target as doc: Markdown. [Open the specification](https://example.test/spec) External sites, downloads, or other URLs without a Shoalrun document ID. Keeps the authored URL. [Jump to fields](#fields) A section on the current page. Keeps the fragment link. Prefer doc: Markdown for ordinary prose. Both ID-based forms survive a target slug change and fail the build if the target is unavailable in this publication. A normal Markdown link to a Shoalrun route can work, but the authored URL must be updated if that route changes. Raw HTML or JSX anchors such as <a href=\"...\"> do not have a semantic adapter in this prototype and fail the build; use Markdown links instead. Syntax <DocLink doc=\"guide.frontmatter\">Read the frontmatter guide</DocLink> Attribute Required Meaning doc Yes Stable ID of a page available in the current publication. If the body is empty, the target page title supplies the link text. Keep explicit body text plain. See content and stable IDs . HTML, Markdown, and agents The build keeps only the plain text inside DocLink , so emphasis or code formatting there is dropped. HTML links to the page; the Markdown twin links to its .md URL. An agent following that link receives the target’s Markdown page. Related reading Related topics"},{"filters":{"focus":["write"]},"text":"Content and stable IDs — Link to pages by stable ID so links survive slug changes. Cards and collections — Link to a page inline, or show it as a card with its summary."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3786,"markdownTokens":770,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.fields","demo":false,"url":"/author/components/fields","markdownUrl":"/author/components/fields.md","title":"Fields","summary":"Write field lists in MDX with the same readable format as OpenAPI schemas.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-prose","headings":[{"id":"syntax","title":"Syntax"},{"id":"attribute-reference","title":"Attribute reference"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use <Fields> and <Field> to describe fields that are not selected from an OpenAPI schema, or to explain a small task-specific subset in your own words. The list uses the same field styling as generated schemas. If the exact contract already exists in OpenAPI, ApiSchema can include the source schema or one of its fields. Syntax < Fields > < Field name = \"name\" type = \"string\" required minLength = \"1\" maxLength = \"80\" example = \"Casey\" > The name shown to readers. </ Field > < Field name = \"options\" type = \"object\" optional nullable > Extra display settings. < Fields > < Field name = \"compact\" type = \"boolean\" optional default = \"false\" > Use a shorter layout. </ Field > </ Fields > </ Field > </ Fields > name — required string; minLength: 1; maxLength: 80 Example: Casey The name shown to readers. options — optional object; nullable Extra display settings. compact — optional boolean Default: false Use a shorter layout. Fields takes no attributes and needs direct Field children. A Field body accepts ordinary Markdown and supported MDX, including a nested Fields list. A standalone Field or other direct child of Fields fails the build. Attribute reference All values are literal MDX attributes. Text and numbers use quoted strings; flags are bare attributes. These declarations describe fields in the published page. They do not validate user input at runtime. Field attribute Required Meaning name Yes Nonempty field name. type Yes Nonempty type label, such as string , integer , or array of objects . required , optional No Bare presence flags. Omission means optional; the two flags cannot appear together. nullable No Bare flag allowing a null value. It does not change whether the field is present. min , max No Finite numeric value bounds; minimum and maximum are equivalent spellings. minLength , maxLength No Nonnegative integer string-length bounds. minItems , maxItems No Nonnegative integer array-size bounds. format , pattern No Nonempty text for a format name or pattern. example , default No Literal text shown as an example or default value. deprecated No Bare flag marking the field as deprecated. Bounds must be numeric, and each minimum must be no greater than its maximum. min cannot be combined with minimum , nor max with maximum . Keep the declared type, constraints, and examples consistent with the actual contract. < Fields > < Field name = \"rank\" type = \"integer\" optional min = \"0\" max = \"10\" example = \"3\" > Position in the list. </ Field > </ Fields > HTML, Markdown, and agents The build writes a normal nested Markdown list. Each item starts with the field name and presence rule, followed by its type and authored body. For the first field above, the twin contains: - `name` — **required** string; minLength: 1; maxLength: 80 Example: `Casey` The name shown to readers. Both formats include every field and description. The authored text is part of the page rather than copied from OpenAPI, so keep it aligned with the contract when it describes an API. Related reading Related topics ApiExample and ApiSchema — Write field lists by hand in the same format as generated schemas.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Fields> and <Field> to describe fields that are not selected from an OpenAPI schema, or to explain a small task-specific subset in your own words. The list uses the same field styling as generated schemas. If the exact contract already exists in OpenAPI, ApiSchema can include the source schema or one of its fields. Syntax <Fields> <Field name=\"name\" type=\"string\" required minLength=\"1\" maxLength=\"80\" example=\"Casey\"> The name shown to readers. </Field> <Field name=\"options\" type=\"object\" optional nullable> Extra display settings. <Fields> <Field name=\"compact\" type=\"boolean\" optional default=\"false\"> Use a shorter layout. </Field> </Fields> </Field> </Fields> name — required string; minLength: 1; maxLength: 80 Example: Casey The name shown to readers. options — optional object; nullable Extra display settings. compact — optional boolean Default: false Use a shorter layout. Fields takes no attributes and needs direct Field children. A Field body accepts ordinary Markdown and supported MDX, including a nested Fields list. A standalone Field or other direct child of Fields fails the build. Attribute reference All values are literal MDX attributes. Text and numbers use quoted strings; flags are bare attributes. These declarations describe fields in the published page. They do not validate user input at runtime. Field attribute Required Meaning name Yes Nonempty field name. type Yes Nonempty type label, such as string , integer , or array of objects . required , optional No Bare presence flags. Omission means optional; the two flags cannot appear together. nullable No Bare flag allowing a null value. It does not change whether the field is present. min , max No Finite numeric value bounds; minimum and maximum are equivalent spellings. minLength , maxLength No Nonnegative integer string-length bounds. minItems , maxItems No Nonnegative integer array-size bounds. format , pattern No Nonempty text for a format name or pattern. example , default No Literal text shown as an example or default value. deprecated No Bare flag marking the field as deprecated. Bounds must be numeric, and each minimum must be no greater than its maximum. min cannot be combined with minimum , nor max with maximum . Keep the declared type, constraints, and examples consistent with the actual contract. <Fields> <Field name=\"rank\" type=\"integer\" optional min=\"0\" max=\"10\" example=\"3\"> Position in the list. </Field> </Fields> HTML, Markdown, and agents The build writes a normal nested Markdown list. Each item starts with the field name and presence rule, followed by its type and authored body. For the first field above, the twin contains: - `name` — **required** string; minLength: 1; maxLength: 80 Example: `Casey` The name shown to readers. Both formats include every field and description. The authored text is part of the page rather than copied from OpenAPI, so keep it aligned with the contract when it describes an API. Related reading Related topics"},{"filters":{"focus":["write"]},"text":"ApiExample and ApiSchema — Write field lists by hand in the same format as generated schemas."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4842,"markdownTokens":1078,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.file-tree","demo":false,"url":"/author/components/file-tree","markdownUrl":"/author/components/file-tree.md","title":"File trees","summary":"Show nested files and folders with links and an indented Markdown equivalent.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-code","headings":[{"id":"expand-and-collapse-folders","title":"Expand and collapse folders"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"<FileTree> shows a file layout or other hierarchy. <Tree> is an alias. Add <Folder> branches and <File> leaves; folders may contain more folders or files. < FileTree > < Folder name = \"docs\" > < Folder name = \"content\" > < File name = \"start.mdx\" doc = \"guide.overview\" /> < File name = \"configuration.mdx\" /> < Folder name = \"assets\" collapsed > < File name = \"overview.svg\" /> </ Folder > </ Folder > < File name = \"docs.config.yaml\" /> </ Folder > < File name = \"package.json\" /> </ FileTree > docs content start.mdx configuration.mdx assets overview.svg docs.config.yaml package.json Every node needs a nonempty name . Folders and files get icons automatically, and a folder’s icon changes when it opens. Optional doc or href makes its label a link; use only one. Optional icon accepts a lowercase Lucide name to override the default. <File> cannot have children. Expand and collapse folders Folders start expanded. Readers can toggle them with a click, tap, Enter, or Space without JavaScript. Add collapsed to a folder to start it closed, and controls to the tree for optional expand-all and collapse-all buttons: < FileTree controls > < Folder name = \"project\" > < File name = \"README.md\" /> < Folder name = \"content\" collapsed > < File name = \"start.mdx\" /> </ Folder > </ Folder > </ FileTree > Expand all Collapse all project README.md content start.mdx With JavaScript, Up and Down move through visible controls and links; Home and End jump to the first and last. Right opens a folder or moves forward, and Left closes it or moves to its parent. Type a name to jump to a matching visible item, or press * to expand sibling folders at the current level. Tab still follows normal focus order. Expand-all and collapse-all buttons appear only when JavaScript is available. HTML, Markdown, and agents HTML uses nested lists and native folder disclosures. Every file is in the initial HTML, including files in closed folders. Links retain normal keyboard behavior. Markdown is a nested list with every node and destination visible, so an agent can follow the hierarchy and links. Icons are decorative, so names must carry the meaning.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<FileTree> shows a file layout or other hierarchy. <Tree> is an alias. Add <Folder> branches and <File> leaves; folders may contain more folders or files. <FileTree> <Folder name=\"docs\"> <Folder name=\"content\"> <File name=\"start.mdx\" doc=\"guide.overview\" /> <File name=\"configuration.mdx\" /> <Folder name=\"assets\" collapsed> <File name=\"overview.svg\" /> </Folder> </Folder> <File name=\"docs.config.yaml\" /> </Folder> <File name=\"package.json\" /> </FileTree> docs content start.mdx configuration.mdx assets overview.svg docs.config.yaml package.json Every node needs a nonempty name . Folders and files get icons automatically, and a folder’s icon changes when it opens. Optional doc or href makes its label a link; use only one. Optional icon accepts a lowercase Lucide name to override the default. <File> cannot have children. Expand and collapse folders Folders start expanded. Readers can toggle them with a click, tap, Enter, or Space without JavaScript. Add collapsed to a folder to start it closed, and controls to the tree for optional expand-all and collapse-all buttons: <FileTree controls> <Folder name=\"project\"> <File name=\"README.md\" /> <Folder name=\"content\" collapsed> <File name=\"start.mdx\" /> </Folder> </Folder> </FileTree> Expand all Collapse all project README.md content start.mdx With JavaScript, Up and Down move through visible controls and links; Home and End jump to the first and last. Right opens a folder or moves forward, and Left closes it or moves to its parent. Type a name to jump to a matching visible item, or press * to expand sibling folders at the current level. Tab still follows normal focus order. Expand-all and collapse-all buttons appear only when JavaScript is available. HTML, Markdown, and agents HTML uses nested lists and native folder disclosures. Every file is in the initial HTML, including files in closed folders. Links retain normal keyboard behavior. Markdown is a nested list with every node and destination visible, so an agent can follow the hierarchy and links. Icons are decorative, so names must carry the meaning."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2959,"markdownTokens":721,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.images","demo":false,"url":"/author/components/images","markdownUrl":"/author/components/images.md","title":"Images","summary":"Add responsive images with optional width limits, captions, and expanded viewing.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-visuals","headings":[{"id":"basic-image","title":"Basic image"},{"id":"set-a-width","title":"Set a width"},{"id":"center-an-image","title":"Center an image"},{"id":"add-a-caption-and-expanded-view","title":"Add a caption and expanded view"},{"id":"attributes","title":"Attributes"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use <Image> to show an image with optional sizing, a caption, or click-to-expand viewing. Plain Markdown image syntax also works when you only need an image and alt text. Basic image Provide a source and alt text. Local paths are relative to the page's MDX file; Shoalrun copies the image into the build. HTTPS URLs work too. < Image src = \"./assets/image-example.svg\" alt = \"A documentation page with navigation, content, and a table of contents\" /> Images fit the content column and shrink on narrow screens. They keep their aspect ratio. Plain Markdown has the same default sizing: ![ A documentation page ] (./assets/image-example.svg) Set a width width sets a maximum in pixels. It does not force an image to overflow a smaller screen. Leave it out to use the available content width. < Image src = \"./assets/image-example.svg\" alt = \"A documentation page layout\" width = \"480\" /> Center an image Use align=\"center\" with a width limit to center an image in the content column. The caption and expanded-view link stay with the image. You can also choose left or right . < Image src = \"./assets/image-example.svg\" alt = \"A documentation page layout\" width = \"480\" align = \"center\" caption = \"A centered image with a width limit.\" expand /> A centered image with a width limit. Add a caption and expanded view Use caption for visible context below the image. Add the bare expand attribute to let readers open a larger view. Select the example to try it. < Image src = \"./assets/image-example.svg\" alt = \"Navigation beside the main content, with a table of contents on the right\" width = \"480\" caption = \"A documentation page has three reading areas.\" expand /> A documentation page has three reading areas. The expanded view supports Escape to close and returns focus to the image link. Without JavaScript or modal-dialog support, the link opens the original asset. A larger view cannot add detail that is missing from a low-resolution source. Attributes All attributes use literal values. expand is a bare boolean attribute. Attribute Required Meaning src Yes Local .png , .jpg , .jpeg , .webp , or .svg path, or an HTTPS URL. alt Yes Text describing the image's meaning. Use alt=\"\" only for decorative images. width No Maximum width in pixels, from 1 to 4096. align No left , center , or right . Default placement follows the surrounding content. caption No Plain text shown below the image and retained in Markdown. expand No Opens a modal image viewer when supported, with an original-image link as fallback. <Image> is an empty block component. It does not accept children, HTML strings, or dynamic expressions. Keep essential explanations in nearby prose and meaningful alt text. For generated diagrams, use Diagram . HTML, Markdown, and agents HTML contains a normal image with alt text. Captions use figure and figcaption . Expandable images use a link enhanced by a modal viewer; the image remains usable without scripts. Modified clicks still open the link normally. Markdown includes the image and alt text, followed by its caption when present. Expandable images also include a link to the original asset. Width, alignment, and modal state do not hide content from agents. Related reading Related topics Diagrams — Render a diagram from source with a caption and responsive width.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Image> to show an image with optional sizing, a caption, or click-to-expand viewing. Plain Markdown image syntax also works when you only need an image and alt text. Basic image Provide a source and alt text. Local paths are relative to the page's MDX file; Shoalrun copies the image into the build. HTTPS URLs work too. <Image src=\"./assets/image-example.svg\" alt=\"A documentation page with navigation, content, and a table of contents\" /> Images fit the content column and shrink on narrow screens. They keep their aspect ratio. Plain Markdown has the same default sizing:  Set a width width sets a maximum in pixels. It does not force an image to overflow a smaller screen. Leave it out to use the available content width. <Image src=\"./assets/image-example.svg\" alt=\"A documentation page layout\" width=\"480\" /> Center an image Use align=\"center\" with a width limit to center an image in the content column. The caption and expanded-view link stay with the image. You can also choose left or right . <Image src=\"./assets/image-example.svg\" alt=\"A documentation page layout\" width=\"480\" align=\"center\" caption=\"A centered image with a width limit.\" expand /> A centered image with a width limit. Add a caption and expanded view Use caption for visible context below the image. Add the bare expand attribute to let readers open a larger view. Select the example to try it. <Image src=\"./assets/image-example.svg\" alt=\"Navigation beside the main content, with a table of contents on the right\" width=\"480\" caption=\"A documentation page has three reading areas.\" expand /> A documentation page has three reading areas. The expanded view supports Escape to close and returns focus to the image link. Without JavaScript or modal-dialog support, the link opens the original asset. A larger view cannot add detail that is missing from a low-resolution source. Attributes All attributes use literal values. expand is a bare boolean attribute. Attribute Required Meaning src Yes Local .png , .jpg , .jpeg , .webp , or .svg path, or an HTTPS URL. alt Yes Text describing the image's meaning. Use alt=\"\" only for decorative images. width No Maximum width in pixels, from 1 to 4096. align No left , center , or right . Default placement follows the surrounding content. caption No Plain text shown below the image and retained in Markdown. expand No Opens a modal image viewer when supported, with an original-image link as fallback. <Image> is an empty block component. It does not accept children, HTML strings, or dynamic expressions. Keep essential explanations in nearby prose and meaningful alt text. For generated diagrams, use Diagram . HTML, Markdown, and agents HTML contains a normal image with alt text. Captions use figure and figcaption . Expandable images use a link enhanced by a modal viewer; the image remains usable without scripts. Modified clicks still open the link normally. Markdown includes the image and alt text, followed by its caption when present. Expandable images also include a link to the original asset. Width, alignment, and modal state do not hide content from agents. Related reading Related topics"},{"filters":{"focus":["write"]},"text":"Diagrams — Render a diagram from source with a caption and responsive width."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5234,"markdownTokens":1163,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.info-hint","demo":false,"url":"/author/components/info-hint","markdownUrl":"/author/components/info-hint.md","title":"Short definitions","summary":"Let readers open a brief definition with a click, tap, or keyboard.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-prose","headings":[{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"Use <InfoHint> for a short definition that readers can open when they need it. It is a click-to-expand disclosure. Use a tooltip for brief text that appears on hover or keyboard focus. Put longer explanations in a callout or a linked page. Syntax Give the disclosure a visible label and one short plain-text definition. < InfoHint label = \"Canonical URL\" > The preferred address for a page when several addresses show the same content. </ InfoHint > Canonical URL The preferred address for a page when several addresses show the same content. Attribute Required Meaning label Yes Nonempty text shown on the disclosure control. <InfoHint> must be a block element with one plain-text definition. It does not accept links, multiple paragraphs, or other components inside the definition. <Tooltip> previously named this same disclosure. Use <InfoHint> to keep click-to-expand behavior; <Tooltip> now provides hover and focus behavior. HTML, Markdown, and agents HTML uses native <details> and <summary> elements. Readers can open the definition with a click, tap, Enter, or Space without JavaScript. The definition is present in the initial HTML even while the disclosure is closed. Markdown writes the label and definition together in ordinary text. An agent can read the explanation without opening a disclosure. Related reading Related topics Callouts — Choose a short optional definition or an explanation visible in the reading path. Keyboard shortcuts — Use key styling for shortcuts and a disclosure for optional definitions. Often confused with Collapsibles — A short definition contains plain text; a collapsible holds longer rich content. Tooltips — Tooltips open on hover or focus; short definitions use native click-to-expand disclosures.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <InfoHint> for a short definition that readers can open when they need it. It is a click-to-expand disclosure. Use a tooltip for brief text that appears on hover or keyboard focus. Put longer explanations in a callout or a linked page. Syntax Give the disclosure a visible label and one short plain-text definition. <InfoHint label=\"Canonical URL\"> The preferred address for a page when several addresses show the same content. </InfoHint> Canonical URL The preferred address for a page when several addresses show the same content. Attribute Required Meaning label Yes Nonempty text shown on the disclosure control. <InfoHint> must be a block element with one plain-text definition. It does not accept links, multiple paragraphs, or other components inside the definition. <Tooltip> previously named this same disclosure. Use <InfoHint> to keep click-to-expand behavior; <Tooltip> now provides hover and focus behavior. HTML, Markdown, and agents HTML uses native <details> and <summary> elements. Readers can open the definition with a click, tap, Enter, or Space without JavaScript. The definition is present in the initial HTML even while the disclosure is closed. Markdown writes the label and definition together in ordinary text. An agent can read the explanation without opening a disclosure. Related reading Related topics Often confused with"},{"filters":{"focus":["write"]},"text":"Callouts — Choose a short optional definition or an explanation visible in the reading path. Keyboard shortcuts — Use key styling for shortcuts and a disclosure for optional definitions. Collapsibles — A short definition contains plain text; a collapsible holds longer rich content. Tooltips — Tooltips open on hover or focus; short definitions use native click-to-expand disclosures."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3052,"markdownTokens":693,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.kbd","demo":false,"url":"/author/components/kbd","markdownUrl":"/author/components/kbd.md","title":"Keyboard shortcuts","summary":"Mark up key names and shortcuts inside documentation text.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-code","headings":[{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use <Kbd> to name a key or shortcut in a sentence. Include the action in the sentence; key styling alone does not explain what the shortcut does. Syntax Put each key in its own <Kbd> tag and write any separator as ordinary text. Press < Kbd >⌘</ Kbd > + < Kbd >C</ Kbd > to copy selected text. Press ⌘ + C to copy selected text. <Kbd> takes nonempty plain text and no attributes. It works inside prose, headings, and table cells. HTML, Markdown, and agents HTML renders each key as a semantic <kbd> element. There is no interactive behavior or JavaScript requirement. Markdown keeps the key names as ordinary text. An agent receives the same instruction and shortcut without interpreting the visual key style. Related reading Related topics Short definitions — Use key styling for shortcuts and a disclosure for optional definitions.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Kbd> to name a key or shortcut in a sentence. Include the action in the sentence; key styling alone does not explain what the shortcut does. Syntax Put each key in its own <Kbd> tag and write any separator as ordinary text. Press <Kbd>⌘</Kbd> + <Kbd>C</Kbd> to copy selected text. Press ⌘ + C to copy selected text. <Kbd> takes nonempty plain text and no attributes. It works inside prose, headings, and table cells. HTML, Markdown, and agents HTML renders each key as a semantic <kbd> element. There is no interactive behavior or JavaScript requirement. Markdown keeps the key names as ordinary text. An agent receives the same instruction and shortcut without interpreting the visual key style. Related reading Related topics"},{"filters":{"focus":["write"]},"text":"Short definitions — Use key styling for shortcuts and a disclosure for optional definitions."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1668,"markdownTokens":414,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.math","demo":false,"url":"/author/components/math","markdownUrl":"/author/components/math.md","title":"Math","summary":"Render inline and display LaTeX expressions at build time.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-visuals","headings":[{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"Use <Math> with a literal LaTeX expression. It supports the KaTeX math subset and reports invalid expressions during the build. Energy is < Math expression = \"E=mc^2\" />. < Math display expression = \"c^2=a^2+b^2\" /> Energy is E = m c 2 E=mc^2 . c 2 = a 2 + b 2 c^2=a^2+b^2 expression is required and nonempty. Add the bare display attribute on a block element for centered display math. The component does not parse dollar delimiters in ordinary prose or code fences. Escape quotes in MDX attributes as needed. HTML, Markdown, and agents HTML contains build-time MathML with the source expression as an annotation. The expression remains available to assistive technology without client JavaScript. Markdown keeps inline expressions as code and display expressions in a latex code block. An agent can read the original LaTeX in either form. Check complicated notation with the screen readers your readers use.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Math> with a literal LaTeX expression. It supports the KaTeX math subset and reports invalid expressions during the build. Energy is <Math expression=\"E=mc^2\" />. <Math display expression=\"c^2=a^2+b^2\" /> Energy is SHOALRUNMATH6398e8ebe893aa5192688f4f . SHOALRUNMATH433cb0dd42a1fbe0238724df expression is required and nonempty. Add the bare display attribute on a block element for centered display math. The component does not parse dollar delimiters in ordinary prose or code fences. Escape quotes in MDX attributes as needed. HTML, Markdown, and agents HTML contains build-time MathML with the source expression as an annotation. The expression remains available to assistive technology without client JavaScript. Markdown keeps inline expressions as code and display expressions in a latex code block. An agent can read the original LaTeX in either form. Check complicated notation with the screen readers your readers use."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1616,"markdownTokens":400,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.only","demo":false,"url":"/author/components/only","markdownUrl":"/author/components/only.md","title":"Content for one format","summary":"Use Only to add content to the HTML page or its Markdown twin alone.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"Use <Only> to author content for one output format. Shared material stays outside the blocks; a block can contain an instruction, explanation, example, or link that serves only one version: Shared setup steps appear in both formats. < Only format = \"html\" > Choose a tab below to inspect a response. </ Only > < Only format = \"markdown\" > The response examples follow as labeled sections. </ Only > The example below is live. This HTML page shows the first sentence; its Markdown twin shows the second. The same mechanism can hold a larger section. An HTML section might teach through a visual walkthrough. Its Markdown counterpart can provide file paths and a command sequence for an agent. Each version should give its reader enough to complete the task, and shared product facts should stay consistent. This sentence appears only on the HTML page. HTML, Markdown, and agents An agent that fetches the direct .md URL, or requests this page with Accept: text/markdown on a host that supports content negotiation , receives the shared text and format=\"markdown\" blocks. It does not receive format=\"html\" blocks. For the live example above, the relevant Markdown line is: This sentence appears only in the Markdown twin. The build validates the contents of both blocks, including their links and supported components. <Only> needs block content and exactly one literal format attribute: html or markdown . Dynamic expressions and other values fail the build. Keep facts, warnings, and task steps that both readers need outside <Only> , or provide suitable versions in both formats. You can add or suppress content in either output when that helps its intended reader. Check that each version remains accurate and usable for its task; see Shoalrun's position on shared and format-specific content . The browser search index uses the HTML output, so Markdown-only text is not included in that search. See publishing and agent representations for the full output contract. Related reading Related topics Content negotiation — Write instructions that apply to only the HTML page or only the Markdown twin. Often confused with Tabs — Tabs show alternate views to every reader; Only limits content to the HTML page or its Markdown twin.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Only> to author content for one output format. Shared material stays outside the blocks; a block can contain an instruction, explanation, example, or link that serves only one version: Shared setup steps appear in both formats. <Only format=\"html\"> Choose a tab below to inspect a response. </Only> <Only format=\"markdown\"> The response examples follow as labeled sections. </Only> The example below is live. This HTML page shows the first sentence; its Markdown twin shows the second. The same mechanism can hold a larger section. An HTML section might teach through a visual walkthrough. Its Markdown counterpart can provide file paths and a command sequence for an agent. Each version should give its reader enough to complete the task, and shared product facts should stay consistent. This sentence appears only on the HTML page. HTML, Markdown, and agents An agent that fetches the direct .md URL, or requests this page with Accept: text/markdown on a host that supports content negotiation , receives the shared text and format=\"markdown\" blocks. It does not receive format=\"html\" blocks. For the live example above, the relevant Markdown line is: This sentence appears only in the Markdown twin. The build validates the contents of both blocks, including their links and supported components. <Only> needs block content and exactly one literal format attribute: html or markdown . Dynamic expressions and other values fail the build. Keep facts, warnings, and task steps that both readers need outside <Only> , or provide suitable versions in both formats. You can add or suppress content in either output when that helps its intended reader. Check that each version remains accurate and usable for its task; see Shoalrun's position on shared and format-specific content . The browser search index uses the HTML output, so Markdown-only text is not included in that search. See publishing and agent representations for the full output contract. Related reading Related topics Often confused with"},{"filters":{"focus":["configure"]},"text":"Content negotiation — Write instructions that apply to only the HTML page or only the Markdown twin."},{"filters":{"focus":["write"]},"text":"Tabs — Tabs show alternate views to every reader; Only limits content to the HTML page or its Markdown twin."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3393,"markdownTokens":770,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.progress","demo":false,"url":"/author/components/progress","markdownUrl":"/author/components/progress.md","title":"Progress","summary":"Show a bounded count with a visible label and native progress bar.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"syntax","title":"Syntax"},{"id":"when-to-use-it","title":"When to use it"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"often-confused-with","title":"Often confused with"}],"text":"Use <Progress> for a published count in a tutorial or migration guide. It shows the amount completed as text and as a bar. Update the source and rebuild the site when the shared state changes. Syntax < Progress label = \"Migration tasks\" value = \"3\" max = \"5\" /> Migration tasks: 3 of 5 complete 3 of 5 Attribute Required Meaning label Yes Nonempty name shown beside the count and used as the bar's accessible name. value Yes A number from zero through max . max Yes A number greater than zero. <Progress> is a block element without a body. All three attributes must be literal values. The build rejects a value outside the range or a maximum of zero. When to use it Use this component when a count has a known maximum, such as 3 of 5 migration tasks complete. It is a read-only display: readers cannot mark a task complete or move the bar. For a process with named stages and descriptions, use a timeline . HTML, Markdown, and agents HTML shows “Migration tasks: 3 of 5 complete” alongside a native <progress> element. The text carries the count even without CSS or color. There is no JavaScript behavior or keyboard control. Markdown states the same label and count in a sentence. An agent does not need to estimate completion from the bar. Related reading Often confused with Timelines — Progress reports a bounded count; a timeline names and describes stages.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Progress> for a published count in a tutorial or migration guide. It shows the amount completed as text and as a bar. Update the source and rebuild the site when the shared state changes. Syntax <Progress label=\"Migration tasks\" value=\"3\" max=\"5\" /> Migration tasks: 3 of 5 complete 3 of 5 Attribute Required Meaning label Yes Nonempty name shown beside the count and used as the bar's accessible name. value Yes A number from zero through max . max Yes A number greater than zero. <Progress> is a block element without a body. All three attributes must be literal values. The build rejects a value outside the range or a maximum of zero. When to use it Use this component when a count has a known maximum, such as 3 of 5 migration tasks complete. It is a read-only display: readers cannot mark a task complete or move the bar. For a process with named stages and descriptions, use a timeline . HTML, Markdown, and agents HTML shows “Migration tasks: 3 of 5 complete” alongside a native <progress> element. The text carries the count even without CSS or color. There is no JavaScript behavior or keyboard control. Markdown states the same label and count in a sentence. An agent does not need to estimate completion from the bar. Related reading Often confused with"},{"filters":{"focus":["write"]},"text":"Timelines — Progress reports a bounded count; a timeline names and describes stages."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2568,"markdownTokens":573,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.related-reading","demo":false,"url":"/author/components/related-reading","markdownUrl":"/author/components/related-reading.md","title":"RelatedReading","summary":"Display authored relationships as links or cards.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-navigation","headings":[{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"}],"text":"<RelatedReading> presents connections declared in the central relationships config. Use it for prerequisites, next steps, references, related topics, and distinctions that need a reason. Syntax < RelatedReading relation = \"next-step\" /> Attribute Meaning relation Select one relationship type; omit for all types grouped by purpose. relatedTo Source document ID; defaults to this page. It must be available in the current publication. layout list by default, or cards . Card layout includes card overrides, summaries, and reasons. empty Text for no matches; default is “No matching documents.” Empty groups are omitted. This is a standalone empty element. A selected relation has no automatic heading, so give that view a page heading when useful. See related reading for config fields, relationship types, and ordering. HTML, Markdown, and agents With layout=\"list\" , HTML and Markdown show links with the relationship reasons; layout=\"cards\" adds previews. Only connections whose endpoints are public in the current publication appear. Both layouts export ordinary links and reasons to Markdown, with .md destinations, so agents can follow the same reading paths. The HTML wrapper has the related-reading class for project CSS . When a top-level view describes the current page, section Markdown also carries its prerequisite and next-step links if they would otherwise be omitted. A Page reading path label explains the scope. Nested views and views with another relatedTo source stay in their original context. See section reading paths for boundaries and size rules. Related reading Read first Related reading — Declare the relationships this component displays.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<RelatedReading> presents connections declared in the central relationships config. Use it for prerequisites, next steps, references, related topics, and distinctions that need a reason. Syntax <RelatedReading relation=\"next-step\" /> Attribute Meaning relation Select one relationship type; omit for all types grouped by purpose. relatedTo Source document ID; defaults to this page. It must be available in the current publication. layout list by default, or cards . Card layout includes card overrides, summaries, and reasons. empty Text for no matches; default is “No matching documents.” Empty groups are omitted. This is a standalone empty element. A selected relation has no automatic heading, so give that view a page heading when useful. See related reading for config fields, relationship types, and ordering. HTML, Markdown, and agents With layout=\"list\" , HTML and Markdown show links with the relationship reasons; layout=\"cards\" adds previews. Only connections whose endpoints are public in the current publication appear. Both layouts export ordinary links and reasons to Markdown, with .md destinations, so agents can follow the same reading paths. The HTML wrapper has the related-reading class for project CSS . When a top-level view describes the current page, section Markdown also carries its prerequisite and next-step links if they would otherwise be omitted. A Page reading path label explains the scope. Nested views and views with another relatedTo source stay in their original context. See section reading paths for boundaries and size rules. Related reading Read first"},{"filters":{"focus":["write"]},"text":"Related reading — Declare the relationships this component displays."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2951,"markdownTokens":646,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.steps","demo":false,"url":"/author/components/steps","markdownUrl":"/author/components/steps.md","title":"Steps","summary":"Show a short procedure as numbered steps with full instructions in both outputs.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"create-a-page","title":"Create a page"},{"id":"build-the-site","title":"Build the site"},{"id":"choose-a-style","title":"Choose a style"},{"id":"prepare","title":"Prepare"},{"id":"publish","title":"Publish"},{"id":"prepare-2","title":"Prepare"},{"id":"publish-2","title":"Publish"},{"id":"step-headings-and-the-page-outline","title":"Step headings and the page outline"},{"id":"install","title":"Install"},{"id":"configure","title":"Configure"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"Use <Steps> when each part of a procedure needs a title and supporting content. For a simple sequence with no step titles, an ordinary Markdown numbered list is enough. For code that changes between steps, use a Walkthrough . < Steps > < Step title = \"Create a page\" > Add ` content/first-page.mdx ` with frontmatter and a short body. </ Step > < Step title = \"Build the site\" > Run ` shoalrun build docs.config.yaml dist ` , then open the output. </ Step > </ Steps > Create a page Add content/first-page.mdx with frontmatter and a short body. Build the site Run shoalrun build docs.config.yaml dist , then open the output. Choose a style rail is the default: numbered circles and a connecting line keep a longer procedure easy to scan. Use cards to separate steps with substantial examples or decisions. Use plain for a quiet numbered list. The style changes HTML presentation; all three produce the same complete ordered list in Markdown. < Steps variant = \"cards\" > < Step title = \"Prepare\" icon = \"file-check-2\" >Check the draft page.</ Step > < Step title = \"Publish\" icon = \"upload\" >Build and deploy the site.</ Step > </ Steps > Prepare Check the draft page. Publish Build and deploy the site. < Steps variant = \"plain\" > < Step title = \"Prepare\" >Check the draft page.</ Step > < Step title = \"Publish\" >Build and deploy the site.</ Step > </ Steps > Prepare Check the draft page. Publish Build and deploy the site. Attribute Where Meaning variant Steps rail (default), cards , or plain . toc Steps ignore (default) or include . Controls whether step headings appear in the page table of contents. headingLevel Steps Heading level 2 (default) through 6 for every step title in the group. title Step Required, nonempty literal title. icon Step Optional lowercase Lucide name. Decorative beside the title in HTML. <Steps> accepts one or more direct <Step> children with nonempty bodies. The body accepts ordinary Markdown and supported components. The same <Step> tag is also used in Walkthrough . Its parent selects a separate component contract: Parent <Step> attributes Output <Steps> title , optional icon Numbered procedure with configurable heading level and TOC behavior. <Walkthrough> title , optional code source and highlighting attributes Code walkthrough with synchronized explanations. Use the attributes documented for the parent you are writing. The two forms do not share rendering or settings. Step headings and the page outline Each step title renders as a real heading with an anchor ID. It defaults to <h2> ; set headingLevel to match the surrounding page structure. Step headings are omitted from the page table of contents by default, keeping the outline focused when a page contains several procedures. Set toc=\"include\" when readers should be able to jump to individual steps: < Steps toc = \"include\" headingLevel = \"3\" > < Step title = \"Install\" >Install the package.</ Step > < Step title = \"Configure\" >Add the configuration.</ Step > </ Steps > Install Install the package. Configure Add the configuration. The page's tocDepth frontmatter still applies. For example, tocDepth: 2 omits the level-three steps above, while tocDepth: 0 hides the whole outline. Markdown keeps an ordered list with headings at the chosen level and complete bodies. HTML, Markdown, and agents HTML renders a semantic ordered list. Numbers, titles, and full bodies are visible without JavaScript or animation, including when CSS is unavailable. An icon never carries the only meaning. There are no controls, so ordinary link and code-block keyboard behavior applies. Markdown keeps the complete ordered list and each step heading at the chosen level. An agent receives every instruction in sequence without needing the visual rail or cards.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Steps> when each part of a procedure needs a title and supporting content. For a simple sequence with no step titles, an ordinary Markdown numbered list is enough. For code that changes between steps, use a Walkthrough . <Steps> <Step title=\"Create a page\"> Add `content/first-page.mdx` with frontmatter and a short body. </Step> <Step title=\"Build the site\"> Run `shoalrun build docs.config.yaml dist`, then open the output. </Step> </Steps> Create a page Add content/first-page.mdx with frontmatter and a short body. Build the site Run shoalrun build docs.config.yaml dist , then open the output. Choose a style rail is the default: numbered circles and a connecting line keep a longer procedure easy to scan. Use cards to separate steps with substantial examples or decisions. Use plain for a quiet numbered list. The style changes HTML presentation; all three produce the same complete ordered list in Markdown. <Steps variant=\"cards\"> <Step title=\"Prepare\" icon=\"file-check-2\">Check the draft page.</Step> <Step title=\"Publish\" icon=\"upload\">Build and deploy the site.</Step> </Steps> Prepare Check the draft page. Publish Build and deploy the site. <Steps variant=\"plain\"> <Step title=\"Prepare\">Check the draft page.</Step> <Step title=\"Publish\">Build and deploy the site.</Step> </Steps> Prepare Check the draft page. Publish Build and deploy the site. Attribute Where Meaning variant Steps rail (default), cards , or plain . toc Steps ignore (default) or include . Controls whether step headings appear in the page table of contents. headingLevel Steps Heading level 2 (default) through 6 for every step title in the group. title Step Required, nonempty literal title. icon Step Optional lowercase Lucide name. Decorative beside the title in HTML. <Steps> accepts one or more direct <Step> children with nonempty bodies. The body accepts ordinary Markdown and supported components. The same <Step> tag is also used in Walkthrough . Its parent selects a separate component contract: Parent <Step> attributes Output <Steps> title , optional icon Numbered procedure with configurable heading level and TOC behavior. <Walkthrough> title , optional code source and highlighting attributes Code walkthrough with synchronized explanations. Use the attributes documented for the parent you are writing. The two forms do not share rendering or settings. Step headings and the page outline Each step title renders as a real heading with an anchor ID. It defaults to <h2> ; set headingLevel to match the surrounding page structure. Step headings are omitted from the page table of contents by default, keeping the outline focused when a page contains several procedures. Set toc=\"include\" when readers should be able to jump to individual steps: <Steps toc=\"include\" headingLevel=\"3\"> <Step title=\"Install\">Install the package.</Step> <Step title=\"Configure\">Add the configuration.</Step> </Steps> Install Install the package. Configure Add the configuration. The page's tocDepth frontmatter still applies. For example, tocDepth: 2 omits the level-three steps above, while tocDepth: 0 hides the whole outline. Markdown keeps an ordered list with headings at the chosen level and complete bodies. HTML, Markdown, and agents HTML renders a semantic ordered list. Numbers, titles, and full bodies are visible without JavaScript or animation, including when CSS is unavailable. An icon never carries the only meaning. There are no controls, so ordinary link and code-block keyboard behavior applies. Markdown keeps the complete ordered list and each step heading at the chosen level. An agent receives every instruction in sequence without needing the visual rail or cards."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5597,"markdownTokens":1199,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.table","demo":false,"url":"/author/components/tables","markdownUrl":"/author/components/tables.md","title":"Tables","summary":"Add optional filtering and sticky headings to long HTML tables while preserving every row in Markdown.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-visuals","headings":[{"id":"try-the-controls","title":"Try the controls"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"Ordinary Markdown tables work without a component. For a long table, wrap one table in <Table> to add a filter box, sticky column headings, or both in HTML: < Table filter sticky > | Name | Environment | Status | | --- | --- | --- | | Accounts | Production | Enabled | | Invoices | Sandbox | Disabled | </ Table > filter and sticky are bare boolean attributes. Use either one alone or both. <Table> takes exactly one Markdown table and no other content. Its complete table, without controls, appears in the Markdown twin . Try the controls Filter this table by a name, environment, or status. Several words must all occur in a row; matching ignores case. Press Escape in the filter box to clear it. Scroll inside the table to keep the headings visible. Filter rows Name Environment Status Accounts Production Enabled Billing Sandbox Enabled Catalog Production Disabled Delivery Sandbox Disabled Events Production Enabled Files Sandbox Enabled Groups Production Disabled History Sandbox Enabled Invoices Production Enabled Jobs Sandbox Disabled Keys Production Enabled Limits Sandbox Enabled Metrics Production Disabled Notes Sandbox Enabled Orders Production Enabled Profiles Sandbox Disabled HTML, Markdown, and agents The filter needs JavaScript. Without it, the filter field stays hidden and all rows remain visible. Sticky headings use CSS and still work without JavaScript. On narrow screens the table scrolls horizontally. Keyboard users can focus the scrollable table region. The Markdown twin contains all 16 rows as a regular table. Agents and text-only readers do not need the filter to find a row. Use an ordinary Markdown table when these HTML controls are unnecessary.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Ordinary Markdown tables work without a component. For a long table, wrap one table in <Table> to add a filter box, sticky column headings, or both in HTML: <Table filter sticky> | Name | Environment | Status | | --- | --- | --- | | Accounts | Production | Enabled | | Invoices | Sandbox | Disabled | </Table> filter and sticky are bare boolean attributes. Use either one alone or both. <Table> takes exactly one Markdown table and no other content. Its complete table, without controls, appears in the Markdown twin . Try the controls Filter this table by a name, environment, or status. Several words must all occur in a row; matching ignores case. Press Escape in the filter box to clear it. Scroll inside the table to keep the headings visible. Filter rows Name Environment Status Accounts Production Enabled Billing Sandbox Enabled Catalog Production Disabled Delivery Sandbox Disabled Events Production Enabled Files Sandbox Enabled Groups Production Disabled History Sandbox Enabled Invoices Production Enabled Jobs Sandbox Disabled Keys Production Enabled Limits Sandbox Enabled Metrics Production Disabled Notes Sandbox Enabled Orders Production Enabled Profiles Sandbox Disabled HTML, Markdown, and agents The filter needs JavaScript. Without it, the filter field stays hidden and all rows remain visible. Sticky headings use CSS and still work without JavaScript. On narrow screens the table scrolls horizontally. Keyboard users can focus the scrollable table region. The Markdown twin contains all 16 rows as a regular table. Agents and text-only readers do not need the filter to find a row. Use an ordinary Markdown table when these HTML controls are unnecessary."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2762,"markdownTokens":655,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.tabs","demo":false,"url":"/author/components/tabs","markdownUrl":"/author/components/tabs.md","title":"Tabs","summary":"Group alternate views while retaining every view in Markdown.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"syntax","title":"Syntax"},{"id":"keep-the-height-steady","title":"Keep the height steady"},{"id":"synchronize-related-examples","title":"Synchronize related examples"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"often-confused-with","title":"Often confused with"}],"text":"<Tabs> presents alternate views, such as two output formats. Use it only when the choices are truly alternatives; a normal heading sequence is easier to read when readers need every section. Syntax < Tabs label = \"Output format\" > < Tab label = \"HTML\" > The page has navigation and controls. </ Tab > < Tab label = \"Markdown\" > The page keeps the content as text. </ Tab > </ Tabs > HTML Markdown HTML The page has navigation and controls. Markdown The page keeps the content as text. Element Attribute Meaning Tabs label Required literal name for the whole group, used by assistive technology. Tabs equalHeight Optional bare attribute. Keeps the group as tall as its tallest tab. See Keep the height steady . Tabs sync Optional group name for matching selections across tab groups on this page. Tab value Optional matching key; defaults to the tab label. Values must be unique within a group. Tab label Required nonempty literal name for its control and Markdown heading. Use at least two nonempty, direct Tab children. A Tab cannot stand alone. Other direct children and attributes fail the build. Keep the height steady By default, the group is as tall as its selected tab. When a reader switches between a short tab and a long one, the page jumps. Add equalHeight to size the group to its tallest tab instead. The content below the group stays put. < Tabs label = \"Output format\" equalHeight > The setting changes the HTML only. Without JavaScript, all panels stay visible. The Markdown twin is the same with or without it. Use it when your tabs differ in length. If one tab is much longer than the rest, leave it off, because every shorter tab then shows blank space. Synchronize related examples Give related groups the same sync name. Choosing a tab updates other groups with a matching value , or a matching label when no value is supplied. Matching is case-sensitive. A group without that choice keeps its current selection; groups without sync stay independent. < Tabs label = \"Install a client\" sync = \"language\" > < Tab label = \"JavaScript\" value = \"js\" > npm install example-client </ Tab > < Tab label = \"Python\" value = \"py\" > pip install example-client </ Tab > </ Tabs > These two examples share a selection. Try choosing Python in either group: JavaScript Python JavaScript Install the JavaScript client with npm. Python Install the Python client with pip. JavaScript Python JavaScript Import the JavaScript client in your application. Python Import the Python client in your application. sync names use up to 64 letters, numbers, dashes, or underscores, starting with a letter or number. Synchronization follows reader choices within this page; it does not store a cross-page preference or move focus to another group. Markdown still includes every tab. HTML, Markdown, and agents HTML contains every panel before scripts run. Without JavaScript, all panels remain visible. With JavaScript, Left and Right arrows switch tabs, while Home and End choose the first and last. The build replaces the tab controls with ordinary Markdown sections. Each Tab label becomes a level-three heading, followed by that tab's complete body, in source order. The outer Tabs label is for the HTML control and does not appear in Markdown. The first example on this page renders like this in the Markdown twin: ### HTML The page has navigation and controls. ### Markdown The page keeps the content as text. An agent reading the .md page gets every alternative without choosing a tab. Markdown inside each body stays Markdown; supported MDX components expand to their own Markdown forms during the build. Each Tab body accepts ordinary Markdown, including lists, links, and fenced code, plus supported MDX components such as Callout , DocLink , and Collapsible . Put other content inside a Tab body. Dynamic MDX expressions and unknown components are not supported. Related reading Often confused with Collapsibles — A collapsible hides optional detail behind one summary; tabs switch between alternate views of the same content. Content for one format — Tabs show alternate views to every reader; Only limits content to the HTML page or its Markdown twin.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"<Tabs> presents alternate views, such as two output formats. Use it only when the choices are truly alternatives; a normal heading sequence is easier to read when readers need every section. Syntax <Tabs label=\"Output format\"> <Tab label=\"HTML\"> The page has navigation and controls. </Tab> <Tab label=\"Markdown\"> The page keeps the content as text. </Tab> </Tabs> HTML Markdown HTML The page has navigation and controls. Markdown The page keeps the content as text. Element Attribute Meaning Tabs label Required literal name for the whole group, used by assistive technology. Tabs equalHeight Optional bare attribute. Keeps the group as tall as its tallest tab. See Keep the height steady . Tabs sync Optional group name for matching selections across tab groups on this page. Tab value Optional matching key; defaults to the tab label. Values must be unique within a group. Tab label Required nonempty literal name for its control and Markdown heading. Use at least two nonempty, direct Tab children. A Tab cannot stand alone. Other direct children and attributes fail the build. Keep the height steady By default, the group is as tall as its selected tab. When a reader switches between a short tab and a long one, the page jumps. Add equalHeight to size the group to its tallest tab instead. The content below the group stays put. <Tabs label=\"Output format\" equalHeight> The setting changes the HTML only. Without JavaScript, all panels stay visible. The Markdown twin is the same with or without it. Use it when your tabs differ in length. If one tab is much longer than the rest, leave it off, because every shorter tab then shows blank space. Synchronize related examples Give related groups the same sync name. Choosing a tab updates other groups with a matching value , or a matching label when no value is supplied. Matching is case-sensitive. A group without that choice keeps its current selection; groups without sync stay independent. <Tabs label=\"Install a client\" sync=\"language\"> <Tab label=\"JavaScript\" value=\"js\"> npm install example-client </Tab> <Tab label=\"Python\" value=\"py\"> pip install example-client </Tab> </Tabs> These two examples share a selection. Try choosing Python in either group: JavaScript Python JavaScript Install the JavaScript client with npm. Python Install the Python client with pip. JavaScript Python JavaScript Import the JavaScript client in your application. Python Import the Python client in your application. sync names use up to 64 letters, numbers, dashes, or underscores, starting with a letter or number. Synchronization follows reader choices within this page; it does not store a cross-page preference or move focus to another group. Markdown still includes every tab. HTML, Markdown, and agents HTML contains every panel before scripts run. Without JavaScript, all panels remain visible. With JavaScript, Left and Right arrows switch tabs, while Home and End choose the first and last. The build replaces the tab controls with ordinary Markdown sections. Each Tab label becomes a level-three heading, followed by that tab's complete body, in source order. The outer Tabs label is for the HTML control and does not appear in Markdown. The first example on this page renders like this in the Markdown twin: ### HTML The page has navigation and controls. ### Markdown The page keeps the content as text. An agent reading the .md page gets every alternative without choosing a tab. Markdown inside each body stays Markdown; supported MDX components expand to their own Markdown forms during the build. Each Tab body accepts ordinary Markdown, including lists, links, and fenced code, plus supported MDX components such as Callout , DocLink , and Collapsible . Put other content inside a Tab body. Dynamic MDX expressions and unknown components are not supported. Related reading Often confused with"},{"filters":{"focus":["write"]},"text":"Collapsibles — A collapsible hides optional detail behind one summary; tabs switch between alternate views of the same content. Content for one format — Tabs show alternate views to every reader; Only limits content to the HTML page or its Markdown twin."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5629,"markdownTokens":1191,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.timeline","demo":false,"url":"/author/components/timeline","markdownUrl":"/author/components/timeline.md","title":"Timelines","summary":"Show the current milestone and overall progress through a process.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-procedures","headings":[{"id":"when-to-use-it","title":"When to use it"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"}],"text":"Use <Timeline> to show progress through an ordered set of milestones. Set current to the id of the milestone in progress. Earlier milestones become complete; later milestones become upcoming. This is a read-only progress display . Readers can see the current stage, but they cannot mark milestones complete or move the bar. Update current in the source and rebuild the site when the shared process advances. Links inside milestone content work normally. When to use it Show which stage a product launch or feature rollout has reached. Show where a proposal sits in a draft, review, and approval process. Show progress through a published migration or deprecation plan. An optional simulation mode could let readers move through the milestones to see each stage of a process. The current component shows only the published state; it has no next, previous, or reset controls. < Timeline current = \"review\" > < Milestone id = \"draft\" title = \"Draft\" > Write the first version of the guide. </ Milestone > < Milestone id = \"review\" title = \"Review\" > Check the guide with the team. </ Milestone > < Milestone id = \"publish\" title = \"Publish\" > Make the approved guide available to readers. </ Milestone > </ Timeline > 1 of 3 milestones complete · Current: Review Draft Complete Write the first version of the guide. Review Current Check the guide with the team. Publish Upcoming Make the approved guide available to readers. The bar counts completed milestones. In this example it shows 1 of 3 complete; Review is still in progress. The current milestone also has a visible status label, and the HTML list marks it with aria-current=\"step\" . The bar uses a native <progress> element with an accessible name. Markdown includes the same progress summary and status labels. Attribute Where Required Meaning current Timeline Yes The ID of the milestone in progress. id Milestone Yes A unique ID using lowercase letters, numbers, and hyphens. Start with a letter. title Milestone Yes Visible milestone title. date Milestone No A real date in YYYY-MM-DD form. Rendered as <time> in HTML. Add one or more direct <Milestone> children in process order. Each milestone needs body content and can contain ordinary Markdown and supported components. HTML, Markdown, and agents HTML shows the progress bar and milestone list with visible status labels; the current item has aria-current=\"step\" . Markdown includes the same progress summary, status labels, and full milestone bodies. An agent can identify the current stage and read every milestone without interpreting the bar.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Timeline> to show progress through an ordered set of milestones. Set current to the id of the milestone in progress. Earlier milestones become complete; later milestones become upcoming. This is a read-only progress display . Readers can see the current stage, but they cannot mark milestones complete or move the bar. Update current in the source and rebuild the site when the shared process advances. Links inside milestone content work normally. When to use it Show which stage a product launch or feature rollout has reached. Show where a proposal sits in a draft, review, and approval process. Show progress through a published migration or deprecation plan. An optional simulation mode could let readers move through the milestones to see each stage of a process. The current component shows only the published state; it has no next, previous, or reset controls. <Timeline current=\"review\"> <Milestone id=\"draft\" title=\"Draft\"> Write the first version of the guide. </Milestone> <Milestone id=\"review\" title=\"Review\"> Check the guide with the team. </Milestone> <Milestone id=\"publish\" title=\"Publish\"> Make the approved guide available to readers. </Milestone> </Timeline> 1 of 3 milestones complete · Current: Review Draft Complete Write the first version of the guide. Review Current Check the guide with the team. Publish Upcoming Make the approved guide available to readers. The bar counts completed milestones. In this example it shows 1 of 3 complete; Review is still in progress. The current milestone also has a visible status label, and the HTML list marks it with aria-current=\"step\" . The bar uses a native <progress> element with an accessible name. Markdown includes the same progress summary and status labels. Attribute Where Required Meaning current Timeline Yes The ID of the milestone in progress. id Milestone Yes A unique ID using lowercase letters, numbers, and hyphens. Start with a letter. title Milestone Yes Visible milestone title. date Milestone No A real date in YYYY-MM-DD form. Rendered as <time> in HTML. Add one or more direct <Milestone> children in process order. Each milestone needs body content and can contain ordinary Markdown and supported components. HTML, Markdown, and agents HTML shows the progress bar and milestone list with visible status labels; the current item has aria-current=\"step\" . Markdown includes the same progress summary, status labels, and full milestone bodies. An agent can identify the current stage and read every milestone without interpreting the bar."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3770,"markdownTokens":812,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.tooltip","demo":false,"url":"/author/components/tooltips","markdownUrl":"/author/components/tooltips.md","title":"Tooltips","summary":"Show brief supporting text on hover or keyboard focus, with a tap option for touch readers.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-prose","headings":[{"id":"syntax","title":"Syntax"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"often-confused-with","title":"Often confused with"}],"text":"Use <Tooltip> for brief supporting text beside a term. The text appears when readers hover over or focus the label. Use Short definitions for click-to-expand explanations, or a callout for warnings and instructions that belong in the reading path. Syntax Compare the < Tooltip label = \"build digest\" >A fingerprint of the published build's content.</ Tooltip > before refreshing your cache. Compare the build digest : A fingerprint of the published build's content. before refreshing your cache. Attribute Required Meaning label Yes Nonempty text shown on the focusable trigger. The body must be one brief plain-text explanation. Links, formatted text, multiple paragraphs, and other components are unsupported. A tooltip may appear inline in a paragraph or as a standalone block. <Tooltip> previously aliased <InfoHint> . Use <InfoHint> for the original native disclosure behavior. HTML, Markdown, and agents With JavaScript, the label becomes a button linked to its explanation through aria-describedby . Hovering or focusing the label opens a popup with role=\"tooltip\" . Readers can move the pointer over the popup without closing it. Escape dismisses it while focus stays on the label. Moving focus and the pointer away closes it. Touch readers can tap the label to open or close it, or tap elsewhere to dismiss it. The popup contains no focusable controls. Use an ordinary link or disclosure when readers need to interact with the explanation. Keep tooltips supplementary; essential warnings, choices, and instructions belong in visible page content. Without JavaScript, the label and explanation remain visible together in the page. Markdown includes the label and full explanation as ordinary text, so agents do not need hover, focus, or browser scripts. For the inline example above, the Markdown twin reads: Compare the build digest (A fingerprint of the published build's content.) before refreshing your cache. The interaction follows the WAI tooltip pattern and its guidance on content shown on hover or focus . Related reading Often confused with Short definitions — Tooltips open on hover or focus; short definitions use native click-to-expand disclosures.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Tooltip> for brief supporting text beside a term. The text appears when readers hover over or focus the label. Use Short definitions for click-to-expand explanations, or a callout for warnings and instructions that belong in the reading path. Syntax Compare the <Tooltip label=\"build digest\">A fingerprint of the published build's content.</Tooltip> before refreshing your cache. Compare the build digest : A fingerprint of the published build's content. before refreshing your cache. Attribute Required Meaning label Yes Nonempty text shown on the focusable trigger. The body must be one brief plain-text explanation. Links, formatted text, multiple paragraphs, and other components are unsupported. A tooltip may appear inline in a paragraph or as a standalone block. <Tooltip> previously aliased <InfoHint> . Use <InfoHint> for the original native disclosure behavior. HTML, Markdown, and agents With JavaScript, the label becomes a button linked to its explanation through aria-describedby . Hovering or focusing the label opens a popup with role=\"tooltip\" . Readers can move the pointer over the popup without closing it. Escape dismisses it while focus stays on the label. Moving focus and the pointer away closes it. Touch readers can tap the label to open or close it, or tap elsewhere to dismiss it. The popup contains no focusable controls. Use an ordinary link or disclosure when readers need to interact with the explanation. Keep tooltips supplementary; essential warnings, choices, and instructions belong in visible page content. Without JavaScript, the label and explanation remain visible together in the page. Markdown includes the label and full explanation as ordinary text, so agents do not need hover, focus, or browser scripts. For the inline example above, the Markdown twin reads: Compare the build digest (A fingerprint of the published build's content.) before refreshing your cache. The interaction follows the WAI tooltip pattern and its guidance on content shown on hover or focus . Related reading Often confused with"},{"filters":{"focus":["write"]},"text":"Short definitions — Tooltips open on hover or focus; short definitions use native click-to-expand disclosures."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3415,"markdownTokens":757,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.component.walkthrough","demo":false,"url":"/author/components/walkthroughs","markdownUrl":"/author/components/walkthroughs.md","title":"Walkthroughs","summary":"Build code tutorials that explain code one step at a time, with a scrolling pane in HTML and every step in Markdown.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-code","headings":[{"id":"build-up-code","title":"Build up code"},{"id":"explain-one-file","title":"Explain one file"},{"id":"take-code-from-a-file","title":"Take code from a file"},{"id":"choose-a-layout","title":"Choose a layout"},{"id":"attributes","title":"Attributes"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use <Walkthrough> to explain code step by step. Each step pairs an explanation with code built up across steps or read from a project file. When there is room for two columns, explanations scroll on the left and code stays on the right. Scrolling or selecting a step updates the code pane. At either end, scrolling continues through the page. On narrower screens, each step shows its explanation and code in order. The spotlight layout uses step buttons instead of a scroller. Code that stays the same between steps slides to its new position, so readers can follow the changes. Use a walkthrough when readers build up code or study one file in parts. For steps without code, use an ordinary numbered list. Build up code In the default mode, each <Step> has an explanation and can end with one code fence. Give each step the complete code at that point, not only the new lines. highlight picks lines in the step's code to emphasize. MDX source: build up code This source defines the interactive example below. < Walkthrough title = \"Verify a webhook\" > < Step title = \"Read the raw body\" > Signatures cover the exact bytes, so read the body as text. ``` ts export async function handler (request : Request ) { const body = await request .text (); return new Response ( 'ok' ); } ``` </ Step > < Step title = \"Check the signature\" highlight = \"3-5\" > Compare the header with a signature of the body. ``` ts export async function handler (request : Request ) { const body = await request .text (); const signature = request . headers .get ( 'x-signature' ); if ( ! verify (body , signature)) { return new Response ( 'invalid signature' , { status : 401 }); } return new Response ( 'ok' ); } ``` </ Step > </ Walkthrough > Verify a webhook Step 1 Read the raw body Signatures cover the exact bytes, so read the body as text. Parsing JSON first can change spacing and key order. export async function handler ( request : Request ) { const body = await request . text ( ) ; return new Response ( ' ok ' ) ; } Step 2 Check the signature Compare the signature header with a signature of the body. Reject the request before doing any work. export async function handler ( request : Request ) { const body = await request . text ( ) ; const signature = request . headers . get ( ' x - signature ' ) ; if ( ! verify ( body , signature ) ) { return new Response ( ' invalid signature ' , { status : 401 } ) ; } return new Response ( ' ok ' ) ; } Step 3 Parse the event Parse the body after the check passes. The event type decides what happens next. export async function handler ( request : Request ) { const body = await request . text ( ) ; const signature = request . headers . get ( ' x - signature ' ) ; if ( ! verify ( body , signature ) ) { return new Response ( ' invalid signature ' , { status : 401 } ) ; } const event = JSON . parse ( body ) ; await route ( event . type , event . data ) ; return new Response ( ' ok ' ) ; } Step 4 Acknowledge quickly Queue slow work and answer at once. Senders retry requests that time out. export async function handler ( request : Request ) { const body = await request . text ( ) ; const signature = request . headers . get ( ' x - signature ' ) ; if ( ! verify ( body , signature ) ) { return new Response ( ' invalid signature ' , { status : 401 } ) ; } const event = JSON . parse ( body ) ; await queue . send ( { type : event . type , data : event . data } ) ; return new Response ( null , { status : 202 } ) ; } Explain one file Put one code fence directly inside <Walkthrough> , before the steps, to explain a single file. Steps then have no code of their own. Each step's highlight picks the lines it explains. MDX source: explain one file This source defines the interactive example below. < Walkthrough title = \"Read a retry policy\" > ``` yaml title=\"retry.yaml\" retry : attempts : 5 backoff : exponential initialDelay : 2s maxDelay : 5m ``` < Step title = \"Set the number of attempts\" highlight = \"2\" > Five attempts cover most short outages. </ Step > < Step title = \"Choose the delay\" highlight = \"3-5\" > Each retry waits twice as long, from two seconds up to five minutes. </ Step > </ Walkthrough > Read a retry policy retry.yaml retry : attempts : 5 backoff : exponential initialDelay : 2s maxDelay : 5m retryOn : - 429 - 503 - timeout deadLetter : queue : webhooks - failed keep : 14d Step 1 Set the number of attempts Five attempts cover most short outages without hiding a real failure. Line 2 Step 2 Choose the delay Each retry waits twice as long as the one before, from two seconds up to five minutes. Lines 3–5 Step 3 Pick what to retry Retry rate limits, unavailable services, and timeouts. Other errors fail at once, because retrying won't fix them. Lines 6–9 Step 4 Keep failures Requests that use every attempt go to a separate queue for 14 days, so you can replay them. Lines 10–12 Take code from a file Code in a fence can drift from the code your project ru","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use <Walkthrough> to explain code step by step. Each step pairs an explanation with code built up across steps or read from a project file. When there is room for two columns, explanations scroll on the left and code stays on the right. Scrolling or selecting a step updates the code pane. At either end, scrolling continues through the page. On narrower screens, each step shows its explanation and code in order. The spotlight layout uses step buttons instead of a scroller. Code that stays the same between steps slides to its new position, so readers can follow the changes. Use a walkthrough when readers build up code or study one file in parts. For steps without code, use an ordinary numbered list. Build up code In the default mode, each <Step> has an explanation and can end with one code fence. Give each step the complete code at that point, not only the new lines. highlight picks lines in the step's code to emphasize. MDX source: build up code This source defines the interactive example below. <Walkthrough title=\"Verify a webhook\"> <Step title=\"Read the raw body\"> Signatures cover the exact bytes, so read the body as text. ```ts export async function handler(request: Request) { const body = await request.text(); return new Response('ok'); } ``` </Step> <Step title=\"Check the signature\" highlight=\"3-5\"> Compare the header with a signature of the body. ```ts export async function handler(request: Request) { const body = await request.text(); const signature = request.headers.get('x-signature'); if (!verify(body, signature)) { return new Response('invalid signature', { status: 401 }); } return new Response('ok'); } ``` </Step> </Walkthrough> Verify a webhook Step 1 Read the raw body Signatures cover the exact bytes, so read the body as text. Parsing JSON first can change spacing and key order. export async function handler(request: Request) { const body = await request.text(); return new Response('ok'); } Step 2 Check the signature Compare the signature header with a signature of the body. Reject the request before doing any work. export async function handler(request: Request) { const body = await request.text(); const signature = request.headers.get('x-signature'); if (!verify(body, signature)) { return new Response('invalid signature', { status: 401 }); } return new Response('ok'); } Step 3 Parse the event Parse the body after the check passes. The event type decides what happens next. export async function handler(request: Request) { const body = await request.text(); const signature = request.headers.get('x-signature'); if (!verify(body, signature)) { return new Response('invalid signature', { status: 401 }); } const event = JSON.parse(body); await route(event.type, event.data); return new Response('ok'); } Step 4 Acknowledge quickly Queue slow work and answer at once. Senders retry requests that time out. export async function handler(request: Request) { const body = await request.text(); const signature = request.headers.get('x-signature'); if (!verify(body, signature)) { return new Response('invalid signature', { status: 401 }); } const event = JSON.parse(body); await queue.send({ type: event.type, data: event.data }); return new Response(null, { status: 202 }); } Explain one file Put one code fence directly inside <Walkthrough> , before the steps, to explain a single file. Steps then have no code of their own. Each step's highlight picks the lines it explains. MDX source: explain one file This source defines the interactive example below. <Walkthrough title=\"Read a retry policy\"> ```yaml title=\"retry.yaml\" retry: attempts: 5 backoff: exponential initialDelay: 2s maxDelay: 5m ``` <Step title=\"Set the number of attempts\" highlight=\"2\"> Five attempts cover most short outages. </Step> <Step title=\"Choose the delay\" highlight=\"3-5\"> Each retry waits twice as long, from two seconds up to five minutes. </Step> </Walkthrough> Read a retry policy retry: attempts: 5 backoff: exponential initialDelay: 2s maxDelay: 5m retryOn: - 429 - 503 - timeout deadLetter: queue: webhooks-failed keep: 14d Step 1 Set the number of attempts Five attempts cover most short outages without hiding a real failure. Line 2 Step 2 Choose the delay Each retry waits twice as long as the one before, from two seconds up to five minutes. Lines 3–5 Step 3 Pick what to retry Retry rate limits, unavailable services, and timeouts. Other errors fail at once, because retrying won't fix them. Lines 6–9 Step 4 Keep failures Requests that use every attempt go to a separate queue for 14 days, so you can replay them. Lines 10–12 Take code from a file Code in a fence can drift from the code your project runs and tests. To show the real file instead, set file on a <Step> in place of its code fence, or on <Walkthrough> in place of its shared fence. The path is relative to the page. <Step title=\"Check the signature\" file=\"../../examples/webhook.ts\" region=\"verify\" highlight=\"2-4\"> Compare the header with a signature of the body. </Step> Attribute Meaning"},{"filters":{"focus":["write"]},"text":"Code blocks — Walkthroughs build on code blocks to explain an example one step at a time."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14363,"markdownTokens":3318,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"build-up-code","title":"Build up code","markdownUrl":"/author/components/walkthroughs.sections/build-up-code.md","markdownBytes":4371,"markdownTokens":1039},{"id":"explain-one-file","title":"Explain one file","markdownUrl":"/author/components/walkthroughs.sections/explain-one-file.md","markdownBytes":3371,"markdownTokens":888},{"id":"take-code-from-a-file","title":"Take code from a file","markdownUrl":"/author/components/walkthroughs.sections/take-code-from-a-file.md","markdownBytes":4363,"markdownTokens":936},{"id":"choose-a-layout","title":"Choose a layout","markdownUrl":"/author/components/walkthroughs.sections/choose-a-layout.md","markdownBytes":4321,"markdownTokens":1065},{"id":"attributes","title":"Attributes","markdownUrl":"/author/components/walkthroughs.sections/attributes.md","markdownBytes":3723,"markdownTokens":751},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/components/walkthroughs.sections/html-markdown-and-agents.md","markdownBytes":2855,"markdownTokens":665},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/components/walkthroughs.sections/related-reading.md","markdownBytes":1848,"markdownTokens":448}]},{"id":"guide.components","demo":false,"url":"/author/components","markdownUrl":"/author/components.md","title":"Component reference","summary":"Find a dedicated guide for every supported MDX component and code block.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-overview","headings":[{"id":"reading-and-layout","title":"Reading and layout"},{"id":"links-and-reading-paths","title":"Links and reading paths"},{"id":"reuse-and-api-content","title":"Reuse and API content"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"next-steps","title":"Next steps"}],"text":"Shoalrun accepts GitHub Flavored Markdown (tables, task lists, strikethrough, footnotes, and autolinks) and the MDX components below. Each component family has a page with syntax, attributes, HTML and Markdown behavior, and limits. Component names and attributes are case-sensitive. Unknown components, dynamic MDX expressions, and exports fail the build because they have no shared HTML and Markdown representation. The build drops import lines, so imported components are not available. Custom components let trusted project plugins lower into the shared content pipeline. Navigation and breadcrumbs are configured site features. Their guides live under Customize. Reading and layout Callouts — notes, tips, important messages, warnings, and cautions. Badges — short inline labels for statuses, platforms, and versions. Keyboard shortcuts — key names inside instructions. Short definitions — brief definitions that readers expand with a click, tap, or keyboard. Tooltips — supporting text shown on hover or keyboard focus. Progress — a bounded count with visible text and a bar. Definition lists — terms and rich explanations in semantic HTML. Action links — prominent next-step and download links. Math — inline and display LaTeX expressions rendered to MathML. File trees — nested files, folders, icons, and links. Steps — numbered procedures with titles and full instructions. Timelines — milestone progress with a current stage and completion bar. Collapsibles — individual disclosures and compact groups for optional detail. Tabs — alternate views and their child panels. Code blocks — fenced examples, filenames, and copy behavior. Images — responsive images, captions, width limits, and expanded viewing. Diagrams — D2 and Mermaid source rendered to SVG with Markdown source preserved. Only — a short block for HTML or Markdown alone. Tables — optional row filtering and sticky headings for long tables. Walkthroughs — code explained step by step beside a scrolling code pane. Hero — a landing page opener with a title, tagline, and action buttons. Section — a full-width band on a splash page. ThemePreview — a live switcher for trying presets, palettes, and color modes. ReaderSection, ReaderChoice, and ReaderFilter — marked sections, choice buttons, and in-page filter controls. FrontmatterReference — publish this project's built-in and declared page fields as a live reference. Links and reading paths DocLink — a link by stable document ID. DocCard, DocCards, and DocCollection — document previews, curated lists, and filtered collections. CookbookChooser — choose among custodian-approved sets of prebuilt recipes. RelatedReading — authored relationships as links or cards. Reuse and API content Snippet and Var — shared content and typed values. ApiExample and ApiSchema — named OpenAPI samples and schemas. Fields — authored field lists that match schema formatting. Code highlighting explains Shiki, theme selection, plain output, and custom adapters. Tabs and collapsibles accept ordinary Markdown and supported MDX components in their bodies; their subpages explain the exact nesting rules. Related reading Read first Content and stable IDs — Write a page with a stable ID before adding components to it. Next steps Custom components — Register trusted components that preserve shared content.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Shoalrun accepts GitHub Flavored Markdown (tables, task lists, strikethrough, footnotes, and autolinks) and the MDX components below. Each component family has a page with syntax, attributes, HTML and Markdown behavior, and limits. Component names and attributes are case-sensitive. Unknown components, dynamic MDX expressions, and exports fail the build because they have no shared HTML and Markdown representation. The build drops import lines, so imported components are not available. Custom components let trusted project plugins lower into the shared content pipeline. Navigation and breadcrumbs are configured site features. Their guides live under Customize. Reading and layout Callouts — notes, tips, important messages, warnings, and cautions. Badges — short inline labels for statuses, platforms, and versions. Keyboard shortcuts — key names inside instructions. Short definitions — brief definitions that readers expand with a click, tap, or keyboard. Tooltips — supporting text shown on hover or keyboard focus. Progress — a bounded count with visible text and a bar. Definition lists — terms and rich explanations in semantic HTML. Action links — prominent next-step and download links. Math — inline and display LaTeX expressions rendered to MathML. File trees — nested files, folders, icons, and links. Steps — numbered procedures with titles and full instructions. Timelines — milestone progress with a current stage and completion bar. Collapsibles — individual disclosures and compact groups for optional detail. Tabs — alternate views and their child panels. Code blocks — fenced examples, filenames, and copy behavior. Images — responsive images, captions, width limits, and expanded viewing. Diagrams — D2 and Mermaid source rendered to SVG with Markdown source preserved. Only — a short block for HTML or Markdown alone. Tables — optional row filtering and sticky headings for long tables. Walkthroughs — code explained step by step beside a scrolling code pane. Hero — a landing page opener with a title, tagline, and action buttons. Section — a full-width band on a splash page. ThemePreview — a live switcher for trying presets, palettes, and color modes. ReaderSection, ReaderChoice, and ReaderFilter — marked sections, choice buttons, and in-page filter controls. FrontmatterReference — publish this project's built-in and declared page fields as a live reference. Links and reading paths DocLink — a link by stable document ID. DocCard, DocCards, and DocCollection — document previews, curated lists, and filtered collections. CookbookChooser — choose among custodian-approved sets of prebuilt recipes. RelatedReading — authored relationships as links or cards. Reuse and API content Snippet and Var — shared content and typed values. ApiExample and ApiSchema — named OpenAPI samples and schemas. Fields — authored field lists that match schema formatting. Code highlighting explains Shiki, theme selection, plain output, and custom adapters. Tabs and collapsibles accept ordinary Markdown and supported MDX components in their bodies; their subpages explain the exact nesting rules. Related reading Read first Next steps"},{"filters":{"focus":["write"]},"text":"Content and stable IDs — Write a page with a stable ID before adding components to it. Custom components — Register trusted components that preserve shared content."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6300,"markdownTokens":1516,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.concepts","demo":false,"url":"/concepts","markdownUrl":"/concepts.md","title":"How Shoalrun works","summary":"Follow a page from source file to published HTML and Markdown, and learn the terms the rest of these docs use.","type":"explanation","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"choose-your-focus","title":"Choose your focus"},{"id":"the-build-pipeline","title":"The build pipeline"},{"id":"identity-ids-slugs-and-routes","title":"Identity: IDs, slugs, and routes"},{"id":"publications","title":"Publications"},{"id":"drafts-and-publishing","title":"Drafts and publishing"},{"id":"config-composition","title":"Config composition"},{"id":"glossary","title":"Glossary"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun is a static documentation compiler. It reads a project config, Markdown and MDX pages, and local OpenAPI files. It writes an HTML site and a Markdown copy of every page. A build makes no network requests and no model calls, so the same inputs always give the same output. Choose your focus Pick a path to narrow the site's navigation and search. The choice persists across visits; All in the header shows every page again. Both paths keep foundational guides like this one visible. Write documentation Configure & publish Start with adding a page , then use page metadata and components to shape it. Start with project configuration , then explore themes and publishing . The build pipeline examples, schemas, reference pages docs.config.yaml Validate frontmatter and publications Pages (.md, .mdx) Shared content tree OpenAPI files HTML pages Markdown twins Manifests and discovery files Shoalrun build pipeline — Config and sources pass through validation and one shared content tree, which produces HTML pages, Markdown twins, and manifests. Load config. The build reads docs.config.yaml and every file it includes or extends. Unknown top-level keys fail. See the configuration reference . Read pages. Every .md and .mdx file in the content directory is parsed, and its frontmatter is merged with project defaults and checked. Drafts are checked too. Choose publications. A public page can name one publication or list several. One source file can therefore produce several page variants, with optional version-specific sections. Write separate files only when the pages need substantially different content. Build the content tree. MDX components, snippets, doc: links, cards, API embeds, and diagrams become one shared tree. Generated API reference pages join here. Render. The same tree produces the HTML page and its Markdown twin, so the two can't drift apart. Diagrams are rendered to SVG at this step: D2 and Pele both run in-process, without a browser. Write the site. The build writes pages, assets, API contracts, and manifests. See published outputs . Identity: IDs, slugs, and routes A page has a stable ID , such as guide.concepts , and a slug , such as /concepts . Links, cards, navigation, and relationships use the ID, so you can rename a file or change a slug without breaking them. The slug sets the URL path, so changing a slug changes the URL. Add a redirect from the old path if readers or other sites link to it. The route is the final URL. It combines site.basePath , a language prefix for a non-default language, the channel's and version's pathPrefix , and the slug. For example, a German page at /guides/retry in a v2 version with pathPrefix: /v2 has the route /de/v2/guides/retry . API operations have three identifiers: Identifier Example Where it comes from Source operationId createNote The OpenAPI file. Stable operation ID notes.create Your apis config. Pages and navigation refer to this. Reference page ID reference.create-note The page that presents the operation. The stable operation ID keeps pages linked even if the OpenAPI operationId changes. See API references . Publications A publication is one enabled combination of channel, version, and language: A channel is an audience or environment, such as production or sandbox . A version is an API or documentation edition, such as v1 or current . A language is a content language, such as en . publications.enabled lists the combinations to build. A page's frontmatter picks one or several of them; files for other versions or languages can share its id . Links, cards, and related reading stay inside the current publication, so a v1 page never links to a v2 page by accident. Each published copy of a page is a variant . The HTML and Markdown copy for each variant include only content selected for that publication. Git branches and tags select source revisions for a build; they do not select publication channels or preserve earlier deployed sites. The deployment and version guide explains how those choices fit together. For a complete versioning and translation workflow, follow put multiple versions on one site . Drafts and publishing Only pages with access.policy: public are published. Anything else, such as draft , is still validated but never written to the site. New pages from shoalrun scaffold start as drafts with placeholder prompts. A public page fails the build until every placeholder is replaced. See templates . Config composition A project config can be one file or many. Four directives combine files: $include replaces a value with the contents of another YAML file. extends layers the current file over one or more preset files. $concat appends to a list inherited from a preset. $remove drops inherited map keys or list items by id . shoalrun config explain <key> reports which file set a value. Follow configure your project for a worked example of composition, precedence, file paths, and debugging. Glossary Terms such as publication , variant , Markdown ","readerFilters":{},"readerSegments":[{"filters":{},"text":"Shoalrun is a static documentation compiler. It reads a project config, Markdown and MDX pages, and local OpenAPI files. It writes an HTML site and a Markdown copy of every page. A build makes no network requests and no model calls, so the same inputs always give the same output. Choose your focus Pick a path to narrow the site's navigation and search. The choice persists across visits; All in the header shows every page again. Both paths keep foundational guides like this one visible. Write documentation Configure & publish The build pipeline Shoalrun build pipeline — Config and sources pass through validation and one shared content tree, which produces HTML pages, Markdown twins, and manifests. Load config. The build reads docs.config.yaml and every file it includes or extends. Unknown top-level keys fail. See the configuration reference . Read pages. Every .md and .mdx file in the content directory is parsed, and its frontmatter is merged with project defaults and checked. Drafts are checked too. Choose publications. A public page can name one publication or list several. One source file can therefore produce several page variants, with optional version-specific sections. Write separate files only when the pages need substantially different content. Build the content tree. MDX components, snippets, doc: links, cards, API embeds, and diagrams become one shared tree. Generated API reference pages join here. Render. The same tree produces the HTML page and its Markdown twin, so the two can't drift apart. Diagrams are rendered to SVG at this step: D2 and Pele both run in-process, without a browser. Write the site. The build writes pages, assets, API contracts, and manifests. See published outputs . Identity: IDs, slugs, and routes A page has a stable ID , such as guide.concepts , and a slug , such as /concepts . Links, cards, navigation, and relationships use the ID, so you can rename a file or change a slug without breaking them. The slug sets the URL path, so changing a slug changes the URL. Add a redirect from the old path if readers or other sites link to it. The route is the final URL. It combines site.basePath , a language prefix for a non-default language, the channel's and version's pathPrefix , and the slug. For example, a German page at /guides/retry in a v2 version with pathPrefix: /v2 has the route /de/v2/guides/retry . API operations have three identifiers: Identifier Example Where it comes from Source operationId createNote The OpenAPI file. Stable operation ID notes.create Your apis config. Pages and navigation refer to this. Reference page ID reference.create-note The page that presents the operation. The stable operation ID keeps pages linked even if the OpenAPI operationId changes. See API references . Publications A publication is one enabled combination of channel, version, and language: A channel is an audience or environment, such as production or sandbox . A version is an API or documentation edition, such as v1 or current . A language is a content language, such as en . publications.enabled lists the combinations to build. A page's frontmatter picks one or several of them; files for other versions or languages can share its id . Links, cards, and related reading stay inside the current publication, so a v1 page never links to a v2 page by accident. Each published copy of a page is a variant . The HTML and Markdown copy for each variant include only content selected for that publication. Git branches and tags select source revisions for a build; they do not select publication channels or preserve earlier deployed sites. The deployment and version guide explains how those choices fit together. For a complete versioning and translation workflow, follow put multiple versions on one site . Drafts and publishing Only pages with access.policy: public are published. Anything else, such as draft , is still validated but never written to the site. New pages from shoalrun scaffold start as drafts with placeholder prompts. A public page fails the build until every placeholder is replaced. See templates . Config composition A project config can be one file or many. Four directives combine files: $include replaces a value with the contents of another YAML file. extends layers the current file over one or more preset files. $concat appends to a list inherited from a preset. $remove drops inherited map keys or list items by id . shoalrun config explain <key> reports which file set a value. Follow configure your project for a worked example of composition, precedence, file paths, and debugging. Glossary Terms such as publication , variant , Markdown twin , and focused contract are defined in the glossary . It lists more than a hundred terms, sorted A to Z, and links each one to its guide. Related reading Next steps Reference while working Glossary — Look up any term used on this page, and more than a hundred others. Related topics Getting started — Learn the build pipeline and the terms the rest of th"},{"filters":{"focus":["write"]},"text":"Start with adding a page , then use page metadata and components to shape it. Content and stable IDs — Apply IDs, slugs, and publication variants to your own pages."},{"filters":{"focus":["configure"]},"text":"Start with project configuration , then explore themes and publishing . Organize project configuration — Compose your project settings and trace how they resolve. Configuration reference — Check every top-level setting the build reads. Publishing and agent representations — Find each HTML, Markdown, and manifest file the pipeline writes."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":8442,"markdownTokens":1990,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.config-apis","demo":false,"url":"/config/apis","markdownUrl":"/config/apis.md","title":"API and audit settings","summary":"Configure OpenAPI sources, generated references, focused contracts, and local validation.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"apis","title":"apis"},{"id":"audit","title":"audit"},{"id":"agent-evaluation-reports","title":"Agent evaluation reports"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Configure OpenAPI sources, generated references, focused contracts, and local validation. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. apis A mapping from API ID to its source and operations. See API references and focused contracts . Key Meaning source.kind Must be file . source.path Local OpenAPI 3.0 or 3.1 file, relative to the declaring config file. source.focused true writes a focused contract for each reference page. source.publish true publishes the full source file, which must end in .yaml , .yml , or .json . Also turns on focused contracts. publicReview.digest Required SHA-256 review digest when API content appears on a public page or in a focused contract. Generate a candidate with shoalrun api review <config> --output <local-directory> , inspect it, then pin the reported digest. discovery.endpoint Public HTTPS API URL for /.well-known/api-catalog . Needs source.publish and site.origin . operations A list of { id, sourceOperationId, reference } bindings. Stable IDs are unique across all APIs. publications A list of { channel, version, source, discovery } entries for publications other than the default. generateReferences true , or { pathPrefix, include } or { pathPrefix, exclude } . pathPrefix defaults to /reference/<apiId> . mappings.subjectLifecycle Explicitly map an operation-level x-* scalar or dotted property to beta , in-development , experimental , or deprecated . See OpenAPI extension mappings . querySyntax Opt-in rules for a placeholder query parameter whose filter expressions go directly in the URL. Each rule has parameter , pathPrefixes , style: unwrapped , and example . See API generation . One authored reference page for one operation. The spec stays private: config/api.yaml payments : source : { kind : file , path : ../apis/payments/openapi.yaml } operations : - id : payments.create sourceOperationId : createPayment reference : reference.create-payment Publish the spec, a focused contract per page, and the API catalog. This also needs site.origin : config/api.yaml payments : source : { kind : file , path : ../apis/payments/openapi.yaml , publish : true } discovery : endpoint : https://api.example.com operations : - { id : payments.create , sourceOperationId : createPayment , reference : reference.create-payment } Keep the spec private but publish focused contracts: config/api.yaml payments : source : { kind : file , path : ../apis/payments/openapi.yaml , focused : true } operations : - { id : payments.create , sourceOperationId : createPayment , reference : reference.create-payment } Generate reference pages for every operation except two: config/api.yaml payments : source : { kind : file , path : ../apis/payments/openapi.yaml } generateReferences : pathPrefix : /api-reference/payments exclude : [ internalReconcile , debugEcho ] Give the v2 publication its own spec. The top-level source covers the default publication: config/api.yaml payments : source : { kind : file , path : ../apis/payments/v1.yaml } publications : - channel : production version : v2 source : { kind : file , path : ../apis/payments/v2.yaml , publish : true } operations : - { id : payments.create , sourceOperationId : createPayment , reference : reference.create-payment } audit Optional local audit settings. Run shoalrun check [config] or shoalrun audit [config] to execute configured tests and build a temporary site. The checks compare API representations, inspect focused contracts, and validate local links. check prints readable results ( --json selects JSON); audit returns JSON. Both exit with code 1 on failure. docs.config.yaml audit : tests : - id : project-tests run : [ node , --test , scripts/docs.test.mjs ] api : true focusedContracts : true links : true audit.tests is the integration point for external test suites. We recommend Doc Detective for documentation behavior tests; any command that exits nonzero on failure can be used. Each test needs a unique lowercase id and a nonempty run argument list. The first argument names the executable; the rest are passed without a shell. Commands run from the directory containing docs.config.yaml , so use project-relative paths. The api , focusedContracts , and links switches default to true . Set any to false to skip that group. The site build always runs because it checks the complete project and supplies focused contracts. See audit a docs project for a Doc Detective example, execution order, output, timeouts, and limits. For snapshot validation, declare local check dependencies with optional inputs paths relative to the directory containing docs.config.yaml : docs.config.yaml audit : tests : - id : formatting run : [ vale , --config=../format.ini , content ] inputs : [ ../format.ini , ../styles ] The snapshot copies declared files and directories within the project parent. It rejects missing inputs","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure OpenAPI sources, generated references, focused contracts, and local validation. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. apis A mapping from API ID to its source and operations. See API references and focused contracts . Key Meaning source.kind Must be file . source.path Local OpenAPI 3.0 or 3.1 file, relative to the declaring config file. source.focused true writes a focused contract for each reference page. source.publish true publishes the full source file, which must end in .yaml , .yml , or .json . Also turns on focused contracts. publicReview.digest Required SHA-256 review digest when API content appears on a public page or in a focused contract. Generate a candidate with shoalrun api review <config> --output <local-directory> , inspect it, then pin the reported digest. discovery.endpoint Public HTTPS API URL for /.well-known/api-catalog . Needs source.publish and site.origin . operations A list of { id, sourceOperationId, reference } bindings. Stable IDs are unique across all APIs. publications A list of { channel, version, source, discovery } entries for publications other than the default. generateReferences true , or { pathPrefix, include } or { pathPrefix, exclude } . pathPrefix defaults to /reference/<apiId> . mappings.subjectLifecycle Explicitly map an operation-level x-* scalar or dotted property to beta , in-development , experimental , or deprecated . See OpenAPI extension mappings . querySyntax Opt-in rules for a placeholder query parameter whose filter expressions go directly in the URL. Each rule has parameter , pathPrefixes , style: unwrapped , and example . See API generation . One authored reference page for one operation. The spec stays private: payments: source: { kind: file, path: ../apis/payments/openapi.yaml } operations: - id: payments.create sourceOperationId: createPayment reference: reference.create-payment Publish the spec, a focused contract per page, and the API catalog. This also needs site.origin : payments: source: { kind: file, path: ../apis/payments/openapi.yaml, publish: true } discovery: endpoint: https://api.example.com operations: - { id: payments.create, sourceOperationId: createPayment, reference: reference.create-payment } Keep the spec private but publish focused contracts: payments: source: { kind: file, path: ../apis/payments/openapi.yaml, focused: true } operations: - { id: payments.create, sourceOperationId: createPayment, reference: reference.create-payment } Generate reference pages for every operation except two: payments: source: { kind: file, path: ../apis/payments/openapi.yaml } generateReferences: pathPrefix: /api-reference/payments exclude: [internalReconcile, debugEcho] Give the v2 publication its own spec. The top-level source covers the default publication: payments: source: { kind: file, path: ../apis/payments/v1.yaml } publications: - channel: production version: v2 source: { kind: file, path: ../apis/payments/v2.yaml, publish: true } operations: - { id: payments.create, sourceOperationId: createPayment, reference: reference.create-payment } audit Optional local audit settings. Run shoalrun check [config] or shoalrun audit [config] to execute configured tests and build a temporary site. The checks compare API representations, inspect focused contracts, and validate local links. check prints readable results ( --json selects JSON); audit returns JSON. Both exit with code 1 on failure. audit: tests: - id: project-tests run: [node, --test, scripts/docs.test.mjs] api: true focusedContracts: true links: true audit.tests is the integration point for external test suites. We recommend Doc Detective for documentation behavior tests; any command that exits nonzero on failure can be used. Each test needs a unique lowercase id and a nonempty run argument list. The first argument names the executable; the rest are passed without a shell. Commands run from the directory containing docs.config.yaml , so use project-relative paths. The api , focusedContracts , and links switches default to true . Set any to false to skip that group. The site build always runs because it checks the complete project and supplies focused contracts. See audit a docs project for a Doc Detective example, execution order, output, timeouts, and limits. For snapshot validation, declare local check dependencies with optional inputs paths relative to the directory containing docs.config.yaml : audit: tests: - id: formatting run: [vale, --config=../format.ini, content] inputs: [../format.ini, ../styles] The snapshot copies declared files and directories within the project parent. It rejects missing inputs, symlinks, credentials, dependency folders, and paths outside that boundary. Directory declarations also track added and deleted files for freshness. Declare the configuration's supporting files too; Shoalrun does not i"},{"filters":{"focus":["configure"]},"text":"Organize project configuration — Learn how files combine and how to validate configuration changes. Configuration reference — Find configuration settings in another topic."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9830,"markdownTokens":1899,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.config-content","demo":false,"url":"/config/content","markdownUrl":"/config/content.md","title":"Authoring and content settings","summary":"Configure authoring guidance, page defaults, reusable content, reading paths, and reader views.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"authoring","title":"authoring"},{"id":"frontmatter","title":"frontmatter"},{"id":"variables","title":"variables"},{"id":"snippets","title":"snippets"},{"id":"templates","title":"templates"},{"id":"callouts","title":"callouts"},{"id":"badges","title":"badges"},{"id":"cookbooks","title":"cookbooks"},{"id":"relationships","title":"relationships"},{"id":"readerfilters","title":"readerFilters"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Configure authoring guidance, page defaults, reusable content, reading paths, and reader views. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. authoring Optional project guidance and read-only source locations. These settings do not choose a model or read external files during a site build. Key Meaning directives Nonempty project writing instructions. guideFiles Project-relative writing-guide paths. exemplarFiles Project-relative reviewed examples. sourceRoots Named local folders for source search. Each entry has path , optional name , and optional include and exclude glob lists. pageSources Stable page IDs mapped to source file paths or globs. These seed evidence selection for known features. Source paths resolve from the root configuration directory. Source folders and page-source files may be outside the docs project; guide and exemplar paths remain inside it. URLs are not source folders. Git is not required. Your coding agent selects the evidence scope under its own permissions. docs.config.yaml authoring : sourceRoots : - name : Application implementation path : ../application/src include : [ \"**/*.ts\" , \"**/*.tsx\" ] exclude : [ \"**/*.test.ts\" ] pageSources : guide.authentication : - ../application/src/authentication.ts Project discovery reports these configured source locations. Use your coding agent's own search and read tools, with its execution permissions, to investigate external implementation files. docs source reads only paths inside the project. See authoring tools commands for current discovery and validation commands. frontmatter Global defaults , enforced values, per-language formatting locales , custom fields declarations, and changelogIdentifier . Pages can replace defaults but not enforced values. id and slug can't be set globally. See frontmatter and release notes and changelog . Let pages leave out common values: config/frontmatter.yaml defaults : type : guide channel : production version : current access : { policy : public } Force a value on every page: config/frontmatter.yaml enforced : audiences : [ partners ] Choose what identifies each changelog entry. The default is either ; date and version are also available: config/frontmatter.yaml changelogIdentifier : either Here version means the page's releaseVersion field, not the documentation publication version. Declare custom fields. public: true lets a field appear in the Markdown twin's header: config/frontmatter.yaml fields : owner : type : string required : true description : Team that maintains the page. agent.intent : type : string public : true reviewStatus : type : string enum : [ draft , reviewed , approved ] variables A mapping of project-wide values for snippets . They override snippet defaults and are overridden by page variables and invocation values. Values are strings, numbers, or booleans. docs.config.yaml variables : product : Payments supportEmail : support@example.com retryLimit : 3 betaFeatures : false A page overrides a project value for itself: content/sandbox-guide.mdx (frontmatter) variables : product : Payments sandbox A single include overrides both: content/sandbox-guide.mdx < Snippet id = \"payment.request-prep\" values = {{ product : \"Payments test mode\" }} /> snippets A mapping from snippet ID to { file, variables } . Each variable has a type ( string , number , or boolean ) and optional required , default , and enum . See snippets . A snippet with no variables: config/snippets.yaml legal.beta-notice : file : ../snippets/beta-notice.mdx Required and default values: config/snippets.yaml payment.request-prep : file : ../snippets/request-prep.mdx variables : product : { type : string , required : true } header : { type : string , default : Idempotency-Key } A value limited to a list, and a number: config/snippets.yaml limits.rate : file : ../snippets/rate-limit.mdx variables : plan : { type : string , enum : [ free , team , enterprise ] , default : free } perMinute : { type : number , required : true } templates An optional mapping from template ID to { type, body, required } . Built-in templates need no registration; reuse a built-in ID to override it or add a custom ID. type becomes the new page's type , and body is a .md or .mdx file that can open with commented frontmatter. The only required value is operations . See templates . config/templates.yaml how-to : type : how-to body : ../templates/how-to.mdx Override the built-in API reference while retaining its operation requirement: config/templates.yaml api-reference : type : api-reference body : ../templates/api-reference.mdx required : [ operations ] Replace a built-in template by reusing its ID: config/templates.yaml guide : type : guide body : ../templates/our-guide.mdx callouts Custom callout types and color tones . A type has a label , a tone , and an optional Lucide icon . A tone has line , ba","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure authoring guidance, page defaults, reusable content, reading paths, and reader views. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. authoring Optional project guidance and read-only source locations. These settings do not choose a model or read external files during a site build. Key Meaning directives Nonempty project writing instructions. guideFiles Project-relative writing-guide paths. exemplarFiles Project-relative reviewed examples. sourceRoots Named local folders for source search. Each entry has path , optional name , and optional include and exclude glob lists. pageSources Stable page IDs mapped to source file paths or globs. These seed evidence selection for known features. Source paths resolve from the root configuration directory. Source folders and page-source files may be outside the docs project; guide and exemplar paths remain inside it. URLs are not source folders. Git is not required. Your coding agent selects the evidence scope under its own permissions. authoring: sourceRoots: - name: Application implementation path: ../application/src include: [\"**/*.ts\", \"**/*.tsx\"] exclude: [\"**/*.test.ts\"] pageSources: guide.authentication: - ../application/src/authentication.ts Project discovery reports these configured source locations. Use your coding agent's own search and read tools, with its execution permissions, to investigate external implementation files. docs source reads only paths inside the project. See authoring tools commands for current discovery and validation commands. frontmatter Global defaults , enforced values, per-language formatting locales , custom fields declarations, and changelogIdentifier . Pages can replace defaults but not enforced values. id and slug can't be set globally. See frontmatter and release notes and changelog . Let pages leave out common values: defaults: type: guide channel: production version: current access: { policy: public } Force a value on every page: enforced: audiences: [partners] Choose what identifies each changelog entry. The default is either ; date and version are also available: changelogIdentifier: either Here version means the page's releaseVersion field, not the documentation publication version. Declare custom fields. public: true lets a field appear in the Markdown twin's header: fields: owner: type: string required: true description: Team that maintains the page. agent.intent: type: string public: true reviewStatus: type: string enum: [draft, reviewed, approved] variables A mapping of project-wide values for snippets . They override snippet defaults and are overridden by page variables and invocation values. Values are strings, numbers, or booleans. variables: product: Payments supportEmail: support@example.com retryLimit: 3 betaFeatures: false A page overrides a project value for itself: variables: product: Payments sandbox A single include overrides both: <Snippet id=\"payment.request-prep\" values={{ product: \"Payments test mode\" }} /> snippets A mapping from snippet ID to { file, variables } . Each variable has a type ( string , number , or boolean ) and optional required , default , and enum . See snippets . A snippet with no variables: legal.beta-notice: file: ../snippets/beta-notice.mdx Required and default values: payment.request-prep: file: ../snippets/request-prep.mdx variables: product: { type: string, required: true } header: { type: string, default: Idempotency-Key } A value limited to a list, and a number: limits.rate: file: ../snippets/rate-limit.mdx variables: plan: { type: string, enum: [free, team, enterprise], default: free } perMinute: { type: number, required: true } templates An optional mapping from template ID to { type, body, required } . Built-in templates need no registration; reuse a built-in ID to override it or add a custom ID. type becomes the new page's type , and body is a .md or .mdx file that can open with commented frontmatter. The only required value is operations . See templates . how-to: type: how-to body: ../templates/how-to.mdx Override the built-in API reference while retaining its operation requirement: api-reference: type: api-reference body: ../templates/api-reference.mdx required: [operations] Replace a built-in template by reusing its ID: guide: type: guide body: ../templates/our-guide.mdx callouts Custom callout types and color tones . A type has a label , a tone , and an optional Lucide icon . A tone has line , background , and text colors, and an optional dark set. See callouts for configuration examples and contrast requirements. badges badges.variants adds or overrides inline badge colors. Each lowercase kebab-case name needs light.background and light.text hex colors; light.border is optional and defaults to the text color. Add the same fields under dark when the site uses dark or system mode. The build checks badge text cont"},{"filters":{"focus":["configure"]},"text":"Organize project configuration — Learn how files combine and how to validate configuration changes. Configuration reference — Find configuration settings in another topic."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":11306,"markdownTokens":2590,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"authoring","title":"authoring","markdownUrl":"/config/content.sections/authoring.md","markdownBytes":3642,"markdownTokens":705},{"id":"frontmatter","title":"frontmatter","markdownUrl":"/config/content.sections/frontmatter.md","markdownBytes":2789,"markdownTokens":668},{"id":"variables","title":"variables","markdownUrl":"/config/content.sections/variables.md","markdownBytes":2169,"markdownTokens":519},{"id":"snippets","title":"snippets","markdownUrl":"/config/content.sections/snippets.md","markdownBytes":2351,"markdownTokens":590},{"id":"templates","title":"templates","markdownUrl":"/config/content.sections/templates.md","markdownBytes":2346,"markdownTokens":568},{"id":"callouts","title":"callouts","markdownUrl":"/config/content.sections/callouts.md","markdownBytes":1798,"markdownTokens":438},{"id":"badges","title":"badges","markdownUrl":"/config/content.sections/badges.md","markdownBytes":1957,"markdownTokens":465},{"id":"cookbooks","title":"cookbooks","markdownUrl":"/config/content.sections/cookbooks.md","markdownBytes":2311,"markdownTokens":535},{"id":"relationships","title":"relationships","markdownUrl":"/config/content.sections/relationships.md","markdownBytes":2899,"markdownTokens":728},{"id":"readerfilters","title":"readerFilters","markdownUrl":"/config/content.sections/readerfilters.md","markdownBytes":2255,"markdownTokens":536},{"id":"related-reading","title":"Related reading","markdownUrl":"/config/content.sections/related-reading.md","markdownBytes":1574,"markdownTokens":371}]},{"id":"reference.config-integrations","demo":false,"url":"/config/integrations","markdownUrl":"/config/integrations.md","title":"Search and integration settings","summary":"Configure search synonyms, the read-only MCP endpoint, and browser analytics.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"search","title":"search"},{"id":"mcp","title":"mcp"},{"id":"analytics","title":"analytics"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Configure search synonyms, the read-only MCP endpoint, and browser analytics. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. search Optional. search.synonyms is a list of groups of two or more words or phrases. Each term in a group can find the others, with exact matches ranked higher. A term can appear in only one group. Use $include to keep the groups in a project-owned YAML file. The site search guide shows the format and which search paths use it. mcp Enable a read-only HTTP MCP endpoint on Node or in Vercel output for one public publication: docs.config.yaml mcp : enabled : true access : public path : /mcp publication : { channel : production , version : current , language : en } path defaults to /mcp and is mounted beneath site.basePath . The build rejects conflicting output routes. enabled must be a boolean, and enabled configurations require access: public and all three publication coordinates. Optional allowedHosts lists exact hostnames without ports or wildcards. Optional allowedOrigins lists exact HTTP(S) browser origins. site.origin contributes its hostname and origin automatically; the local Node server also permits loopback requests. Unknown settings fail validation. Omit the section, set mcp: false , or set enabled: false to disable it. The Node server reads generated settings, and shoalrun vercel build packages an independent function automatically. Read-only SDK calls have been verified on this site’s production Vercel endpoint. See connect an MCP client for setup and request limits. Optional mcp.analytics.module names a local .js or .mjs server adapter exporting capture(event) and optional flush() . It resolves relative to the declaring config file. The build copies the module and its dependencies without executing it. Relative imports must stay within its directory. Credentials belong in runtime environment variables. Optional mcp.analytics.consent contains header and value . When configured, only requests with that exact header value can load or call the analytics adapter. Other requests can use the documentation tools without tracking. The header must be a lowercase custom x- name; forwarded, Vercel, and MCP protocol headers are reserved. The value is a case-sensitive policy identifier of up to 64 letters, digits, dots, underscores, or hyphens. The header gate is off when omitted or set to false ; readers then need no special client configuration for analytics. Use the gate only when your deployment requires explicit caller opt-in. In that mode, removing the header stops collection on future requests. This feature does not determine your privacy obligations. See analytics safeguards . Optional mcp.analytics.clientMetadata: true adds normalized client labels and model labels from a fixed registry when supported request metadata is present. It defaults to false . Labels are unverified; raw headers, unrelated metadata, queries, and intent are excluded. Optional mcp.analytics.intent and mcp.analytics.conversationIds are booleans that default to false . An adapter’s optional instrument(server, options) hook implements them. The PostHog example can add context/model arguments and conversation handles while excluding raw queries and results. Its context argument requests a fixed intent category. Free-text or invalid values are replaced with a per-tool category before analytics delivery; raw intent is never stored by that example. Other adapters must implement their own safeguards. Omit mcp.analytics or set it to false to disable collection. It is independent of browser analytics and does not instrument stdio. See measure MCP tool usage for fields, service mappings, and a PostHog example. analytics Analytics is disabled by default. Configure a local browser adapter to receive interaction events: docs.config.yaml analytics : module : ./analytics.js The adapter must export track(event) and can export an asynchronous init(context) . module resolves relative to the declaring config file and is copied to the public assets without being executed during the build. analytics: false disables it. Shoalrun emits documented events; your adapter owns the service, consent, and delivery. See bring your own analytics . Related reading Read first Organize project configuration — Learn how files combine and how to validate configuration changes. Reference while working Configuration reference — Find configuration settings in another topic.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure search synonyms, the read-only MCP endpoint, and browser analytics. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. search Optional. search.synonyms is a list of groups of two or more words or phrases. Each term in a group can find the others, with exact matches ranked higher. A term can appear in only one group. Use $include to keep the groups in a project-owned YAML file. The site search guide shows the format and which search paths use it. mcp Enable a read-only HTTP MCP endpoint on Node or in Vercel output for one public publication: mcp: enabled: true access: public path: /mcp publication: { channel: production, version: current, language: en } path defaults to /mcp and is mounted beneath site.basePath . The build rejects conflicting output routes. enabled must be a boolean, and enabled configurations require access: public and all three publication coordinates. Optional allowedHosts lists exact hostnames without ports or wildcards. Optional allowedOrigins lists exact HTTP(S) browser origins. site.origin contributes its hostname and origin automatically; the local Node server also permits loopback requests. Unknown settings fail validation. Omit the section, set mcp: false , or set enabled: false to disable it. The Node server reads generated settings, and shoalrun vercel build packages an independent function automatically. Read-only SDK calls have been verified on this site’s production Vercel endpoint. See connect an MCP client for setup and request limits. Optional mcp.analytics.module names a local .js or .mjs server adapter exporting capture(event) and optional flush() . It resolves relative to the declaring config file. The build copies the module and its dependencies without executing it. Relative imports must stay within its directory. Credentials belong in runtime environment variables. Optional mcp.analytics.consent contains header and value . When configured, only requests with that exact header value can load or call the analytics adapter. Other requests can use the documentation tools without tracking. The header must be a lowercase custom x- name; forwarded, Vercel, and MCP protocol headers are reserved. The value is a case-sensitive policy identifier of up to 64 letters, digits, dots, underscores, or hyphens. The header gate is off when omitted or set to false ; readers then need no special client configuration for analytics. Use the gate only when your deployment requires explicit caller opt-in. In that mode, removing the header stops collection on future requests. This feature does not determine your privacy obligations. See analytics safeguards . Optional mcp.analytics.clientMetadata: true adds normalized client labels and model labels from a fixed registry when supported request metadata is present. It defaults to false . Labels are unverified; raw headers, unrelated metadata, queries, and intent are excluded. Optional mcp.analytics.intent and mcp.analytics.conversationIds are booleans that default to false . An adapter’s optional instrument(server, options) hook implements them. The PostHog example can add context/model arguments and conversation handles while excluding raw queries and results. Its context argument requests a fixed intent category. Free-text or invalid values are replaced with a per-tool category before analytics delivery; raw intent is never stored by that example. Other adapters must implement their own safeguards. Omit mcp.analytics or set it to false to disable collection. It is independent of browser analytics and does not instrument stdio. See measure MCP tool usage for fields, service mappings, and a PostHog example. analytics Analytics is disabled by default. Configure a local browser adapter to receive interaction events: analytics: module: ./analytics.js The adapter must export track(event) and can export an asynchronous init(context) . module resolves relative to the declaring config file and is copied to the public assets without being executed during the build. analytics: false disables it. Shoalrun emits documented events; your adapter owns the service, consent, and delivery. See bring your own analytics . Related reading Read first Reference while working"},{"filters":{"focus":["configure"]},"text":"Organize project configuration — Learn how files combine and how to validate configuration changes. Configuration reference — Find configuration settings in another topic."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5940,"markdownTokens":1295,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.config-outputs","demo":false,"url":"/config/outputs","markdownUrl":"/config/outputs.md","title":"Output and export settings","summary":"Configure metadata providers, application exports, Markdown headers, and discovery indexes.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"metadata","title":"metadata"},{"id":"exports","title":"exports"},{"id":"outputs","title":"outputs"},{"id":"agent-discovery-index","title":"Agent discovery index"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Configure metadata providers, application exports, Markdown headers, and discovery indexes. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. metadata metadata.provider.module names an optional local module that exports provideMetadata(context) . The module can supply owned page fields to the build. The framework does not run an external vocabulary validator or publish supplied fields automatically. See custom metadata for the return shape and ownership rule. docs.config.yaml metadata : provider : module : ./metadata/provider.mjs The path is relative to the config file that declares it. provider accepts only module . exports Optional named targets for shoalrun export . They select portable application content independently of website navigation and site.contentFilter . The normal website build does not emit export bundles automatically. See export content into an application . Each target accepts these fields: Field Default Meaning formats [markdown, html] A nonempty unique list of markdown and/or html . documents All eligible pages Explicit document IDs. Missing, inaccessible, or export-filtered IDs fail. publication The only enabled publication One complete { channel, version, language } combination. Required when selection is ambiguous. contentFilter None Optional configured reader facets; every facet must match any listed choice. Unmarked pages do not match. publicBase / Root-relative mount with a trailing slash, such as /help/ . It locates bundle content and assets in the app. assetRoots Content directory only Extra local asset directories, relative to the declaring config file. Only referenced supported files are copied. notices Renderer notices only Local text or Markdown license/notice files to retain in NOTICES.txt . Paths are relative to the declaring config file. apiReview Matching API-level approval, if any API IDs mapped to reviewed SHA-256 digests for this export selection. exports : app-help : formats : [ markdown , html ] documents : [ guide.api-keys , guide.billing ] publicBase : /help/ The export preserves whole-page content, including all reader sections. It flattens interactive components into readable static content and omits website/browser runtimes. Unsupported output, escaping assets, and unavailable document fallbacks fail. exports and its target fields are validated for unknown keys. outputs Use outputs to configure the HTML, Markdown, discovery, and text artifacts produced by a build. Key Meaning markdown.metadata The Markdown twin's YAML header: format , fields , addFields , removeFields , omitNull , byType , and profiles . format defaults to none . See Markdown metadata . html.shareImages true : a generated 1200×630 link-preview image per page. false turns them off; a mapping with template and fonts replaces the design. See share images and favicon . html.highlighting Code highlighting provider , theme , and module . Defaults to Shiki with the site theme, which takes code colors from the palette. See code blocks . html.navigation.showCounts Show page counts beside navigation groups. Defaults to true ; set false to omit them. See navigation . html.search Search provider , module , and index . See search . text Ordered frontmatter field paths for card , pageHeader , search , htmlDescription , and socialCard . See custom metadata . The build always writes /llms.txt , documents.json , redirects.json , and resource-headers.json ; there are no settings for them. A short Markdown header on every page: docs.config.yaml outputs : markdown : metadata : format : yaml-frontmatter fields : id : frontmatter.id title : frontmatter.title summary : frontmatter.summary description : frontmatter.description canonical : publication.canonicalUrl Add fields for one page type, and define a profile pages can select with markdownMetadata: versioned : docs.config.yaml outputs : markdown : metadata : format : yaml-frontmatter fields : { id : frontmatter.id , title : frontmatter.title } byType : api-reference : addFields : { operations : frontmatter.operations } profiles : versioned : addFields : { version : publication.version , language : publication.language } Use another Shiki theme, and turn off search: docs.config.yaml outputs : html : highlighting : { provider : shiki , theme : github-light } search : { provider : none } Plug in your own search and highlighter modules: docs.config.yaml outputs : html : highlighting : { provider : custom , module : ./highlight.mjs } search : { provider : custom , module : ./search/hosted.js } Agent discovery index Every published page is included automatically, using its title and frontmatter summary. You do not need to list page IDs. Omit outputs.llms for automatic grouping, or choose a bare alphabetical list of links and summaries: docs.config.yaml outputs : llms : format : flat format accepts grouped (the default) o","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure metadata providers, application exports, Markdown headers, and discovery indexes. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. metadata metadata.provider.module names an optional local module that exports provideMetadata(context) . The module can supply owned page fields to the build. The framework does not run an external vocabulary validator or publish supplied fields automatically. See custom metadata for the return shape and ownership rule. metadata: provider: module: ./metadata/provider.mjs The path is relative to the config file that declares it. provider accepts only module . exports Optional named targets for shoalrun export . They select portable application content independently of website navigation and site.contentFilter . The normal website build does not emit export bundles automatically. See export content into an application . Each target accepts these fields: Field Default Meaning formats [markdown, html] A nonempty unique list of markdown and/or html . documents All eligible pages Explicit document IDs. Missing, inaccessible, or export-filtered IDs fail. publication The only enabled publication One complete { channel, version, language } combination. Required when selection is ambiguous. contentFilter None Optional configured reader facets; every facet must match any listed choice. Unmarked pages do not match. publicBase / Root-relative mount with a trailing slash, such as /help/ . It locates bundle content and assets in the app. assetRoots Content directory only Extra local asset directories, relative to the declaring config file. Only referenced supported files are copied. notices Renderer notices only Local text or Markdown license/notice files to retain in NOTICES.txt . Paths are relative to the declaring config file. apiReview Matching API-level approval, if any API IDs mapped to reviewed SHA-256 digests for this export selection. exports: app-help: formats: [markdown, html] documents: [guide.api-keys, guide.billing] publicBase: /help/ The export preserves whole-page content, including all reader sections. It flattens interactive components into readable static content and omits website/browser runtimes. Unsupported output, escaping assets, and unavailable document fallbacks fail. exports and its target fields are validated for unknown keys. outputs Use outputs to configure the HTML, Markdown, discovery, and text artifacts produced by a build. Key Meaning markdown.metadata The Markdown twin's YAML header: format , fields , addFields , removeFields , omitNull , byType , and profiles . format defaults to none . See Markdown metadata . html.shareImages true : a generated 1200×630 link-preview image per page. false turns them off; a mapping with template and fonts replaces the design. See share images and favicon . html.highlighting Code highlighting provider , theme , and module . Defaults to Shiki with the site theme, which takes code colors from the palette. See code blocks . html.navigation.showCounts Show page counts beside navigation groups. Defaults to true ; set false to omit them. See navigation . html.search Search provider , module , and index . See search . text Ordered frontmatter field paths for card , pageHeader , search , htmlDescription , and socialCard . See custom metadata . The build always writes /llms.txt , documents.json , redirects.json , and resource-headers.json ; there are no settings for them. A short Markdown header on every page: outputs: markdown: metadata: format: yaml-frontmatter fields: id: frontmatter.id title: frontmatter.title summary: frontmatter.summary description: frontmatter.description canonical: publication.canonicalUrl Add fields for one page type, and define a profile pages can select with markdownMetadata: versioned : outputs: markdown: metadata: format: yaml-frontmatter fields: { id: frontmatter.id, title: frontmatter.title } byType: api-reference: addFields: { operations: frontmatter.operations } profiles: versioned: addFields: { version: publication.version, language: publication.language } Use another Shiki theme, and turn off search: outputs: html: highlighting: { provider: shiki, theme: github-light } search: { provider: none } Plug in your own search and highlighter modules: outputs: html: highlighting: { provider: custom, module: ./highlight.mjs } search: { provider: custom, module: ./search/hosted.js } Agent discovery index Every published page is included automatically, using its title and frontmatter summary. You do not need to list page IDs. Omit outputs.llms for automatic grouping, or choose a bare alphabetical list of links and summaries: outputs: llms: format: flat format accepts grouped (the default) or flat . Flat mode includes all pages under Pages , without optional groups or repeated type labels. Discovery resources and API contracts remain linked, and fiction"},{"filters":{"focus":["configure"]},"text":"Organize project configuration — Learn how files combine and how to validate configuration changes. Configuration reference — Find configuration settings in another topic."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10425,"markdownTokens":2038,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"metadata","title":"metadata","markdownUrl":"/config/outputs.sections/metadata.md","markdownBytes":2028,"markdownTokens":462},{"id":"exports","title":"exports","markdownUrl":"/config/outputs.sections/exports.md","markdownBytes":4075,"markdownTokens":789},{"id":"related-reading","title":"Related reading","markdownUrl":"/config/outputs.sections/related-reading.md","markdownBytes":1554,"markdownTokens":362}]},{"id":"reference.config-publishing","demo":false,"url":"/config/publishing","markdownUrl":"/config/publishing.md","title":"Publications and routing settings","summary":"Configure versions, languages, navigation, and redirects.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"publications","title":"publications"},{"id":"navigation","title":"navigation"},{"id":"redirects","title":"redirects"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Configure versions, languages, navigation, and redirects. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. publications Required. Declares which channel, version, and language combinations to build. See how Shoalrun works for the concepts. These settings select page variants within a build. For separate branches and domains, see use Git branches for separate docs sites . Key Meaning enabled At least one { channel, version, language } entry. language is optional and defaults to the default language. channels.<name>.pathPrefix Route prefix for a channel. Every channel used in enabled must be declared, even with pathPrefix: \"\" . versions.<name>.pathPrefix Route prefix for a version. Same rule as channels. defaults.channel , defaults.version The publication that uses each API's top-level source , and the defaults for scaffold and api select . Required when the project has apis . defaults.language The default language, which gets no route prefix. Global frontmatter can override it. Falls back to en . externalSites Optional links in the Version menu. Each entry needs a label and HTTP(S) baseUrl , which links to that site's root. Add a local manifest file containing its built documents.json to link only matching document IDs at their published paths. For a page in several enabled combinations, set its frontmatter publications to a list of { channel, version } pairs. This is separate from apis.<name>.publications , which binds API source files. A page without a list uses its resolved single channel and version. A list may include a declared but disabled combination; that copy is omitted from the build. See share pages across documentation versions for an example with version-specific sections. A single publication with no prefixes. Pages set channel: production and version: current : docs.config.yaml publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } Two API versions side by side. A v1 page at /guides/start is published at /v1/guides/start : docs.config.yaml publications : defaults : { channel : production , version : v2 } channels : production : { pathPrefix : \"\" } versions : v1 : { pathPrefix : /v1 } v2 : { pathPrefix : /v2 } enabled : - { channel : production , version : v1 } - { channel : production , version : v2 } A sandbox channel, with a version that is declared but not yet built. Leave a combination out of enabled to stop publishing it without deleting its pages: docs.config.yaml publications : defaults : { channel : production , version : v1 } channels : production : { pathPrefix : \"\" } sandbox : { pathPrefix : /sandbox } versions : v1 : { pathPrefix : \"\" } v2 : { pathPrefix : /v2 } enabled : - { channel : production , version : v1 } - { channel : sandbox , version : v1 } English at the root and German under /de . Pages without a language are English: docs.config.yaml publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } - { channel : production , version : current , language : de } navigation A list of sidebar nodes. Each node has a unique id and exactly one of doc , operation , generated , or items . Unknown node keys fail. See navigation . Key Meaning id Unique node ID. Required. doc A page ID. operation A stable operation ID; shows that operation's reference page. items Child nodes, optionally loaded from another YAML list with $include ; makes the node a group. Groups need a label . label Menu text. Defaults to the page title for doc and operation nodes. search Extra words for the sidebar navigation filter, separate from site-wide search. Allowed on page and operation nodes, not groups or generators. api Limits a group or generator to one API. Children inherit it. tab Set true on a top-level group to give it a navigation tab and sidebar. Requires landing ; nested tabs are rejected. landing Stable ID of a page inside the tab's items. The tab links to that page in each publication. tag An OpenAPI tag for a group that uses generated: remaining . generated tags or remaining . Adds generated reference pages. Pages and groups: config/nav.yaml - id : start doc : guide.overview - id : guides label : Guides items : - id : first-payment doc : guide.create-payment label : Your first payment search : checkout charge - id : errors doc : guide.handle-errors Mix authored pages, a pinned API operation, and generated reference pages grouped by OpenAPI tag: config/nav.yaml - id : payments label : Payments API api : payments items : - id : payment-guide doc : guide.create-payment - id : create-payment operati","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure versions, languages, navigation, and redirects. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. publications Required. Declares which channel, version, and language combinations to build. See how Shoalrun works for the concepts. These settings select page variants within a build. For separate branches and domains, see use Git branches for separate docs sites . Key Meaning enabled At least one { channel, version, language } entry. language is optional and defaults to the default language. channels.<name>.pathPrefix Route prefix for a channel. Every channel used in enabled must be declared, even with pathPrefix: \"\" . versions.<name>.pathPrefix Route prefix for a version. Same rule as channels. defaults.channel , defaults.version The publication that uses each API's top-level source , and the defaults for scaffold and api select . Required when the project has apis . defaults.language The default language, which gets no route prefix. Global frontmatter can override it. Falls back to en . externalSites Optional links in the Version menu. Each entry needs a label and HTTP(S) baseUrl , which links to that site's root. Add a local manifest file containing its built documents.json to link only matching document IDs at their published paths. For a page in several enabled combinations, set its frontmatter publications to a list of { channel, version } pairs. This is separate from apis.<name>.publications , which binds API source files. A page without a list uses its resolved single channel and version. A list may include a declared but disabled combination; that copy is omitted from the build. See share pages across documentation versions for an example with version-specific sections. A single publication with no prefixes. Pages set channel: production and version: current : publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } Two API versions side by side. A v1 page at /guides/start is published at /v1/guides/start : publications: defaults: { channel: production, version: v2 } channels: production: { pathPrefix: \"\" } versions: v1: { pathPrefix: /v1 } v2: { pathPrefix: /v2 } enabled: - { channel: production, version: v1 } - { channel: production, version: v2 } A sandbox channel, with a version that is declared but not yet built. Leave a combination out of enabled to stop publishing it without deleting its pages: publications: defaults: { channel: production, version: v1 } channels: production: { pathPrefix: \"\" } sandbox: { pathPrefix: /sandbox } versions: v1: { pathPrefix: \"\" } v2: { pathPrefix: /v2 } enabled: - { channel: production, version: v1 } - { channel: sandbox, version: v1 } English at the root and German under /de . Pages without a language are English: publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } - { channel: production, version: current, language: de } navigation A list of sidebar nodes. Each node has a unique id and exactly one of doc , operation , generated , or items . Unknown node keys fail. See navigation . Key Meaning id Unique node ID. Required. doc A page ID. operation A stable operation ID; shows that operation's reference page. items Child nodes, optionally loaded from another YAML list with $include ; makes the node a group. Groups need a label . label Menu text. Defaults to the page title for doc and operation nodes. search Extra words for the sidebar navigation filter, separate from site-wide search. Allowed on page and operation nodes, not groups or generators. api Limits a group or generator to one API. Children inherit it. tab Set true on a top-level group to give it a navigation tab and sidebar. Requires landing ; nested tabs are rejected. landing Stable ID of a page inside the tab's items. The tab links to that page in each publication. tag An OpenAPI tag for a group that uses generated: remaining . generated tags or remaining . Adds generated reference pages. Pages and groups: - id: start doc: guide.overview - id: guides label: Guides items: - id: first-payment doc: guide.create-payment label: Your first payment search: checkout charge - id: errors doc: guide.handle-errors Mix authored pages, a pinned API operation, and generated reference pages grouped by OpenAPI tag: - id: payments label: Payments API api: payments items: - id: payment-guide doc: guide.create-payment - id: create-payment operation: payments.create - id: other-payment-pages generated: tags Fill one hand-made group with the remaining operations for a tag: - id: reports label: Reports api: payments tag: Reports items: - id: report-guide doc:"},{"filters":{"focus":["configure"]},"text":"Organize project configuration — Learn how files combine and how to validate configuration changes. Configuration reference — Find configuration settings in another topic."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":12385,"markdownTokens":2434,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"navigation","title":"navigation","markdownUrl":"/config/publishing.sections/navigation.md","markdownBytes":4654,"markdownTokens":913},{"id":"redirects","title":"redirects","markdownUrl":"/config/publishing.sections/redirects.md","markdownBytes":4202,"markdownTokens":963},{"id":"related-reading","title":"Related reading","markdownUrl":"/config/publishing.sections/related-reading.md","markdownBytes":1514,"markdownTokens":355}]},{"id":"reference.config-site","demo":false,"url":"/config/site","markdownUrl":"/config/site.md","title":"Site and theme settings","summary":"Configure the site identity, header, footer, agent guidance, colors, and fonts.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"site","title":"site"},{"id":"site-agentdiscovery","title":"site.agentDiscovery"},{"id":"content-freshness","title":"Content freshness"},{"id":"theme","title":"theme"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Configure the site identity, header, footer, agent guidance, colors, and fonts. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. site Required. Key Default Meaning title None Site name in the masthead and the heading of /llms.txt . contentDir content Page directory, relative to the root config file. Every .md and .mdx file in it is read. contentFilter None Build-time whole-page selection by configured reader facets. All selected facets must match; any listed choice within a facet matches. Unmarked pages are excluded. Unknown or empty selectors and selections with no pages fail. See separate sites from shared content . basePath \"\" Mount point for public pages and resources, such as /docs . Use URL path segments without escapes or dot segments. Build tools keep internal manifests at the output root; the public site is also complete inside the docs/ output subtree. origin None The site's HTTPS origin, such as https://docs.example.com , with no path or trailing slash. Required to publish the API catalog, and makes link-preview URLs absolute. indexing true Set false on previews to add noindex to pages, disallow crawling in robots.txt , and omit the XML sitemap. updated None Optional YYYY-MM-DD fallback for sitemap lastmod , especially on generated API pages. Page updated overrides it. favicon A mark drawn from the preset and palette A local .svg or .png file. See share images and favicon . customCss None A local .css file linked after the framework styles. See CSS . editionBadge auto Masthead publication label: auto shows only the channel, version, or language values that differ across publications; always or never . header.links None Masthead links. See header . agentDiscovery Visually hidden until focused HTML agent guidance, visual presentation, and link labels. See site.agentDiscovery below. footer None Footer columns , bottom-row links , and a text line. See site footer . A minimal site needs only a title: docs.config.yaml site : title : Payments documentation Keep pages in another directory, add a stylesheet, and always show the publication label: docs.config.yaml site : title : Payments documentation contentDir : pages customCss : ./styles/project.css editionBadge : always Publish the API catalog. origin is required once any API sets discovery.endpoint : docs.config.yaml site : title : Payments documentation origin : https://docs.example.com Add masthead links: docs.config.yaml site : title : Payments documentation header : links : - { label : Guides , href : /start } - { label : GitHub , href : \"https://github.com/example/payments\" , style : button } - { label : Sign up , href : \"https://example.com/signup\" , style : primary } Add a footer: docs.config.yaml site : title : Payments documentation footer : columns : - title : Guides links : - { label : Get started , href : /start } links : - { label : Privacy , href : /legal/privacy } text : © 2026 Example, Inc. site.agentDiscovery Optional mapping. It controls the early agent guidance in HTML pages. Key Default Meaning mode focus Controls visual presentation and whether the block is included. See the visual and agent behavior below. label For agents Nonempty plain text before the message and links. Shoalrun adds the colon. message None Optional plain-text guidance. HTML tags are escaped; Markdown syntax stays literal. links.article Skip to article Label for the generated #main link. links.index Documentation index Label for the generated /llms.txt link, including site.basePath . links.markdown Read this page as Markdown Label for the current page's Markdown twin. docs.config.yaml site : title : Payments documentation agentDiscovery : mode : visible label : For agents message : Use the Markdown version for complete examples and nested schemas. links : article : Jump to the article index : Browse all documentation markdown : Read Markdown Only link labels are configurable; Shoalrun generates their destinations for each page. Labels must be nonempty strings. Unknown keys and invalid mode values fail validation and builds. The mode controls visual presentation and whether the instruction is included: Value Visual presentation Agent reading HTML focus Visually hidden until a link receives keyboard focus. The instruction and links are present in the HTML. visible Always shown as a banner. The same instruction and links are present in the HTML. disclosure A compact header toggle, closed initially. Links remain in HTML source; open it for visual navigation. off No agent guidance block appears. The instruction and its links are omitted from the HTML. Screen readers and agents parsing raw HTML can encounter the block in all enabled modes. An agent using screenshots sees the same visual presentation as a human. Some HTML extraction tools discard visually hidden elements; the document head also provides discovery links","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Configure the site identity, header, footer, agent guidance, colors, and fonts. These keys belong in docs.config.yaml or an included configuration file. For file composition and validation commands, see Configure your project . Use the configuration index to find another setting. site Required. Key Default Meaning title None Site name in the masthead and the heading of /llms.txt . contentDir content Page directory, relative to the root config file. Every .md and .mdx file in it is read. contentFilter None Build-time whole-page selection by configured reader facets. All selected facets must match; any listed choice within a facet matches. Unmarked pages are excluded. Unknown or empty selectors and selections with no pages fail. See separate sites from shared content . basePath \"\" Mount point for public pages and resources, such as /docs . Use URL path segments without escapes or dot segments. Build tools keep internal manifests at the output root; the public site is also complete inside the docs/ output subtree. origin None The site's HTTPS origin, such as https://docs.example.com , with no path or trailing slash. Required to publish the API catalog, and makes link-preview URLs absolute. indexing true Set false on previews to add noindex to pages, disallow crawling in robots.txt , and omit the XML sitemap. updated None Optional YYYY-MM-DD fallback for sitemap lastmod , especially on generated API pages. Page updated overrides it. favicon A mark drawn from the preset and palette A local .svg or .png file. See share images and favicon . customCss None A local .css file linked after the framework styles. See CSS . editionBadge auto Masthead publication label: auto shows only the channel, version, or language values that differ across publications; always or never . header.links None Masthead links. See header . agentDiscovery Visually hidden until focused HTML agent guidance, visual presentation, and link labels. See site.agentDiscovery below. footer None Footer columns , bottom-row links , and a text line. See site footer . A minimal site needs only a title: site: title: Payments documentation Keep pages in another directory, add a stylesheet, and always show the publication label: site: title: Payments documentation contentDir: pages customCss: ./styles/project.css editionBadge: always Publish the API catalog. origin is required once any API sets discovery.endpoint : site: title: Payments documentation origin: https://docs.example.com Add masthead links: site: title: Payments documentation header: links: - { label: Guides, href: /start } - { label: GitHub, href: \"https://github.com/example/payments\", style: button } - { label: Sign up, href: \"https://example.com/signup\", style: primary } Add a footer: site: title: Payments documentation footer: columns: - title: Guides links: - { label: Get started, href: /start } links: - { label: Privacy, href: /legal/privacy } text: © 2026 Example, Inc. site.agentDiscovery Optional mapping. It controls the early agent guidance in HTML pages. Key Default Meaning mode focus Controls visual presentation and whether the block is included. See the visual and agent behavior below. label For agents Nonempty plain text before the message and links. Shoalrun adds the colon. message None Optional plain-text guidance. HTML tags are escaped; Markdown syntax stays literal. links.article Skip to article Label for the generated #main link. links.index Documentation index Label for the generated /llms.txt link, including site.basePath . links.markdown Read this page as Markdown Label for the current page's Markdown twin. site: title: Payments documentation agentDiscovery: mode: visible label: For agents message: Use the Markdown version for complete examples and nested schemas. links: article: Jump to the article index: Browse all documentation markdown: Read Markdown Only link labels are configurable; Shoalrun generates their destinations for each page. Labels must be nonempty strings. Unknown keys and invalid mode values fail validation and builds. The mode controls visual presentation and whether the instruction is included: Value Visual presentation Agent reading HTML focus Visually hidden until a link receives keyboard focus. The instruction and links are present in the HTML. visible Always shown as a banner. The same instruction and links are present in the HTML. disclosure A compact header toggle, closed initially. Links remain in HTML source; open it for visual navigation. off No agent guidance block appears. The instruction and its links are omitted from the HTML. Screen readers and agents parsing raw HTML can encounter the block in all enabled modes. An agent using screenshots sees the same visual presentation as a human. Some HTML extraction tools discard visually hidden elements; the document head also provides discovery links. Visually hiding the block does not make it private. This setting affects HTML only. It does not change the Markdown index link, generated discovery fil"},{"filters":{"focus":["configure"]},"text":"Organize project configuration — Learn how files combine and how to validate configuration changes. Configuration reference — Find configuration settings in another topic."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14747,"markdownTokens":2422,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"theme","title":"theme","markdownUrl":"/config/site.sections/theme.md","markdownBytes":3628,"markdownTokens":805},{"id":"related-reading","title":"Related reading","markdownUrl":"/config/site.sections/related-reading.md","markdownBytes":1510,"markdownTokens":364}]},{"id":"reference.config","demo":false,"url":"/config","markdownUrl":"/config.md","title":"Configuration reference","summary":"Find configuration settings by topic and compose a project configuration.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"find-a-setting","title":"Find a setting"},{"id":"start-a-configuration-file","title":"Start a configuration file"},{"id":"split-and-combine-config-files","title":"Split and combine config files"},{"id":"include","title":"$include"},{"id":"extends","title":"extends"},{"id":"concat-and-remove","title":"$concat and $remove"},{"id":"settings-by-key","title":"Settings by key"},{"id":"search","title":"search"},{"id":"authoring","title":"authoring"},{"id":"site","title":"site"},{"id":"site-agentdiscovery","title":"site.agentDiscovery"},{"id":"content-freshness","title":"Content freshness"},{"id":"theme","title":"theme"},{"id":"publications","title":"publications"},{"id":"navigation","title":"navigation"},{"id":"redirects","title":"redirects"},{"id":"apis","title":"apis"},{"id":"audit","title":"audit"},{"id":"agent-evaluation-reports","title":"Agent evaluation reports"},{"id":"cookbooks","title":"cookbooks"},{"id":"relationships","title":"relationships"},{"id":"variables","title":"variables"},{"id":"snippets","title":"snippets"},{"id":"callouts","title":"callouts"},{"id":"badges","title":"badges"},{"id":"templates","title":"templates"},{"id":"readerfilters","title":"readerFilters"},{"id":"frontmatter","title":"frontmatter"},{"id":"mcp","title":"mcp"},{"id":"analytics","title":"analytics"},{"id":"metadata","title":"metadata"},{"id":"exports","title":"exports"},{"id":"outputs","title":"outputs"},{"id":"agent-discovery-index","title":"Agent discovery index"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"related-topics","title":"Related topics"}],"text":"A project's configuration starts at docs.config.yaml . The CLI looks for that name by default, and shoalrun scaffold -n searches parent directories for it. For a guided workflow, start with Configure your project . For complete working projects, see Example configs . Find a setting Each reference below contains the field definitions, defaults, validation rules, and examples for its topic. Reference Configuration keys Site and theme settings site , theme Publications and routing settings publications , navigation , redirects Authoring and content settings authoring , frontmatter , variables , snippets , templates , callouts , badges , cookbooks , relationships , readerFilters API and audit settings apis , audit Search and integration settings search , mcp , analytics Output and export settings metadata , exports , outputs Start a configuration file The root file must be a YAML mapping with schemaVersion: 1 . YAML is parsed strictly: duplicate keys fail. Unknown top-level keys fail with unknown setting <key> . See the focused references for validation rules within each setting. docs.config.yaml schemaVersion : 1 site : title : Example documentation publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } navigation : { $include : ./config/nav.yaml } Split and combine config files These directives compose configuration values. Paths resolve relative to the file declaring them. For complete examples, merge order, and troubleshooting, follow Configure your project . $include { $include: ./path.yaml } replaces a value at any depth with the contents of another YAML file. The mapping can have no other keys. Included files can include others; a cycle fails with Configuration cycle and the chain of files. Normal inheritance rules apply to the resolved value. extends A top-level extends: [./base.yaml] layers one or more presets in order, followed by the current file. Mappings merge key by key; lists and scalar values replace earlier values. Presets may extend other presets. A top-level extends always names config files, including in an included file; it cannot serve another purpose there. $concat and $remove { $concat: [...] } appends items to an inherited list, or becomes the list when none is inherited. It also accepts included lists. { $remove: [name, ...] } removes inherited mapping keys by name or list items by id ; it fails when nothing is inherited. Run shoalrun config explain <key> docs.config.yaml to inspect a value's source and overrides. See the CLI reference for other inspection commands. Settings by key Use these links to jump directly to a setting in its focused reference. search See search settings . authoring See authoring settings . site See site settings . site.agentDiscovery See site.agentDiscovery settings . Content freshness See Content freshness settings . theme See theme settings . publications See publications settings . navigation See navigation settings . redirects See redirects settings . apis See apis settings . audit See audit settings . Agent evaluation reports See Agent evaluation reports settings . cookbooks See cookbooks settings . relationships See relationships settings . variables See variables settings . snippets See snippets settings . callouts See callouts settings . badges See badges settings . templates See templates settings . readerFilters See readerFilters settings . frontmatter See frontmatter settings . mcp See mcp settings . analytics See analytics settings . metadata See metadata settings . exports See exports settings . outputs See outputs settings . Agent discovery index See Agent discovery index settings . Related reading Read first How Shoalrun works — Understand publications, stable IDs, and config composition before changing settings. Related topics CLI reference — Build, serve, and inspect a config from the command line. Example configs — The same settings, combined into complete, working files.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"A project's configuration starts at docs.config.yaml . The CLI looks for that name by default, and shoalrun scaffold -n searches parent directories for it. For a guided workflow, start with Configure your project . For complete working projects, see Example configs . Find a setting Each reference below contains the field definitions, defaults, validation rules, and examples for its topic. Reference Configuration keys Site and theme settings site , theme Publications and routing settings publications , navigation , redirects Authoring and content settings authoring , frontmatter , variables , snippets , templates , callouts , badges , cookbooks , relationships , readerFilters API and audit settings apis , audit Search and integration settings search , mcp , analytics Output and export settings metadata , exports , outputs Start a configuration file The root file must be a YAML mapping with schemaVersion: 1 . YAML is parsed strictly: duplicate keys fail. Unknown top-level keys fail with unknown setting <key> . See the focused references for validation rules within each setting. schemaVersion: 1 site: title: Example documentation publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } navigation: { $include: ./config/nav.yaml } Split and combine config files These directives compose configuration values. Paths resolve relative to the file declaring them. For complete examples, merge order, and troubleshooting, follow Configure your project . $include { $include: ./path.yaml } replaces a value at any depth with the contents of another YAML file. The mapping can have no other keys. Included files can include others; a cycle fails with Configuration cycle and the chain of files. Normal inheritance rules apply to the resolved value. extends A top-level extends: [./base.yaml] layers one or more presets in order, followed by the current file. Mappings merge key by key; lists and scalar values replace earlier values. Presets may extend other presets. A top-level extends always names config files, including in an included file; it cannot serve another purpose there. $concat and $remove { $concat: [...] } appends items to an inherited list, or becomes the list when none is inherited. It also accepts included lists. { $remove: [name, ...] } removes inherited mapping keys by name or list items by id ; it fails when nothing is inherited. Run shoalrun config explain <key> docs.config.yaml to inspect a value's source and overrides. See the CLI reference for other inspection commands. Settings by key Use these links to jump directly to a setting in its focused reference. search See search settings . authoring See authoring settings . site See site settings . site.agentDiscovery See site.agentDiscovery settings . Content freshness See Content freshness settings . theme See theme settings . publications See publications settings . navigation See navigation settings . redirects See redirects settings . apis See apis settings . audit See audit settings . Agent evaluation reports See Agent evaluation reports settings . cookbooks See cookbooks settings . relationships See relationships settings . variables See variables settings . snippets See snippets settings . callouts See callouts settings . badges See badges settings . templates See templates settings . readerFilters See readerFilters settings . frontmatter See frontmatter settings . mcp See mcp settings . analytics See analytics settings . metadata See metadata settings . exports See exports settings . outputs See outputs settings . Agent discovery index See Agent discovery index settings . Related reading Read first How Shoalrun works — Understand publications, stable IDs, and config composition before changing settings. Related topics CLI reference — Build, serve, and inspect a config from the command line."},{"filters":{"focus":["configure"]},"text":"Example configs — The same settings, combined into complete, working files."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":8300,"markdownTokens":1808,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.configuration","demo":false,"url":"/configuration","markdownUrl":"/configuration.md","title":"Organize project configuration","summary":"Learn how Shoalrun resolves config files, layers presets, tracks path origins, and applies page defaults before building publications.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"understand-the-three-stages","title":"Understand the three stages"},{"id":"find-the-section-you-need","title":"Find the section you need"},{"id":"start-with-one-working-file","title":"Start with one working file"},{"id":"extract-a-section-with-include","title":"Extract a section with $include"},{"id":"share-defaults-through-extends","title":"Share defaults through extends"},{"id":"predict-a-merge-before-you-make-it","title":"Predict a merge before you make it"},{"id":"change-inherited-lists-deliberately","title":"Change inherited lists deliberately"},{"id":"know-the-directive-limits","title":"Know the directive limits"},{"id":"understand-where-paths-point","title":"Understand where paths point"},{"id":"separate-config-inheritance-from-page-metadata","title":"Separate config inheritance from page metadata"},{"id":"publication-defaults-serve-a-different-purpose","title":"Publication defaults serve a different purpose"},{"id":"inspect-and-validate-changes","title":"Inspect and validate changes"},{"id":"recover-common-configuration-failures","title":"Recover common configuration failures"},{"id":"build-several-sites-from-shared-content","title":"Build several sites from shared content"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"docs.config.yaml connects your content, presentation, and publication settings. Start with one file, then extract sections or share defaults when several projects need them. This guide explains how those choices interact and how to inspect the result. Use the configuration reference to look up individual fields. Use example projects for complete configurations you can copy. Understand the three stages Configuration takes effect in three stages: Resolve configuration. Read the entry file, load presets and includes, and merge them into one value. Track which file supplied each setting. Resolve pages. Apply configured frontmatter defaults, the page's own metadata, and enforced metadata. Validate the resulting page fields. Build publications. Select public pages for enabled channel/version/language combinations, resolve links and APIs, then produce HTML, Markdown, and discovery files. A preset changes configuration. A page default changes metadata. An enabled publication selects an edition to build. These mechanisms have separate rules; changing one does not automatically create pages or translations. Find the section you need Start with the configuration sections that control the behavior you want to change. Goal Configuration sections Name the site and locate content site Choose editions and routes publications , redirects Organize pages and related reading navigation , relationships Define page metadata and authoring conventions frontmatter , metadata , templates , authoring Reuse text and semantic content variables , snippets , callouts , badges Register local OpenAPI sources and operations apis Style the site and configure rendering theme , outputs Configure reader views and project checks readerFilters , audit Every entry config resolves to a YAML mapping with schemaVersion: 1 . Duplicate YAML keys and unknown top-level settings fail. Nested settings are not all checked for unknown keys, so verify spelling against the reference. Start with one working file The examples use the compiled CLI from the quickstart . From the Shoalrun checkout root, create a separate minimal project: SHOALRUN_CLI = \"$PWD/framework/dist/cli.js\" CONFIG_DEMO = \"$( mktemp -d )\" node \"$SHOALRUN_CLI\" init \"$CONFIG_DEMO/site\" --starter minimal cd \"$CONFIG_DEMO/site\" The starter has two pages and this basic configuration structure: docs.config.yaml schemaVersion : 1 site : title : Acme handbook publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } frontmatter : defaults : type : guide channel : production version : current access : { policy : public } navigation : - id : welcome doc : guide.welcome - id : setup label : Setup items : - id : install doc : guide.install Build once before reorganizing: node \"$SHOALRUN_CLI\" build docs.config.yaml dist This produces the same two pages after each reorganization below. Keep dist/ separate from content and configuration inputs. Extract a section with $include An include substitutes another YAML value at its location. The included file can contain a mapping, list, or scalar, depending on the setting that receives it. Create a config/ directory: mkdir -p config Move the navigation list into this file: config/nav.yaml - id : welcome doc : guide.welcome - id : setup label : Setup items : - id : install doc : guide.install Replace the entire navigation section in docs.config.yaml with: navigation : { $include : ./config/nav.yaml } The included file contains the list itself, without a surrounding navigation: key. Adding that wrapper would supply a mapping where navigation expects a list. An include has no sibling keys. For example, placing both $include and label in the same mapping fails with exactly one directive is required . Include a smaller value or use inheritance to combine settings. Includes work at any depth and can include other files. Paths in $include are relative to the YAML file containing that directive. A cycle fails with Configuration cycle and the file chain. Inspect the substituted value and its source: node \"$SHOALRUN_CLI\" config resolve docs.config.yaml node \"$SHOALRUN_CLI\" config explain navigation.0.doc docs.config.yaml The first command prints the effective value, digest, and configuration dependencies. The second identifies config/nav.yaml as the source of guide.welcome . Share defaults through extends Use extends when several projects should inherit shared settings. Presets are ordinary YAML mappings and can extend other presets. Each file's extends list is processed in order; later presets override earlier ones, and the local file overrides them all. Create a shared directory beside the site: mkdir -p ../shared Create the following preset: ../shared/base.yaml schemaVersion : 1 site : title : Company handbook customCss : ./brand.css header : links : - { label : Support , href : \"https://support.example","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"docs.config.yaml connects your content, presentation, and publication settings. Start with one file, then extract sections or share defaults when several projects need them. This guide explains how those choices interact and how to inspect the result. Use the configuration reference to look up individual fields. Use example projects for complete configurations you can copy. Understand the three stages Configuration takes effect in three stages: Resolve configuration. Read the entry file, load presets and includes, and merge them into one value. Track which file supplied each setting. Resolve pages. Apply configured frontmatter defaults, the page's own metadata, and enforced metadata. Validate the resulting page fields. Build publications. Select public pages for enabled channel/version/language combinations, resolve links and APIs, then produce HTML, Markdown, and discovery files. A preset changes configuration. A page default changes metadata. An enabled publication selects an edition to build. These mechanisms have separate rules; changing one does not automatically create pages or translations. Find the section you need Start with the configuration sections that control the behavior you want to change. Goal Configuration sections Name the site and locate content site Choose editions and routes publications , redirects Organize pages and related reading navigation , relationships Define page metadata and authoring conventions frontmatter , metadata , templates , authoring Reuse text and semantic content variables , snippets , callouts , badges Register local OpenAPI sources and operations apis Style the site and configure rendering theme , outputs Configure reader views and project checks readerFilters , audit Every entry config resolves to a YAML mapping with schemaVersion: 1 . Duplicate YAML keys and unknown top-level settings fail. Nested settings are not all checked for unknown keys, so verify spelling against the reference. Start with one working file The examples use the compiled CLI from the quickstart . From the Shoalrun checkout root, create a separate minimal project: SHOALRUN_CLI=\"$PWD/framework/dist/cli.js\" CONFIG_DEMO=\"$(mktemp -d)\" node \"$SHOALRUN_CLI\" init \"$CONFIG_DEMO/site\" --starter minimal cd \"$CONFIG_DEMO/site\" The starter has two pages and this basic configuration structure: schemaVersion: 1 site: title: Acme handbook publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } frontmatter: defaults: type: guide channel: production version: current access: { policy: public } navigation: - id: welcome doc: guide.welcome - id: setup label: Setup items: - id: install doc: guide.install Build once before reorganizing: node \"$SHOALRUN_CLI\" build docs.config.yaml dist This produces the same two pages after each reorganization below. Keep dist/ separate from content and configuration inputs. Extract a section with $include An include substitutes another YAML value at its location. The included file can contain a mapping, list, or scalar, depending on the setting that receives it. Create a config/ directory: mkdir -p config Move the navigation list into this file: - id: welcome doc: guide.welcome - id: setup label: Setup items: - id: install doc: guide.install Replace the entire navigation section in docs.config.yaml with: navigation: { $include: ./config/nav.yaml } The included file contains the list itself, without a surrounding navigation: key. Adding that wrapper would supply a mapping where navigation expects a list. An include has no sibling keys. For example, placing both $include and label in the same mapping fails with exactly one directive is required . Include a smaller value or use inheritance to combine settings. Includes work at any depth and can include other files. Paths in $include are relative to the YAML file containing that directive. A cycle fails with Configuration cycle and the file chain. Inspect the substituted value and its source: node \"$SHOALRUN_CLI\" config resolve docs.config.yaml node \"$SHOALRUN_CLI\" config explain navigation.0.doc docs.config.yaml The first command prints the effective value, digest, and configuration dependencies. The second identifies config/nav.yaml as the source of guide.welcome . Share defaults through extends Use extends when several projects should inherit shared settings. Presets are ordinary YAML mappings and can extend other presets. Each file's extends list is processed in order; later presets override earlier ones, and the local file overrides them all. Create a shared directory beside the site: mkdir -p ../shared Create the following preset: schemaVersion: 1 site: title: Company handbook customCss: ./brand.css header: links: - { label: Support, href: \"https://support.example.com\" } publications: defaults: { channel: production, version: current, language: en } channels: production: { "},{"filters":{"focus":["configure"]},"text":"Build separate sites from shared content — Reuse shared configuration and content for separately selected sites. Configuration reference — Look up individual settings and their defaults. Example configs — Explore complete projects using composition, versions, and languages."},{"filters":{"focus":["write"]},"text":"Frontmatter field reference — Inspect generated native and project-defined page fields."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":20373,"markdownTokens":4146,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"understand-the-three-stages","title":"Understand the three stages","markdownUrl":"/configuration.sections/understand-the-three-stages.md","markdownBytes":3748,"markdownTokens":740},{"id":"start-with-one-working-file","title":"Start with one working file","markdownUrl":"/configuration.sections/start-with-one-working-file.md","markdownBytes":2811,"markdownTokens":681},{"id":"extract-a-section-with-include","title":"Extract a section with $include","markdownUrl":"/configuration.sections/extract-a-section-with-include.md","markdownBytes":3079,"markdownTokens":703},{"id":"share-defaults-through-extends","title":"Share defaults through extends","markdownUrl":"/configuration.sections/share-defaults-through-extends.md","markdownBytes":5156,"markdownTokens":1132},{"id":"change-inherited-lists-deliberately","title":"Change inherited lists deliberately","markdownUrl":"/configuration.sections/change-inherited-lists-deliberately.md","markdownBytes":3563,"markdownTokens":807},{"id":"understand-where-paths-point","title":"Understand where paths point","markdownUrl":"/configuration.sections/understand-where-paths-point.md","markdownBytes":3469,"markdownTokens":723},{"id":"separate-config-inheritance-from-page-metadata","title":"Separate config inheritance from page metadata","markdownUrl":"/configuration.sections/separate-config-inheritance-from-page-metadata.md","markdownBytes":3430,"markdownTokens":723},{"id":"inspect-and-validate-changes","title":"Inspect and validate changes","markdownUrl":"/configuration.sections/inspect-and-validate-changes.md","markdownBytes":5467,"markdownTokens":1083},{"id":"build-several-sites-from-shared-content","title":"Build several sites from shared content","markdownUrl":"/configuration.sections/build-several-sites-from-shared-content.md","markdownBytes":2008,"markdownTokens":456},{"id":"related-reading","title":"Related reading","markdownUrl":"/configuration.sections/related-reading.md","markdownBytes":2006,"markdownTokens":458}]},{"id":"guide.site-mcp","demo":false,"url":"/connect/mcp","markdownUrl":"/connect/mcp.md","title":"Use this site's MCP","summary":"Connect your agent to Shoalrun's public documentation and ask it to search, read pages, or fetch sections.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-mcp","headings":[{"id":"connect-and-ask-a-question","title":"Connect and ask a question"},{"id":"add-the-documentation-server","title":"Add the documentation server"},{"id":"connect-and-discover-the-tools","title":"Connect and discover the tools"},{"id":"ask-the-agent-to-use-the-documentation","title":"Ask the agent to use the documentation"},{"id":"what-the-tools-do","title":"What the tools do"},{"id":"if-the-connection-fails","title":"If the connection fails"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Connect an MCP client to Shoalrun's live documentation at https://www.shoalrun.com/mcp . You need an agent application that supports remote HTTP MCP servers. No Shoalrun account, API key, custom header, or local installation is required. This endpoint reads Shoalrun's public documentation. To host an endpoint for your own documentation, use the separate MCP hosting guide . Connect and ask a question The setting names vary by client. Use its remote MCP server connection settings: Add the documentation server Create a remote server connection named shoalrun-docs . Choose HTTP or Streamable HTTP when your client asks for the transport. Enter this server URL: https://www.shoalrun.com/mcp Leave authentication and custom headers unset. The URL is an MCP endpoint, not a web page; opening it directly in a browser may show a method error. Connect and discover the tools Save the connection and enable it. Restart or reconnect the client if it does not refresh its tools automatically. Look for search_docs , get_page , get_outline , and get_section under the connection. Your client may prefix their names with shoalrun-docs . Ask the agent to use the documentation Try this request in your agent: Use the Shoalrun docs MCP to find how to configure analytics. Read the relevant documentation and give me the answer with source links. Inspect the agent's tool activity. It should call search_docs and follow a returned read instruction. Answers and links alone do not prove that it used MCP. What the tools do These tools only read published documentation. They cannot edit your files, change a project, or deploy a site. Tool Use search_docs Find relevant pages and suggested read instructions. get_page Read a Markdown page by its stable document ID. get_outline List a page's sections and their exact IDs. get_section Read one section by page ID and section ID. Use IDs returned by the tools rather than guessing them from a page title or URL. When a tool says the result does not fit its token budget, retry with the recommended maxTokens value. Do not treat an incomplete response as the complete documentation. If the connection fails Check that your client supports remote HTTP MCP and that the URL ends in /mcp . A client that only launches local stdio commands cannot connect directly to this URL. If tools are missing after saving, reconnect the server or restart the client. If the client insists on an API key or OAuth login, check that you selected an unauthenticated remote connection. This endpoint does not provide an OAuth login. This site's MCP analytics measures tool usage, available harness/model labels, and fixed intent categories. It excludes raw queries, free-text intent, returned content, and request headers. Session grouping uses pseudonymous IDs. Hosting access logs are separate; see the analytics safeguards . No private test settings are needed to use the tools or supply supported metadata. Missing or unrecognized labels remain absent; the server does not guess them. Related reading Next steps Connect an MCP client — Host the same documentation tools for your own project. Related topics Agent-friendly documentation — Understand the Markdown and discovery outputs behind the tools.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Connect an MCP client to Shoalrun's live documentation at https://www.shoalrun.com/mcp . You need an agent application that supports remote HTTP MCP servers. No Shoalrun account, API key, custom header, or local installation is required. This endpoint reads Shoalrun's public documentation. To host an endpoint for your own documentation, use the separate MCP hosting guide . Connect and ask a question The setting names vary by client. Use its remote MCP server connection settings: Add the documentation server Create a remote server connection named shoalrun-docs . Choose HTTP or Streamable HTTP when your client asks for the transport. Enter this server URL: https://www.shoalrun.com/mcp Leave authentication and custom headers unset. The URL is an MCP endpoint, not a web page; opening it directly in a browser may show a method error. Connect and discover the tools Save the connection and enable it. Restart or reconnect the client if it does not refresh its tools automatically. Look for search_docs , get_page , get_outline , and get_section under the connection. Your client may prefix their names with shoalrun-docs . Ask the agent to use the documentation Try this request in your agent: Use the Shoalrun docs MCP to find how to configure analytics. Read the relevant documentation and give me the answer with source links. Inspect the agent's tool activity. It should call search_docs and follow a returned read instruction. Answers and links alone do not prove that it used MCP. What the tools do These tools only read published documentation. They cannot edit your files, change a project, or deploy a site. Tool Use search_docs Find relevant pages and suggested read instructions. get_page Read a Markdown page by its stable document ID. get_outline List a page's sections and their exact IDs. get_section Read one section by page ID and section ID. Use IDs returned by the tools rather than guessing them from a page title or URL. When a tool says the result does not fit its token budget, retry with the recommended maxTokens value. Do not treat an incomplete response as the complete documentation. If the connection fails Check that your client supports remote HTTP MCP and that the URL ends in /mcp . A client that only launches local stdio commands cannot connect directly to this URL. If tools are missing after saving, reconnect the server or restart the client. If the client insists on an API key or OAuth login, check that you selected an unauthenticated remote connection. This endpoint does not provide an OAuth login. This site's MCP analytics measures tool usage, available harness/model labels, and fixed intent categories. It excludes raw queries, free-text intent, returned content, and request headers. Session grouping uses pseudonymous IDs. Hosting access logs are separate; see the analytics safeguards . No private test settings are needed to use the tools or supply supported metadata. Missing or unrecognized labels remain absent; the server does not guess them. Related reading Next steps Related topics"},{"filters":{"focus":["configure"]},"text":"Connect an MCP client — Host the same documentation tools for your own project. Agent-friendly documentation — Understand the Markdown and discovery outputs behind the tools."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4485,"markdownTokens":1009,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.content-export","demo":false,"url":"/publish/content-export","markdownUrl":"/publish/content-export.md","title":"Export content into your application","summary":"Export shared content for application help.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[{"id":"prerequisites","title":"Prerequisites"},{"id":"export-selected-pages","title":"Export selected pages"},{"id":"define-an-export-target","title":"Define an export target"},{"id":"build-the-portable-bundle","title":"Build the portable bundle"},{"id":"mount-and-load-the-content-in-your-app","title":"Mount and load the content in your app"},{"id":"handle-document-links-and-check-the-result","title":"Handle document links and check the result"},{"id":"check-the-result","title":"Check the result"},{"id":"what-the-representations-retain","title":"What the representations retain"},{"id":"assets-downloads-and-notices","title":"Assets, downloads, and notices"},{"id":"review-exported-api-material","title":"Review exported API material"},{"id":"inspect-the-manifest","title":"Inspect the manifest"},{"id":"try-the-help-drawer-example","title":"Try the help-drawer example"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Keep application help and your documentation website in one content source. shoalrun export produces a directory of resolved Markdown, passive HTML fragments, referenced assets, and a manifest. Your application owns the help drawer, onboarding screen, or other interface that displays the content. It does not need a Shoalrun browser runtime. Prerequisites Content exports require Shoalrun CLI 0.1.0-alpha.6 or later. Start with a Shoalrun project and public pages assigned to an enabled publication. Navigation, facets, a site title, and a previous website build are optional. A site origin is needed only when links must fall back to pages on the documentation website. The export does not generate embeddings or run documentation chat. Export selected pages Define an export target Add a named target to docs.config.yaml . These IDs refer to pages in the project's configured content directory: exports : app-help : formats : [ markdown , html ] documents : [ guide.api-keys , guide.billing ] publicBase : /help/ Omit documents to export all eligible public pages in one enabled publication. If more than one publication is enabled, select all three coordinates: exports : app-help : formats : [ html ] documents : [ guide.api-keys , guide.billing ] publication : { channel : production , version : current , language : en } publicBase : /help/ Optional contentFilter uses configured reader facets. Every selected facet must match; choices within a facet are alternatives. Pages missing a selected facet are excluded. An explicitly requested ID that is absent, private, unavailable in the publication, or excluded by the export filter fails with a diagnostic. Export selection is independent of the website's site.contentFilter and navigation. Changing a website menu does not change the app's help collection. See separate sites from shared content for website selection. Build the portable bundle From the documentation project, run: shoalrun export docs.config.yaml --target app-help --out ../app/public/help Replace the output path with the directory your application will distribute. The command prints JSON with its publication, formats, selected document IDs, asset count, digest, API review requirements, and diagnostics. A successful export replaces an earlier export in that directory. A failure preserves it. Source directories, unrelated nonempty directories, and previous website builds cannot be used as the export destination. The result has this structure: help/ manifest.json content/ ...HTML and Markdown files assets/ ...referenced local files NOTICES.txt File names derive from stable document identity and publication, not titles or source-file names. Read paths from the manifest rather than constructing them in your app. For a one-off export without a named target: shoalrun export docs.config.yaml --out ../app/public/help \\ --format html --document guide.api-keys --document guide.billing \\ --public-base /help/ Mount and load the content in your app /help/ is an example value, not a required path. Choose any root-relative path ending with a slash, such as /resources/ . Set publicBase to that path, serve the generated bundle there, and update the manifest URL in your app's loader to match (for example, /resources/manifest.json ). The --out filesystem directory can have a different name from the URL path. The examples below use /help/ . This base locates content and assets; it does not define your application's routes. Your app can find a page by ID and load its HTML fragment: const manifest = await fetch ( '/help/manifest.json' ) .then (response => response .json ()); if ( manifest .schemaVersion !== 1 || manifest . review .status !== 'ok' ) { throw new Error ( 'Unsupported or unreviewed help export' ); } const help = manifest . documents .find (document => document .id === 'guide.api-keys' ); const html = await fetch ( manifest .publicBase + help . representations . html .path) .then (response => response .text ()); helpContainer .innerHTML = html; Use this pattern for trusted output from your own documentation build. Handle missing documents and failed requests in your application's loading and error states. The manifest also provides Markdown paths if your app uses its own Markdown renderer. Images use the configured mount. This matters when HTML fetched from /help/content/ is inserted into an app page such as /settings/account : relative image URLs would otherwise resolve against the app page. Handle document links and check the result Links to other exported pages have data-export-link markers. Each marker identifies a record in that representation's links array. For kind: document , your app can prevent ordinary navigation and open documentId in the drawer. fragment identifies the original heading or anchor; the HTML representation's anchors array maps it to its namespaced exportedId . A link to an omitted document uses its canonical website URL only when that document is public, enabled, and selected for the website. Without","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Keep application help and your documentation website in one content source. shoalrun export produces a directory of resolved Markdown, passive HTML fragments, referenced assets, and a manifest. Your application owns the help drawer, onboarding screen, or other interface that displays the content. It does not need a Shoalrun browser runtime. Prerequisites Content exports require Shoalrun CLI 0.1.0-alpha.6 or later. Start with a Shoalrun project and public pages assigned to an enabled publication. Navigation, facets, a site title, and a previous website build are optional. A site origin is needed only when links must fall back to pages on the documentation website. The export does not generate embeddings or run documentation chat. Export selected pages Define an export target Add a named target to docs.config.yaml . These IDs refer to pages in the project's configured content directory: exports: app-help: formats: [markdown, html] documents: [guide.api-keys, guide.billing] publicBase: /help/ Omit documents to export all eligible public pages in one enabled publication. If more than one publication is enabled, select all three coordinates: exports: app-help: formats: [html] documents: [guide.api-keys, guide.billing] publication: { channel: production, version: current, language: en } publicBase: /help/ Optional contentFilter uses configured reader facets. Every selected facet must match; choices within a facet are alternatives. Pages missing a selected facet are excluded. An explicitly requested ID that is absent, private, unavailable in the publication, or excluded by the export filter fails with a diagnostic. Export selection is independent of the website's site.contentFilter and navigation. Changing a website menu does not change the app's help collection. See separate sites from shared content for website selection. Build the portable bundle From the documentation project, run: shoalrun export docs.config.yaml --target app-help --out ../app/public/help Replace the output path with the directory your application will distribute. The command prints JSON with its publication, formats, selected document IDs, asset count, digest, API review requirements, and diagnostics. A successful export replaces an earlier export in that directory. A failure preserves it. Source directories, unrelated nonempty directories, and previous website builds cannot be used as the export destination. The result has this structure: help/ manifest.json content/ ...HTML and Markdown files assets/ ...referenced local files NOTICES.txt File names derive from stable document identity and publication, not titles or source-file names. Read paths from the manifest rather than constructing them in your app. For a one-off export without a named target: shoalrun export docs.config.yaml --out ../app/public/help \\ --format html --document guide.api-keys --document guide.billing \\ --public-base /help/ Mount and load the content in your app /help/ is an example value, not a required path. Choose any root-relative path ending with a slash, such as /resources/ . Set publicBase to that path, serve the generated bundle there, and update the manifest URL in your app's loader to match (for example, /resources/manifest.json ). The --out filesystem directory can have a different name from the URL path. The examples below use /help/ . This base locates content and assets; it does not define your application's routes. Your app can find a page by ID and load its HTML fragment: const manifest = await fetch('/help/manifest.json').then(response => response.json()); if (manifest.schemaVersion !== 1 || manifest.review.status !== 'ok') { throw new Error('Unsupported or unreviewed help export'); } const help = manifest.documents.find(document => document.id === 'guide.api-keys'); const html = await fetch(manifest.publicBase + help.representations.html.path) .then(response => response.text()); helpContainer.innerHTML = html; Use this pattern for trusted output from your own documentation build. Handle missing documents and failed requests in your application's loading and error states. The manifest also provides Markdown paths if your app uses its own Markdown renderer. Images use the configured mount. This matters when HTML fetched from /help/content/ is inserted into an app page such as /settings/account : relative image URLs would otherwise resolve against the app page. Handle document links and check the result Links to other exported pages have data-export-link markers. Each marker identifies a record in that representation's links array. For kind: document , your app can prevent ordinary navigation and open documentId in the drawer. fragment identifies the original heading or anchor; the HTML representation's anchors array maps it to its namespaced exportedId . A link to an omitted document uses its canonical website URL only when that document is public, enabled, and selected for the website. Without an eligible destination and a configured origin, the export "},{"filters":{"focus":["configure"]},"text":"Configuration reference — Look up named export targets and selection settings. Build separate sites from shared content — Reuse the same authored content inside an application."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":13168,"markdownTokens":2621,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"prerequisites","title":"Prerequisites","markdownUrl":"/publish/content-export.sections/prerequisites.md","markdownBytes":1559,"markdownTokens":365},{"id":"export-selected-pages","title":"Export selected pages","markdownUrl":"/publish/content-export.sections/export-selected-pages.md","markdownBytes":5967,"markdownTokens":1286},{"id":"check-the-result","title":"Check the result","markdownUrl":"/publish/content-export.sections/check-the-result.md","markdownBytes":1481,"markdownTokens":340},{"id":"what-the-representations-retain","title":"What the representations retain","markdownUrl":"/publish/content-export.sections/what-the-representations-retain.md","markdownBytes":3559,"markdownTokens":620},{"id":"assets-downloads-and-notices","title":"Assets, downloads, and notices","markdownUrl":"/publish/content-export.sections/assets-downloads-and-notices.md","markdownBytes":2212,"markdownTokens":501},{"id":"review-exported-api-material","title":"Review exported API material","markdownUrl":"/publish/content-export.sections/review-exported-api-material.md","markdownBytes":2157,"markdownTokens":487},{"id":"inspect-the-manifest","title":"Inspect the manifest","markdownUrl":"/publish/content-export.sections/inspect-the-manifest.md","markdownBytes":1923,"markdownTokens":434},{"id":"try-the-help-drawer-example","title":"Try the help-drawer example","markdownUrl":"/publish/content-export.sections/try-the-help-drawer-example.md","markdownBytes":1961,"markdownTokens":455},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/content-export.sections/related-reading.md","markdownBytes":1652,"markdownTokens":387}]},{"id":"guide.content-negotiation","demo":false,"url":"/publish/content-negotiation","markdownUrl":"/publish/content-negotiation.md","title":"Content negotiation","summary":"Understand content negotiation, why it helps agents, and what a hosting provider needs to do.","type":"reference","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[{"id":"why-this-matters","title":"Why this matters"},{"id":"what-shoalrun-builds-and-what-the-host-does","title":"What Shoalrun builds and what the host does"},{"id":"hosting-contract","title":"Hosting contract"},{"id":"validators-and-manifest-links","title":"Validators and manifest links"},{"id":"missing-pages","title":"Missing pages"},{"id":"what-if-the-host-cannot-negotiate","title":"What if the host cannot negotiate?"},{"id":"verify-the-deployed-url","title":"Verify the deployed URL"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun builds two versions of every published page from one authored source. The HTML version is for people using a browser. The generated Markdown version contains shared material in a form agents can read directly. Authors can also add or suppress format-specific content in either version. The versions share a core but need not contain identical text. Content negotiation lets a visitor ask for a format at the page's usual URL. Some agents send the request header Accept: text/markdown . A host that supports negotiation responds with Shoalrun's Markdown version. A browser asking for HTML gets the HTML version. The URL stays the same: Request to /publish/output/ Response Browser sends Accept: text/html HTML page, Content-Type: text/html Agent sends Accept: text/markdown Markdown page, Content-Type: text/markdown Accept says what the visitor can use. Content-Type says what the host actually returned. The .md URL, such as /publish/output.md , also works directly. Why this matters An agent reading HTML may receive navigation, styles, scripts, and interactive controls along with the article. It may then have to extract the useful content or convert the HTML to Markdown. Shoalrun's generated Markdown gives it the article directly, including material inside tabs and collapsibles and resolved OpenAPI examples. This can make the page easier to retrieve and less likely to lose content during conversion. AFDocs checks both .md URLs and content negotiation for this reason. The direct .md links in each HTML page and /llms.txt help agents that know to follow them. Negotiation helps an agent that arrives at the ordinary page URL and requests Markdown without first discovering a second URL. It does not require writers to maintain a separate article. What Shoalrun builds and what the host does Shoalrun creates the HTML page, its .md twin, and a /documents.json manifest listing both URLs. It also writes /resource-headers.json with content types for Markdown and discovery files. The host receives each HTTP request. It must read Accept and select the right built file. Providers use different names for this step: a server handler, a routing rule, or an edge function. The HTTP behavior is the same. A static file alone cannot read a request header. Shoalrun's Node server handles this. The standalone Vercel build generates Vercel rules. On another host, use the contract below to configure its routing feature. The host adapter guide covers adding Shoalrun's files to another build. Hosting contract For each published page, use the two URLs in documents.json . Configure the host as follows: At the page URL, return the Markdown twin when Accept explicitly requests text/markdown with a nonzero quality value. Otherwise return HTML. Keep the URL in the browser unchanged when serving the twin. Use an internal rewrite or server response, not a redirect to .md . On the Markdown response, set Content-Type: text/markdown; charset=utf-8 , Vary: Accept , and Content-Location to the .md URL. On both page responses, set Link: <PAGE.md>; rel=\"alternate\"; type=\"text/markdown\" . Keep the HTML document's existing alternate link as well. Serve direct .md URLs as text/markdown . Apply the content types in /resource-headers.json to discovery files, especially /.well-known/api-catalog when it is published. Limit the negotiation rule to published documentation pages. Leave assets, API contracts, and /llms.txt alone. Missing routes use the error responses described below. The Vercel rule matches the Node server except when text/markdown and the HTML or wildcard entry it competes with both have fractional weights. The Vercel guide gives the details. The Node server compares the requested HTML and Markdown weights. When the weights tie, Markdown wins. A wildcard such as text/* or */* alone never selects Markdown; the request must name text/markdown . To try it locally, run npm run docs:preview from the repository root, then request a page: curl -i -H 'Accept: text/markdown' http://127.0.0.1:8770/publish/agent-friendliness/ Validators and manifest links A Markdown response includes its canonical HTML link and a rel=\"describedby\" link to its current manifest record. The latter uses a JSON Pointer fragment, such as /documents.json#/documents/3 . Fetch the manifest and select that array entry to read the page's ID, publication variant, and digests. The index can move between builds; use the response's current link and verify the Markdown digest. Generated hosting metadata specifies a strong ETag equal to the quoted SHA-256 Markdown digest and Cache-Control: public, max-age=0, must-revalidate . The Node server handles matching If-None-Match requests with 304 and no body, including Markdown negotiated at an HTML URL. Negotiated responses retain Vary: Accept . Vercel receives the generated headers but can replace the ETag with its own validator, including a weak validator for compressed responses. Send the ETag returned by the host in If-None-Match ; treat i","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Shoalrun builds two versions of every published page from one authored source. The HTML version is for people using a browser. The generated Markdown version contains shared material in a form agents can read directly. Authors can also add or suppress format-specific content in either version. The versions share a core but need not contain identical text. Content negotiation lets a visitor ask for a format at the page's usual URL. Some agents send the request header Accept: text/markdown . A host that supports negotiation responds with Shoalrun's Markdown version. A browser asking for HTML gets the HTML version. The URL stays the same: Request to /publish/output/ Response Browser sends Accept: text/html HTML page, Content-Type: text/html Agent sends Accept: text/markdown Markdown page, Content-Type: text/markdown Accept says what the visitor can use. Content-Type says what the host actually returned. The .md URL, such as /publish/output.md , also works directly. Why this matters An agent reading HTML may receive navigation, styles, scripts, and interactive controls along with the article. It may then have to extract the useful content or convert the HTML to Markdown. Shoalrun's generated Markdown gives it the article directly, including material inside tabs and collapsibles and resolved OpenAPI examples. This can make the page easier to retrieve and less likely to lose content during conversion. AFDocs checks both .md URLs and content negotiation for this reason. The direct .md links in each HTML page and /llms.txt help agents that know to follow them. Negotiation helps an agent that arrives at the ordinary page URL and requests Markdown without first discovering a second URL. It does not require writers to maintain a separate article. What Shoalrun builds and what the host does Shoalrun creates the HTML page, its .md twin, and a /documents.json manifest listing both URLs. It also writes /resource-headers.json with content types for Markdown and discovery files. The host receives each HTTP request. It must read Accept and select the right built file. Providers use different names for this step: a server handler, a routing rule, or an edge function. The HTTP behavior is the same. A static file alone cannot read a request header. Shoalrun's Node server handles this. The standalone Vercel build generates Vercel rules. On another host, use the contract below to configure its routing feature. The host adapter guide covers adding Shoalrun's files to another build. Hosting contract For each published page, use the two URLs in documents.json . Configure the host as follows: At the page URL, return the Markdown twin when Accept explicitly requests text/markdown with a nonzero quality value. Otherwise return HTML. Keep the URL in the browser unchanged when serving the twin. Use an internal rewrite or server response, not a redirect to .md . On the Markdown response, set Content-Type: text/markdown; charset=utf-8 , Vary: Accept , and Content-Location to the .md URL. On both page responses, set Link: <PAGE.md>; rel=\"alternate\"; type=\"text/markdown\" . Keep the HTML document's existing alternate link as well. Serve direct .md URLs as text/markdown . Apply the content types in /resource-headers.json to discovery files, especially /.well-known/api-catalog when it is published. Limit the negotiation rule to published documentation pages. Leave assets, API contracts, and /llms.txt alone. Missing routes use the error responses described below. The Vercel rule matches the Node server except when text/markdown and the HTML or wildcard entry it competes with both have fractional weights. The Vercel guide gives the details. The Node server compares the requested HTML and Markdown weights. When the weights tie, Markdown wins. A wildcard such as text/* or */* alone never selects Markdown; the request must name text/markdown . To try it locally, run npm run docs:preview from the repository root, then request a page: curl -i -H 'Accept: text/markdown' http://127.0.0.1:8770/publish/agent-friendliness/ Validators and manifest links A Markdown response includes its canonical HTML link and a rel=\"describedby\" link to its current manifest record. The latter uses a JSON Pointer fragment, such as /documents.json#/documents/3 . Fetch the manifest and select that array entry to read the page's ID, publication variant, and digests. The index can move between builds; use the response's current link and verify the Markdown digest. Generated hosting metadata specifies a strong ETag equal to the quoted SHA-256 Markdown digest and Cache-Control: public, max-age=0, must-revalidate . The Node server handles matching If-None-Match requests with 304 and no body, including Markdown negotiated at an HTML URL. Negotiated responses retain Vary: Accept . Vercel receives the generated headers but can replace the ETag with its own validator, including a weak validator for compressed responses. Send the ETag returned by the host in If-None-Match ; treat its va"},{"filters":{"focus":["configure"]},"text":"Publish on Vercel — Generate a Vercel deployment with negotiation already configured. Add Shoalrun to another build or host — Supply the same HTTP rules on another host."},{"filters":{"focus":["write"]},"text":"Content for one format — Write instructions that apply to only the HTML page or only the Markdown twin."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":11547,"markdownTokens":2605,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"why-this-matters","title":"Why this matters","markdownUrl":"/publish/content-negotiation.sections/why-this-matters.md","markdownBytes":3287,"markdownTokens":743},{"id":"what-shoalrun-builds-and-what-the-host-does","title":"What Shoalrun builds and what the host does","markdownUrl":"/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md","markdownBytes":3342,"markdownTokens":785},{"id":"hosting-contract","title":"Hosting contract","markdownUrl":"/publish/content-negotiation.sections/hosting-contract.md","markdownBytes":4108,"markdownTokens":976},{"id":"validators-and-manifest-links","title":"Validators and manifest links","markdownUrl":"/publish/content-negotiation.sections/validators-and-manifest-links.md","markdownBytes":3947,"markdownTokens":881},{"id":"missing-pages","title":"Missing pages","markdownUrl":"/publish/content-negotiation.sections/missing-pages.md","markdownBytes":3669,"markdownTokens":835},{"id":"what-if-the-host-cannot-negotiate","title":"What if the host cannot negotiate?","markdownUrl":"/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md","markdownBytes":3266,"markdownTokens":748},{"id":"verify-the-deployed-url","title":"Verify the deployed URL","markdownUrl":"/publish/content-negotiation.sections/verify-the-deployed-url.md","markdownBytes":4244,"markdownTokens":981},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/content-negotiation.sections/related-reading.md","markdownBytes":2538,"markdownTokens":592}]},{"id":"guide.content-identity","demo":false,"url":"/author/content","markdownUrl":"/author/content.md","title":"Content and stable IDs","summary":"Give each page a durable identity and publish explicit variants.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-pages","headings":[{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Author pages as .md or .mdx under the content directory, site.contentDir (default content , relative to docs.config.yaml ). The build parses and validates every .md and .mdx file there, drafts included, so a stray README without frontmatter fails the build. The id identifies a document independently of its filename, title, slug, and navigation position. A page's slug sets its public route. The compiler rejects route collisions and duplicate IDs within a publication variant. Keeping identity separate from location lets the documentation grow without reconnecting every reference. A filename is an authoring choice; a slug is a reader's address; the ID is the lasting connection used by links, navigation, and relationships. Renaming a page can leave its ID intact even when its URL needs a redirect. --- id : guide.example title : Example guide summary : A short description for navigation and discovery. type : guide slug : /guides/example channel : production version : current access : { policy : public } --- Publication channel, API version, and language are separate axes. Published pages need channel and version, supplied on the page or through global frontmatter . Language uses global frontmatter defaults/enforced values first, then publications.defaults.language , then en . An explicit page language overrides that default. Enabled publication entries can also omit language to inherit the same default; the project config declares supported combinations and route prefixes. Nonpublic pages are excluded before rendering. The prototype does not yet provide hosted role-based access control. Link to another document by ID with [the guide](doc:guide.example) or <DocLink doc=\"guide.example\">the guide</DocLink> . These become the current route in HTML and the corresponding .md route in Markdown. A slug or filename change leaves ID-based links intact. Unknown IDs fail the build. The current MDX semantic adapters cover GitHub Flavored Markdown and the elements in the component reference , including diagrams . Dynamic expressions and unknown components fail because they cannot yet be represented faithfully in both HTML and Markdown. See published outputs for what an agent receives. Set the root language once, for example: publications : defaults : { channel : production , version : current , language : fr } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } - { channel : production , version : current , language : de } Pages without language use French at their ordinary route. A page with language: de uses the German publication and a /de route prefix. Related reading Read first How Shoalrun works — See how IDs, slugs, and routes fit into the build. Next steps Page metadata — Add the metadata fields each page needs after inheritance. Organize site navigation — Place the page in the site menu. Related topics DocLink — Link to pages by stable ID so links survive slug changes.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Author pages as .md or .mdx under the content directory, site.contentDir (default content , relative to docs.config.yaml ). The build parses and validates every .md and .mdx file there, drafts included, so a stray README without frontmatter fails the build. The id identifies a document independently of its filename, title, slug, and navigation position. A page's slug sets its public route. The compiler rejects route collisions and duplicate IDs within a publication variant. Keeping identity separate from location lets the documentation grow without reconnecting every reference. A filename is an authoring choice; a slug is a reader's address; the ID is the lasting connection used by links, navigation, and relationships. Renaming a page can leave its ID intact even when its URL needs a redirect. --- id: guide.example title: Example guide summary: A short description for navigation and discovery. type: guide slug: /guides/example channel: production version: current access: { policy: public } --- Publication channel, API version, and language are separate axes. Published pages need channel and version, supplied on the page or through global frontmatter . Language uses global frontmatter defaults/enforced values first, then publications.defaults.language , then en . An explicit page language overrides that default. Enabled publication entries can also omit language to inherit the same default; the project config declares supported combinations and route prefixes. Nonpublic pages are excluded before rendering. The prototype does not yet provide hosted role-based access control. Link to another document by ID with [the guide](doc:guide.example) or <DocLink doc=\"guide.example\">the guide</DocLink> . These become the current route in HTML and the corresponding .md route in Markdown. A slug or filename change leaves ID-based links intact. Unknown IDs fail the build. The current MDX semantic adapters cover GitHub Flavored Markdown and the elements in the component reference , including diagrams . Dynamic expressions and unknown components fail because they cannot yet be represented faithfully in both HTML and Markdown. See published outputs for what an agent receives. Set the root language once, for example: publications: defaults: { channel: production, version: current, language: fr } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } - { channel: production, version: current, language: de } Pages without language use French at their ordinary route. A page with language: de uses the German publication and a /de route prefix. Related reading Read first How Shoalrun works — See how IDs, slugs, and routes fit into the build. Next steps Related topics"},{"filters":{"focus":["write"],"audience":["authors","maintainers"]},"text":"Page metadata — Add the metadata fields each page needs after inheritance."},{"filters":{"focus":["write"]},"text":"Organize site navigation — Place the page in the site menu. DocLink — Link to pages by stable ID so links survive slug changes."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4226,"markdownTokens":966,"markdownTokenEncoding":"cl100k_base"},{"id":"cookbook.authoring","demo":false,"url":"/cookbooks/authoring","markdownUrl":"/cookbooks/authoring.md","title":"Authoring workflows","summary":"Choose a complete Shoalrun workflow for adding a guide, previewing a change, or refreshing agent docs.","type":"cookbook","variant":"production|current|en","area":"authoring","subarea":"authoring-composition","headings":[{"id":"choose-your-task","title":"Choose your task"},{"id":"related-reading","title":"Related reading"},{"id":"go-deeper","title":"Go deeper"},{"id":"related-topics","title":"Related topics"}],"text":"Choose the outcome you need for Shoalrun's own documentation. Each recipe includes setup, ordered work, handoffs, and an observable final check. Choose your task What are you working on? Add a new guide Use when: A task needs a new page with navigation and current agent documentation. You need: A topic, a stable page ID, and time to write and review the actual instructions. You will have: A local public page, passing checks, and a refreshed agent bundle ready for review. Preview an existing change Use when: You want to inspect the current page in a browser and as Markdown. You need: An edited checkout and a free local port. You will have: A local HTTP preview with the changed page verified in both formats. Refresh the agent bundle Use when: Authored documentation changed and the CLI needs the updated offline content. You need: Completed source edits and the stable ID of a page to check. You will have: Current CLI search and page lookup, a reviewed generated diff, and passing audits. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Add a new guide — Add a page to this documentation site Preview an existing change — Preview a documentation change locally Refresh the agent bundle — Refresh Shoalrun's bundled agent docs Adding a guide includes manual writing and review. The recipe then builds and audits the page and refreshes the agent bundle. Previewing an existing change starts a local server; refreshing the bundle verifies what the CLI can search and read. Choose one task at a time so shared setup runs once within that recipe. Use Link to this path to share the selected instructions, Download Markdown to work from a saved copy, or Print this path for a checklist. These workflows prepare local changes for review; they do not commit or deploy them. Related reading Go deeper Compose and maintain recipes — See how these workflows are composed from checked-in ingredient files. Related topics Add a page to this documentation site — Choose a related Shoalrun workflow. Preview a documentation change locally — Choose a related Shoalrun workflow. Refresh Shoalrun's bundled agent docs — Choose a related Shoalrun workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Choose the outcome you need for Shoalrun's own documentation. Each recipe includes setup, ordered work, handoffs, and an observable final check. Choose your task What are you working on? Add a new guide Use when: A task needs a new page with navigation and current agent documentation. You need: A topic, a stable page ID, and time to write and review the actual instructions. You will have: A local public page, passing checks, and a refreshed agent bundle ready for review. Preview an existing change Use when: You want to inspect the current page in a browser and as Markdown. You need: An edited checkout and a free local port. You will have: A local HTTP preview with the changed page verified in both formats. Refresh the agent bundle Use when: Authored documentation changed and the CLI needs the updated offline content. You need: Completed source edits and the stable ID of a page to check. You will have: Current CLI search and page lookup, a reviewed generated diff, and passing audits. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Add a new guide — Add a page to this documentation site Preview an existing change — Preview a documentation change locally Refresh the agent bundle — Refresh Shoalrun's bundled agent docs Adding a guide includes manual writing and review. The recipe then builds and audits the page and refreshes the agent bundle. Previewing an existing change starts a local server; refreshing the bundle verifies what the CLI can search and read. Choose one task at a time so shared setup runs once within that recipe. Use Link to this path to share the selected instructions, Download Markdown to work from a saved copy, or Print this path for a checklist. These workflows prepare local changes for review; they do not commit or deploy them. Related reading Go deeper Related topics Add a page to this documentation site — Choose a related Shoalrun workflow. Preview a documentation change locally — Choose a related Shoalrun workflow. Refresh Shoalrun's bundled agent docs — Choose a related Shoalrun workflow."},{"filters":{"focus":["write"]},"text":"Compose and maintain recipes — See how these workflows are composed from checked-in ingredient files."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3319,"markdownTokens":784,"markdownTokenEncoding":"cl100k_base"},{"id":"cookbook.site-workflows","demo":false,"url":"/cookbooks/site-workflows","markdownUrl":"/cookbooks/site-workflows.md","title":"Site workflows","summary":"Choose a build check or a complete build-and-audit workflow for Shoalrun.","type":"cookbook","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[{"id":"choose-your-check","title":"Choose your check"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"go-deeper","title":"Go deeper"},{"id":"related-topics","title":"Related topics"}],"text":"Use these recipes on a local Shoalrun checkout after editing documentation. Choose the level of validation you need. The audit path already includes the build and artifact checks, so run one complete path. Choose your check How much validation do you need? Build and check page artifacts Use when: You want to confirm a documentation edit compiles into HTML and Markdown. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build and the checked paths for both page formats. Build and run project audits Use when: You are preparing a change for review and need the configured API and project checks too. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build, checked artifacts, and no failed configured audits. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Build and check page artifacts — Build this documentation site Build and run project audits — Build and audit this documentation site These recipes use the same compile, build, and artifact-check ingredients. The audit recipe adds the configured project and API checks. Neither path deploys the site. Use the preview workflow to inspect the rendered result before publishing. Related reading Next steps Preview a documentation change locally — Inspect the successful build over local HTTP. Go deeper Compose and maintain recipes — Inspect the recipe specs and reusable handoffs. Related topics Build and audit this documentation site — Choose a related Shoalrun workflow. Build this documentation site — Choose a related Shoalrun workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Use these recipes on a local Shoalrun checkout after editing documentation. Choose the level of validation you need. The audit path already includes the build and artifact checks, so run one complete path. Choose your check How much validation do you need? Build and check page artifacts Use when: You want to confirm a documentation edit compiles into HTML and Markdown. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build and the checked paths for both page formats. Build and run project audits Use when: You are preparing a change for review and need the configured API and project checks too. You need: A Shoalrun checkout with dependencies installed and the page's stable ID. You will have: A successful build, checked artifacts, and no failed configured audits. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Build and check page artifacts — Build this documentation site Build and run project audits — Build and audit this documentation site These recipes use the same compile, build, and artifact-check ingredients. The audit recipe adds the configured project and API checks. Neither path deploys the site. Use the preview workflow to inspect the rendered result before publishing. Related reading Next steps Preview a documentation change locally — Inspect the successful build over local HTTP. Go deeper Related topics Build and audit this documentation site — Choose a related Shoalrun workflow. Build this documentation site — Choose a related Shoalrun workflow."},{"filters":{"focus":["write"]},"text":"Compose and maintain recipes — Inspect the recipe specs and reusable handoffs."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2678,"markdownTokens":630,"markdownTokenEncoding":"cl100k_base"},{"id":"cookbook.welcome-email","demo":false,"url":"/cookbooks/welcome-email","markdownUrl":"/cookbooks/welcome-email.md","title":"Welcome email workflows","summary":"Choose an acceptance check or follow the same message through delivery.","type":"cookbook","variant":"production|current|en","area":"api","subarea":"api-examples","headings":[{"id":"choose-your-outcome","title":"Choose your outcome"},{"id":"related-reading","title":"Related reading"},{"id":"go-deeper","title":"Go deeper"},{"id":"related-topics","title":"Related topics"}],"text":"An accepted request is the first checkpoint. Choose how far you want to follow the message. Both paths use a local simulation that sends no email. Each recipe includes the setup command, inputs, and success check. You need a Shoalrun checkout, cURL, and Node.js. The demo runs on your own computer at 127.0.0.1:8787 . Choose your outcome What do you need to confirm? Confirm the request was accepted Use when: You are testing the request payload and only need an acceptance check. You need: A running local demo, cURL, and Node.js. You will have: A queued response and a message ID. Delivery is still unknown. Follow the email through delivery Use when: You need to distinguish acceptance, delivery, and a delivery failure. You need: A running local demo, cURL, and Node.js. You will have: A delivery status tied to the message you queued, with a failure check. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Confirm the request was accepted — Queue a welcome email Follow the email through delivery — Send a welcome email and confirm delivery The delivery path includes the queue step, so choose one path. Use Link to this path to share your selection, Download Markdown to keep the instructions, or Print this path for a paper copy. Shared links contain your recipe choice only; they do not contain a message ID. Related reading Go deeper Compose and maintain recipes — See how the recipe connects declared ingredient inputs and outputs. Related topics Send a welcome email and confirm delivery — Compare the complete delivery path with the acceptance-only path.","readerFilters":{},"readerSegments":[{"filters":{},"text":"An accepted request is the first checkpoint. Choose how far you want to follow the message. Both paths use a local simulation that sends no email. Each recipe includes the setup command, inputs, and success check. You need a Shoalrun checkout, cURL, and Node.js. The demo runs on your own computer at 127.0.0.1:8787 . Choose your outcome What do you need to confirm? Confirm the request was accepted Use when: You are testing the request payload and only need an acceptance check. You need: A running local demo, cURL, and Node.js. You will have: A queued response and a message ID. Delivery is still unknown. Follow the email through delivery Use when: You need to distinguish acceptance, delivery, and a delivery failure. You need: A running local demo, cURL, and Node.js. You will have: A delivery status tied to the message you queued, with a failure check. Choose one recipe. Link to this path Download Markdown Print this path Recipes in this cookbook: Confirm the request was accepted — Queue a welcome email Follow the email through delivery — Send a welcome email and confirm delivery The delivery path includes the queue step, so choose one path. Use Link to this path to share your selection, Download Markdown to keep the instructions, or Print this path for a paper copy. Shared links contain your recipe choice only; they do not contain a message ID. Related reading Go deeper Related topics Send a welcome email and confirm delivery — Compare the complete delivery path with the acceptance-only path."},{"filters":{"focus":["write"]},"text":"Compose and maintain recipes — See how the recipe connects declared ingredient inputs and outputs."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2532,"markdownTokens":611,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.cookbooks","demo":false,"url":"/author/cookbooks","markdownUrl":"/author/cookbooks.md","title":"Let readers choose recipes with a cookbook","summary":"Create a page that helps readers choose among complete published recipes.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-composition","headings":[{"id":"1-prepare-the-destination-recipes","title":"1. Prepare the destination recipes"},{"id":"2-configure-the-choices","title":"2. Configure the choices"},{"id":"3-put-the-chooser-on-a-cookbook-page","title":"3. Put the chooser on a cookbook page"},{"id":"choose-single-or-multiple-selection-deliberately","title":"Choose single or multiple selection deliberately"},{"id":"what-readers-and-agents-receive","title":"What readers and agents receive"},{"id":"check-the-result","title":"Check the result"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"}],"text":"A cookbook combines an authored introduction with a list or chooser of published recipe pages . It does not read ingredient files. Ingredients have already been copied into the recipes during authoring. This guide uses the Site workflows cookbook . It offers a build check or a build-and-audit check. The audit recipe already includes the build, so the reader chooses one complete path. 1. Prepare the destination recipes Publish each destination as a type: recipe page in the same channel, version, and language as the cookbook. Each recipe should contain the setup, steps, and success checks needed to follow it on its own. Our two destinations are recipe.build-docs and recipe.audit-docs . They can be opened directly, even if the cookbook is removed. See compose and maintain recipes for how their ingredient source becomes a complete page. 2. Configure the choices The following configuration points to those finished pages by stable document ID: docs/config/cookbooks.yaml site-checks : title : How much validation do you need? mode : single options : - id : build label : Build and check page artifacts doc : recipe.build-docs when : You want to confirm an edit produces HTML and Markdown. needs : A Shoalrun checkout and the page's stable ID. outcome : A successful build and checked page files. - id : audit label : Build and run project audits doc : recipe.audit-docs when : You also need the configured API and project checks. needs : A Shoalrun checkout and the page's stable ID. outcome : Checked page files and no failed configured audits. doc selects the recipe. label names the choice. The optional when , needs , and outcome fields explain the choice; they are descriptive text, not requirements the browser verifies. When when is omitted, the recipe's summary is shown. Load this mapping from the project configuration. Shoalrun already has this include: docs/docs.config.yaml cookbooks : { $include : ./config/cookbooks.yaml } 3. Put the chooser on a cookbook page Write an MDX page with type: cookbook , the usual page identity and publication fields, and an introduction explaining the choices. Its body can contain: Choose the level of validation you need. The audit path includes the build. < CookbookChooser id = \"site-checks\" /> The component's id is the configuration key site-checks . It is separate from the cookbook page's document ID, cookbook.site-workflows . A normal site build publishes the cookbook's own text and chooser. When a reader makes a selection, the browser fetches the selected recipe's HTML and shows the instructions under Your path . It does not call the recipe assembler, fetch ingredients, or execute commands. For a simple directory of recipes, use DocCards instead of a chooser. A page with type: cookbook does not require an interactive component. Choose single or multiple selection deliberately Choose the selection mode based on whether readers should follow one path or combine several. Setting Reader behavior Appropriate use mode: single Choose one recipe with radio buttons. Alternative tasks or overlapping paths, such as build versus build-and-audit. mode: multiple Select several recipes with checkboxes; display them in configuration order. Recipes that the author has checked make sense together. This is the default. Multiple selection displays whole recipe bodies, including any repeated setup. It does not deduplicate steps, connect outputs between recipes, or check their combined dependencies. If a combined task needs shared setup and explicit handoffs, compose it as one recipe and offer that recipe as a choice. What readers and agents receive The published surfaces expose cookbook choices in different forms. Surface Content Cookbook HTML before selection The authored introduction, choices, descriptions, and recipe links. Cookbook HTML after selection The selected published recipe instructions, loaded in the browser. Cookbook Markdown The authored introduction and all choice descriptions and recipe links. Recipe Markdown The complete published instructions for that one recipe. Download Markdown A file containing the selected recipes' instructions. Link to this path preserves the selection in the browser URL. It does not create a new published Markdown page. An agent reading the cookbook's Markdown can choose a recipe link. Give a task-performing agent the recipe's Markdown or the downloaded selection. Print this path prints the loaded instructions. If a recipe cannot load, its source link remains available. Markdown downloads fail as a whole rather than saving an incomplete selection. Without JavaScript, the visible recipe links still work. Check the result Build the site and open the cookbook in HTML and Markdown. For single selection, try each option. For multiple selection, also try the combinations you intend readers to use. Follow each offered workflow and inspect its success checks. The build rejects missing, draft, wrong-type, or wrong-publication recipe targets and duplicate option IDs,","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A cookbook combines an authored introduction with a list or chooser of published recipe pages . It does not read ingredient files. Ingredients have already been copied into the recipes during authoring. This guide uses the Site workflows cookbook . It offers a build check or a build-and-audit check. The audit recipe already includes the build, so the reader chooses one complete path. 1. Prepare the destination recipes Publish each destination as a type: recipe page in the same channel, version, and language as the cookbook. Each recipe should contain the setup, steps, and success checks needed to follow it on its own. Our two destinations are recipe.build-docs and recipe.audit-docs . They can be opened directly, even if the cookbook is removed. See compose and maintain recipes for how their ingredient source becomes a complete page. 2. Configure the choices The following configuration points to those finished pages by stable document ID: site-checks: title: How much validation do you need? mode: single options: - id: build label: Build and check page artifacts doc: recipe.build-docs when: You want to confirm an edit produces HTML and Markdown. needs: A Shoalrun checkout and the page's stable ID. outcome: A successful build and checked page files. - id: audit label: Build and run project audits doc: recipe.audit-docs when: You also need the configured API and project checks. needs: A Shoalrun checkout and the page's stable ID. outcome: Checked page files and no failed configured audits. doc selects the recipe. label names the choice. The optional when , needs , and outcome fields explain the choice; they are descriptive text, not requirements the browser verifies. When when is omitted, the recipe's summary is shown. Load this mapping from the project configuration. Shoalrun already has this include: cookbooks: { $include: ./config/cookbooks.yaml } 3. Put the chooser on a cookbook page Write an MDX page with type: cookbook , the usual page identity and publication fields, and an introduction explaining the choices. Its body can contain: Choose the level of validation you need. The audit path includes the build. <CookbookChooser id=\"site-checks\" /> The component's id is the configuration key site-checks . It is separate from the cookbook page's document ID, cookbook.site-workflows . A normal site build publishes the cookbook's own text and chooser. When a reader makes a selection, the browser fetches the selected recipe's HTML and shows the instructions under Your path . It does not call the recipe assembler, fetch ingredients, or execute commands. For a simple directory of recipes, use DocCards instead of a chooser. A page with type: cookbook does not require an interactive component. Choose single or multiple selection deliberately Choose the selection mode based on whether readers should follow one path or combine several. Setting Reader behavior Appropriate use mode: single Choose one recipe with radio buttons. Alternative tasks or overlapping paths, such as build versus build-and-audit. mode: multiple Select several recipes with checkboxes; display them in configuration order. Recipes that the author has checked make sense together. This is the default. Multiple selection displays whole recipe bodies, including any repeated setup. It does not deduplicate steps, connect outputs between recipes, or check their combined dependencies. If a combined task needs shared setup and explicit handoffs, compose it as one recipe and offer that recipe as a choice. What readers and agents receive The published surfaces expose cookbook choices in different forms. Surface Content Cookbook HTML before selection The authored introduction, choices, descriptions, and recipe links. Cookbook HTML after selection The selected published recipe instructions, loaded in the browser. Cookbook Markdown The authored introduction and all choice descriptions and recipe links. Recipe Markdown The complete published instructions for that one recipe. Download Markdown A file containing the selected recipes' instructions. Link to this path preserves the selection in the browser URL. It does not create a new published Markdown page. An agent reading the cookbook's Markdown can choose a recipe link. Give a task-performing agent the recipe's Markdown or the downloaded selection. Print this path prints the loaded instructions. If a recipe cannot load, its source link remains available. Markdown downloads fail as a whole rather than saving an incomplete selection. Without JavaScript, the visible recipe links still work. Check the result Build the site and open the cookbook in HTML and Markdown. For single selection, try each option. For multiple selection, also try the combinations you intend readers to use. Follow each offered workflow and inspect its success checks. The build rejects missing, draft, wrong-type, or wrong-publication recipe targets and duplicate option IDs, labels, or targets. A passing build establishes that the references are va"},{"filters":{"focus":["write"]},"text":"Understand ingredients, recipes, and cookbooks — Understand what ingredients, recipe pages, and cookbook choices each contribute. CookbookChooser — Look up the chooser's syntax and validation rules."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":7397,"markdownTokens":1487,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.create-note","demo":true,"url":"/example-api/create-note","markdownUrl":"/example-api/create-note.md","title":"Create a note","summary":"Preview an API operation page built from a small, fictional OpenAPI file.","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-examples","headings":[{"id":"post-notes","title":"POST /notes"},{"id":"servers","title":"Servers"},{"id":"request-body","title":"Request body"},{"id":"application-json","title":"application/json"},{"id":"responses","title":"Responses"},{"id":"201-created","title":"201: Created"},{"id":"related-guides","title":"Related guides"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This page is a live example of an API reference generated by Shoalrun. The source OpenAPI file defines one fictional operation; this introduction is authored in MDX. The build combines them into the operation details below and the example panel on the right. Example only: The Notes API is fictional. These requests are examples, not calls to a live service. OpenAPI for this operation: Download JSON . POST /notes Create a note Save a short note in this fictional API. Servers https://api.example.test Request body Required. application/json object 1 property text string required ⓘ maxLength: 280 The note to save. Responses 201: Created application/json The saved note. A saved note with its author, labels, and display metadata. 7 properties id string always present ⓘ The generated note ID. text string always present ⓘ maxLength: 280 The saved text. createdAt string always present ⓘ format: date-time When the note was created. archivedAt string always present nullable ⓘ format: date-time When the note was archived, or null while active. author object always present ⓘ The person who created the note. 2 properties id string always present ⓘ The author's user ID. displayName string always present ⓘ The author's display name. tags list of string may be absent ⓘ Labels used to organize the note. Array items: string metadata object may be absent ⓘ Optional display information for a note. 2 properties source string may be absent ⓘ Where the note came from. pinned boolean may be absent ⓘ Whether the note stays at the top. Related guides Prepare a note request — Prepare a fictional note payload and follow its linked operation contracts.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This page is a live example of an API reference generated by Shoalrun. The source OpenAPI file defines one fictional operation; this introduction is authored in MDX. The build combines them into the operation details below and the example panel on the right. Example only: The Notes API is fictional. These requests are examples, not calls to a live service. OpenAPI for this operation: Download JSON . POST /notes Create a note Save a short note in this fictional API. Servers https://api.example.test Request body Required. application/json object 1 property text string required ⓘ maxLength: 280 The note to save. Responses 201: Created application/json The saved note. A saved note with its author, labels, and display metadata. 7 properties id string always present ⓘ The generated note ID. text string always present ⓘ maxLength: 280 The saved text. createdAt string always present ⓘ format: date-time When the note was created. archivedAt string always present nullable ⓘ format: date-time When the note was archived, or null while active. author object always present ⓘ The person who created the note. 2 properties id string always present ⓘ The author's user ID. displayName string always present ⓘ The author's display name. tags list of string may be absent ⓘ Labels used to organize the note. Array items: string metadata object may be absent ⓘ Optional display information for a note. 2 properties source string may be absent ⓘ Where the note came from. pinned boolean may be absent ⓘ Whether the note stays at the top. Related guides Prepare a note request — Prepare a fictional note payload and follow its linked operation contracts."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":7141,"markdownTokens":1936,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.css","demo":false,"url":"/author/css","markdownUrl":"/author/css.md","title":"CSS and theme reference","summary":"Customize colors, typography, layout, navigation, code, and component styles with one project stylesheet.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-themes","headings":[{"id":"typography-shape-and-width-tokens","title":"Typography, shape, and width tokens"},{"id":"core-color-tokens","title":"Core color tokens"},{"id":"borders-fields-and-navigation-tokens","title":"Borders, fields, and navigation tokens"},{"id":"status-code-and-callout-tokens","title":"Status, code, and callout tokens"},{"id":"preset-specific-tokens","title":"Preset-specific tokens"},{"id":"layout-and-component-selectors","title":"Layout and component selectors"},{"id":"page-attributes","title":"Page attributes"},{"id":"responsive-behavior","title":"Responsive behavior"},{"id":"page-transitions","title":"Page transitions"}],"text":"The built site loads /assets/site.css , which imports /assets/tokens.css . To customize a project, set site.customCss to a local stylesheet. The build copies it to /assets/project.css and links it after the framework CSS on every HTML page. Paths resolve from the config file that declares them, including imported config fragments. The stylesheet is a build dependency, so changes are picked up on rebuild. docs.config.yaml site : title : Example documentation customCss : ./styles/project.css styles/project.css :root { --font-body : Inter , ui-sans-serif , system-ui , sans-serif ; --color-accent : #2458a6 ; --color-link : #2458a6 ; --width-site : 92 rem ; } .page-head h1 { letter-spacing : -.02 em ; } Pages link these stylesheets in order, and later files win: /assets/site.css (which imports tokens.css and header.css ), a preset's /assets/theme.css , the generated /assets/palette.css , the generated /assets/fonts.css , then /assets/project.css . Themes lists when each one is present. To use your own font files, set theme.fonts instead of writing @font-face rules here. The build then copies the files, preloads the body font, and sets --font-body , --font-heading , and --font-code for you. Use tokens for broad changes and the generated classes below for a particular region. The project stylesheet is copied as one file; relative images or @import files are not copied automatically. Use site-root URLs for separately hosted assets. Markdown twins contain content, not CSS. Before writing CSS, check whether a theme preset , palette , or color mode already covers the change. Project CSS loads after all three, so the tokens below override them. The build checks palette colors for contrast. It does not check colors set here. Inline badges use --color-field-surface , --color-ink , and --color-border for neutral ; info , success , warning , and new use the matching callout note, tip, warning, and important tokens. Register a color in badges.variants to add or override a variant with checked light and dark text contrast. The generated /assets/badges.css loads after palette CSS and before project CSS. Typography, shape, and width tokens Use these tokens to adjust text, corner shapes, and content widths. Token Controls --font-body Body and interface font stack. --font-code Inline code, blocks, and small technical labels. --font-heading Page titles and section headings. Defaults to --font-body . --radius-small Inputs, small panels, code, tabs, and disclosures. --radius-panel Larger cards and example panels. --shadow-edge A faint outline and top highlight on code blocks and reef panels. Empty in light mode; palettes set it in dark mode. --width-site Maximum width of the page shell, whether or not a right rail is present. --width-reference Maximum width of the masthead. --landing-width Maximum width of a landing page, a splash section, and their masthead. Defaults to 76rem . --nav-item-height , --nav-item-pad-y Height and vertical padding of navigation rows. Rows are 44px tall for touch and 32px tall with a mouse or trackpad on wider screens. Each preset's font stack starts with its bundled font, followed by a matching fallback face named after it, such as \"Inter Fallback\" . The fallback is a local system font resized to the bundled font's metrics, so text keeps its place while the font loads. fonts.css defines these faces; with theme.fonts: system , the build omits them and the stacks fall through to system fonts. The root text size is 16px and line height is 1.65 in site.css . Override :root in the project stylesheet if the whole site needs different type scale. Article paragraphs, headings, and code blocks also have local sizes that can be overridden by their selectors. Core color tokens These tokens control the main surface, text, and accent colors. Token Controls --color-text Default body text. --color-page Page background. --color-surface Panels and masthead background. --color-ink Strong headings and controls. --color-link Links at rest. --color-link-hover Hovered links. --color-focus Keyboard focus outline. --color-accent Brand mark and active navigation accent. --color-accent-contrast Text on accent fills, such as a primary header link. Defaults to #fff . --color-strong-surface , --color-strong-text Inked bands and their text, such as the ledger masthead and selected tabs. Default to --color-ink and --color-surface . --color-muted Secondary text and markers. --color-emphasis Eyebrows, markers, and card icons. --color-summary Page summary text. --color-section-heading Smaller headings and tab labels. Borders, fields, and navigation tokens These tokens control boundaries, input fields, and navigation states. Token Controls --color-header-muted Publication label text. --color-header-border Publication label border. --color-border Main outlines and dividers. --color-border-soft Quiet separators within content. --color-border-nested Nested navigation and lists. --color-field-surface Tables, tabs, and input surfaces. --color","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"The built site loads /assets/site.css , which imports /assets/tokens.css . To customize a project, set site.customCss to a local stylesheet. The build copies it to /assets/project.css and links it after the framework CSS on every HTML page. Paths resolve from the config file that declares them, including imported config fragments. The stylesheet is a build dependency, so changes are picked up on rebuild. site: title: Example documentation customCss: ./styles/project.css :root { --font-body: Inter, ui-sans-serif, system-ui, sans-serif; --color-accent: #2458a6; --color-link: #2458a6; --width-site: 92rem; } .page-head h1 { letter-spacing: -.02em; } Pages link these stylesheets in order, and later files win: /assets/site.css (which imports tokens.css and header.css ), a preset's /assets/theme.css , the generated /assets/palette.css , the generated /assets/fonts.css , then /assets/project.css . Themes lists when each one is present. To use your own font files, set theme.fonts instead of writing @font-face rules here. The build then copies the files, preloads the body font, and sets --font-body , --font-heading , and --font-code for you. Use tokens for broad changes and the generated classes below for a particular region. The project stylesheet is copied as one file; relative images or @import files are not copied automatically. Use site-root URLs for separately hosted assets. Markdown twins contain content, not CSS. Before writing CSS, check whether a theme preset , palette , or color mode already covers the change. Project CSS loads after all three, so the tokens below override them. The build checks palette colors for contrast. It does not check colors set here. Inline badges use --color-field-surface , --color-ink , and --color-border for neutral ; info , success , warning , and new use the matching callout note, tip, warning, and important tokens. Register a color in badges.variants to add or override a variant with checked light and dark text contrast. The generated /assets/badges.css loads after palette CSS and before project CSS. Typography, shape, and width tokens Use these tokens to adjust text, corner shapes, and content widths. Token Controls --font-body Body and interface font stack. --font-code Inline code, blocks, and small technical labels. --font-heading Page titles and section headings. Defaults to --font-body . --radius-small Inputs, small panels, code, tabs, and disclosures. --radius-panel Larger cards and example panels. --shadow-edge A faint outline and top highlight on code blocks and reef panels. Empty in light mode; palettes set it in dark mode. --width-site Maximum width of the page shell, whether or not a right rail is present. --width-reference Maximum width of the masthead. --landing-width Maximum width of a landing page, a splash section, and their masthead. Defaults to 76rem . --nav-item-height , --nav-item-pad-y Height and vertical padding of navigation rows. Rows are 44px tall for touch and 32px tall with a mouse or trackpad on wider screens. Each preset's font stack starts with its bundled font, followed by a matching fallback face named after it, such as \"Inter Fallback\" . The fallback is a local system font resized to the bundled font's metrics, so text keeps its place while the font loads. fonts.css defines these faces; with theme.fonts: system , the build omits them and the stacks fall through to system fonts. The root text size is 16px and line height is 1.65 in site.css . Override :root in the project stylesheet if the whole site needs different type scale. Article paragraphs, headings, and code blocks also have local sizes that can be overridden by their selectors. Core color tokens These tokens control the main surface, text, and accent colors. Token Controls --color-text Default body text. --color-page Page background. --color-surface Panels and masthead background. --color-ink Strong headings and controls. --color-link Links at rest. --color-link-hover Hovered links. --color-focus Keyboard focus outline. --color-accent Brand mark and active navigation accent. --color-accent-contrast Text on accent fills, such as a primary header link. Defaults to #fff . --color-strong-surface , --color-strong-text Inked bands and their text, such as the ledger masthead and selected tabs. Default to --color-ink and --color-surface . --color-muted Secondary text and markers. --color-emphasis Eyebrows, markers, and card icons. --color-summary Page summary text. --color-section-heading Smaller headings and tab labels. Borders, fields, and navigation tokens These tokens control boundaries, input fields, and navigation states. Token Controls --color-header-muted Publication label text. --color-header-border Publication label border. --color-border Main outlines and dividers. --color-border-soft Quiet separators within content. --color-border-nested Nested navigation and lists. --color-field-surface Tables, tabs, and input surfaces. --color-field-border Active disclosure and input border. --co"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":43566,"markdownTokens":6176,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"typography-shape-and-width-tokens","title":"Typography, shape, and width tokens","markdownUrl":"/author/css.sections/typography-shape-and-width-tokens.md","markdownBytes":6222,"markdownTokens":1278},{"id":"core-color-tokens","title":"Core color tokens","markdownUrl":"/author/css.sections/core-color-tokens.md","markdownBytes":6248,"markdownTokens":1142},{"id":"borders-fields-and-navigation-tokens","title":"Borders, fields, and navigation tokens","markdownUrl":"/author/css.sections/borders-fields-and-navigation-tokens.md","markdownBytes":4476,"markdownTokens":1078},{"id":"status-code-and-callout-tokens","title":"Status, code, and callout tokens","markdownUrl":"/author/css.sections/status-code-and-callout-tokens.md","markdownBytes":11539,"markdownTokens":1791},{"id":"page-attributes","title":"Page attributes","markdownUrl":"/author/css.sections/page-attributes.md","markdownBytes":5103,"markdownTokens":1180},{"id":"responsive-behavior","title":"Responsive behavior","markdownUrl":"/author/css.sections/responsive-behavior.md","markdownBytes":4483,"markdownTokens":1097},{"id":"page-transitions","title":"Page transitions","markdownUrl":"/author/css.sections/page-transitions.md","markdownBytes":4008,"markdownTokens":978}]},{"id":"guide.custom-components.react","demo":false,"url":"/author/components/custom/react","markdownUrl":"/author/components/custom/react.md","title":"Data-driven React components","summary":"Follow local data through a component plugin, shared documentation, and a React calculator.","type":"explanation","variant":"production|current|en","area":"components","subarea":"components-custom","headings":[{"id":"where-the-content-lives","title":"Where the content lives"},{"id":"start-with-data","title":"Start with data"},{"id":"use-the-component-in-a-page","title":"Use the component in a page"},{"id":"registration","title":"Registration"},{"id":"interactive-react-example","title":"Interactive React example"},{"id":"share-the-model-with-the-browser","title":"Share the model with the browser"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"}],"text":"Use a declared data file when a component needs to generate tables, calculations, or other structured documentation. This advanced example adds data and generated explanations to the small CopyText example . A data file is optional; ordinary component text can stay in MDX. Where the content lives A custom component is a small program that writes part of a documentation page. Its build function produces shared content, which Shoalrun renders as HTML and Markdown. An optional React interface adds browser controls afterward. Shoalrun does not convert React into Markdown. The retry example splits its work across these files: File What you write there What readers get The page's .mdx file Task-specific explanations and the <RetryBudget /> invocation. The surrounding documentation in HTML and Markdown. policy.json Retry counts, delays, supported status codes, and the safety warning. The configured values and warning in both formats. plugin.mjs Validation, reusable explanatory text, formulas, tables, and code examples. The component's shared HTML and Markdown content. browser.jsx React controls, state, input validation, and the interactive timeline. A browser interface for trying alternative values. style.css Optional styles for the browser interface. The files the HTML page loads for that interface. policy.json is this example's data format, not a Shoalrun requirement. A simpler component can use only MDX attributes and child content. Keep page-specific prose in the page; put recurring explanations and generated content in the plugin. Start with data For example, policy.json contains a complete configured policy: { \"attempts\" : 4 , \"baseDelayMs\" : 500 , \"maxDelayMs\" : 30000 , \"backoff\" : \"exponential\" , \"jitter\" : \"none\" , \"retryableStatuses\" : [ 429 , 502 , 503 , 504 ] , \"warning\" : \"Retry only idempotent operations, or requests protected by an idempotency key. Honor a server's Retry-After header; it can require a longer wait than this policy.\" } The plugin's content() function imports that data, validates it, and returns shared content nodes. This shortened excerpt shows how a value becomes a paragraph; the complete plugin also generates the tables, warning, formula, schedule, code, and link: const policy = validatePolicy (importedPolicy); return { content : c .paragraph ( `Allow at most ${ policy .attempts } attempts, including the first request.` ) , data : policy }; That paragraph becomes <p>Allow at most 4 attempts, including the first request.</p> in HTML and the same sentence in Markdown. There is no separate Markdown renderer to write for these shared nodes. Use the component in a page The page author supplies the surrounding context and invokes the registered component: ## Retrying a request Check whether the operation is safe to repeat before enabling retries. The policy below shows the configured wait budget. < RetryBudget title = \"Request retry policy\" /> With the example policy, the generated Markdown includes this worked schedule: | Attempt | Wait before attempt | Cumulative wait | | --- | --- | --- | | 1 | 0 ms | 0 ms | | 2 | 500 ms | 500 ms | | 3 | 1000 ms | 1500 ms | | 4 | 2000 ms | 3500 ms | HTML displays the same documented schedule. React receives the same validated policy directly and adds the calculator shown below. Changing a browser control changes that reader's calculation; it does not edit policy.json , the documented schedule, or Markdown. To change the documented policy, edit the data file and rebuild. Registration Add registrations to your project configuration: components : - ./components/retry-budget/components.json The manifest declares the build module, browser source, and styles relative to the package. Shoalrun compiles the module graph and includes imported JSON and shared functions in dependency tracking. The build module imports policy.json ; there is no separate files registration. Interactive React example A retry policy is a useful documentation component: readers need to understand the safety rules and calculate how repeated attempts affect total wait time. The packaged examples/components/retry-budget/ folder contains a working plugin, policy data, React source, shared model module, and stylesheet. Copy the whole folder to components/retry-budget/ , then install its dependencies from your project directory: npm ci --prefix components/retry-budget Use the registration above to enable the component. The plugin validates the JSON policy and generates a settings table, formulas, a worked schedule, a warning, a code example, and a specification link. React receives that validated policy as instance data and adds controls for exploring other policies. Both representations start from the same configured values. < RetryBudget title = \"Request retry policy\" /> Request retry policy Before you retry: Retry only idempotent operations, or requests protected by an idempotency key. Honor a server's Retry-After header; it can require a longer wait than this pol","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use a declared data file when a component needs to generate tables, calculations, or other structured documentation. This advanced example adds data and generated explanations to the small CopyText example . A data file is optional; ordinary component text can stay in MDX. Where the content lives A custom component is a small program that writes part of a documentation page. Its build function produces shared content, which Shoalrun renders as HTML and Markdown. An optional React interface adds browser controls afterward. Shoalrun does not convert React into Markdown. The retry example splits its work across these files: File What you write there What readers get The page's .mdx file Task-specific explanations and the <RetryBudget /> invocation. The surrounding documentation in HTML and Markdown. policy.json Retry counts, delays, supported status codes, and the safety warning. The configured values and warning in both formats. plugin.mjs Validation, reusable explanatory text, formulas, tables, and code examples. The component's shared HTML and Markdown content. browser.jsx React controls, state, input validation, and the interactive timeline. A browser interface for trying alternative values. style.css Optional styles for the browser interface. The files the HTML page loads for that interface. policy.json is this example's data format, not a Shoalrun requirement. A simpler component can use only MDX attributes and child content. Keep page-specific prose in the page; put recurring explanations and generated content in the plugin. Start with data For example, policy.json contains a complete configured policy: { \"attempts\": 4, \"baseDelayMs\": 500, \"maxDelayMs\": 30000, \"backoff\": \"exponential\", \"jitter\": \"none\", \"retryableStatuses\": [429, 502, 503, 504], \"warning\": \"Retry only idempotent operations, or requests protected by an idempotency key. Honor a server's Retry-After header; it can require a longer wait than this policy.\" } The plugin's content() function imports that data, validates it, and returns shared content nodes. This shortened excerpt shows how a value becomes a paragraph; the complete plugin also generates the tables, warning, formula, schedule, code, and link: const policy = validatePolicy(importedPolicy); return { content: c.paragraph(`Allow at most ${policy.attempts} attempts, including the first request.`), data: policy }; That paragraph becomes <p>Allow at most 4 attempts, including the first request.</p> in HTML and the same sentence in Markdown. There is no separate Markdown renderer to write for these shared nodes. Use the component in a page The page author supplies the surrounding context and invokes the registered component: ## Retrying a request Check whether the operation is safe to repeat before enabling retries. The policy below shows the configured wait budget. <RetryBudget title=\"Request retry policy\" /> With the example policy, the generated Markdown includes this worked schedule: | Attempt | Wait before attempt | Cumulative wait | | --- | --- | --- | | 1 | 0 ms | 0 ms | | 2 | 500 ms | 500 ms | | 3 | 1000 ms | 1500 ms | | 4 | 2000 ms | 3500 ms | HTML displays the same documented schedule. React receives the same validated policy directly and adds the calculator shown below. Changing a browser control changes that reader's calculation; it does not edit policy.json , the documented schedule, or Markdown. To change the documented policy, edit the data file and rebuild. Registration Add registrations to your project configuration: components: - ./components/retry-budget/components.json The manifest declares the build module, browser source, and styles relative to the package. Shoalrun compiles the module graph and includes imported JSON and shared functions in dependency tracking. The build module imports policy.json ; there is no separate files registration. Interactive React example A retry policy is a useful documentation component: readers need to understand the safety rules and calculate how repeated attempts affect total wait time. The packaged examples/components/retry-budget/ folder contains a working plugin, policy data, React source, shared model module, and stylesheet. Copy the whole folder to components/retry-budget/ , then install its dependencies from your project directory: npm ci --prefix components/retry-budget Use the registration above to enable the component. The plugin validates the JSON policy and generates a settings table, formulas, a worked schedule, a warning, a code example, and a specification link. React receives that validated policy as instance data and adds controls for exploring other policies. Both representations start from the same configured values. <RetryBudget title=\"Request retry policy\" /> Request retry policy Before you retry: Retry only idempotent operations, or requests protected by an idempotency key. Honor a server's Retry-After header; it can require a longer wait than this policy. Configured policy. Attempts include the first request; o"},{"filters":{"focus":["write"]},"text":"Custom components — Start with a small component whose content stays in MDX."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10623,"markdownTokens":2256,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"where-the-content-lives","title":"Where the content lives","markdownUrl":"/author/components/custom/react.sections/where-the-content-lives.md","markdownBytes":5167,"markdownTokens":1123},{"id":"registration","title":"Registration","markdownUrl":"/author/components/custom/react.sections/registration.md","markdownBytes":1878,"markdownTokens":423},{"id":"interactive-react-example","title":"Interactive React example","markdownUrl":"/author/components/custom/react.sections/interactive-react-example.md","markdownBytes":4867,"markdownTokens":1089},{"id":"share-the-model-with-the-browser","title":"Share the model with the browser","markdownUrl":"/author/components/custom/react.sections/share-the-model-with-the-browser.md","markdownBytes":2504,"markdownTokens":548},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/components/custom/react.sections/html-markdown-and-agents.md","markdownBytes":2149,"markdownTokens":470},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/components/custom/react.sections/related-reading.md","markdownBytes":1414,"markdownTokens":333}]},{"id":"guide.custom-components","demo":false,"url":"/author/components/custom","markdownUrl":"/author/components/custom.md","title":"Custom components","summary":"Register trusted component plugins with shared HTML and Markdown content.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-custom","headings":[{"id":"use-a-component","title":"Use a component"},{"id":"develop-a-component","title":"Develop a component"},{"id":"attributes-and-children","title":"Attributes and children"},{"id":"browser-data-and-behavior","title":"Browser data and behavior"},{"id":"dependencies-and-assets","title":"Dependencies and assets"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"use-the-component-authoring-skill","title":"Use the component-authoring skill"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"}],"text":"A component package adds a custom component, such as <CopyText> , that authors can use in their pages. Its content() function produces the content shown in both HTML and Markdown. An optional browser module adds interactive behavior. Use a component Install the component package and add its exported manifest to your configuration. For a local component, register its manifest path: components : - ./components/copy-text/components.json An installed package can export its manifest as its entry point, or as a subpath such as @acme/docs-components/shoalrun . Replace that illustrative name with your installed package's export. Paths resolve relative to the configuration file that declares them, including includes and presets. The page supplies the content: < CopyText > Contact support@example.com for help. </ CopyText > Contact support@example.com for help. CopyText requires child content and accepts no attributes. Its copy button is optional browser behavior. Markdown retains the authored text: Contact < support@example.com > for help. Develop a component The package's manifest declares its names and implementation files. Consumers register this manifest once; they do not configure its internal browser files: { \"apiVersion\" : 1 , \"components\" : { \"CopyText\" : { \"module\" : \"./plugin.mjs\" , \"browser\" : \"./browser.jsx\" } } } Each component needs module . browser and a styles list are optional. These paths are relative to the manifest. Names start with an uppercase letter, contain only letters and digits, and must be unique across registrations. They cannot replace built-ins. The complete build module for the small example passes the page's children through unchanged: import { defineComponent } from '@shoalrun/cli/components' ; export default defineComponent ({ children : 'required' , content ({ children }) { return children; } }); A component that generates documentation uses the supported content helpers: import { defineComponent , content as c } from '@shoalrun/cli/components' ; export default defineComponent ({ attributes : { label : { type : 'string' , required : true } } , children : 'required' , content ({ attributes , children }) { return [ c .paragraph ( c .strong ( attributes .label)) , children]; } }); Helpers include paragraph , strong , emphasis , inlineCode , code , heading , link , list , table , group , and component . They create shared content without requiring compiler-node objects. component composes an existing Shoalrun component using its documented attributes. Raw HTML and representation filters are unsupported. content() is required. A missing function or empty result fails with a diagnostic; there is no separate HTML-only renderer. It receives validated attributes and the authored children. It runs once per invocation before either output is rendered. Attributes and children Attribute schemas define the values page authors may supply: Setting Meaning type string , boolean , or number . required Whether the attribute must be present when it has no default. default A value matching the declared type and constraints. values Allowed string values. min , max , integer Optional numeric constraints. Booleans accept a bare attribute or quoted \"true\" and \"false\" . Numbers use quoted literals such as attempts=\"4\" . Dynamic expressions are unsupported. Unknown or duplicate attributes fail. The TypeScript API infers attribute types from the schema. children is none by default, or optional or required . Return the supplied children to preserve page-authored content. Use content.component to compose built-ins with more specific child rules. Browser data and behavior For an interactive component, resolve its model in content() and return both shared documentation and browser data: content ({ attributes }) { const policy = makePolicy (attributes); return { content : describePolicy (policy) , data : policy }; } makePolicy and describePolicy represent your component's model and content functions. data must contain only JSON values. Shoalrun snapshots it per invocation and gives that same data to the browser. Do not recover data by parsing tables or matching display labels. Import shared validation and calculation functions into both implementations when they need the same behavior. The browser module exports an enhancement function: export async function enhance ({ root , controls , content , data }) { // Mount optional controls into the empty controls element. // Read the instance model from data, not from presentation markup. // Keep the shared documentation in content intact. // Reveal controls after mounting; return when the interface is ready. } root contains this component instance; content contains its rendered documentation. React can mount into controls . Browser behavior enhances the shared documentation; this is not an arbitrary React renderer or an MDX import mechanism. If enhancement fails or JavaScript is disabled, shared content remains readable. The data-driven React fixtur","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A component package adds a custom component, such as <CopyText> , that authors can use in their pages. Its content() function produces the content shown in both HTML and Markdown. An optional browser module adds interactive behavior. Use a component Install the component package and add its exported manifest to your configuration. For a local component, register its manifest path: components: - ./components/copy-text/components.json An installed package can export its manifest as its entry point, or as a subpath such as @acme/docs-components/shoalrun . Replace that illustrative name with your installed package's export. Paths resolve relative to the configuration file that declares them, including includes and presets. The page supplies the content: <CopyText> Contact support@example.com for help. </CopyText> Contact support@example.com for help. CopyText requires child content and accepts no attributes. Its copy button is optional browser behavior. Markdown retains the authored text: Contact <support@example.com> for help. Develop a component The package's manifest declares its names and implementation files. Consumers register this manifest once; they do not configure its internal browser files: { \"apiVersion\": 1, \"components\": { \"CopyText\": { \"module\": \"./plugin.mjs\", \"browser\": \"./browser.jsx\" } } } Each component needs module . browser and a styles list are optional. These paths are relative to the manifest. Names start with an uppercase letter, contain only letters and digits, and must be unique across registrations. They cannot replace built-ins. The complete build module for the small example passes the page's children through unchanged: import { defineComponent } from '@shoalrun/cli/components'; export default defineComponent({ children: 'required', content({ children }) { return children; } }); A component that generates documentation uses the supported content helpers: import { defineComponent, content as c } from '@shoalrun/cli/components'; export default defineComponent({ attributes: { label: { type: 'string', required: true } }, children: 'required', content({ attributes, children }) { return [c.paragraph(c.strong(attributes.label)), children]; } }); Helpers include paragraph , strong , emphasis , inlineCode , code , heading , link , list , table , group , and component . They create shared content without requiring compiler-node objects. component composes an existing Shoalrun component using its documented attributes. Raw HTML and representation filters are unsupported. content() is required. A missing function or empty result fails with a diagnostic; there is no separate HTML-only renderer. It receives validated attributes and the authored children. It runs once per invocation before either output is rendered. Attributes and children Attribute schemas define the values page authors may supply: Setting Meaning type string , boolean , or number . required Whether the attribute must be present when it has no default. default A value matching the declared type and constraints. values Allowed string values. min , max , integer Optional numeric constraints. Booleans accept a bare attribute or quoted \"true\" and \"false\" . Numbers use quoted literals such as attempts=\"4\" . Dynamic expressions are unsupported. Unknown or duplicate attributes fail. The TypeScript API infers attribute types from the schema. children is none by default, or optional or required . Return the supplied children to preserve page-authored content. Use content.component to compose built-ins with more specific child rules. Browser data and behavior For an interactive component, resolve its model in content() and return both shared documentation and browser data: content({ attributes }) { const policy = makePolicy(attributes); return { content: describePolicy(policy), data: policy }; } makePolicy and describePolicy represent your component's model and content functions. data must contain only JSON values. Shoalrun snapshots it per invocation and gives that same data to the browser. Do not recover data by parsing tables or matching display labels. Import shared validation and calculation functions into both implementations when they need the same behavior. The browser module exports an enhancement function: export async function enhance({ root, controls, content, data }) { // Mount optional controls into the empty controls element. // Read the instance model from data, not from presentation markup. // Keep the shared documentation in content intact. // Reveal controls after mounting; return when the interface is ready. } root contains this component instance; content contains its rendered documentation. React can mount into controls . Browser behavior enhances the shared documentation; this is not an arbitrary React renderer or an MDX import mechanism. If enhancement fails or JavaScript is disabled, shared content remains readable. The data-driven React fixture exercises the explicit model handoff and shared calculation module. D"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Check working-tree documentation edits — Validate component fixtures and review matching HTML and Markdown snapshots. (Status: experimental.)"},{"filters":{"focus":["write"]},"text":"Data-driven React components — Add local data and generated documentation to a React interface."},{"filters":{"focus":["configure"]},"text":"Publishing and agent representations — Check the published content and artifacts available to readers and agents."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9822,"markdownTokens":1964,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.custom-metadata","demo":false,"url":"/author/custom-metadata","markdownUrl":"/author/custom-metadata.md","title":"Metadata customization","summary":"Configure metadata defaults, enforcement, fields, and providers.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-metadata","headings":[{"id":"global-defaults-and-enforced-values","title":"Global defaults and enforced values"},{"id":"add-a-custom-page-field","title":"Add a custom page field"},{"id":"choose-text-for-each-surface","title":"Choose text for each surface"},{"id":"read-metadata-from-a-project-module","title":"Read metadata from a project module"},{"id":"preview-changes-to-metadata-providers","title":"Preview changes to metadata providers"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"}],"text":"Use this guide when your project needs shared metadata rules or fields beyond the native page metadata . To choose which values appear in published Markdown, see Markdown metadata . Global defaults and enforced values The project config is the root docs.config.yaml plus any imported fragments. Its frontmatter block supplies shared page values; this block does not appear inside an individual page's header. Configure it in the root file or an imported fragment: frontmatter : locales : { en : en-US } defaults : type : guide channel : production version : v1 language : en audiences : [ developers ] access : { policy : draft } seo : description : Documentation for the example API. variables : product : Payments enforced : audiences : [ partners ] editorial : owner : API documentation fields : editorial.owner : type : string description : Team responsible for the documentation. defaults fills in values that a page may replace. enforced sets values the page cannot replace. Precedence is defaults → page frontmatter → enforced values . Objects merge recursively, and arrays replace rather than concatenate. In this example, every page's effective audience is partners , even if its source lists another audience. A page can override the default SEO description, but cannot override the enforced editorial owner. The id and slug fields must stay on each page; they cannot be global defaults or enforced values. Other native and custom metadata can be inherited. Required fields and declared types are checked after merging, so an inherited type , summary , or required custom field satisfies validation. The generated JSON Schema omits inherited fields from its source-level required lists. Global values do not bypass public metadata projection rules. access follows the same precedence. A default public policy allows a page to remain an explicit draft. An enforced public policy replaces even an explicit draft policy, so use defaults if authors need to keep individual pages unpublished. Scaffolded files are still initially written with draft access. For language, a page uses the enforced language, its own language, the frontmatter default, publications.defaults.language , then en , in that order. Enabled publication entries that omit language use the enforced/default global language, then the publication default, then en . The current router leaves the default language unprefixed. Future translation URL conventions remain open. frontmatter.locales sets the usual formatting locale for each language. A page can override it with its own locale ; frontmatter.enforced.locale takes precedence over both. The locale has no routing effect. A project with one language can instead use frontmatter.defaults.locale without a map. When updating an earlier prototype project, rename these settings: Earlier name Current name If left unchanged publications.defaults.locale , publications.enabled[].locale language The config loader fails with a migration message. Page locale used to choose a publication language The page uses the default language, and locale sets only formatting conventions. redirects[].to.locale redirects[].to.language The build fails because the redirect has no full target publication. publication.locale in Markdown metadata sources publication.language The build fails with an unknown metadata source. Page lifecycle: beta , in-development , experimental , or deprecated subjectLifecycle No status badge appears, and the build reports no error. --locale CLI option --language The command fails with an unknown-option error. locale in a custom search provider's context language The value is undefined . Review page locale values individually, because that name now means formatting conventions. Set nested global values with YAML mappings, as shown above. Dotted names such as editorial.owner belong in fields declarations and metadata projections. Global settings are applied in memory during the build; source pages are not rewritten. There are no directory-specific or document-type global policies yet. Add a custom page field The page metadata guide uses the optional, project-defined agent.intent field to record the task it helps a reader complete. Shoalrun does not require or interpret that field. A custom field has two parts: a declaration in project config and a value in a page header. The declaration appears in the published field reference and the local generated reference; the value belongs to that page. docs/docs.config.yaml loads the field declarations from a separate file: docs/docs.config.yaml frontmatter : { $include : ./config/frontmatter.yaml } docs/config/frontmatter.yaml declares both fields used by that guide: docs/config/frontmatter.yaml fields : agent.intent : type : string description : The reader task this page helps an agent complete. public : true editorial.reviewNote : type : string description : Internal note for documentation reviewers. public : false This page, docs/content/frontmatter.mdx , gives them these values: ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use this guide when your project needs shared metadata rules or fields beyond the native page metadata . To choose which values appear in published Markdown, see Markdown metadata . Global defaults and enforced values The project config is the root docs.config.yaml plus any imported fragments. Its frontmatter block supplies shared page values; this block does not appear inside an individual page's header. Configure it in the root file or an imported fragment: frontmatter: locales: { en: en-US } defaults: type: guide channel: production version: v1 language: en audiences: [developers] access: { policy: draft } seo: description: Documentation for the example API. variables: product: Payments enforced: audiences: [partners] editorial: owner: API documentation fields: editorial.owner: type: string description: Team responsible for the documentation. defaults fills in values that a page may replace. enforced sets values the page cannot replace. Precedence is defaults → page frontmatter → enforced values . Objects merge recursively, and arrays replace rather than concatenate. In this example, every page's effective audience is partners , even if its source lists another audience. A page can override the default SEO description, but cannot override the enforced editorial owner. The id and slug fields must stay on each page; they cannot be global defaults or enforced values. Other native and custom metadata can be inherited. Required fields and declared types are checked after merging, so an inherited type , summary , or required custom field satisfies validation. The generated JSON Schema omits inherited fields from its source-level required lists. Global values do not bypass public metadata projection rules. access follows the same precedence. A default public policy allows a page to remain an explicit draft. An enforced public policy replaces even an explicit draft policy, so use defaults if authors need to keep individual pages unpublished. Scaffolded files are still initially written with draft access. For language, a page uses the enforced language, its own language, the frontmatter default, publications.defaults.language , then en , in that order. Enabled publication entries that omit language use the enforced/default global language, then the publication default, then en . The current router leaves the default language unprefixed. Future translation URL conventions remain open. frontmatter.locales sets the usual formatting locale for each language. A page can override it with its own locale ; frontmatter.enforced.locale takes precedence over both. The locale has no routing effect. A project with one language can instead use frontmatter.defaults.locale without a map. When updating an earlier prototype project, rename these settings: Earlier name Current name If left unchanged publications.defaults.locale , publications.enabled[].locale language The config loader fails with a migration message. Page locale used to choose a publication language The page uses the default language, and locale sets only formatting conventions. redirects[].to.locale redirects[].to.language The build fails because the redirect has no full target publication. publication.locale in Markdown metadata sources publication.language The build fails with an unknown metadata source. Page lifecycle: beta , in-development , experimental , or deprecated subjectLifecycle No status badge appears, and the build reports no error. --locale CLI option --language The command fails with an unknown-option error. locale in a custom search provider's context language The value is undefined . Review page locale values individually, because that name now means formatting conventions. Set nested global values with YAML mappings, as shown above. Dotted names such as editorial.owner belong in fields declarations and metadata projections. Global settings are applied in memory during the build; source pages are not rewritten. There are no directory-specific or document-type global policies yet. Add a custom page field The page metadata guide uses the optional, project-defined agent.intent field to record the task it helps a reader complete. Shoalrun does not require or interpret that field. A custom field has two parts: a declaration in project config and a value in a page header. The declaration appears in the published field reference and the local generated reference; the value belongs to that page. docs/docs.config.yaml loads the field declarations from a separate file: frontmatter: { $include: ./config/frontmatter.yaml } docs/config/frontmatter.yaml declares both fields used by that guide: fields: agent.intent: type: string description: The reader task this page helps an agent complete. public: true editorial.reviewNote: type: string description: Internal note for documentation reviewers. public: false This page, docs/content/frontmatter.mdx , gives them these values: agent: intent: Help authors understand and configure page metadata. editorial: reviewNote"},{"filters":{"focus":["write"]},"text":"Markdown metadata — Choose which eligible project fields to publish."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":12170,"markdownTokens":2477,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"add-a-custom-page-field","title":"Add a custom page field","markdownUrl":"/author/custom-metadata.sections/add-a-custom-page-field.md","markdownBytes":3802,"markdownTokens":874},{"id":"choose-text-for-each-surface","title":"Choose text for each surface","markdownUrl":"/author/custom-metadata.sections/choose-text-for-each-surface.md","markdownBytes":2616,"markdownTokens":604},{"id":"read-metadata-from-a-project-module","title":"Read metadata from a project module","markdownUrl":"/author/custom-metadata.sections/read-metadata-from-a-project-module.md","markdownBytes":3080,"markdownTokens":701},{"id":"preview-changes-to-metadata-providers","title":"Preview changes to metadata providers","markdownUrl":"/author/custom-metadata.sections/preview-changes-to-metadata-providers.md","markdownBytes":1773,"markdownTokens":412},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/custom-metadata.sections/related-reading.md","markdownBytes":1246,"markdownTokens":307}]},{"id":"reference.d2-gallery","demo":false,"url":"/author/components/diagrams/d2-gallery","markdownUrl":"/author/components/diagrams/d2-gallery.md","title":"D2 gallery","summary":"Browse D2 diagrams, layout engines, and basic shapes with copyable source.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-visuals","headings":[{"id":"flows-and-structures","title":"Flows and structures"},{"id":"connected-steps","title":"Connected steps"},{"id":"decision-flow","title":"Decision flow"},{"id":"connection-styles","title":"Connection styles"},{"id":"nested-containers","title":"Nested containers"},{"id":"service-architecture","title":"Service architecture"},{"id":"sql-tables","title":"SQL tables"},{"id":"uml-classes","title":"UML classes"},{"id":"sequences-and-grids","title":"Sequences and grids"},{"id":"sequence-diagram","title":"Sequence diagram"},{"id":"grid-layout","title":"Grid layout"},{"id":"styles-and-code","title":"Styles and code"},{"id":"reusable-styles","title":"Reusable styles"},{"id":"code-block","title":"Code block"},{"id":"layout-engines","title":"Layout engines"},{"id":"tala-layout","title":"TALA layout"},{"id":"elk-layout","title":"ELK layout"},{"id":"dagre-layout","title":"Dagre layout"},{"id":"basic-shapes","title":"Basic shapes"},{"id":"d2-shapes-1","title":"D2 shapes 1"},{"id":"d2-shapes-2","title":"D2 shapes 2"},{"id":"d2-shapes-3","title":"D2 shapes 3"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"These 17 examples cover connected flows, containers, SQL tables, UML classes, sequences, grids, and 18 basic D2 shapes. Each uses Shoalrun’s Diagram component , with a width cap and copyable source. The diagrams illustrate notation rather than live services. D2 generates separate light and dark SVG images. They follow the site’s color mode, but do not inherit its live palette or fonts. Use D2 themes and styles to customize the source. For Mermaid syntax rendered by Pele, see the Pele gallery . The examples set vars.d2-config.pad to 16 pixels to keep the diagram padding compact. Width caps keep smaller examples from filling the page. Flows and structures Connected steps Connect the stages of a documentation build. Connected steps — Connect the stages of a documentation build. Source: Connected steps vars: { d2-config: { pad: 16 } } direction: right source: Source files build: Build documentation site: Published site source -> build: compile build -> site: publish Decision flow Show approval and revision paths. Decision flow — Show approval and revision paths. Source: Decision flow vars: { d2-config: { pad: 16 } } direction: down draft: Draft guide review: Ready to publish? { shape: diamond } publish: Publish guide revise: Revise guide draft -> review review -> publish: yes review -> revise: no revise -> draft Connection styles Distinguish directed, two-way, and dashed relationships. Connection styles — Distinguish directed, two-way, and dashed relationships. Source: Connection styles vars: { d2-config: { pad: 16 } } direction: right writer: Writer reviewer: Reviewer archive: Archive { shape: cylinder } writer <-> reviewer: discuss reviewer -> archive: approved copy writer -> archive: reference { style.stroke-dash: 4 } Nested containers Group a site and its supporting services. Nested containers — Group a site and its supporting services. Source: Nested containers vars: { d2-config: { pad: 16 } } direction: right project: Documentation project { content: Content files config: Configuration } site: Published site { html: HTML pages markdown: Markdown pages } project.content -> site.html project.content -> site.markdown project.config -> site Service architecture Connect readers, a documentation endpoint, and stored content. Service architecture — Connect readers, a documentation endpoint, and stored content. Source: Service architecture vars: { d2-config: { pad: 16 } } reader: Reader { shape: person } site: Documentation site mcp: MCP endpoint content: Published content { shape: cylinder } reader -> site: browse reader -> mcp: read with tools site -> content mcp -> content SQL tables Show columns, key constraints, and a foreign-key relationship. SQL tables — Show columns, key constraints, and a foreign-key relationship. Source: SQL tables vars: { d2-config: { pad: 16 } } direction: right pages: Pages { shape: sql_table id: text { constraint: primary_key } title: text } sections: Sections { shape: sql_table id: text { constraint: primary_key } page_id: text { constraint: foreign_key } heading: text } sections.page_id -> pages.id UML classes Describe a page class and its section class. UML classes — Describe a page class and its section class. Source: UML classes vars: { d2-config: { pad: 16 } } direction: right Page: { shape: class title: string slug: string render(): HTML } Section: { shape: class heading: string text: string } Page -> Section: contains Sequences and grids Sequence diagram Read requests and responses in their declared order. Sequence diagram — Read requests and responses in their declared order. Source: Sequence diagram vars: { d2-config: { pad: 16 } } shape: sequence_diagram agent: Agent server: MCP server index: Published index agent -> server: Search documentation server -> index: Find matching pages index -> server: Page IDs server -> agent: Read instruction agent -> server: Read selected page server -> agent: Markdown and citation Grid layout Arrange related topics in a fixed number of columns. Grid layout — Arrange related topics in a fixed number of columns. Source: Grid layout vars: { d2-config: { pad: 16 } } grid-columns: 3 start: Start configure: Configure author: Author publish: Publish measure: Measure maintain: Maintain Styles and code Explicit source colors stay fixed in both modes. The reusable style below sets text and background together to preserve contrast. Reusable styles Apply a shared style with explicit contrasting text and fill colors. Reusable styles — Apply a shared style with explicit contrasting text and fill colors. Source: Reusable styles vars: { d2-config: { pad: 16 } } direction: right classes: { step: { style.fill: \"#e9f3ef\" style.font-color: \"#16332e\" style.stroke: \"#52706a\" style.border-radius: 8 } } a: Draft { class: step } b: Review { class: step } c: Publish { class: step } a -> b -> c Code block Include a short source-code excerpt as a diagram node. Code block — Include a short source-code excerpt as a diagram node. Source: Code block vars: { d2-conf","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"These 17 examples cover connected flows, containers, SQL tables, UML classes, sequences, grids, and 18 basic D2 shapes. Each uses Shoalrun’s Diagram component , with a width cap and copyable source. The diagrams illustrate notation rather than live services. D2 generates separate light and dark SVG images. They follow the site’s color mode, but do not inherit its live palette or fonts. Use D2 themes and styles to customize the source. For Mermaid syntax rendered by Pele, see the Pele gallery . The examples set vars.d2-config.pad to 16 pixels to keep the diagram padding compact. Width caps keep smaller examples from filling the page. Flows and structures Connected steps Connect the stages of a documentation build. Connected steps — Connect the stages of a documentation build. Source: Connected steps vars: { d2-config: { pad: 16 } } direction: right source: Source files build: Build documentation site: Published site source -> build: compile build -> site: publish Decision flow Show approval and revision paths. Decision flow — Show approval and revision paths. Source: Decision flow vars: { d2-config: { pad: 16 } } direction: down draft: Draft guide review: Ready to publish? { shape: diamond } publish: Publish guide revise: Revise guide draft -> review review -> publish: yes review -> revise: no revise -> draft Connection styles Distinguish directed, two-way, and dashed relationships. Connection styles — Distinguish directed, two-way, and dashed relationships. Source: Connection styles vars: { d2-config: { pad: 16 } } direction: right writer: Writer reviewer: Reviewer archive: Archive { shape: cylinder } writer <-> reviewer: discuss reviewer -> archive: approved copy writer -> archive: reference { style.stroke-dash: 4 } Nested containers Group a site and its supporting services. Nested containers — Group a site and its supporting services. Source: Nested containers vars: { d2-config: { pad: 16 } } direction: right project: Documentation project { content: Content files config: Configuration } site: Published site { html: HTML pages markdown: Markdown pages } project.content -> site.html project.content -> site.markdown project.config -> site Service architecture Connect readers, a documentation endpoint, and stored content. Service architecture — Connect readers, a documentation endpoint, and stored content. Source: Service architecture vars: { d2-config: { pad: 16 } } reader: Reader { shape: person } site: Documentation site mcp: MCP endpoint content: Published content { shape: cylinder } reader -> site: browse reader -> mcp: read with tools site -> content mcp -> content SQL tables Show columns, key constraints, and a foreign-key relationship. SQL tables — Show columns, key constraints, and a foreign-key relationship. Source: SQL tables vars: { d2-config: { pad: 16 } } direction: right pages: Pages { shape: sql_table id: text { constraint: primary_key } title: text } sections: Sections { shape: sql_table id: text { constraint: primary_key } page_id: text { constraint: foreign_key } heading: text } sections.page_id -> pages.id UML classes Describe a page class and its section class. UML classes — Describe a page class and its section class. Source: UML classes vars: { d2-config: { pad: 16 } } direction: right Page: { shape: class title: string slug: string render(): HTML } Section: { shape: class heading: string text: string } Page -> Section: contains Sequences and grids Sequence diagram Read requests and responses in their declared order. Sequence diagram — Read requests and responses in their declared order. Source: Sequence diagram vars: { d2-config: { pad: 16 } } shape: sequence_diagram agent: Agent server: MCP server index: Published index agent -> server: Search documentation server -> index: Find matching pages index -> server: Page IDs server -> agent: Read instruction agent -> server: Read selected page server -> agent: Markdown and citation Grid layout Arrange related topics in a fixed number of columns. Grid layout — Arrange related topics in a fixed number of columns. Source: Grid layout vars: { d2-config: { pad: 16 } } grid-columns: 3 start: Start configure: Configure author: Author publish: Publish measure: Measure maintain: Maintain Styles and code Explicit source colors stay fixed in both modes. The reusable style below sets text and background together to preserve contrast. Reusable styles Apply a shared style with explicit contrasting text and fill colors. Reusable styles — Apply a shared style with explicit contrasting text and fill colors. Source: Reusable styles vars: { d2-config: { pad: 16 } } direction: right classes: { step: { style.fill: \"#e9f3ef\" style.font-color: \"#16332e\" style.stroke: \"#52706a\" style.border-radius: 8 } } a: Draft { class: step } b: Review { class: step } c: Publish { class: step } a -> b -> c Code block Include a short source-code excerpt as a diagram node. Code block — Include a short source-code excerpt as a diagram node. Source: Code block vars: { d2-config: {"},{"filters":{"focus":["write"]},"text":"Diagrams — Configure diagram width, layout engines, and output behavior. Pele gallery — Compare D2 examples with Mermaid syntax rendered by Pele."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":16017,"markdownTokens":4460,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"flows-and-structures","title":"Flows and structures","markdownUrl":"/author/components/diagrams/d2-gallery.sections/flows-and-structures.md","markdownBytes":7226,"markdownTokens":1925},{"id":"sequences-and-grids","title":"Sequences and grids","markdownUrl":"/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md","markdownBytes":3274,"markdownTokens":858},{"id":"styles-and-code","title":"Styles and code","markdownUrl":"/author/components/diagrams/d2-gallery.sections/styles-and-code.md","markdownBytes":3263,"markdownTokens":909},{"id":"layout-engines","title":"Layout engines","markdownUrl":"/author/components/diagrams/d2-gallery.sections/layout-engines.md","markdownBytes":3744,"markdownTokens":1028},{"id":"basic-shapes","title":"Basic shapes","markdownUrl":"/author/components/diagrams/d2-gallery.sections/basic-shapes.md","markdownBytes":4352,"markdownTokens":1272},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md","markdownBytes":2272,"markdownTokens":581},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/components/diagrams/d2-gallery.sections/related-reading.md","markdownBytes":2032,"markdownTokens":522}]},{"id":"guide.deployment-check","demo":false,"url":"/publish/deployment-check","markdownUrl":"/publish/deployment-check.md","title":"Check a deployed site","summary":"Run the provider-neutral HTTP checker after publishing and before release.","type":"how-to","variant":"production|current|en","area":"quality","subarea":"quality-audits","headings":[{"id":"what-it-checks","title":"What it checks"},{"id":"read-the-result","title":"Read the result"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"A local build verifies the generated files. After deployment, check what the host actually serves. This guide uses scripts/check-deployment.mjs from Shoalrun's docs repository; the script is not included in the @shoalrun/cli package. From the docs repository root, pass the deployed site origin to the checker: npm run deploy:check -- https://docs.example.com/ Use the real HTTPS site URL and a trailing slash, including a configured base path such as https://docs.example.com/docs/ . The command does not change the deployed site. For a branch deployment, pass the full hash that the deployment job checked out. The checker reads /build-info.json and fails if that domain serves a different revision: npm run deploy:check -- https://docs.example.com/ --source-commit \"$SOURCE_COMMIT\" SOURCE_COMMIT must be a 40- or 64-character Git commit hash. Supply it from the job that deploys this origin, for example git rev-parse HEAD after checkout. A missing or mismatched record is a failure. For a site with hosted chat and search, add --chat . It checks the public chat settings and both endpoints: GET returns 405, a foreign origin returns 403, and an invalid same-origin request returns 400. Invalid requests stop before model or embedding calls. If chat is already paused, use --chat --chat-paused instead; the checker expects its 503 paused response. It does not change the pause flag. npm run deploy:check -- https://docs.example.com/ --chat What it checks The checker reads the deployed /documents.json and tests every listed page: HTML at the page URL with Accept: text/html , including its content type, Vary: Accept , and alternate Markdown Link header. Markdown at the same URL with Accept: text/markdown , including its content type, Vary , Content-Location , and alternate link. The direct .md URL and exact text equality between its body and the negotiated Markdown body. Each page's og:url and og:image point to the checked public origin. When pages have share images, it fetches one image and checks that the host serves it as an image. Canonical links point to the page being checked, and noindex matches the manifest's indexing choice. /robots.txt advertises the sitemap when one exists. Every sitemap URL matches an indexable manifest page, every indexable page is listed once, and lastmod matches its metadata. The checker fetches child sitemaps and catches redirects and HTTP errors. It also checks /llms.txt , /resource-headers.json , and the API catalog when the resource headers declare one. It verifies discovery content types and that a random missing route returns 404 for both HTML and Markdown requests. This establishes the host's response behavior; it does not judge whether the authored HTML and Markdown prose mean the same thing. Read the result The command prints a PASS or FAIL summary with request, document, and failure counts. On failure, each FAIL line names the route and the missing or incorrect response. For example, a Markdown response served as HTML is reported as a Content-Type failure. Fix the host route or headers, deploy again, and rerun the checker before release. Exit status 0 means every check passed, 1 means the deployed site failed one or more checks, and 2 means the command input is invalid. A passing result does not replace manual review, accessibility checks, or an external scorecard. The content negotiation guide defines the host-independent HTTP contract. The Vercel guide shows one hosting recipe. The checker works against any provider that serves the same contract. Related reading Related topics Host and limit documentation chat — Check a deployed site's headers, redirects, and Markdown negotiation. (Status: experimental.) Often confused with Audit a docs project — The audit checks project sources in CI; the deployment check tests the published site over HTTP.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"A local build verifies the generated files. After deployment, check what the host actually serves. This guide uses scripts/check-deployment.mjs from Shoalrun's docs repository; the script is not included in the @shoalrun/cli package. From the docs repository root, pass the deployed site origin to the checker: npm run deploy:check -- https://docs.example.com/ Use the real HTTPS site URL and a trailing slash, including a configured base path such as https://docs.example.com/docs/ . The command does not change the deployed site. For a branch deployment, pass the full hash that the deployment job checked out. The checker reads /build-info.json and fails if that domain serves a different revision: npm run deploy:check -- https://docs.example.com/ --source-commit \"$SOURCE_COMMIT\" SOURCE_COMMIT must be a 40- or 64-character Git commit hash. Supply it from the job that deploys this origin, for example git rev-parse HEAD after checkout. A missing or mismatched record is a failure. For a site with hosted chat and search, add --chat . It checks the public chat settings and both endpoints: GET returns 405, a foreign origin returns 403, and an invalid same-origin request returns 400. Invalid requests stop before model or embedding calls. If chat is already paused, use --chat --chat-paused instead; the checker expects its 503 paused response. It does not change the pause flag. npm run deploy:check -- https://docs.example.com/ --chat What it checks The checker reads the deployed /documents.json and tests every listed page: HTML at the page URL with Accept: text/html , including its content type, Vary: Accept , and alternate Markdown Link header. Markdown at the same URL with Accept: text/markdown , including its content type, Vary , Content-Location , and alternate link. The direct .md URL and exact text equality between its body and the negotiated Markdown body. Each page's og:url and og:image point to the checked public origin. When pages have share images, it fetches one image and checks that the host serves it as an image. Canonical links point to the page being checked, and noindex matches the manifest's indexing choice. /robots.txt advertises the sitemap when one exists. Every sitemap URL matches an indexable manifest page, every indexable page is listed once, and lastmod matches its metadata. The checker fetches child sitemaps and catches redirects and HTTP errors. It also checks /llms.txt , /resource-headers.json , and the API catalog when the resource headers declare one. It verifies discovery content types and that a random missing route returns 404 for both HTML and Markdown requests. This establishes the host's response behavior; it does not judge whether the authored HTML and Markdown prose mean the same thing. Read the result The command prints a PASS or FAIL summary with request, document, and failure counts. On failure, each FAIL line names the route and the missing or incorrect response. For example, a Markdown response served as HTML is reported as a Content-Type failure. Fix the host route or headers, deploy again, and rerun the checker before release. Exit status 0 means every check passed, 1 means the deployed site failed one or more checks, and 2 means the command input is invalid. A passing result does not replace manual review, accessibility checks, or an external scorecard. The content negotiation guide defines the host-independent HTTP contract. The Vercel guide shows one hosting recipe. The checker works against any provider that serves the same contract. Related reading Related topics Often confused with"},{"filters":{"focus":["configure"]},"text":"Host and limit documentation chat — Check a deployed site's headers, redirects, and Markdown negotiation. (Status: experimental.) Audit a docs project — The audit checks project sources in CI; the deployment check tests the published site over HTTP."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4895,"markdownTokens":1132,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.design-templates","demo":false,"url":"/author/design-templates","markdownUrl":"/author/design-templates.md","title":"Design templates","summary":"Make repeatable page structures that help authors and agents serve readers.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-templates","headings":[{"id":"start-with-a-reader-need","title":"Start with a reader need"},{"id":"make-prompts-actionable","title":"Make prompts actionable"},{"id":"keep-structure-and-checks-separate","title":"Keep structure and checks separate"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"}],"text":"A template defines the starting structure of a page. Use it for information that belongs in most pages of a particular kind. A writing guide explains how to write that information. Start with a reader need Choose the page's purpose before choosing headings. A how-to helps a reader complete a task; a reference supports lookup; an explanation builds understanding; a tutorial teaches through a guided exercise. Keep distinct needs on separate pages when combining them makes either harder to use. For an ingredient, define one reusable action, its inputs, and its success check. For a recipe, give the complete ordered procedure and recovery advice. A cookbook helps readers choose among recipes. These structures support reuse without making readers assemble their own instructions. Make prompts actionable A useful placeholder asks for specific missing information: prerequisites, a tested command, expected output, or a recovery action. Avoid vague prompts such as “add useful details.” Tell the agent to flag missing evidence instead of filling gaps with plausible facts. Keep required sections small. Make optional sections clearly optional, and provide a reviewed example outside the template. A copied example's technical details are not evidence for a different feature. Keep structure and checks separate Shoalrun's template overrides control scaffold text. They do not automatically change configured lint rules. Match the template to your page-type conventions and configure checks explicitly. Review a template by drafting several real pages with it. Remove sections authors repeatedly leave empty, and add prompts where readers repeatedly lack information. Check both HTML and Markdown so essential instructions survive every representation. Related reading Reference while working Templates — Configure project template overrides. Design a writing guide — Give agents editorial guidance alongside the page structure.","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"A template defines the starting structure of a page. Use it for information that belongs in most pages of a particular kind. A writing guide explains how to write that information. Start with a reader need Choose the page's purpose before choosing headings. A how-to helps a reader complete a task; a reference supports lookup; an explanation builds understanding; a tutorial teaches through a guided exercise. Keep distinct needs on separate pages when combining them makes either harder to use. For an ingredient, define one reusable action, its inputs, and its success check. For a recipe, give the complete ordered procedure and recovery advice. A cookbook helps readers choose among recipes. These structures support reuse without making readers assemble their own instructions. Make prompts actionable A useful placeholder asks for specific missing information: prerequisites, a tested command, expected output, or a recovery action. Avoid vague prompts such as “add useful details.” Tell the agent to flag missing evidence instead of filling gaps with plausible facts. Keep required sections small. Make optional sections clearly optional, and provide a reviewed example outside the template. A copied example's technical details are not evidence for a different feature. Keep structure and checks separate Shoalrun's template overrides control scaffold text. They do not automatically change configured lint rules. Match the template to your page-type conventions and configure checks explicitly. Review a template by drafting several real pages with it. Remove sections authors repeatedly leave empty, and add prompts where readers repeatedly lack information. Check both HTML and Markdown so essential instructions survive every representation. Related reading Reference while working"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates — Configure project template overrides. Design a writing guide — Give agents editorial guidance alongside the page structure."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2937,"markdownTokens":604,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.design-writing-guides","demo":false,"url":"/author/design-writing-guides","markdownUrl":"/author/design-writing-guides.md","title":"Design a writing guide","summary":"Give authors and agents clear editorial rules, examples, and review expectations.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-writing","headings":[{"id":"put-guidance-in-project-configuration","title":"Put guidance in project configuration"},{"id":"state-the-decisions-that-matter","title":"State the decisions that matter"},{"id":"show-reviewed-examples","title":"Show reviewed examples"},{"id":"define-evidence-and-review-expectations","title":"Define evidence and review expectations"},{"id":"automate-the-repeatable-rules","title":"Automate the repeatable rules"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"}],"text":"A project writing guide explains your readers, terminology, and editorial decisions. Give your agent the guide's file path in project instructions so it can read the same rules as human authors. Put guidance in project configuration Use authoring to give agents shared editorial instructions and file paths: authoring : directives : | Write for the reader's task. Verify technical claims against inspected sources. Use Steps for titled procedures; leave numbers out of headings. guideFiles : - content/writing-guide.mdx exemplarFiles : - content/reviewed-how-to.mdx Paths are relative to docs.config.yaml and point to files your agent should read. docs context returns this guidance and its configuration owner. For a new page, your agent can read it with config resolve . Shoalrun validates the field shapes; it does not load these files into a model, run the instructions, or require a provider key. These authoring settings do not configure a model. State the decisions that matter Describe who reads the docs, what they already know, and what they need to accomplish. Define preferred product names and terms, how to introduce unfamiliar concepts, and how much explanation different page types need. Separate rules from preferences. Give a reason when it changes how a writer should decide. For example: “Use Steps for a titled procedure so readers can scan the sequence; leave numbers out of heading text.” Show reviewed examples Pair a short rule with a concrete example or link to a reviewed page. Explain what makes the example useful. Choose examples for the same reader purpose: an API reference is a poor model for an introductory explanation. Include ingredients, recipes, and cookbooks if your project uses them. Explain what belongs in a reusable action, a complete procedure, and a page that helps readers choose. The example writing guide shows this site's choices. Adapt it to your own readers rather than treating it as a required Shoalrun style. Define evidence and review expectations Tell the agent to support changed technical claims with sources it has inspected, verify examples when possible, and report missing facts. Your agent handles source discovery and evidence gathering with its own tools. Keep editorial examples separate from factual sources. Define what the reviewer needs: a diff, changed claims and their sources, check results, and unresolved questions. Do not treat a clean style report as approval to publish. Automate the repeatable rules Use Vale or your preferred checker for rules it can assess reliably. Put the command and configuration path in project instructions. Keep judgment about clarity, technical accuracy, and reader usefulness in review. Maintain the guide as a project file. Change a rule when reviewed work demonstrates a better choice, then update its examples and checker configuration together. Related reading Reference while working Example writing guide — Read a complete project writing guide example.","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"A project writing guide explains your readers, terminology, and editorial decisions. Give your agent the guide's file path in project instructions so it can read the same rules as human authors. Put guidance in project configuration Use authoring to give agents shared editorial instructions and file paths: authoring: directives: | Write for the reader's task. Verify technical claims against inspected sources. Use Steps for titled procedures; leave numbers out of headings. guideFiles: - content/writing-guide.mdx exemplarFiles: - content/reviewed-how-to.mdx Paths are relative to docs.config.yaml and point to files your agent should read. docs context returns this guidance and its configuration owner. For a new page, your agent can read it with config resolve . Shoalrun validates the field shapes; it does not load these files into a model, run the instructions, or require a provider key. These authoring settings do not configure a model. State the decisions that matter Describe who reads the docs, what they already know, and what they need to accomplish. Define preferred product names and terms, how to introduce unfamiliar concepts, and how much explanation different page types need. Separate rules from preferences. Give a reason when it changes how a writer should decide. For example: “Use Steps for a titled procedure so readers can scan the sequence; leave numbers out of heading text.” Show reviewed examples Pair a short rule with a concrete example or link to a reviewed page. Explain what makes the example useful. Choose examples for the same reader purpose: an API reference is a poor model for an introductory explanation. Include ingredients, recipes, and cookbooks if your project uses them. Explain what belongs in a reusable action, a complete procedure, and a page that helps readers choose. The example writing guide shows this site's choices. Adapt it to your own readers rather than treating it as a required Shoalrun style. Define evidence and review expectations Tell the agent to support changed technical claims with sources it has inspected, verify examples when possible, and report missing facts. Your agent handles source discovery and evidence gathering with its own tools. Keep editorial examples separate from factual sources. Define what the reviewer needs: a diff, changed claims and their sources, check results, and unresolved questions. Do not treat a clean style report as approval to publish. Automate the repeatable rules Use Vale or your preferred checker for rules it can assess reliably. Put the command and configuration path in project instructions. Keep judgment about clarity, technical accuracy, and reader usefulness in review. Maintain the guide as a project file. Change a rule when reviewed work demonstrates a better choice, then update its examples and checker configuration together. Related reading Reference while working"},{"filters":{"focus":["write"]},"text":"Example writing guide — Read a complete project writing guide example."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4003,"markdownTokens":849,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.pele-gallery","demo":false,"url":"/author/components/diagrams/pele-gallery","markdownUrl":"/author/components/diagrams/pele-gallery.md","title":"Pele gallery","summary":"Browse Mermaid-syntax diagrams and flowchart shapes rendered with Pele.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-visuals","headings":[{"id":"flows-and-behavior","title":"Flows and behavior"},{"id":"flowchart","title":"Flowchart"},{"id":"sequence","title":"Sequence"},{"id":"state","title":"State"},{"id":"agentflow","title":"Agentflow"},{"id":"swimlane","title":"Swimlane"},{"id":"user-journey","title":"User journey"},{"id":"event-modeling","title":"Event modeling"},{"id":"use-case","title":"Use case"},{"id":"systems-and-structures","title":"Systems and structures"},{"id":"class","title":"Class"},{"id":"entity-relationship","title":"Entity relationship"},{"id":"architecture","title":"Architecture"},{"id":"c4","title":"C4"},{"id":"block","title":"Block"},{"id":"mindmap","title":"Mindmap"},{"id":"tree-view","title":"Tree view"},{"id":"requirement","title":"Requirement"},{"id":"charts-and-planning","title":"Charts and planning"},{"id":"gantt","title":"Gantt"},{"id":"git-graph","title":"Git graph"},{"id":"pie","title":"Pie"},{"id":"kanban","title":"Kanban"},{"id":"timeline","title":"Timeline"},{"id":"quadrant-chart","title":"Quadrant chart"},{"id":"xy-chart","title":"XY chart"},{"id":"sankey","title":"Sankey"},{"id":"radar","title":"Radar"},{"id":"treemap","title":"Treemap"},{"id":"specialized-diagrams","title":"Specialized diagrams"},{"id":"cynefin","title":"Cynefin"},{"id":"wardley-map","title":"Wardley map"},{"id":"ishikawa","title":"Ishikawa"},{"id":"packet","title":"Packet"},{"id":"railroad","title":"Railroad"},{"id":"venn","title":"Venn"},{"id":"renderer-information","title":"Renderer information"},{"id":"flowchart-shapes","title":"Flowchart shapes"},{"id":"flowchart-shapes-1","title":"Flowchart shapes 1"},{"id":"flowchart-shapes-2","title":"Flowchart shapes 2"},{"id":"flowchart-shapes-3","title":"Flowchart shapes 3"},{"id":"flowchart-shapes-4","title":"Flowchart shapes 4"},{"id":"flowchart-shapes-5","title":"Flowchart shapes 5"},{"id":"flowchart-shapes-6","title":"Flowchart shapes 6"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Browse examples of Pele's 33 built-in diagram families, including its version display, and 48 flowchart shapes. Every example uses Shoalrun's Diagram component with Mermaid syntax. These illustrate notation; they do not describe live services or measured product results. Open Source beneath a diagram to copy its syntax. See Pele's examples for more variations and compatibility notes for differences from Mermaid. Flows and behavior Flowchart Follow decisions and retry paths. Yes No Draft page Checks pass? Publish Revise page Flowchart — Follow decisions and retry paths. Source: Flowchart flowchart TD Draft[Draft page] --> Check{Checks pass?} Check -->|Yes| Publish[Publish] Check -->|No| Revise[Revise page] Revise --> Draft Sequence Trace messages between an agent and documentation tools. search_docs Page IDs get_page Markdown and citation Agent Docs Agent Docs Sequence — Trace messages between an agent and documentation tools. Source: Sequence sequenceDiagram participant Agent participant Docs Agent->>Docs: search_docs Docs-->>Agent: Page IDs Agent->>Docs: get_page Docs-->>Agent: Markdown and citation State Explain a document lifecycle. revise approve Draft Review Published State — Explain a document lifecycle. Source: State stateDiagram-v2 [*] --> Draft Draft --> Review Review --> Draft : revise Review --> Published : approve Published --> [*] Agentflow Show agent tasks and decisions. yes no Draft guide Checks pass? Publish guide Agentflow — Show agent tasks and decisions. Source: Agentflow agentflow-beta TB draft[\"Draft guide\"]@{ shape: task } check[\"Checks pass?\"]@{ shape: decision } publish[\"Publish guide\"]@{ shape: action } draft --> check check -- yes --> publish check -- no --> draft Swimlane Separate work by team. Reviewers Authors Draft guide Review guide Swimlane — Separate work by team. Source: Swimlane swimlane-beta LR subgraph Authors draft[Draft guide] end subgraph Reviewers review[Review guide] end draft --> review User journey Show the stages and participants in a reader journey. Find an answer 5 4 3 2 1 Discover Search docs Reader Open guide Reader Apply Try example Reader Check result Reader Reader User journey — Show the stages and participants in a reader journey. Source: User journey journey title Find an answer section Discover Search docs: 4: Reader Open guide: 5: Reader section Apply Try example: 4: Reader Check result: 5: Reader Event modeling Trace interface actions and resulting events. UI/Automation Command/Read Model Events Editor PublishPage PagePublished Event modeling — Trace interface actions and resulting events. Source: Event modeling eventmodeling tf 01 ui Editor tf 02 cmd PublishPage tf 03 evt PagePublished Use case Connect an actor to a supported action. Reader Browse documentation Search documentation Use case — Connect an actor to a supported action. Source: Use case usecase-beta actor Reader Browse[Browse documentation] Search[Search documentation] Reader --> Browse Reader --> Search Systems and structures Class Describe types, fields, and relationships. 1 many Page +String title +String slug +render() Section +String heading Class — Describe types, fields, and relationships. Source: Class classDiagram class Page { +String title +String slug +render() } class Section { +String heading } Page \"1\" *-- \"many\" Section Entity relationship Show entities and relationship cardinality. contains contains PROJECT PAGE string id PK string title SECTION string heading Entity relationship — Show entities and relationship cardinality. Source: Entity relationship erDiagram PROJECT ||--o{ PAGE : contains PAGE ||--o{ SECTION : contains PAGE { string id PK string title } SECTION { string heading } Architecture Connect services using built-in symbols. Documentation Site Content Architecture — Connect services using built-in symbols. Source: Architecture architecture-beta group docs(cloud)[Documentation] service app(server)[Site] in docs service store(database)[Content] in docs app:R -- L:store C4 Describe a system and its users at a high level. Documentation context «person» Reader Finds instructions «system» Documentation Published guides Reads C4 — Describe a system and its users at a high level. Source: C4 C4Context title Documentation context Person(reader, \"Reader\", \"Finds instructions\") System(docs, \"Documentation\", \"Published guides\") Rel(reader, docs, \"Reads\") Block Arrange connected blocks in explicit columns. Author Build Publish Block — Arrange connected blocks in explicit columns. Source: Block block-beta columns 3 a[\"Author\"] b[\"Build\"] c[\"Publish\"] a --> b b --> c Mindmap Organize related documentation topics. Authoring Pages Components Publishing Builds Hosting Documentation Mindmap — Organize related documentation topics. Source: Mindmap mindmap root((Documentation)) Authoring Pages Components Publishing Builds Hosting Tree view Display a directory hierarchy. docs content start.mdx configuration.mdx docs.config.yaml Tree view — Display a directory hierarchy. Source: Tree ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Browse examples of Pele's 33 built-in diagram families, including its version display, and 48 flowchart shapes. Every example uses Shoalrun's Diagram component with Mermaid syntax. These illustrate notation; they do not describe live services or measured product results. Open Source beneath a diagram to copy its syntax. See Pele's examples for more variations and compatibility notes for differences from Mermaid. Flows and behavior Flowchart Follow decisions and retry paths. Flowchart — Follow decisions and retry paths. Source: Flowchart flowchart TD Draft[Draft page] --> Check{Checks pass?} Check -->|Yes| Publish[Publish] Check -->|No| Revise[Revise page] Revise --> Draft Sequence Trace messages between an agent and documentation tools. Sequence — Trace messages between an agent and documentation tools. Source: Sequence sequenceDiagram participant Agent participant Docs Agent->>Docs: search_docs Docs-->>Agent: Page IDs Agent->>Docs: get_page Docs-->>Agent: Markdown and citation State Explain a document lifecycle. State — Explain a document lifecycle. Source: State stateDiagram-v2 [*] --> Draft Draft --> Review Review --> Draft : revise Review --> Published : approve Published --> [*] Agentflow Show agent tasks and decisions. Agentflow — Show agent tasks and decisions. Source: Agentflow agentflow-beta TB draft[\"Draft guide\"]@{ shape: task } check[\"Checks pass?\"]@{ shape: decision } publish[\"Publish guide\"]@{ shape: action } draft --> check check -- yes --> publish check -- no --> draft Swimlane Separate work by team. Swimlane — Separate work by team. Source: Swimlane swimlane-beta LR subgraph Authors draft[Draft guide] end subgraph Reviewers review[Review guide] end draft --> review User journey Show the stages and participants in a reader journey. User journey — Show the stages and participants in a reader journey. Source: User journey journey title Find an answer section Discover Search docs: 4: Reader Open guide: 5: Reader section Apply Try example: 4: Reader Check result: 5: Reader Event modeling Trace interface actions and resulting events. Event modeling — Trace interface actions and resulting events. Source: Event modeling eventmodeling tf 01 ui Editor tf 02 cmd PublishPage tf 03 evt PagePublished Use case Connect an actor to a supported action. Use case — Connect an actor to a supported action. Source: Use case usecase-beta actor Reader Browse[Browse documentation] Search[Search documentation] Reader --> Browse Reader --> Search Systems and structures Class Describe types, fields, and relationships. Class — Describe types, fields, and relationships. Source: Class classDiagram class Page { +String title +String slug +render() } class Section { +String heading } Page \"1\" *-- \"many\" Section Entity relationship Show entities and relationship cardinality. Entity relationship — Show entities and relationship cardinality. Source: Entity relationship erDiagram PROJECT ||--o{ PAGE : contains PAGE ||--o{ SECTION : contains PAGE { string id PK string title } SECTION { string heading } Architecture Connect services using built-in symbols. Architecture — Connect services using built-in symbols. Source: Architecture architecture-beta group docs(cloud)[Documentation] service app(server)[Site] in docs service store(database)[Content] in docs app:R -- L:store C4 Describe a system and its users at a high level. C4 — Describe a system and its users at a high level. Source: C4 C4Context title Documentation context Person(reader, \"Reader\", \"Finds instructions\") System(docs, \"Documentation\", \"Published guides\") Rel(reader, docs, \"Reads\") Block Arrange connected blocks in explicit columns. Block — Arrange connected blocks in explicit columns. Source: Block block-beta columns 3 a[\"Author\"] b[\"Build\"] c[\"Publish\"] a --> b b --> c Mindmap Organize related documentation topics. Mindmap — Organize related documentation topics. Source: Mindmap mindmap root((Documentation)) Authoring Pages Components Publishing Builds Hosting Tree view Display a directory hierarchy. Tree view — Display a directory hierarchy. Source: Tree view treeView-beta \"docs\" \"content\" \"start.mdx\" \"configuration.mdx\" \"docs.config.yaml\" Requirement Connect an implementation element to a requirement. Requirement — Connect an implementation element to a requirement. Source: Requirement requirementDiagram requirement readable { id: 1 text: Preserve essential instructions risk: low verifymethod: test } element markdown { type: renderer } markdown - satisfies -> readable Charts and planning Gantt Schedule work against explicit dates. Gantt — Schedule work against explicit dates. Source: Gantt gantt title Documentation release dateFormat YYYY-MM-DD section Preparation Draft guides :a, 2026-10-01, 3d Review guides :b, after a, 2d section Release Publish :after b, 1d Git graph Illustrate branches, commits, and merges. Git graph — Illustrate branches, commits, and merges. Source: Git graph gitGraph commit id: \"Start\" branch guide checkout guide commit id: \"Draft\" check"},{"filters":{"focus":["write"]},"text":"Diagrams — Configure diagram width, styling, and Mermaid compatibility. D2 gallery — Compare D2 examples with Mermaid syntax rendered by Pele."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":27093,"markdownTokens":8216,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"flows-and-behavior","title":"Flows and behavior","markdownUrl":"/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md","markdownBytes":5873,"markdownTokens":1575},{"id":"systems-and-structures","title":"Systems and structures","markdownUrl":"/author/components/diagrams/pele-gallery.sections/systems-and-structures.md","markdownBytes":5761,"markdownTokens":1510},{"id":"charts-and-planning","title":"Charts and planning","markdownUrl":"/author/components/diagrams/pele-gallery.sections/charts-and-planning.md","markdownBytes":6900,"markdownTokens":2034},{"id":"specialized-diagrams","title":"Specialized diagrams","markdownUrl":"/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md","markdownBytes":4851,"markdownTokens":1327},{"id":"flowchart-shapes","title":"Flowchart shapes","markdownUrl":"/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md","markdownBytes":8345,"markdownTokens":3006},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md","markdownBytes":2014,"markdownTokens":474},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/components/diagrams/pele-gallery.sections/related-reading.md","markdownBytes":1733,"markdownTokens":440}]},{"id":"guide.evals","demo":false,"url":"/publish/evals","markdownUrl":"/publish/evals.md","title":"Evaluate agent tasks against your docs","summary":"Define realistic tasks, record reviewed answers from your own agent, and check the results against a documentation build.","type":"how-to","variant":"production|current|en","area":"quality","subarea":"quality-evaluations","headings":[{"id":"define-a-task-file","title":"Define a task file"},{"id":"prepare-a-report-for-the-built-site","title":"Prepare a report for the built site"},{"id":"diagnose-a-different-build","title":"Diagnose a different build"},{"id":"run-and-review-the-tasks","title":"Run and review the tasks"},{"id":"check-the-report","title":"Check the report"},{"id":"add-the-audit-hook","title":"Add the audit hook"},{"id":"shoalrun-s-own-example","title":"Shoalrun's own example"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Use evaluation tasks to check whether an agent can accomplish important work using your documentation. Shoalrun defines task and result formats, prepares report templates, and checks those reports during an audit. You run your own agent and arrange human or external review of its answers. Shoalrun does not launch agents, choose a model, or grade prose. You need a built docs site, a few realistic tasks, and an agent or manual workflow for running them. The ordinary build does not execute evaluations or call a model. Evaluations are opt-in audit checks. Define a task file Save YAML or JSON with schemaVersion: 1 and a nonempty tasks list. Each task needs a unique lowercase ID, a prompt, an allowedTools list, and criteria with unique IDs and descriptions. Tasks are required by default; set required: false for an exploratory task that should not block an audit. evals/tasks.yaml schemaVersion : 1 tasks : - id : reader-views prompt : Explain what reader views hide and whether they protect private content. allowedTools : [ docs.search , docs.read ] criteria : - id : visibility description : Explain visibility versus access control and cite the reader-views page. - id : markdown description : Explain that published Markdown retains reader-marked content. Use the same tool names in your task file and runner report, such as search , fetch , docs.search , or mcp.get_page . Shoalrun validates the recorded runner tools against each executed task's allowed list. It cannot observe or enforce what tools an external agent actually used. Use a shared allowed tool set within a report; prepare separate suites for runs with different tool permissions. Write criteria that an expert can assess. Valid citations and complete report fields are mechanical checks. Whether the answer correctly explains your product remains a review judgment. Prepare a report for the built site shoalrun build docs.config.yaml site-dist shoalrun eval prepare site-dist --tasks evals/tasks.yaml --out evals/results.json Create the evals directory first. Preparation refuses to overwrite an existing report; use a new output filename for another run. The template contains a task-file digest, a documentation-build digest, a per-file buildFiles inventory, a timestamp, empty runner details, and each task marked skipped . It records no passing results and does not run the tasks. A template with skipped required tasks fails the check until you complete the run and review. The task digest uses normalized definitions, so whitespace-only changes do not invalidate a run. Prompt, criteria, tools, or required-status changes do. The build digest covers published output files, including HTML, Markdown, indexes, discovery, and assets. It excludes build-info.json , private ai/ artifacts, and .shoalrun/ state. File touches do not invalidate otherwise identical output; changed published bytes do. Other published metadata, including build IDs embedded in manifests, remains covered even when it reflects deployment provenance. Diagnose a different build Save a file inventory alongside an evaluation build: shoalrun eval snapshot site-dist > evaluated-build.json shoalrun eval snapshot rebuilt-site > current-build.json shoalrun eval compare current-build.json --since evaluated-build.json The comparison lists added, changed, and removed file paths. It exits 0 for identical snapshots and 1 for differences or invalid input. Each inventory binds relative file paths and SHA-256 byte digests to the same build digest used by evaluation reports. It contains no answers or grades. New report templates include this inventory in buildFiles . When a report is stale, eval check includes the file comparison in details.buildChanges . Older reports still receive the exact-build check, but cannot identify which earlier files differ. Editing the stored digest or deleting changed files is not a new evaluation. For local review of a hosted build, download and retain that exact output, task file, and report template. Run the tasks against the downloaded site and check the completed report against it. Rebuilding the source on another operating system can change rendered assets; a report about the downloaded build does not automatically cover that rebuild. Archive the source revision and build inventory with the run. A successful build capture records no evaluation pass. Run and review the tasks Use your own agent with the declared tool access. Record the actual runner name, optional model, available tools, and any limitations in runner . Replace recordedAt with the run's UTC ISO timestamp. For each task, record its status ( pass , fail , or skipped ), answer, citations, and criterion judgments. A passing result needs a nonempty answer, at least one citation, and a passing judgment with a reason for every defined criterion. Identify citations by stable page ID and publication, so editions and languages cannot be confused: { \"taskId\" : \"reader-views\" , \"status\" : \"pass\" , \"answer\" : \"Reader views change visi","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Use evaluation tasks to check whether an agent can accomplish important work using your documentation. Shoalrun defines task and result formats, prepares report templates, and checks those reports during an audit. You run your own agent and arrange human or external review of its answers. Shoalrun does not launch agents, choose a model, or grade prose. You need a built docs site, a few realistic tasks, and an agent or manual workflow for running them. The ordinary build does not execute evaluations or call a model. Evaluations are opt-in audit checks. Define a task file Save YAML or JSON with schemaVersion: 1 and a nonempty tasks list. Each task needs a unique lowercase ID, a prompt, an allowedTools list, and criteria with unique IDs and descriptions. Tasks are required by default; set required: false for an exploratory task that should not block an audit. schemaVersion: 1 tasks: - id: reader-views prompt: Explain what reader views hide and whether they protect private content. allowedTools: [docs.search, docs.read] criteria: - id: visibility description: Explain visibility versus access control and cite the reader-views page. - id: markdown description: Explain that published Markdown retains reader-marked content. Use the same tool names in your task file and runner report, such as search , fetch , docs.search , or mcp.get_page . Shoalrun validates the recorded runner tools against each executed task's allowed list. It cannot observe or enforce what tools an external agent actually used. Use a shared allowed tool set within a report; prepare separate suites for runs with different tool permissions. Write criteria that an expert can assess. Valid citations and complete report fields are mechanical checks. Whether the answer correctly explains your product remains a review judgment. Prepare a report for the built site shoalrun build docs.config.yaml site-dist shoalrun eval prepare site-dist --tasks evals/tasks.yaml --out evals/results.json Create the evals directory first. Preparation refuses to overwrite an existing report; use a new output filename for another run. The template contains a task-file digest, a documentation-build digest, a per-file buildFiles inventory, a timestamp, empty runner details, and each task marked skipped . It records no passing results and does not run the tasks. A template with skipped required tasks fails the check until you complete the run and review. The task digest uses normalized definitions, so whitespace-only changes do not invalidate a run. Prompt, criteria, tools, or required-status changes do. The build digest covers published output files, including HTML, Markdown, indexes, discovery, and assets. It excludes build-info.json , private ai/ artifacts, and .shoalrun/ state. File touches do not invalidate otherwise identical output; changed published bytes do. Other published metadata, including build IDs embedded in manifests, remains covered even when it reflects deployment provenance. Diagnose a different build Save a file inventory alongside an evaluation build: shoalrun eval snapshot site-dist > evaluated-build.json shoalrun eval snapshot rebuilt-site > current-build.json shoalrun eval compare current-build.json --since evaluated-build.json The comparison lists added, changed, and removed file paths. It exits 0 for identical snapshots and 1 for differences or invalid input. Each inventory binds relative file paths and SHA-256 byte digests to the same build digest used by evaluation reports. It contains no answers or grades. New report templates include this inventory in buildFiles . When a report is stale, eval check includes the file comparison in details.buildChanges . Older reports still receive the exact-build check, but cannot identify which earlier files differ. Editing the stored digest or deleting changed files is not a new evaluation. For local review of a hosted build, download and retain that exact output, task file, and report template. Run the tasks against the downloaded site and check the completed report against it. Rebuilding the source on another operating system can change rendered assets; a report about the downloaded build does not automatically cover that rebuild. Archive the source revision and build inventory with the run. A successful build capture records no evaluation pass. Run and review the tasks Use your own agent with the declared tool access. Record the actual runner name, optional model, available tools, and any limitations in runner . Replace recordedAt with the run's UTC ISO timestamp. For each task, record its status ( pass , fail , or skipped ), answer, citations, and criterion judgments. A passing result needs a nonempty answer, at least one citation, and a passing judgment with a reason for every defined criterion. Identify citations by stable page ID and publication, so editions and languages cannot be confused: { \"taskId\": \"reader-views\", \"status\": \"pass\", \"answer\": \"Reader views change visibility. Public Markdown still inclu"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":12345,"markdownTokens":2628,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"define-a-task-file","title":"Define a task file","markdownUrl":"/publish/evals.sections/define-a-task-file.md","markdownBytes":2782,"markdownTokens":629},{"id":"prepare-a-report-for-the-built-site","title":"Prepare a report for the built site","markdownUrl":"/publish/evals.sections/prepare-a-report-for-the-built-site.md","markdownBytes":2619,"markdownTokens":590},{"id":"diagnose-a-different-build","title":"Diagnose a different build","markdownUrl":"/publish/evals.sections/diagnose-a-different-build.md","markdownBytes":2794,"markdownTokens":610},{"id":"run-and-review-the-tasks","title":"Run and review the tasks","markdownUrl":"/publish/evals.sections/run-and-review-the-tasks.md","markdownBytes":3171,"markdownTokens":741},{"id":"check-the-report","title":"Check the report","markdownUrl":"/publish/evals.sections/check-the-report.md","markdownBytes":2295,"markdownTokens":511},{"id":"add-the-audit-hook","title":"Add the audit hook","markdownUrl":"/publish/evals.sections/add-the-audit-hook.md","markdownBytes":3623,"markdownTokens":813},{"id":"shoalrun-s-own-example","title":"Shoalrun's own example","markdownUrl":"/publish/evals.sections/shoalrun-s-own-example.md","markdownBytes":3385,"markdownTokens":745},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/evals.sections/related-reading.md","markdownBytes":1719,"markdownTokens":412}]},{"id":"reference.config-examples","demo":false,"url":"/config/examples","markdownUrl":"/config/examples.md","title":"Example configs","summary":"Complete, working docs.config.yaml files for common kinds of documentation sites.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"feature-showcase","title":"Feature showcase"},{"id":"minimal-site","title":"Minimal site"},{"id":"parcel-api-documentation","title":"Parcel API documentation"},{"id":"multilingual-help-center","title":"Multilingual help center"},{"id":"shared-company-preset","title":"Shared company preset"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Each example below is a complete project in the repository's framework/example-configs/ directory, with pages and any OpenAPI files it needs. The test suite builds every one, and checks that the configs on this page match the files, so they stay correct. Start with the bundled minimal , api-docs , or showcase project, then build it: shoalrun init my-docs --starter minimal cd my-docs shoalrun build docs.config.yaml site-dist shoalrun serve site-dist Use --starter api-docs for the Cedar Parcel API example, or --starter showcase for a complete component handbook built around that fictional service. The other examples remain available to copy from framework/example-configs/ . The notifications project demonstrates an optional cookbook chooser with email, push, and SMS choices. Its YAML maps supported selections to prebuilt recipe pages. It also includes unpublished ingredient and recipe drafts to show the authoring path. Build it from the repository root: node framework/dist/cli.js build framework/example-configs/notifications/docs.config.yaml /tmp/notifications-site node framework/dist/cli.js serve /tmp/notifications-site The configuration reference explains every key. Feature showcase The showcase starter provides 18 connected pages. Its component examples cover callouts, badges, definitions, tables, field lists, steps, timelines, collapsibles, file trees, code tabs, walkthroughs, and snippets. Other pages demonstrate reader controls, themes, diagrams, images, math, a landing page, cookbook choices, and generated API references. Explore the starter , first in the left navigation, maps the examples to their source pages. shoalrun init my-handbook --starter showcase cd my-handbook shoalrun build docs.config.yaml site-dist shoalrun serve site-dist It needs no provider credentials to build. Replace fictional service names, hostnames, and examples before using it for a real product. Hosted chat, remote search, and analytics need your own services; the starter does not connect to a demonstration account. Minimal site One publication, page defaults so each page needs only an id , title , summary , and slug , and a two-level sidebar. example-configs/minimal/docs.config.yaml # The smallest useful site: one publication, two pages, a sidebar. schemaVersion : 1 site : title : Acme handbook publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } # Every page gets these values unless it sets its own. frontmatter : defaults : type : guide channel : production version : current access : { policy : public } navigation : - id : welcome doc : guide.welcome - id : setup label : Setup items : - id : install doc : guide.install Parcel API documentation The fictional Cedar Parcel API demonstrates enrollment shapes, parcel filters, several response formats, binary uploads, deprecation, and a delivery webhook. Its source matches the API reference styling lab. An overview and quickstart introduce the API; enrollment has an authored reference page and the other operations are generated. The complete spec, focused contracts, and API catalog are published. The Markdown twins get a short header, with operation IDs added on reference pages. example-configs/api-docs/docs.config.yaml # Cedar Parcel API: guides, generated references, and agent-friendly contracts. schemaVersion : 1 site : title : Cedar Parcel API origin : https://docs.cedar-parcel.example # Hidden visually until focused; present in HTML for agents and screen readers. agentDiscovery : mode : focus message : Use Markdown for complete examples and the linked focused API contracts. header : links : - { label : Quickstart , href : /quickstart , style : primary } footer : columns : - title : Start building links : - { label : Overview , href : / } - { label : Quickstart , href : /quickstart } - { label : Enrollment reference , href : /reference/create-enrollment } text : Cedar Parcel is a fictional example API. theme : preset : shoal palette : kelp mode : system toggle : true publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current , language : en } frontmatter : defaults : type : guide channel : production version : current language : en access : { policy : public } apis : cedar : source : { kind : file , path : ./apis/cedar-parcel.yaml , publish : true } discovery : { endpoint : https://api.cedar-parcel.example/v1 } publicReview : digest : a7a7e8eb427a7481f1c1f357d03db40319ad2e79bdeea926501da744cbecfd6f mappings : subjectLifecycle : from : x-docs-availability.phase values : limited : beta building : in-development retired : deprecated querySyntax : - parameter : parameters pathPrefixes : [ /Search/ ] style : unwrapped example : declaredValue(gt","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Each example below is a complete project in the repository's framework/example-configs/ directory, with pages and any OpenAPI files it needs. The test suite builds every one, and checks that the configs on this page match the files, so they stay correct. Start with the bundled minimal , api-docs , or showcase project, then build it: shoalrun init my-docs --starter minimal cd my-docs shoalrun build docs.config.yaml site-dist shoalrun serve site-dist Use --starter api-docs for the Cedar Parcel API example, or --starter showcase for a complete component handbook built around that fictional service. The other examples remain available to copy from framework/example-configs/ . The notifications project demonstrates an optional cookbook chooser with email, push, and SMS choices. Its YAML maps supported selections to prebuilt recipe pages. It also includes unpublished ingredient and recipe drafts to show the authoring path. Build it from the repository root: node framework/dist/cli.js build framework/example-configs/notifications/docs.config.yaml /tmp/notifications-site node framework/dist/cli.js serve /tmp/notifications-site The configuration reference explains every key. Feature showcase The showcase starter provides 18 connected pages. Its component examples cover callouts, badges, definitions, tables, field lists, steps, timelines, collapsibles, file trees, code tabs, walkthroughs, and snippets. Other pages demonstrate reader controls, themes, diagrams, images, math, a landing page, cookbook choices, and generated API references. Explore the starter , first in the left navigation, maps the examples to their source pages. shoalrun init my-handbook --starter showcase cd my-handbook shoalrun build docs.config.yaml site-dist shoalrun serve site-dist It needs no provider credentials to build. Replace fictional service names, hostnames, and examples before using it for a real product. Hosted chat, remote search, and analytics need your own services; the starter does not connect to a demonstration account. Minimal site One publication, page defaults so each page needs only an id , title , summary , and slug , and a two-level sidebar. # The smallest useful site: one publication, two pages, a sidebar. schemaVersion: 1 site: title: Acme handbook publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } # Every page gets these values unless it sets its own. frontmatter: defaults: type: guide channel: production version: current access: { policy: public } navigation: - id: welcome doc: guide.welcome - id: setup label: Setup items: - id: install doc: guide.install Parcel API documentation The fictional Cedar Parcel API demonstrates enrollment shapes, parcel filters, several response formats, binary uploads, deprecation, and a delivery webhook. Its source matches the API reference styling lab. An overview and quickstart introduce the API; enrollment has an authored reference page and the other operations are generated. The complete spec, focused contracts, and API catalog are published. The Markdown twins get a short header, with operation IDs added on reference pages. # Cedar Parcel API: guides, generated references, and agent-friendly contracts. schemaVersion: 1 site: title: Cedar Parcel API origin: https://docs.cedar-parcel.example # Hidden visually until focused; present in HTML for agents and screen readers. agentDiscovery: mode: focus message: Use Markdown for complete examples and the linked focused API contracts. header: links: - { label: Quickstart, href: /quickstart, style: primary } footer: columns: - title: Start building links: - { label: Overview, href: / } - { label: Quickstart, href: /quickstart } - { label: Enrollment reference, href: /reference/create-enrollment } text: Cedar Parcel is a fictional example API. theme: preset: shoal palette: kelp mode: system toggle: true publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current, language: en } frontmatter: defaults: type: guide channel: production version: current language: en access: { policy: public } apis: cedar: source: { kind: file, path: ./apis/cedar-parcel.yaml, publish: true } discovery: { endpoint: https://api.cedar-parcel.example/v1 } publicReview: digest: a7a7e8eb427a7481f1c1f357d03db40319ad2e79bdeea926501da744cbecfd6f mappings: subjectLifecycle: from: x-docs-availability.phase values: limited: beta building: in-development retired: deprecated querySyntax: - parameter: parameters pathPrefixes: [/Search/] style: unwrapped example: declaredValue(gt)=100 operations: - id: cedar.createEnrollment sourceOperationId: createEnrollment reference: reference.create-enrollment generateReferences: pathPrefix: /reference navigation: - { id: overview, doc: guid"},{"filters":{"focus":["configure"]},"text":"Configuration reference — The same settings, combined into complete, working files. Organize project configuration — Explore complete projects using composition, versions, and languages."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":11676,"markdownTokens":2781,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"feature-showcase","title":"Feature showcase","markdownUrl":"/config/examples.sections/feature-showcase.md","markdownBytes":2989,"markdownTokens":695},{"id":"minimal-site","title":"Minimal site","markdownUrl":"/config/examples.sections/minimal-site.md","markdownBytes":2982,"markdownTokens":726},{"id":"parcel-api-documentation","title":"Parcel API documentation","markdownUrl":"/config/examples.sections/parcel-api-documentation.md","markdownBytes":5656,"markdownTokens":1340},{"id":"multilingual-help-center","title":"Multilingual help center","markdownUrl":"/config/examples.sections/multilingual-help-center.md","markdownBytes":3946,"markdownTokens":964},{"id":"shared-company-preset","title":"Shared company preset","markdownUrl":"/config/examples.sections/shared-company-preset.md","markdownBytes":4319,"markdownTokens":1035},{"id":"related-reading","title":"Related reading","markdownUrl":"/config/examples.sections/related-reading.md","markdownBytes":2440,"markdownTokens":574}]},{"id":"guide.explore","demo":false,"url":"/explore","markdownUrl":"/explore.md","title":"Explore the docs","summary":"Explore topics and follow connections to find your next page.","type":"overview","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"start-with-a-topic","title":"Start with a topic"}],"text":"Experimental visualization. Layouts, filters, and interactions may change as we improve this explorer. Choose a topic, find a page, and follow the connections. Filter by area, subarea, or page type to narrow your view. Select a page to read its summary and see where it leads. Start with a topic Get started : understand Shoalrun and set up a documentation project. Write documentation : create a page and publish it in navigation. Use components : add examples, diagrams, and other structured content. Publish your site : build and deploy your documentation. Browse recipes : choose a procedure for your task. The map groups pages by their declared area and subarea. These categories describe the subject of each page independently of navigation. Circles show topics within topics. Select a topic circle to zoom into it, then select a page to preview it. Branches start with the main node. Select it to reveal topics, then expand or collapse individual branches to find their pages. Connections show the reading relationships between pages. Matrix places source pages on rows and destination pages on columns. Select a marked cell to inspect its relationships. Filtered matrices open at a readable size. Scroll to move through the matrix, or pinch or hold Ctrl while scrolling to zoom. Readable restores the label size; Fit shows the whole matrix. Symbols identify relationship types without relying on color, and related topics and comparisons appear in both directions. Force arranges pages around those same reading relationships. Circle size reflects the number of pages in a topic. Scroll or pinch to zoom, drag to pan, or use the zoom buttons. Fit brings the whole map into view. When the map is focused, use the arrow keys to pan, + and - to zoom, and 0 to fit. Filter relationships to follow prerequisites, next steps, references, related topics, comparisons, or deeper reading. Edges show their type and point from the source page to its related page. Related topics and comparisons apply in both directions. Focus, Audience, and Reader filters use the site's configured page facets. Pages without a value for a facet remain available to every reader. The sidebar's Why they’re connected explanation is authored text from each relationship's reason field in docs/config/relationships.yaml , published in documents.json at build time. Viewing the graph makes no model calls and generates no new relationships or explanations. To change that text, edit the reason and rebuild. Declare relationships explains the fields and validation. Select a page to preview its summary and follow a connection, or choose Read this page to open it. The matching page list offers the same page selection without using the map. Connections use the site's declared reading relationships; a page can be useful even when it has no declared connections.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Experimental visualization. Layouts, filters, and interactions may change as we improve this explorer. Choose a topic, find a page, and follow the connections. Filter by area, subarea, or page type to narrow your view. Select a page to read its summary and see where it leads. Start with a topic Get started : understand Shoalrun and set up a documentation project. Write documentation : create a page and publish it in navigation. Use components : add examples, diagrams, and other structured content. Publish your site : build and deploy your documentation. Browse recipes : choose a procedure for your task. The map groups pages by their declared area and subarea. These categories describe the subject of each page independently of navigation. Circles show topics within topics. Select a topic circle to zoom into it, then select a page to preview it. Branches start with the main node. Select it to reveal topics, then expand or collapse individual branches to find their pages. Connections show the reading relationships between pages. Matrix places source pages on rows and destination pages on columns. Select a marked cell to inspect its relationships. Filtered matrices open at a readable size. Scroll to move through the matrix, or pinch or hold Ctrl while scrolling to zoom. Readable restores the label size; Fit shows the whole matrix. Symbols identify relationship types without relying on color, and related topics and comparisons appear in both directions. Force arranges pages around those same reading relationships. Circle size reflects the number of pages in a topic. Scroll or pinch to zoom, drag to pan, or use the zoom buttons. Fit brings the whole map into view. When the map is focused, use the arrow keys to pan, + and - to zoom, and 0 to fit. Filter relationships to follow prerequisites, next steps, references, related topics, comparisons, or deeper reading. Edges show their type and point from the source page to its related page. Related topics and comparisons apply in both directions. Focus, Audience, and Reader filters use the site's configured page facets. Pages without a value for a facet remain available to every reader. The sidebar's Why they’re connected explanation is authored text from each relationship's reason field in docs/config/relationships.yaml , published in documents.json at build time. Viewing the graph makes no model calls and generates no new relationships or explanations. To change that text, edit the reason and rebuild. Declare relationships explains the fields and validation. Select a page to preview its summary and follow a connection, or choose Read this page to open it. The matching page list offers the same page selection without using the map. Connections use the site's declared reading relationships; a page can be useful even when it has no declared connections."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4742,"markdownTokens":1038,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.focused-contracts","demo":false,"url":"/api-docs/focused-contracts","markdownUrl":"/api-docs/focused-contracts.md","title":"Focused OpenAPI contracts","summary":"Give tools one operation and its required schemas without the rest of the API source.","type":"reference","variant":"production|current|en","area":"api","subarea":"api-contracts","headings":[{"id":"why-use-one","title":"Why use one"},{"id":"generate-and-inspect-it","title":"Generate and inspect it"},{"id":"what-the-export-keeps-and-drops","title":"What the export keeps and drops"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"A focused contract is a generated OpenAPI JSON file for one operation. It contains that operation's path and method, parameters, request and response definitions, named examples, and the schemas and security schemes those definitions use. The build resolves local references so the file stands on its own. Each API reference page links to its focused contract. Why use one An API reference page is made for reading. A focused contract gives an agent, test tool, or client generator the exact machine-readable shape of the operation. A large OpenAPI source can contain many unrelated operations and schemas; the focused file keeps the context to what this operation needs. It is also useful when the full source should stay internal but a selected operation can be published. Generate and inspect it Set focused: true on a local API source. The source can stay unpublished: config/api.yaml notes : source : kind : file path : ../apis/notes/openapi.yaml focused : true operations : - id : notes.create sourceOperationId : createNote reference : reference.create-note The build writes a JSON file under /api/operations/ and links to it from the API reference page. If publish: true also publishes the source OpenAPI file, the focused contract is generated automatically. Open the Create a note reference , then follow its Download JSON link to inspect the output from this site's fictional API. That site's full OpenAPI source is published too, so you can compare them. Before a normal build publishes the contract, review the local candidate and pin the API's publicReview.digest as described in API references . The review covers the contract's transitive schemas and examples as well as the page that links to it. The focused contract describes the selected operation, not the entire API. Use the full source when a tool needs operations outside that page. What the export keeps and drops It keeps the selected path and method, their parameters, and the schemas, examples, and security schemes they reference. The root servers and security carry over, and tags lists only the operation's tags. It drops every x-* extension key, so vendor extensions and internal notes stored there stay out of the public file. It supports local OpenAPI 3.0.x and 3.1.x files with internal and multi-file references. Referenced files must stay inside the main OpenAPI file's directory, including after resolving symlinks. Absolute local paths are rejected. A Path Item $ref , or a JSON Schema $id , $anchor , $dynamicRef , or $dynamicAnchor , stops the build. The URL pattern is /api/operations/<channel>/<version>/<language>/<name>-<sha256>.json . The suffix is the full SHA-256 of the generated JSON bytes. Changing the contract changes its URL; an unchanged contract keeps the same URL. Earlier prototype filenames hashed the operation ID, which did not provide this property. The generated hosting metadata gives these URLs Cache-Control: public, max-age=31536000, immutable and a strong ETag containing the same digest. The Node server applies these headers, and the Vercel adapter includes them in its routing configuration. A CDN can replace the ETag with its own validator. Use the returned ETag for conditional requests and the manifest's focusedContractDigest to verify downloaded bytes. Mutable Markdown and JSON indexes require revalidation. Other hosts must apply the generated cache policy. Old builds are not archived automatically, so the URL identity does not guarantee permanent availability. To check every contract in a built site, run shoalrun api focused-audit <site-directory> . The CLI reference lists what it checks. Related reading Reference while working CLI reference — Check every focused contract in a built site with api focused-audit. Related topics Agent-friendly documentation — Focused contracts are how agents find exact API details without the full spec.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A focused contract is a generated OpenAPI JSON file for one operation. It contains that operation's path and method, parameters, request and response definitions, named examples, and the schemas and security schemes those definitions use. The build resolves local references so the file stands on its own. Each API reference page links to its focused contract. Why use one An API reference page is made for reading. A focused contract gives an agent, test tool, or client generator the exact machine-readable shape of the operation. A large OpenAPI source can contain many unrelated operations and schemas; the focused file keeps the context to what this operation needs. It is also useful when the full source should stay internal but a selected operation can be published. Generate and inspect it Set focused: true on a local API source. The source can stay unpublished: notes: source: kind: file path: ../apis/notes/openapi.yaml focused: true operations: - id: notes.create sourceOperationId: createNote reference: reference.create-note The build writes a JSON file under /api/operations/ and links to it from the API reference page. If publish: true also publishes the source OpenAPI file, the focused contract is generated automatically. Open the Create a note reference , then follow its Download JSON link to inspect the output from this site's fictional API. That site's full OpenAPI source is published too, so you can compare them. Before a normal build publishes the contract, review the local candidate and pin the API's publicReview.digest as described in API references . The review covers the contract's transitive schemas and examples as well as the page that links to it. The focused contract describes the selected operation, not the entire API. Use the full source when a tool needs operations outside that page. What the export keeps and drops It keeps the selected path and method, their parameters, and the schemas, examples, and security schemes they reference. The root servers and security carry over, and tags lists only the operation's tags. It drops every x-* extension key, so vendor extensions and internal notes stored there stay out of the public file. It supports local OpenAPI 3.0.x and 3.1.x files with internal and multi-file references. Referenced files must stay inside the main OpenAPI file's directory, including after resolving symlinks. Absolute local paths are rejected. A Path Item $ref , or a JSON Schema $id , $anchor , $dynamicRef , or $dynamicAnchor , stops the build. The URL pattern is /api/operations/<channel>/<version>/<language>/<name>-<sha256>.json . The suffix is the full SHA-256 of the generated JSON bytes. Changing the contract changes its URL; an unchanged contract keeps the same URL. Earlier prototype filenames hashed the operation ID, which did not provide this property. The generated hosting metadata gives these URLs Cache-Control: public, max-age=31536000, immutable and a strong ETag containing the same digest. The Node server applies these headers, and the Vercel adapter includes them in its routing configuration. A CDN can replace the ETag with its own validator. Use the returned ETag for conditional requests and the manifest's focusedContractDigest to verify downloaded bytes. Mutable Markdown and JSON indexes require revalidation. Other hosts must apply the generated cache policy. Old builds are not archived automatically, so the URL identity does not guarantee permanent availability. To check every contract in a built site, run shoalrun api focused-audit <site-directory> . The CLI reference lists what it checks. Related reading Reference while working CLI reference — Check every focused contract in a built site with api focused-audit. Related topics"},{"filters":{"focus":["configure"]},"text":"Agent-friendly documentation — Focused contracts are how agents find exact API details without the full spec."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5073,"markdownTokens":1141,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.footer","demo":false,"url":"/styling/footer","markdownUrl":"/styling/footer.md","title":"Site footer","summary":"Add link columns, a bottom row of links, and a short text line below every page.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-navigation","headings":[{"id":"footer-settings","title":"Footer settings"},{"id":"layout-and-themes","title":"Layout and themes"},{"id":"related-reading","title":"Related reading"}],"text":"The footer sits below every page, after the navigation and article. Configure it under site.footer . Without that setting, the site has no footer. docs.config.yaml site : title : Example documentation footer : columns : - title : Guides links : - { label : Get started , href : /start } - { label : Authentication , href : /guides/auth } - title : Company links : - { label : Status , href : \"https://status.example.com\" } - { label : Contact support , href : \"mailto:support@example.com\" } links : - { label : Privacy , href : /legal/privacy } - { label : Terms , href : /legal/terms } text : © 2026 Example, Inc. Columns appear first, side by side on wide screens and stacked on phones. Below them, a bottom row shows text on the left and links on the right. Every part is optional, but the footer needs at least one of them. Footer settings These settings configure the footer text and its links. Setting Required Value columns No A list of link groups. Each has a title and a links list with at least one link. links No Links for the bottom row, such as legal pages. text No One line of plain text, such as a copyright notice. The build escapes it, so HTML and Markdown show as typed. Each link takes a label and an href . An href is a site-root path such as /start , an http or https URL, or a mailto: link. External http and https links get rel=\"noopener\" . The build rejects any other URL scheme, including javascript: . Footer links don't take a style . Use header links for buttons and calls to action. Layout and themes The footer uses the page's theme tokens, so each theme preset and palette restyles it. On landing and splash layouts , it matches the narrower landing width. The CSS and theme reference lists its classes. The footer is part of the HTML page only. Markdown twins, search results, and /llms.txt do not include it. Related reading No matching documents.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"The footer sits below every page, after the navigation and article. Configure it under site.footer . Without that setting, the site has no footer. site: title: Example documentation footer: columns: - title: Guides links: - { label: Get started, href: /start } - { label: Authentication, href: /guides/auth } - title: Company links: - { label: Status, href: \"https://status.example.com\" } - { label: Contact support, href: \"mailto:support@example.com\" } links: - { label: Privacy, href: /legal/privacy } - { label: Terms, href: /legal/terms } text: © 2026 Example, Inc. Columns appear first, side by side on wide screens and stacked on phones. Below them, a bottom row shows text on the left and links on the right. Every part is optional, but the footer needs at least one of them. Footer settings These settings configure the footer text and its links. Setting Required Value columns No A list of link groups. Each has a title and a links list with at least one link. links No Links for the bottom row, such as legal pages. text No One line of plain text, such as a copyright notice. The build escapes it, so HTML and Markdown show as typed. Each link takes a label and an href . An href is a site-root path such as /start , an http or https URL, or a mailto: link. External http and https links get rel=\"noopener\" . The build rejects any other URL scheme, including javascript: . Footer links don't take a style . Use header links for buttons and calls to action. Layout and themes The footer uses the page's theme tokens, so each theme preset and palette restyles it. On landing and splash layouts , it matches the narrower landing width. The CSS and theme reference lists its classes. The footer is part of the HTML page only. Markdown twins, search results, and /llms.txt do not include it. Related reading No matching documents."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3301,"markdownTokens":785,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.frontmatter-reference","demo":false,"url":"/author/frontmatter-reference","markdownUrl":"/author/frontmatter-reference.md","title":"Frontmatter field reference","summary":"Browse the built-in and project-defined page fields this site supports.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-metadata","headings":[{"id":"identify-and-route-a-page","title":"Identify and route a page"},{"id":"choose-a-publication-and-visibility","title":"Choose a publication and visibility"},{"id":"categorize-connect-and-present-the-page","title":"Categorize, connect, and present the page"},{"id":"control-output-details","title":"Control output details"},{"id":"project-defined-fields","title":"Project-defined fields"},{"id":"global-defaults-and-enforced-values","title":"Global defaults and enforced values"},{"id":"use-the-local-files-while-authoring","title":"Use the local files while authoring"},{"id":"when-the-files-update","title":"When the files update"},{"id":"point-agents-to-it","title":"Point agents to it"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"This is the field inventory for this documentation site. The tables below are built from Shoalrun's native field definitions and this site's frontmatter.fields declarations on each build. They describe source page headers, not the shorter YAML header selected for a published Markdown page. agent.intent in the project-defined table is an optional string. This site's authors use it to describe the task a page helps an agent complete. It is not a required Shoalrun field or an instruction to an agent. editorial.reviewNote is another site-specific field for internal review notes. A different project can declare different fields. To publish an equivalent inventory on your site, place <FrontmatterReference /> on a page. It takes no attributes or child content and renders the current project's native and declared fields in HTML and Markdown. Identify and route a page Use the page ID for links and cards that should survive a URL change. The slug supplies the page part of the URL; publication prefixes may be added around it. Summary is short preview text; description is a separate, optional fuller account. Project output rules choose which field supplies each surface. Field Type Needed What it changes id string On each page Stable page identity used by document links and cards; keep it when the file or URL changes. title string After inheritance Page heading and default browser title. summary string After inheritance Short page preview, used by cards and other configured text surfaces. description string Optional Fuller description of what the page covers; kept distinct from the short summary. type string After inheritance Document kind, such as guide or api-reference; can select a Markdown metadata profile. slug string On each page Page URL path before channel, version, and language prefixes. Choose a publication and visibility The project enables specific channel/version/language combinations. A page is built only for combinations matching its resolved values. audiences and readerFilters select reader views when the site config enables them; access.policy determines whether the page enters this public build. A draft page is excluded. Field Type Needed What it changes channel string Public page Publication environment, such as sandbox or production; selects an enabled publication and API source. version string Public page API or documentation edition, such as v1; selects an enabled publication and API source. language string Optional Content language; uses frontmatter defaults/enforced values, then publications.defaults.language, then en. locale string Optional Formatting conventions used in the content; can inherit a project locale for the page language and can be overridden per page. access object Public page Controls whether the page enters a public build; this object is not exported to Markdown metadata. access.policy string With access Use public to publish this page; draft pages are excluded from the built site. audiences array Optional Readers this page is intended for; does not control who can access it. readerFilters object Optional Configured reader filter choices for this page. Missing facets are shared. Language is the content language and selects a publication. Locale describes formatting conventions in the content and does not select a publication. frontmatter.locales can set a project locale for each language; pages may override it. Categorize, connect, and present the page By default, product , area , and subarea are optional, nonempty string categories. They can come from project defaults and appear in the document manifest and search index. A matching configured reader facet makes each category a page filter; without that facet it remains taxonomy only. operations links a guide or reference to stable API operation IDs. On a guide or how-to page, relatedApiReferences names API reference page IDs to add cross links in both directions within the same publication. Tags help document collections find the page. Card settings change its preview when another page links to it; they do not change the destination. subjectLifecycle displays the status of the documented API or feature; lifecycle is available for the document's editorial state. tocDepth limits the HTML page table of contents; use 0 to hide it. layout picks the HTML page layout: docs , wide , landing , or splash . showNavigationTabs overrides the navigation tab bar for this page; landing and splash pages hide it by default. image replaces the generated link-preview image. date and releaseVersion can identify a changelog entry under the project's frontmatter.changelogIdentifier rule. Field Type Needed What it changes product string Optional Optional product category. Also selects the product reader facet when that facet is configured. area string or array On each page Optional area category. Also selects the area reader facet when that facet is configured. subarea string or array On each page Optional finer category. Also selects the subarea ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"This is the field inventory for this documentation site. The tables below are built from Shoalrun's native field definitions and this site's frontmatter.fields declarations on each build. They describe source page headers, not the shorter YAML header selected for a published Markdown page. agent.intent in the project-defined table is an optional string. This site's authors use it to describe the task a page helps an agent complete. It is not a required Shoalrun field or an instruction to an agent. editorial.reviewNote is another site-specific field for internal review notes. A different project can declare different fields. To publish an equivalent inventory on your site, place <FrontmatterReference /> on a page. It takes no attributes or child content and renders the current project's native and declared fields in HTML and Markdown. Identify and route a page Use the page ID for links and cards that should survive a URL change. The slug supplies the page part of the URL; publication prefixes may be added around it. Summary is short preview text; description is a separate, optional fuller account. Project output rules choose which field supplies each surface. Field Type Needed What it changes id string On each page Stable page identity used by document links and cards; keep it when the file or URL changes. title string After inheritance Page heading and default browser title. summary string After inheritance Short page preview, used by cards and other configured text surfaces. description string Optional Fuller description of what the page covers; kept distinct from the short summary. type string After inheritance Document kind, such as guide or api-reference; can select a Markdown metadata profile. slug string On each page Page URL path before channel, version, and language prefixes. Choose a publication and visibility The project enables specific channel/version/language combinations. A page is built only for combinations matching its resolved values. audiences and readerFilters select reader views when the site config enables them; access.policy determines whether the page enters this public build. A draft page is excluded. Field Type Needed What it changes channel string Public page Publication environment, such as sandbox or production; selects an enabled publication and API source. version string Public page API or documentation edition, such as v1; selects an enabled publication and API source. language string Optional Content language; uses frontmatter defaults/enforced values, then publications.defaults.language, then en. locale string Optional Formatting conventions used in the content; can inherit a project locale for the page language and can be overridden per page. access object Public page Controls whether the page enters a public build; this object is not exported to Markdown metadata. access.policy string With access Use public to publish this page; draft pages are excluded from the built site. audiences array Optional Readers this page is intended for; does not control who can access it. readerFilters object Optional Configured reader filter choices for this page. Missing facets are shared. Language is the content language and selects a publication. Locale describes formatting conventions in the content and does not select a publication. frontmatter.locales can set a project locale for each language; pages may override it. Categorize, connect, and present the page By default, product , area , and subarea are optional, nonempty string categories. They can come from project defaults and appear in the document manifest and search index. A matching configured reader facet makes each category a page filter; without that facet it remains taxonomy only. operations links a guide or reference to stable API operation IDs. On a guide or how-to page, relatedApiReferences names API reference page IDs to add cross links in both directions within the same publication. Tags help document collections find the page. Card settings change its preview when another page links to it; they do not change the destination. subjectLifecycle displays the status of the documented API or feature; lifecycle is available for the document's editorial state. tocDepth limits the HTML page table of contents; use 0 to hide it. layout picks the HTML page layout: docs , wide , landing , or splash . showNavigationTabs overrides the navigation tab bar for this page; landing and splash pages hide it by default. image replaces the generated link-preview image. date and releaseVersion can identify a changelog entry under the project's frontmatter.changelogIdentifier rule. Field Type Needed What it changes product string Optional Optional product category. Also selects the product reader facet when that facet is configured. area string or array On each page Optional area category. Also selects the area reader facet when that facet is configured. subarea string or array On each page Optional finer category. Also selects the subarea reade"},{"filters":{"focus":["write"]},"text":"Use the bundled agent skills — Point agents at the local inventory of page fields this project accepts."},{"filters":{"focus":["write"],"audience":["authors","maintainers"]},"text":"Page metadata — The local inventory lists every field this project accepts, including custom ones."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":19952,"markdownTokens":3346,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"identify-and-route-a-page","title":"Identify and route a page","markdownUrl":"/author/frontmatter-reference.sections/identify-and-route-a-page.md","markdownBytes":3171,"markdownTokens":643},{"id":"choose-a-publication-and-visibility","title":"Choose a publication and visibility","markdownUrl":"/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md","markdownBytes":4019,"markdownTokens":771},{"id":"control-output-details","title":"Control output details","markdownUrl":"/author/frontmatter-reference.sections/control-output-details.md","markdownBytes":3485,"markdownTokens":688},{"id":"project-defined-fields","title":"Project-defined fields","markdownUrl":"/author/frontmatter-reference.sections/project-defined-fields.md","markdownBytes":3552,"markdownTokens":721},{"id":"global-defaults-and-enforced-values","title":"Global defaults and enforced values","markdownUrl":"/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md","markdownBytes":2181,"markdownTokens":480},{"id":"use-the-local-files-while-authoring","title":"Use the local files while authoring","markdownUrl":"/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md","markdownBytes":2353,"markdownTokens":529},{"id":"when-the-files-update","title":"When the files update","markdownUrl":"/author/frontmatter-reference.sections/when-the-files-update.md","markdownBytes":2019,"markdownTokens":466},{"id":"point-agents-to-it","title":"Point agents to it","markdownUrl":"/author/frontmatter-reference.sections/point-agents-to-it.md","markdownBytes":2207,"markdownTokens":508},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/frontmatter-reference.sections/related-reading.md","markdownBytes":2056,"markdownTokens":469}]},{"id":"guide.frontmatter","demo":false,"url":"/author/frontmatter","markdownUrl":"/author/frontmatter.md","title":"Page metadata","summary":"Learn how page metadata, project defaults, and publication choices shape the site and its Markdown output.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-metadata","headings":[{"id":"required-after-inheritance","title":"Required after inheritance"},{"id":"publication-fields","title":"Publication fields"},{"id":"publishing-policy","title":"Publishing policy"},{"id":"global-defaults-and-enforced-values","title":"Global defaults and enforced values"},{"id":"validation-rules","title":"Validation rules"},{"id":"optional-native-fields","title":"Optional native fields"},{"id":"give-deprecation-guidance","title":"Give deprecation guidance"},{"id":"audience-badges","title":"Audience badges"},{"id":"seo-fields","title":"SEO fields"},{"id":"related-metadata-tasks","title":"Related metadata tasks"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"next-steps","title":"Next steps"},{"id":"go-deeper","title":"Go deeper"},{"id":"related-topics","title":"Related topics"}],"text":"Frontmatter is the YAML header between the first two --- lines of a .md or .mdx page. It gives a page its identity, URL, and publication settings. Start with this complete header, then write the page body below it: --- id : guide.first-page title : Your first page summary : Create and publish a page in your documentation site. type : guide slug : /first-page channel : production version : current language : en access : { policy : public } --- Keep id stable when you rename a file or change its URL. Use it in navigation and links such as [Your first page](doc:guide.first-page) . To try the full workflow, add a page . See the generated frontmatter reference under Write documentation for native and project-defined fields. Each build also writes .shoalrun/frontmatter-reference.md and .shoalrun/frontmatter.schema.json beside docs.config.yaml for local authoring. Required after inheritance These fields identify a page and give it a route. id is the durable target for links and cards; slug is the URL path and may change without breaking those references. summary is short preview text. The optional description can explain the page more fully. A project chooses which field supplies each output surface. The five fields in this table must exist after the compiler combines the page header with project-wide values. Only id and slug must always be written in the page itself. For instance, the project can set a default type: guide while each page keeps its own identity and URL. Field Type Purpose id string Stable identity; keep it when the filename, title, or URL changes. title string Page heading and default HTML title. summary string Short preview for cards and other configured surfaces. type string Document kind, such as guide or api-reference . slug string Explicit URL path before publication prefixes. These related fields are optional: Field Type Purpose description string Fuller account of what the page covers. updated string Last meaningful revision date; an opt-in digest history can derive it from content changes. verified string Author-set YYYY-MM-DD date when the technical claims were checked; independent of Updated. date string Publication date in YYYY-MM-DD form; can identify a changelog entry. releaseVersion string Product release label; can identify a changelog entry. Separate from version . Publication fields Publication fields identify the channel, version, language, and access policy for a page. Field Type Purpose channel string Publication channel, such as sandbox or production . version string API or documentation version. publications list of { channel, version } Publish one source page in several channel/version combinations. Use instead of page-level channel and version . language string Optional content language; resolved from globals, publication defaults, then en . locale string Optional conventions used for dates, numbers, and currency in the content; does not select a publication. access.policy string Set to public for a public page. Channel identifies an environment such as sandbox or production; version identifies an API or documentation edition; language identifies the content language. The resolved combination must be enabled in project config. channel , version , and access can come from global frontmatter. A language on the page overrides the default unless the project enforces one. For an unchanged page that belongs in v1 and v2, replace its page-level channel and version with: publications : - { channel : production , version : v1 } - { channel : production , version : v2 } Each entry must name a declared channel and version, and the pairs must be unique. Only enabled combinations publish. One source file uses one language; write a translated file for another language. To vary just part of a shared page, use <ForPublication version=\"v2\"> as shown in share pages across versions . Publishing policy access.policy controls whether a page is included in the generated site. Write it in the page's YAML header as access: { policy: public } when the page is ready to publish. New pages created by shoalrun scaffold start with access: { policy: draft } so you can finish them before publishing. Policy Build result public Published if the page also matches an enabled channel, version, and language. draft Checked for valid frontmatter, but omitted from the site. Only public publishes a page; other policy strings are treated like drafts. This setting controls build output, not reader sign-in or permissions. A site's global frontmatter.defaults.access can supply a policy for pages that omit it. Global defaults and enforced values Set shared values under frontmatter.defaults in docs.config.yaml . Page values override defaults; frontmatter.enforced overrides page values. Objects merge recursively and arrays replace. Keep id and slug on each page. docs.config.yaml frontmatter : defaults : type : guide channel : production version : current access : { policy : draft } An explicit page policy of public p","readerFilters":{"focus":["write"],"audience":["authors","maintainers"]},"readerSegments":[{"filters":{},"text":"Frontmatter is the YAML header between the first two --- lines of a .md or .mdx page. It gives a page its identity, URL, and publication settings. Start with this complete header, then write the page body below it: --- id: guide.first-page title: Your first page summary: Create and publish a page in your documentation site. type: guide slug: /first-page channel: production version: current language: en access: { policy: public } --- Keep id stable when you rename a file or change its URL. Use it in navigation and links such as [Your first page](doc:guide.first-page) . To try the full workflow, add a page . See the generated frontmatter reference under Write documentation for native and project-defined fields. Each build also writes .shoalrun/frontmatter-reference.md and .shoalrun/frontmatter.schema.json beside docs.config.yaml for local authoring. Required after inheritance These fields identify a page and give it a route. id is the durable target for links and cards; slug is the URL path and may change without breaking those references. summary is short preview text. The optional description can explain the page more fully. A project chooses which field supplies each output surface. The five fields in this table must exist after the compiler combines the page header with project-wide values. Only id and slug must always be written in the page itself. For instance, the project can set a default type: guide while each page keeps its own identity and URL. Field Type Purpose id string Stable identity; keep it when the filename, title, or URL changes. title string Page heading and default HTML title. summary string Short preview for cards and other configured surfaces. type string Document kind, such as guide or api-reference . slug string Explicit URL path before publication prefixes. These related fields are optional: Field Type Purpose description string Fuller account of what the page covers. updated string Last meaningful revision date; an opt-in digest history can derive it from content changes. verified string Author-set YYYY-MM-DD date when the technical claims were checked; independent of Updated. date string Publication date in YYYY-MM-DD form; can identify a changelog entry. releaseVersion string Product release label; can identify a changelog entry. Separate from version . Publication fields Publication fields identify the channel, version, language, and access policy for a page. Field Type Purpose channel string Publication channel, such as sandbox or production . version string API or documentation version. publications list of { channel, version } Publish one source page in several channel/version combinations. Use instead of page-level channel and version . language string Optional content language; resolved from globals, publication defaults, then en . locale string Optional conventions used for dates, numbers, and currency in the content; does not select a publication. access.policy string Set to public for a public page. Channel identifies an environment such as sandbox or production; version identifies an API or documentation edition; language identifies the content language. The resolved combination must be enabled in project config. channel , version , and access can come from global frontmatter. A language on the page overrides the default unless the project enforces one. For an unchanged page that belongs in v1 and v2, replace its page-level channel and version with: publications: - { channel: production, version: v1 } - { channel: production, version: v2 } Each entry must name a declared channel and version, and the pairs must be unique. Only enabled combinations publish. One source file uses one language; write a translated file for another language. To vary just part of a shared page, use <ForPublication version=\"v2\"> as shown in share pages across versions . Publishing policy access.policy controls whether a page is included in the generated site. Write it in the page's YAML header as access: { policy: public } when the page is ready to publish. New pages created by shoalrun scaffold start with access: { policy: draft } so you can finish them before publishing. Policy Build result public Published if the page also matches an enabled channel, version, and language. draft Checked for valid frontmatter, but omitted from the site. Only public publishes a page; other policy strings are treated like drafts. This setting controls build output, not reader sign-in or permissions. A site's global frontmatter.defaults.access can supply a policy for pages that omit it. Global defaults and enforced values Set shared values under frontmatter.defaults in docs.config.yaml . Page values override defaults; frontmatter.enforced overrides page values. Objects merge recursively and arrays replace. Keep id and slug on each page. frontmatter: defaults: type: guide channel: production version: current access: { policy: draft } An explicit page policy of public publishes a finished page with these defaults. "},{"filters":{"focus":["write"]},"text":"Content and stable IDs — Understand stable IDs and publication variants first. Metadata customization — Declare project fields and read metadata from a local provider. Markdown metadata — Select the fields published in Markdown headers. Cards and collections — Configure shared metadata and optional card text overrides. Frontmatter field reference — The local inventory lists every field this project accepts, including custom ones."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates — Pre-fill these fields in the starting points for new pages."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":23970,"markdownTokens":4400,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"required-after-inheritance","title":"Required after inheritance","markdownUrl":"/author/frontmatter.sections/required-after-inheritance.md","markdownBytes":5041,"markdownTokens":1051},{"id":"publication-fields","title":"Publication fields","markdownUrl":"/author/frontmatter.sections/publication-fields.md","markdownBytes":4979,"markdownTokens":1035},{"id":"publishing-policy","title":"Publishing policy","markdownUrl":"/author/frontmatter.sections/publishing-policy.md","markdownBytes":3487,"markdownTokens":812},{"id":"global-defaults-and-enforced-values","title":"Global defaults and enforced values","markdownUrl":"/author/frontmatter.sections/global-defaults-and-enforced-values.md","markdownBytes":3335,"markdownTokens":799},{"id":"validation-rules","title":"Validation rules","markdownUrl":"/author/frontmatter.sections/validation-rules.md","markdownBytes":4259,"markdownTokens":1027},{"id":"optional-native-fields","title":"Optional native fields","markdownUrl":"/author/frontmatter.sections/optional-native-fields.md","markdownBytes":9637,"markdownTokens":1661},{"id":"give-deprecation-guidance","title":"Give deprecation guidance","markdownUrl":"/author/frontmatter.sections/give-deprecation-guidance.md","markdownBytes":5078,"markdownTokens":1122},{"id":"audience-badges","title":"Audience badges","markdownUrl":"/author/frontmatter.sections/audience-badges.md","markdownBytes":3387,"markdownTokens":820},{"id":"seo-fields","title":"SEO fields","markdownUrl":"/author/frontmatter.sections/seo-fields.md","markdownBytes":3493,"markdownTokens":833},{"id":"related-metadata-tasks","title":"Related metadata tasks","markdownUrl":"/author/frontmatter.sections/related-metadata-tasks.md","markdownBytes":3709,"markdownTokens":826},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/frontmatter.sections/related-reading.md","markdownBytes":3144,"markdownTokens":758}]},{"id":"reference.glossary","demo":false,"url":"/glossary","markdownUrl":"/glossary.md","title":"Glossary","summary":"Documentation terms, definitions, and related guides.","type":"reference","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"This page defines the terms used across Shoalrun's documentation. Look a term up when a guide uses a word you don't know. Terms are sorted A to Z, and each definition links to the full guide. Filter the list by a term or a word in its definition, for example publication or agent . In the Markdown version, use your reader's Find command. To see how the main terms fit together, read How Shoalrun works . Filter terms and definitions $concat A directive that adds items to a list inherited through extends . See Configuration reference . $include A directive that replaces a value with the contents of another YAML file. Paths are relative to the file that uses it. See Configuration reference . $remove A directive that drops inherited mapping keys, or list items by id . It fails when nothing is inherited. See Configuration reference . Access policy The access.policy field. public puts a page in the build. Any other value, such as draft , keeps it out. It does not control who can read a published page. See Page metadata . AFDocs An external scorecard for agent-friendly documentation used in development checks. See Agent-friendly documentation . Agent intent A self-reported category describing why an agent called an MCP tool. Optional analytics can record allowed categories; it does not reveal private model reasoning. See MCP analytics . Agent skill Packaged instructions that help an existing agent set up or maintain a Shoalrun project. A skill guides the workflow; documentation tools provide reference lookups. See Bundled agent skills . Alt text Text describing an image for readers who cannot see it. <Image> requires alt ; alt=\"\" marks a decorative image for screen readers to skip. See Images . Analytics adapter A project module that sends supported browser or MCP events to your chosen service. Each integration is optional and off by default. See browser analytics and MCP analytics . Answer cache Temporary storage for checked answers in a running chat server. Matching repeated questions can reuse them while their source passages remain current. It is separate from prepared answer cards. See Answer checks and reuse . Answer card A reviewed answer to a common question, generated ahead of time with shoalrun answers using a chat model. A confirmed match serves it without a new chat-model answer, though matching uses an embedding provider and scorer. It is not a page-preview card. See Prepared answers . API catalog The /.well-known/api-catalog file, a linkset that points an API endpoint to its OpenAPI description. It needs a discovery endpoint and the site origin. See Agent-friendly documentation . ApiExample A component that copies a named example from an OpenAPI source into a guide. See ApiExample and ApiSchema . ApiSchema A component that includes a request body, response body, object, or single field from an OpenAPI source. See ApiExample and ApiSchema . API source An entry in apis that points to a local OpenAPI file. kind: file is the only supported kind. See Add an OpenAPI API . Audit The shoalrun audit command. It runs configured tests, audits OpenAPI sources, builds the site, and checks focused contracts. See Audit a docs project . Authored reference An API reference page you write in MDX. The build adds the operation details below your text. See Add an OpenAPI API . Authoring guidance Project editorial instructions, writing-guide paths, and reviewed examples that help an agent follow team conventions. See writing guides . Automatic footer A list that the build adds to the end of a page without a relationship. Examples are Related documentation and Related API references. See Related reading . Base path The site.basePath setting. It prefixes public page and resource URLs, including assets, search, API downloads, and discovery files. See Configuration reference . Build The shoalrun build command. It compiles a site into an output directory and replaces that directory. See CLI reference . Build provenance The /build-info.json file. It records the config digest and, when you pass them, a source commit and release label. See Publishing and agent representations . Bundled docs The documentation snapshot shipped with an installed Shoalrun package. Local CLI reads and the local documentation MCP server use it without fetching the live site. See CLI reference . Callout A component that highlights a short message. It has a type and an optional label. See Callouts . Callout tone The line, background, and text colors of a callout type. Five tones are built in, and you can register more. See Callouts . Callout type The purpose of a callout: note , tip , important , warning , caution , or a type you register. See Callouts . Card A linked preview of another page. It shows the target's title and summary and follows the target's current URL. It is not an answer card . See Cards and collections . Changelog identifier The frontmatter.changelogIdentifier rule. It decides whether a changelog entry is identified by date, release","readerFilters":{},"readerSegments":[{"filters":{},"text":"This page defines the terms used across Shoalrun's documentation. Look a term up when a guide uses a word you don't know. Terms are sorted A to Z, and each definition links to the full guide. Filter the list by a term or a word in its definition, for example publication or agent . In the Markdown version, use your reader's Find command. To see how the main terms fit together, read How Shoalrun works . Filter terms and definitions $concat A directive that adds items to a list inherited through extends . See Configuration reference . $include A directive that replaces a value with the contents of another YAML file. Paths are relative to the file that uses it. See Configuration reference . $remove A directive that drops inherited mapping keys, or list items by id . It fails when nothing is inherited. See Configuration reference . Access policy The access.policy field. public puts a page in the build. Any other value, such as draft , keeps it out. It does not control who can read a published page. See Page metadata . AFDocs An external scorecard for agent-friendly documentation used in development checks. See Agent-friendly documentation . Agent intent A self-reported category describing why an agent called an MCP tool. Optional analytics can record allowed categories; it does not reveal private model reasoning. See MCP analytics . Agent skill Packaged instructions that help an existing agent set up or maintain a Shoalrun project. A skill guides the workflow; documentation tools provide reference lookups. See Bundled agent skills . Alt text Text describing an image for readers who cannot see it. <Image> requires alt ; alt=\"\" marks a decorative image for screen readers to skip. See Images . Analytics adapter A project module that sends supported browser or MCP events to your chosen service. Each integration is optional and off by default. See browser analytics and MCP analytics . Answer cache Temporary storage for checked answers in a running chat server. Matching repeated questions can reuse them while their source passages remain current. It is separate from prepared answer cards. See Answer checks and reuse . Answer card A reviewed answer to a common question, generated ahead of time with shoalrun answers using a chat model. A confirmed match serves it without a new chat-model answer, though matching uses an embedding provider and scorer. It is not a page-preview card. See Prepared answers . API catalog The /.well-known/api-catalog file, a linkset that points an API endpoint to its OpenAPI description. It needs a discovery endpoint and the site origin. See Agent-friendly documentation . ApiExample A component that copies a named example from an OpenAPI source into a guide. See ApiExample and ApiSchema . ApiSchema A component that includes a request body, response body, object, or single field from an OpenAPI source. See ApiExample and ApiSchema . API source An entry in apis that points to a local OpenAPI file. kind: file is the only supported kind. See Add an OpenAPI API . Audit The shoalrun audit command. It runs configured tests, audits OpenAPI sources, builds the site, and checks focused contracts. See Audit a docs project . Authored reference An API reference page you write in MDX. The build adds the operation details below your text. See Add an OpenAPI API . Authoring guidance Project editorial instructions, writing-guide paths, and reviewed examples that help an agent follow team conventions. See writing guides . Automatic footer A list that the build adds to the end of a page without a relationship. Examples are Related documentation and Related API references. See Related reading . Base path The site.basePath setting. It prefixes public page and resource URLs, including assets, search, API downloads, and discovery files. See Configuration reference . Build The shoalrun build command. It compiles a site into an output directory and replaces that directory. See CLI reference . Build provenance The /build-info.json file. It records the config digest and, when you pass them, a source commit and release label. See Publishing and agent representations . Bundled docs The documentation snapshot shipped with an installed Shoalrun package. Local CLI reads and the local documentation MCP server use it without fetching the live site. See CLI reference . Callout A component that highlights a short message. It has a type and an optional label. See Callouts . Callout tone The line, background, and text colors of a callout type. Five tones are built in, and you can register more. See Callouts . Callout type The purpose of a callout: note , tip , important , warning , caution , or a type you register. See Callouts . Card A linked preview of another page. It shows the target's title and summary and follows the target's current URL. It is not an answer card . See Cards and collections . Changelog identifier The frontmatter.changelogIdentifier rule. It decides whether a changelog entry is identified by date, release vers"},{"filters":{"focus":["write"]},"text":"Definition lists — See a long, filterable definition list in use."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":43871,"markdownTokens":10635,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.header","demo":false,"url":"/styling/header","markdownUrl":"/styling/header.md","title":"Header links","summary":"Add links and buttons to the site masthead.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-navigation","headings":[{"id":"link-settings","title":"Link settings"},{"id":"layout-and-themes","title":"Layout and themes"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"The masthead shows the site title, the publication label, the search box , the dark mode toggle when it's on, and any links you configure. Add links under site.header.links : docs.config.yaml site : title : Example documentation header : links : - { label : Guides , href : /start } - { label : GitHub , href : \"https://github.com/example/project\" , style : button } - { label : Get started , href : /start , style : primary } Links appear in list order, after the search box and toggle. Link settings Use these settings to configure each link shown in the header. Setting Required Value label Yes Visible link text. href Yes A site-root path such as /start , an http or https URL, or a mailto: link. style No link (default), button , or primary . link renders as plain text. button has an outline. primary fills with --color-accent and uses --color-accent-contrast for its text. Use one primary link at most, for the action you most want readers to take. External http and https links get rel=\"noopener\" . The build rejects any other URL scheme, including javascript: . Layout and themes On narrow screens, the search box and links wrap onto their own row below the site title. Each theme preset restyles them to match its shape. The CSS and theme reference lists their classes. Header links are part of the HTML page only. Markdown twins and /llms.txt do not include them. Related reading Reference while working CSS and theme reference — Look up the header classes each preset styles. Related topics Light and dark mode — The dark mode toggle appears in the header beside your links. Site search — The search box sits in the site header, before your header links.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"The masthead shows the site title, the publication label, the search box , the dark mode toggle when it's on, and any links you configure. Add links under site.header.links : site: title: Example documentation header: links: - { label: Guides, href: /start } - { label: GitHub, href: \"https://github.com/example/project\", style: button } - { label: Get started, href: /start, style: primary } Links appear in list order, after the search box and toggle. Link settings Use these settings to configure each link shown in the header. Setting Required Value label Yes Visible link text. href Yes A site-root path such as /start , an http or https URL, or a mailto: link. style No link (default), button , or primary . link renders as plain text. button has an outline. primary fills with --color-accent and uses --color-accent-contrast for its text. Use one primary link at most, for the action you most want readers to take. External http and https links get rel=\"noopener\" . The build rejects any other URL scheme, including javascript: . Layout and themes On narrow screens, the search box and links wrap onto their own row below the site title. Each theme preset restyles them to match its shape. The CSS and theme reference lists their classes. Header links are part of the HTML page only. Markdown twins and /llms.txt do not include them. Related reading Reference while working Related topics"},{"filters":{"focus":["configure"]},"text":"CSS and theme reference — Look up the header classes each preset styles. Light and dark mode — The dark mode toggle appears in the header beside your links. Site search — The search box sits in the site header, before your header links."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3103,"markdownTokens":749,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.home","demo":false,"url":"/","markdownUrl":"/index.md","title":"Shoalrun","summary":"Preview API and product docs with content selection and agent discovery.","type":"overview","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"readable-output-with-checks-you-can-inspect","title":"Readable output, with checks you can inspect"},{"id":"a-tabbed-page-without-missing-panels","title":"A tabbed page, without missing panels"},{"id":"fetch-the-published-output","title":"Fetch the published output"},{"id":"check-both-audiences-before-you-publish","title":"Check both audiences before you publish"},{"id":"control-the-reading-experience","title":"Control the reading experience"},{"id":"make-it-look-like-yours","title":"Make it look like yours"},{"id":"bring-your-own-tools","title":"Bring your own tools"},{"id":"give-your-coding-agent-the-docs","title":"Give your coding agent the docs"}],"text":"Docs for people. Context for agents. One source, with control over how each audience reads it. Build interactive docs for people and readable content for agents, with checks before you publish. See what an agent gets See what works today Try the alpha: Install @shoalrun/cli from npm and build your own site. No account or package token is needed. Pin an exact version while the alpha evolves. Install Shoalrun → Readable output, with checks you can inspect Write Markdown, MDX, and OpenAPI once. People get tabs, disclosures, navigation, and reader views. Agents get the supported content in reading order, with stable page identities and machine-readable contracts. What you can inspect What it gives you A manifest with byte digests Stable page IDs and publication variants, with SHA-256 digests for checking the exact Markdown bytes. Compact discovery and incremental sync Find a page without the full search index; compare saved snapshots when a build changes. Focused per-operation OpenAPI contracts One small contract containing an operation and the local schemas it needs, when enabled. Explicit component representations Tabs and disclosures become labeled sections. Snippets expand into their resolved content. Unsupported components fail the build. Reader views and format-specific content Choose what people see in the browser and write different explanations for HTML and Markdown when needed. A tabbed page, without missing panels This example has two client choices and a closed disclosure. The Markdown includes both clients and the troubleshooting detail. You write People get HTML Agents get Markdown You write content/check-service.mdx < Tabs label = \"Client\" > < Tab label = \"curl\" > ``` sh curl -fsS https://api.example.com/health ``` </ Tab > < Tab label = \"JavaScript\" > ``` js const response = await fetch ( 'https://api.example.com/health' ); console .log ( response .status); ``` </ Tab > </ Tabs > < Collapsible title = \"If the request fails\" > Check the service URL and your network connection. </ Collapsible > People get HTML curl JavaScript curl curl -fsS https://api.example.com/health JavaScript const response = await fetch ( 'https://api.example.com/health' ); console .log ( response .status); If the request fails Check the service URL and your network connection. Agents get Markdown /check-service.md (body excerpt) ### curl ```sh curl -fsS https://api.example.com/health ``` ### JavaScript ```js const response = await fetch ( 'https://api.example.com/health' ); console .log ( response .status); ``` ### If the request fails Check the service URL and your network connection. Fetch the published output Start with the compact page list, choose a page, and fetch its Markdown. The full manifest supplies byte digests when you need verification; build information and sync snapshots let returning clients detect changes. Try the example on the agent-friendly guide to compare live components with tested Markdown output. curl -fsSL https://www.shoalrun.com/llms.min.txt curl -fsSL https://www.shoalrun.com/publish/agent-friendliness.md Hosts that support content negotiation can serve the same Markdown at the HTML route when the request sends Accept: text/markdown : curl -fsSL -H 'Accept: text/markdown' https://www.shoalrun.com/author/search Check both audiences before you publish Shoalrun builds static files for your host. Its audit builds HTML and Markdown, checks links and API contracts, and runs configured project tests. An unsupported component stops the build instead of disappearing from the agent's document. For example, adding <UnknownWidget /> to a page makes shoalrun check fail with the source path: FAIL build …/docs.config.yaml: …/content/welcome.mdx: <UnknownWidget> has no semantic/Markdown adapter Checks failed. Fix the findings above and rerun shoalrun check. This is illustrative output, not a failure on the current site. The check catches unsupported representations; it does not establish that every sentence is correct. Eval reports let you add reviewed task results to the publishing gate. Required failures and reports from an older build fail the audit. You supply the agent run and answer review. Shoalrun's five example tasks are a self-reviewed demonstration, with prior context; they are not an independent measure of agent accuracy or a comparison with other platforms. Audit a docs project Run project tests and local API representation checks with one CI command. Evaluate agent tasks against your docs Define realistic tasks, record reviewed answers from your own agent, and check the results against a documentation build. Add an OpenAPI API Import a local OpenAPI file, author an operation page, review its public content, and build HTML and Markdown. Control the reading experience Reader views use the readerFilters configuration to shape browser navigation, search, cards, and marked sections. A UI reader can follow screen actions while a developer sees request ","readerFilters":{},"readerSegments":[{"filters":{},"text":"Docs for people. Context for agents. One source, with control over how each audience reads it. Build interactive docs for people and readable content for agents, with checks before you publish. See what an agent gets See what works today Try the alpha: Install @shoalrun/cli from npm and build your own site. No account or package token is needed. Pin an exact version while the alpha evolves. Install Shoalrun → Readable output, with checks you can inspect Write Markdown, MDX, and OpenAPI once. People get tabs, disclosures, navigation, and reader views. Agents get the supported content in reading order, with stable page identities and machine-readable contracts. What you can inspect What it gives you A manifest with byte digests Stable page IDs and publication variants, with SHA-256 digests for checking the exact Markdown bytes. Compact discovery and incremental sync Find a page without the full search index; compare saved snapshots when a build changes. Focused per-operation OpenAPI contracts One small contract containing an operation and the local schemas it needs, when enabled. Explicit component representations Tabs and disclosures become labeled sections. Snippets expand into their resolved content. Unsupported components fail the build. Reader views and format-specific content Choose what people see in the browser and write different explanations for HTML and Markdown when needed. A tabbed page, without missing panels This example has two client choices and a closed disclosure. The Markdown includes both clients and the troubleshooting detail. You write People get HTML Agents get Markdown You write <Tabs label=\"Client\"> <Tab label=\"curl\"> ```sh curl -fsS https://api.example.com/health ``` </Tab> <Tab label=\"JavaScript\"> ```js const response = await fetch('https://api.example.com/health'); console.log(response.status); ``` </Tab> </Tabs> <Collapsible title=\"If the request fails\"> Check the service URL and your network connection. </Collapsible> People get HTML curl JavaScript curl curl -fsS https://api.example.com/health JavaScript const response = await fetch('https://api.example.com/health'); console.log(response.status); If the request fails Check the service URL and your network connection. Agents get Markdown ### curl ```sh curl -fsS https://api.example.com/health ``` ### JavaScript ```js const response = await fetch('https://api.example.com/health'); console.log(response.status); ``` ### If the request fails Check the service URL and your network connection. Fetch the published output Start with the compact page list, choose a page, and fetch its Markdown. The full manifest supplies byte digests when you need verification; build information and sync snapshots let returning clients detect changes. Try the example on the agent-friendly guide to compare live components with tested Markdown output. curl -fsSL https://www.shoalrun.com/llms.min.txt curl -fsSL https://www.shoalrun.com/publish/agent-friendliness.md Hosts that support content negotiation can serve the same Markdown at the HTML route when the request sends Accept: text/markdown : curl -fsSL -H 'Accept: text/markdown' https://www.shoalrun.com/author/search Check both audiences before you publish Shoalrun builds static files for your host. Its audit builds HTML and Markdown, checks links and API contracts, and runs configured project tests. An unsupported component stops the build instead of disappearing from the agent's document. For example, adding <UnknownWidget /> to a page makes shoalrun check fail with the source path: FAIL build …/docs.config.yaml: …/content/welcome.mdx: <UnknownWidget> has no semantic/Markdown adapter Checks failed. Fix the findings above and rerun shoalrun check. This is illustrative output, not a failure on the current site. The check catches unsupported representations; it does not establish that every sentence is correct. Eval reports let you add reviewed task results to the publishing gate. Required failures and reports from an older build fail the audit. You supply the agent run and answer review. Shoalrun's five example tasks are a self-reviewed demonstration, with prior context; they are not an independent measure of agent accuracy or a comparison with other platforms. Control the reading experience Reader views use the readerFilters configuration to shape browser navigation, search, cards, and marked sections. A UI reader can follow screen actions while a developer sees request examples. The published Markdown retains every reader-marked section with a label. Reader views are visibility controls, not access controls. Hidden browser content remains in published files. Use access.policy to exclude pages from a public build and host authorization to protect private content. Format-specific content lets you replace an interactive instruction with a useful written explanation. Markdown metadata settings choose which frontmatter fields are published for agents. These are authoring and publication choices; discovery f"},{"filters":{"focus":["configure"]},"text":"Audit a docs project Run project tests and local API representation checks with one CI command. Evaluate agent tasks against your docs Define realistic tasks, record reviewed answers from your own agent, and check the results against a documentation build. Organize project configuration Learn how Shoalrun resolves config files, layers presets, tracks path origins, and applies page defaults before building publications. Configuration reference Find configuration settings by topic and compose a project configuration. Deploy your documentation Build your site, choose Vercel or Node hosting, and verify the deployed HTML and Markdown."},{"filters":{"focus":["write"]},"text":"Add an OpenAPI API Import a local OpenAPI file, author an operation page, review its public content, and build HTML and Markdown. Content for one format Use Only to add content to the HTML page or its Markdown twin alone. Markdown metadata Public field projection, source paths, profiles, precedence, and required values."}],"markdownBytes":11955,"markdownTokens":2524,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.host-adapters","demo":false,"url":"/publish/host-adapters","markdownUrl":"/publish/host-adapters.md","title":"Add Shoalrun to another build or host","summary":"Publish compiled files alongside another site and supply the host's HTTP rules.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-hosting","headings":[{"id":"add-a-build-adapter","title":"Add a build adapter"},{"id":"supply-http-behavior","title":"Supply HTTP behavior"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun builds a complete static site without a host framework. To include its pages in another build system, run Shoalrun's CLI as a build step. Then copy the generated files into the host's output. The host does not need to parse Shoalrun's MDX or OpenAPI sources. shoalrun build docs.config.yaml ./shoalrun-dist The command replaces ./shoalrun-dist on each build. Use a dedicated output directory. With an empty site.basePath , copy its contents to the root of the host's published output. For a site hosted at /docs , set site.basePath: /docs . The Node and Vercel adapters serve the prefixed routes directly. On a static host that mounts a directory at /docs , publish the build output's docs/ subtree as that directory's root. The build keeps internal manifests at the output root for local commands. Static hosts also need routing rules for Markdown content negotiation . With the command above, the public subtree for /docs is shoalrun-dist/docs/ . Add a build adapter An adapter for Astro, another site builder, or a deployment platform can follow these steps: Run shoalrun build <config> <temporary-output> after the host has generated its own files. Enumerate both output trees and fail if a Shoalrun file would replace a host file. Also fail if a file occupies a directory the other tree needs. Compare paths without regard to case so a build that works on one filesystem does not overwrite files on another. Copy the Shoalrun files into the host output, keeping their paths. Do not modify the generated HTML or Markdown: both came from the same content build. Configure the host's routing and response headers as described below. Run the post-deploy checker against the published URL. The generated documents.json lists every page's HTML and Markdown URLs. redirects.json records redirects, and resource-headers.json records content types for Markdown and discovery resources. It also records Content-Security-Policy: sandbox and X-Content-Type-Options: nosniff for generated and local SVG files. Apply those headers when hosting SVGs; the Node server and Vercel adapter do this automatically. /llms.txt , search-index.json , API contracts, images, styles, and scripts are ordinary output files. The output guide lists their paths. Supply HTTP behavior Copying files does not make a static host negotiate Markdown at an HTML URL or apply redirects and special content types. Use the content negotiation contract to configure those rules. A host that cannot inspect request headers can still serve the direct .md URLs, but cannot provide the negotiated response. Shoalrun's Node server handles these rules; the Vercel build generates a deployable configuration for that host. Keep the adapter small: Shoalrun owns content compilation and the generated files, while the host owns request handling. A JavaScript plugin API is not required to call the CLI or publish its output. Related reading Next steps Check a deployed site — Confirm the host applies the HTTP rules correctly. Related topics Deploy your documentation — Apply the hosting contract on another platform. Publish on Vercel — The Vercel build generates its own HTTP rules; other hosts need them supplied.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Shoalrun builds a complete static site without a host framework. To include its pages in another build system, run Shoalrun's CLI as a build step. Then copy the generated files into the host's output. The host does not need to parse Shoalrun's MDX or OpenAPI sources. shoalrun build docs.config.yaml ./shoalrun-dist The command replaces ./shoalrun-dist on each build. Use a dedicated output directory. With an empty site.basePath , copy its contents to the root of the host's published output. For a site hosted at /docs , set site.basePath: /docs . The Node and Vercel adapters serve the prefixed routes directly. On a static host that mounts a directory at /docs , publish the build output's docs/ subtree as that directory's root. The build keeps internal manifests at the output root for local commands. Static hosts also need routing rules for Markdown content negotiation . With the command above, the public subtree for /docs is shoalrun-dist/docs/ . Add a build adapter An adapter for Astro, another site builder, or a deployment platform can follow these steps: Run shoalrun build <config> <temporary-output> after the host has generated its own files. Enumerate both output trees and fail if a Shoalrun file would replace a host file. Also fail if a file occupies a directory the other tree needs. Compare paths without regard to case so a build that works on one filesystem does not overwrite files on another. Copy the Shoalrun files into the host output, keeping their paths. Do not modify the generated HTML or Markdown: both came from the same content build. Configure the host's routing and response headers as described below. Run the post-deploy checker against the published URL. The generated documents.json lists every page's HTML and Markdown URLs. redirects.json records redirects, and resource-headers.json records content types for Markdown and discovery resources. It also records Content-Security-Policy: sandbox and X-Content-Type-Options: nosniff for generated and local SVG files. Apply those headers when hosting SVGs; the Node server and Vercel adapter do this automatically. /llms.txt , search-index.json , API contracts, images, styles, and scripts are ordinary output files. The output guide lists their paths. Supply HTTP behavior Copying files does not make a static host negotiate Markdown at an HTML URL or apply redirects and special content types. Use the content negotiation contract to configure those rules. A host that cannot inspect request headers can still serve the direct .md URLs, but cannot provide the negotiated response. Shoalrun's Node server handles these rules; the Vercel build generates a deployable configuration for that host. Keep the adapter small: Shoalrun owns content compilation and the generated files, while the host owns request handling. A JavaScript plugin API is not required to call the CLI or publish its output. Related reading Next steps Related topics"},{"filters":{"focus":["configure"]},"text":"Check a deployed site — Confirm the host applies the HTTP rules correctly. Deploy your documentation — Apply the hosting contract on another platform. Publish on Vercel — The Vercel build generates its own HTTP rules; other hosts need them supplied."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4506,"markdownTokens":1069,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.host-chat","demo":false,"url":"/chat/host","markdownUrl":"/chat/host.md","title":"Host and limit documentation chat","summary":"Deploy chat on Vercel with shared usage limits, a visitor challenge, optional logs, and an off switch.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-chat","headings":[{"id":"cap-the-daily-spend","title":"Cap the daily spend"},{"id":"identify-callers","title":"Identify callers"},{"id":"use-a-shared-store","title":"Use a shared store"},{"id":"host-the-chat-on-vercel","title":"Host the chat on Vercel"},{"id":"what-the-function-needs","title":"What the function needs"},{"id":"check-visitors-with-turnstile","title":"Check visitors with Turnstile"},{"id":"record-questions","title":"Record questions"},{"id":"change-the-panel-s-words","title":"Change the panel's words"},{"id":"turn-the-chat-off","title":"Turn the chat off"},{"id":"keep-a-record-of-questions","title":"Keep a record of questions"},{"id":"local-log-privacy","title":"Local log privacy"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Host chat after testing it locally . The Vercel function runs beside the documentation site and needs shared usage limits. You can also add a visitor challenge, question logging, and an immediate pause switch. Before building the hosted function, have these ready: Chat and embedding configuration, with the provider keys available in the required environments. A shared store that speaks the Upstash REST API. A Vercel project and the public address in site.origin . The normal site build does not add this function. Hosted provider requests can incur costs. Cap the daily spend chat.budget limits how many questions can reach a chat model each day. These are question limits, not a currency cap; one question can involve several model calls, and embedding or scoring requests are separate. docs.config.yaml chat : budget : { perCaller : 40 , perDay : 1000 } Setting What it does perCaller The most questions one caller can send to the model in a day. perDay The most the whole site can send in a day. It must be at least perCaller . store Where the counters live. Leave it out for memory, or name a shared store. See below. A request reserves one slot before answering. If no chat-model call is made, the slot is returned. Cached answers and excerpts can still be served when the model budget is spent; retrieval or scoring can have their own provider costs. A question that needs a new answer gets links to the closest pages instead. Counters reset at midnight UTC. Each function instance keeps its own cache in memory, so a repeat can still reach the model when another instance answered it first. Answer cards can serve common questions without a new chat-model answer when you generate them into the function's private index before deployment. Identify callers The handler tells callers apart with the clientKey function you give it, such as one that reads the address from a request header. It stores only a hash of the value. Without clientKey , every caller shares one cap. If the counter store fails, the model counts as spent, so an outage can't open it up. Use a shared store With no store , the counters live in memory. They reset when the server restarts and aren't shared between processes, which suits the local preview. A serverless host runs many instances, so it needs a store they all share. store names one that speaks the Upstash REST API, which Upstash Redis and Vercel KV both provide. docs.config.yaml chat : budget : perCaller : 40 perDay : 1000 store : { provider : upstash , urlEnv : KV_REST_API_URL , tokenEnv : KV_REST_API_TOKEN } urlEnv and tokenEnv name the environment variables that hold the address and token, and the config never holds either. A missing variable, a slow store, or a store that returns an error counts as a spent budget. The chat then shows the closest pages and never opens up. Shoalrun prints the reason once to the server log. The store address must use https , and a request that takes more than two seconds fails without a retry. For a caller key on a host, use clientKeyFromHeader with a header the host sets, such as x-vercel-forwarded-for . On a host that passes that header through, a caller can forge it and start a fresh personal cap. The site-wide cap still holds. Because a slot is taken before the answer and not counted after, questions that arrive together can't all get past a cap. If answering fails, the slot stays taken, because the model may already have been paid. Host the chat on Vercel The chat can run as a Vercel function on the same deployment as the site. It is optional, and a build never adds it unless you ask. Add --chat to the Vercel build: shoalrun vercel build docs.config.yaml .vercel/output --chat The build indexes the site and puts the index inside the function's own directory, never in the public static files. It writes the chat settings, without any key, and copies the code the function needs. The function answers at /__shoalrun/ask . If the function cannot be added, the build fails with a reason. Check for: A missing chat or retrieval.embeddings section. A missing chat.budget.store . An embedding key unavailable during the build. What the function needs The function refuses to start without a shared budget store, because counters kept by each server instance would limit nothing. You name the environment variables that hold your keys, and the config never holds a value. Variable Used for VOYAGE_API_KEY (or the variable retrieval.embeddings.keyEnv names) Embedding the passages at build time, and each question at run time. The variable chat.keyEnv names The chat model. JEV_API_KEY (or the variable chat.rerank.keyEnv names) A configured relevance scorer. Without its key, that scorer counts as down. The two variables chat.budget.store names The shared store. Vercel KV adds KV_REST_API_URL and KV_REST_API_TOKEN for you. The variable chat.challenge.secretEnv names The Turnstile secret. Only requests to the site's own addresses are accepted: the production host from site.origin , the depl","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Host chat after testing it locally . The Vercel function runs beside the documentation site and needs shared usage limits. You can also add a visitor challenge, question logging, and an immediate pause switch. Before building the hosted function, have these ready: Chat and embedding configuration, with the provider keys available in the required environments. A shared store that speaks the Upstash REST API. A Vercel project and the public address in site.origin . The normal site build does not add this function. Hosted provider requests can incur costs. Cap the daily spend chat.budget limits how many questions can reach a chat model each day. These are question limits, not a currency cap; one question can involve several model calls, and embedding or scoring requests are separate. chat: budget: { perCaller: 40, perDay: 1000 } Setting What it does perCaller The most questions one caller can send to the model in a day. perDay The most the whole site can send in a day. It must be at least perCaller . store Where the counters live. Leave it out for memory, or name a shared store. See below. A request reserves one slot before answering. If no chat-model call is made, the slot is returned. Cached answers and excerpts can still be served when the model budget is spent; retrieval or scoring can have their own provider costs. A question that needs a new answer gets links to the closest pages instead. Counters reset at midnight UTC. Each function instance keeps its own cache in memory, so a repeat can still reach the model when another instance answered it first. Answer cards can serve common questions without a new chat-model answer when you generate them into the function's private index before deployment. Identify callers The handler tells callers apart with the clientKey function you give it, such as one that reads the address from a request header. It stores only a hash of the value. Without clientKey , every caller shares one cap. If the counter store fails, the model counts as spent, so an outage can't open it up. Use a shared store With no store , the counters live in memory. They reset when the server restarts and aren't shared between processes, which suits the local preview. A serverless host runs many instances, so it needs a store they all share. store names one that speaks the Upstash REST API, which Upstash Redis and Vercel KV both provide. chat: budget: perCaller: 40 perDay: 1000 store: { provider: upstash, urlEnv: KV_REST_API_URL, tokenEnv: KV_REST_API_TOKEN } urlEnv and tokenEnv name the environment variables that hold the address and token, and the config never holds either. A missing variable, a slow store, or a store that returns an error counts as a spent budget. The chat then shows the closest pages and never opens up. Shoalrun prints the reason once to the server log. The store address must use https , and a request that takes more than two seconds fails without a retry. For a caller key on a host, use clientKeyFromHeader with a header the host sets, such as x-vercel-forwarded-for . On a host that passes that header through, a caller can forge it and start a fresh personal cap. The site-wide cap still holds. Because a slot is taken before the answer and not counted after, questions that arrive together can't all get past a cap. If answering fails, the slot stays taken, because the model may already have been paid. Host the chat on Vercel The chat can run as a Vercel function on the same deployment as the site. It is optional, and a build never adds it unless you ask. Add --chat to the Vercel build: shoalrun vercel build docs.config.yaml .vercel/output --chat The build indexes the site and puts the index inside the function's own directory, never in the public static files. It writes the chat settings, without any key, and copies the code the function needs. The function answers at /__shoalrun/ask . If the function cannot be added, the build fails with a reason. Check for: A missing chat or retrieval.embeddings section. A missing chat.budget.store . An embedding key unavailable during the build. What the function needs The function refuses to start without a shared budget store, because counters kept by each server instance would limit nothing. You name the environment variables that hold your keys, and the config never holds a value. Variable Used for VOYAGE_API_KEY (or the variable retrieval.embeddings.keyEnv names) Embedding the passages at build time, and each question at run time. The variable chat.keyEnv names The chat model. JEV_API_KEY (or the variable chat.rerank.keyEnv names) A configured relevance scorer. Without its key, that scorer counts as down. The two variables chat.budget.store names The shared store. Vercel KV adds KV_REST_API_URL and KV_REST_API_TOKEN for you. The variable chat.challenge.secretEnv names The Turnstile secret. Only requests to the site's own addresses are accepted: the production host from site.origin , the deployment's own addresses, and any listed in SHOALRU"},{"filters":{"focus":["configure"]},"text":"Check a deployed site — Check a deployed site's headers, redirects, and Markdown negotiation. Publish on Vercel — Deploy the site itself to Vercel before you add the chat function."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":16004,"markdownTokens":3391,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"cap-the-daily-spend","title":"Cap the daily spend","markdownUrl":"/chat/host.sections/cap-the-daily-spend.md","markdownBytes":4770,"markdownTokens":1077},{"id":"keep-a-record-of-questions","title":"Keep a record of questions","markdownUrl":"/chat/host.sections/keep-a-record-of-questions.md","markdownBytes":3709,"markdownTokens":855},{"id":"related-reading","title":"Related reading","markdownUrl":"/chat/host.sections/related-reading.md","markdownBytes":1839,"markdownTokens":450}]},{"id":"ingredient.audit-site","demo":false,"url":"/ingredients/audit-site","markdownUrl":"/ingredients/audit-site.md","title":"Audit the Shoalrun docs project","summary":"Run configured project checks and inspect failures before sharing a change.","type":"ingredient","variant":"production|current|en","area":"quality","subarea":"quality-audits","headings":[],"text":"Run Shoalrun's configured checks. This repository's formatting check requires Vale 3.20 or newer: npx --no-install shoalrun audit docs/docs.config.yaml The audit checks configured project commands, API representations, and focused contracts. Read any reported finding and fix its source before continuing. This command does not run the complete framework test suite or replace a browser review. Framework source changes and tests belong in the framework repository.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Run Shoalrun's configured checks. This repository's formatting check requires Vale 3.20 or newer: npx --no-install shoalrun audit docs/docs.config.yaml The audit checks configured project commands, API representations, and focused contracts. Read any reported finding and fix its source before continuing. This command does not run the complete framework test suite or replace a browser review. Framework source changes and tests belong in the framework repository."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1323,"markdownTokens":326,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.build-site","demo":false,"url":"/ingredients/build-site","markdownUrl":"/ingredients/build-site.md","title":"Build the Shoalrun docs site","summary":"Compile authored documentation into local HTML, Markdown, and manifests.","type":"ingredient","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[],"text":"Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1318,"markdownTokens":331,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.compile-framework","demo":false,"url":"/ingredients/compile-framework","markdownUrl":"/ingredients/compile-framework.md","title":"Install the site dependencies","summary":"Install the pinned Shoalrun package and this site’s declared dependencies.","type":"ingredient","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[],"text":"Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1394,"markdownTokens":328,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.complete-page","demo":false,"url":"/ingredients/complete-page","markdownUrl":"/ingredients/complete-page.md","title":"Complete the guide and add navigation","summary":"Write the guide, replace scaffold prompts, and make it discoverable in the local build.","type":"ingredient","variant":"production|current|en","area":"authoring","subarea":"authoring-pages","headings":[],"text":"Open the scaffolded file and write the actual task, prerequisites, steps, and an observable success check. Set updated to today's date, replace the draft summary, and resolve every generated TODO prompt. Check every technical claim against the implementation or a tested workflow. Set a suitable card.icon , such as file-text , to meet this site's page-card audit. Once the content is ready for review in the built site, change access.policy to public and add the stable document ID under the appropriate group in docs/config/nav.yaml : - { id : my-new-guide , doc : guide.my-new-guide } For useful next steps, add edges to docs/config/relationships.yaml and put <RelatedReading /> at the end of the page. Preserve the page ID if you later change its title or slug. Setting public access includes the page in the local build; it does not deploy the site.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Open the scaffolded file and write the actual task, prerequisites, steps, and an observable success check. Set updated to today's date, replace the draft summary, and resolve every generated TODO prompt. Check every technical claim against the implementation or a tested workflow. Set a suitable card.icon , such as file-text , to meet this site's page-card audit. Once the content is ready for review in the built site, change access.policy to public and add the stable document ID under the appropriate group in docs/config/nav.yaml : - { id: my-new-guide, doc: guide.my-new-guide } For useful next steps, add edges to docs/config/relationships.yaml and put <RelatedReading /> at the end of the page. Preserve the page ID if you later change its title or slug. Setting public access includes the page in the local build; it does not deploy the site."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1746,"markdownTokens":424,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.inspect-agent-bundle","demo":false,"url":"/ingredients/inspect-agent-bundle","markdownUrl":"/ingredients/inspect-agent-bundle.md","title":"Check agent search and page lookup","summary":"Confirm the refreshed bundle exposes the authored page through search and read.","type":"ingredient","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[],"text":"Search and read the exported site snapshot explicitly: npx --no-install shoalrun docs search \"recipes and cookbooks\" --site agent-docs npx --no-install shoalrun docs read \"$DOC_ID\" --site agent-docs Confirm the returned Markdown includes your change and links. Review agent-docs/provenance.json and the export inventory before handing the artifact to the framework release process. Plain shoalrun docs read uses the installed package’s snapshot, which is independent of this working tree.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Search and read the exported site snapshot explicitly: npx --no-install shoalrun docs search \"recipes and cookbooks\" --site agent-docs npx --no-install shoalrun docs read \"$DOC_ID\" --site agent-docs Confirm the returned Markdown includes your change and links. Review agent-docs/provenance.json and the export inventory before handing the artifact to the framework release process. Plain shoalrun docs read uses the installed package’s snapshot, which is independent of this working tree."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1369,"markdownTokens":339,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.inspect-build","demo":false,"url":"/ingredients/inspect-build","markdownUrl":"/ingredients/inspect-build.md","title":"Check the built page artifacts","summary":"Resolve a document ID through the manifest and check its HTML and Markdown files.","type":"ingredient","variant":"production|current|en","area":"quality","subarea":"quality-audits","headings":[],"text":"Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID = \"${DOC_ID :- guide.recipes-overview}\" node --input-type=module << 'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID=\"${DOC_ID:-guide.recipes-overview}\" node --input-type=module <<'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1913,"markdownTokens":477,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.preview-site","demo":false,"url":"/ingredients/preview-site","markdownUrl":"/ingredients/preview-site.md","title":"Serve the built docs locally","summary":"Open a successful build over HTTP and compare a page with its Markdown twin.","type":"ingredient","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[],"text":"Serve the build from the repository root: npx --no-install shoalrun serve docs/dist --port 8770 This command occupies the terminal. Open http://127.0.0.1:8770/author/recipes/ and http://127.0.0.1:8770/author/recipes.md in a browser. For another page, use its url and markdownUrl from docs/dist/documents.json . Check the page title, navigation, links, images, code copying, and complete instructions in Markdown. Check the page at a narrow window width too. If port 8770 is occupied, select another port and use it in both URLs. Press Ctrl+C when finished. This server serves the existing build; rebuild and reload after editing. Use npm run docs:dev for ongoing work that should rebuild automatically.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Serve the build from the repository root: npx --no-install shoalrun serve docs/dist --port 8770 This command occupies the terminal. Open http://127.0.0.1:8770/author/recipes/ and http://127.0.0.1:8770/author/recipes.md in a browser. For another page, use its url and markdownUrl from docs/dist/documents.json . Check the page title, navigation, links, images, code copying, and complete instructions in Markdown. Check the page at a narrow window width too. If port 8770 is occupied, select another port and use it in both URLs. Press Ctrl+C when finished. This server serves the existing build; rebuild and reload after editing. Use npm run docs:dev for ongoing work that should rebuild automatically."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1559,"markdownTokens":406,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.refresh-agent-bundle","demo":false,"url":"/ingredients/refresh-agent-bundle","markdownUrl":"/ingredients/refresh-agent-bundle.md","title":"Regenerate the agent documentation bundle","summary":"Build the offline Markdown and search index used by the CLI.","type":"ingredient","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[],"text":"Export the already built site for the framework’s next documentation snapshot: npm run agent-docs:build Build the site first. The export copies that output without rebuilding and records the site build identity and pinned package integrity in agent-docs/provenance.json . It does not modify the installed package. Review and transfer the export as a versioned artifact to the framework repository. Framework releases consume an explicitly selected snapshot; they must not fetch the latest site during a package build.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Export the already built site for the framework’s next documentation snapshot: npm run agent-docs:build Build the site first. The export copies that output without rebuilding and records the site build identity and pinned package integrity in agent-docs/provenance.json . It does not modify the installed package. Review and transfer the export as a versioned artifact to the framework repository. Framework releases consume an explicitly selected snapshot; they must not fetch the latest site during a package build."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1398,"markdownTokens":325,"markdownTokenEncoding":"cl100k_base"},{"id":"ingredient.scaffold-page","demo":false,"url":"/ingredients/scaffold-page","markdownUrl":"/ingredients/scaffold-page.md","title":"Scaffold a new guide","summary":"Create a draft guide with a stable ID without overwriting an existing file.","type":"ingredient","variant":"production|current|en","area":"authoring","subarea":"authoring-pages","headings":[],"text":"Choose a file name, title, and stable document ID for your real topic. The commands use my-new-guide as the example; replace those values together. npx --no-install shoalrun scaffold how-to -n docs/content/my-new-guide.mdx \\ --config docs/docs.config.yaml --id \"$DOC_ID\" --title 'My new guide' The command refuses to overwrite an existing file. If this guide already exists, edit it directly instead of scaffolding it again. Keep its access policy set to draft while writing.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Choose a file name, title, and stable document ID for your real topic. The commands use my-new-guide as the example; replace those values together. npx --no-install shoalrun scaffold how-to -n docs/content/my-new-guide.mdx \\ --config docs/docs.config.yaml --id \"$DOC_ID\" --title 'My new guide' The command refuses to overwrite an existing file. If this guide already exists, edit it directly instead of scaffolding it again. Keep its access policy set to draft while writing."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":1295,"markdownTokens":335,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.layouts","demo":false,"url":"/styling/layouts","markdownUrl":"/styling/layouts.md","title":"Page layouts, landing pages, and splash pages","summary":"Configure wide, landing, and splash pages with Hero and Sections.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-layouts","headings":[{"id":"control-navigation-tabs","title":"Control navigation tabs"},{"id":"build-a-landing-page","title":"Build a landing page"},{"id":"hero","title":"Hero"},{"id":"show-an-image-or-code","title":"Show an image or code"},{"id":"rules","title":"Rules"},{"id":"build-a-splash-page","title":"Build a splash page"},{"id":"customize-the-hero","title":"Customize the hero"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Every page uses the docs layout unless its frontmatter sets layout . Layouts change the HTML page only. The Markdown twin, search, and llms.txt stay the same. Layout Sidebar On this page Use it for docs Yes Yes Guides and reference pages. This is the default. wide Yes No Wide tables, diagrams, and API overviews that need the full content width. landing No No Home pages and product entry points. A Hero replaces the page header. splash No No Marketing pages built from full-width bands. A Hero replaces the page header, and Section blocks stack edge to edge. Frontmatter layout : wide An unknown value fails the build. Each preset styles all four layouts, and project CSS can target one through html[data-layout=\"wide\"] , html[data-layout=\"landing\"] , or html[data-layout=\"splash\"] . Control navigation tabs The built-in layouts are docs , wide , landing , and splash . There is no custom layout value; use landing or splash for a custom entry page and style it with project CSS. When the site config defines navigation tabs, docs and wide pages show the section bar by default. Landing and splash pages hide it by default. Override that choice on any page: Frontmatter layout : splash showNavigationTabs : false Set showNavigationTabs: true to include the tab bar on a landing or splash page. Set it to false to suppress it on a docs or wide page. The value must be a boolean and can also come from frontmatter defaults or enforced values. With no configured tabs, neither value creates a bar. This setting affects the HTML section bar only. It does not change the page's sidebar, tab membership, breadcrumbs, Markdown, search records, or agent indexes. An agent can still discover and read every published section without visiting the homepage. Build a landing page Set layout: landing , then open the page with a Hero . To serve the page at the site root, give it slug: / . When a page has slug: / , the site title in the masthead links to it. This example is a small landing page: content/home.mdx --- id : guide.home title : Shoalrun summary : Payments for small teams, in five lines of code. type : overview slug : / layout : landing access : { policy : public } --- < Hero tagline = \"Take your first payment in five lines of code.\" > [ Start building ](doc:guide.overview) [ See how it works ](doc:guide.concepts) </ Hero > ## Start here < DocCards docs = {[ \"guide.overview\" , \"guide.concepts\" , \"guide.api-references\" ]} /> Hero Hero opens a landing page with a large title, a tagline, and up to three action buttons. It can also show an image or a code block beside the text. Attribute Required Meaning tagline Yes One or two sentences under the title. title No The large title. Defaults to the page title . align No center (default) or start , which aligns the title, tagline, and buttons to the left. image No An https URL, or a local .png , .jpg , .webp , or .svg file relative to the page file. imageAlt With image What the image shows. Use imageAlt=\"\" when the image is decorative. Put the actions in the body as ordinary Markdown links, one per line or as a list. The first link is the primary button. doc: links resolve by page ID, like everywhere else. Show an image or code Add image and imageAlt to show a picture beside the text. The build copies a local image to /assets/pages/<page path>/ . < Hero tagline = \"Payments in five lines of code.\" image = \"./images/dashboard.png\" imageAlt = \"The payments dashboard showing today's volume\" > [ Get started ](doc:guide.start) </ Hero > Or put one fenced code block in the body. It appears in an editor-style window with its title and a Copy button, and keeps the site's code colors. The home page of this site uses one. < Hero tagline = \"Build API documentation from Markdown, MDX, and OpenAPI.\" > [ Start building ](doc:guide.overview) ``` sh title=\"Build and preview this site\" npm ci --prefix framework npm run docs:dev ``` </ Hero > With an image or code block, the hero splits into two columns, text first, and aligns to the left. Below 60rem wide, the visual moves under the text. A hero can show an image or a code block, not both. Rules Hero needs layout: landing or layout: splash , and it replaces the page header, including the Read as Markdown link. Put it first on the page. Attributes are literal text. The body can contain only action links and one code block; other content fails the build. In the Markdown twin, Hero becomes the tagline, a list of its links, then its image (when imageAlt isn't empty) or its code block. A custom title that differs from the page title appears in bold before the tagline. Landing pages are centered and at most 76rem wide, and the masthead lines up with them. On a phone, the hero stacks its buttons. Build a splash page A splash page is a marketing page. Set layout: splash , open with a Hero , then build the rest from Section blocks. The layout removes the sidebar, the outline, and the content padding, so the hero and each section run ed","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Every page uses the docs layout unless its frontmatter sets layout . Layouts change the HTML page only. The Markdown twin, search, and llms.txt stay the same. Layout Sidebar On this page Use it for docs Yes Yes Guides and reference pages. This is the default. wide Yes No Wide tables, diagrams, and API overviews that need the full content width. landing No No Home pages and product entry points. A Hero replaces the page header. splash No No Marketing pages built from full-width bands. A Hero replaces the page header, and Section blocks stack edge to edge. layout: wide An unknown value fails the build. Each preset styles all four layouts, and project CSS can target one through html[data-layout=\"wide\"] , html[data-layout=\"landing\"] , or html[data-layout=\"splash\"] . Control navigation tabs The built-in layouts are docs , wide , landing , and splash . There is no custom layout value; use landing or splash for a custom entry page and style it with project CSS. When the site config defines navigation tabs, docs and wide pages show the section bar by default. Landing and splash pages hide it by default. Override that choice on any page: layout: splash showNavigationTabs: false Set showNavigationTabs: true to include the tab bar on a landing or splash page. Set it to false to suppress it on a docs or wide page. The value must be a boolean and can also come from frontmatter defaults or enforced values. With no configured tabs, neither value creates a bar. This setting affects the HTML section bar only. It does not change the page's sidebar, tab membership, breadcrumbs, Markdown, search records, or agent indexes. An agent can still discover and read every published section without visiting the homepage. Build a landing page Set layout: landing , then open the page with a Hero . To serve the page at the site root, give it slug: / . When a page has slug: / , the site title in the masthead links to it. This example is a small landing page: --- id: guide.home title: Shoalrun summary: Payments for small teams, in five lines of code. type: overview slug: / layout: landing access: { policy: public } --- <Hero tagline=\"Take your first payment in five lines of code.\"> [Start building](doc:guide.overview) [See how it works](doc:guide.concepts) </Hero> ## Start here <DocCards docs={[\"guide.overview\", \"guide.concepts\", \"guide.api-references\"]} /> Hero Hero opens a landing page with a large title, a tagline, and up to three action buttons. It can also show an image or a code block beside the text. Attribute Required Meaning tagline Yes One or two sentences under the title. title No The large title. Defaults to the page title . align No center (default) or start , which aligns the title, tagline, and buttons to the left. image No An https URL, or a local .png , .jpg , .webp , or .svg file relative to the page file. imageAlt With image What the image shows. Use imageAlt=\"\" when the image is decorative. Put the actions in the body as ordinary Markdown links, one per line or as a list. The first link is the primary button. doc: links resolve by page ID, like everywhere else. Show an image or code Add image and imageAlt to show a picture beside the text. The build copies a local image to /assets/pages/<page path>/ . <Hero tagline=\"Payments in five lines of code.\" image=\"./images/dashboard.png\" imageAlt=\"The payments dashboard showing today's volume\"> [Get started](doc:guide.start) </Hero> Or put one fenced code block in the body. It appears in an editor-style window with its title and a Copy button, and keeps the site's code colors. The home page of this site uses one. <Hero tagline=\"Build API documentation from Markdown, MDX, and OpenAPI.\"> [Start building](doc:guide.overview) ```sh title=\"Build and preview this site\" npm ci --prefix framework npm run docs:dev ``` </Hero> With an image or code block, the hero splits into two columns, text first, and aligns to the left. Below 60rem wide, the visual moves under the text. A hero can show an image or a code block, not both. Rules Hero needs layout: landing or layout: splash , and it replaces the page header, including the Read as Markdown link. Put it first on the page. Attributes are literal text. The body can contain only action links and one code block; other content fails the build. In the Markdown twin, Hero becomes the tagline, a list of its links, then its image (when imageAlt isn't empty) or its code block. A custom title that differs from the page title appears in bold before the tagline. Landing pages are centered and at most 76rem wide, and the masthead lines up with them. On a phone, the hero stacks its buttons. Build a splash page A splash page is a marketing page. Set layout: splash , open with a Hero , then build the rest from Section blocks. The layout removes the sidebar, the outline, and the content padding, so the hero and each section run edge to edge. This site's home page is a working example. --- id: guide.home title: Acme summary: Payments for small teams. type: ov"},{"filters":{"focus":["configure"]},"text":"CSS and theme reference — Look up the width tokens and layout selectors."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10459,"markdownTokens":2307,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"control-navigation-tabs","title":"Control navigation tabs","markdownUrl":"/styling/layouts.sections/control-navigation-tabs.md","markdownBytes":3230,"markdownTokens":691},{"id":"build-a-landing-page","title":"Build a landing page","markdownUrl":"/styling/layouts.sections/build-a-landing-page.md","markdownBytes":2927,"markdownTokens":667},{"id":"hero","title":"Hero","markdownUrl":"/styling/layouts.sections/hero.md","markdownBytes":5045,"markdownTokens":1127},{"id":"build-a-splash-page","title":"Build a splash page","markdownUrl":"/styling/layouts.sections/build-a-splash-page.md","markdownBytes":4980,"markdownTokens":1004},{"id":"customize-the-hero","title":"Customize the hero","markdownUrl":"/styling/layouts.sections/customize-the-hero.md","markdownBytes":3084,"markdownTokens":701},{"id":"related-reading","title":"Related reading","markdownUrl":"/styling/layouts.sections/related-reading.md","markdownBytes":2399,"markdownTokens":516}]},{"id":"guide.manni","demo":false,"url":"/publish/manni","markdownUrl":"/publish/manni.md","title":"Use Manni with Shoalrun","summary":"Use Manni in your documentation project.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[{"id":"prerequisites","title":"Prerequisites"},{"id":"set-up-manni","title":"Set up Manni"},{"id":"install-the-optional-tools","title":"Install the optional tools"},{"id":"add-a-command-for-running-manni","title":"Add a command for running Manni"},{"id":"choose-your-documents-and-schemas","title":"Choose your documents and schemas"},{"id":"run-manni-s-native-tools","title":"Run Manni's native tools"},{"id":"connect-a-selected-check-to-shoalrun","title":"Connect a selected check to Shoalrun"},{"id":"check-the-result","title":"Check the result"},{"id":"how-this-site-uses-manni","title":"How this site uses Manni"},{"id":"optional-custom-policies","title":"Optional custom policies"}],"text":"Manni is a toolkit for managing and checking documentation. It can validate, query, and help fill page information; manage terminology; track connections between explanations and source code; and build knowledge graphs. It also provides tools for testing documentation and running evaluations. This guide focuses on its checking tools. You choose the rules, and Manni reports pages that break them. For example: A page is missing its title or description. A tutorial gives instructions but never tells readers how to check that they worked. A page refers to a glossary term that no longer exists. Code has changed underneath an explanation, so the explanation needs another look. Shoalrun builds and delivers your docs. Here, we use Manni to add checks before publishing, while its other tools remain available through the same command. You can use either tool without the other. This guide shows how to run Manni in a Shoalrun project and add a check to shoalrun audit . That command runs the checks you configure and reports whether they passed. Start with one useful rule, then add more when you need them. For a working example, see how we use Manni on this site . Manni's documentation site describes its available tools and rules. Your choices go in manni.config.yaml ; you do not need a separate Shoalrun setting for each Manni feature. Prerequisites Start in a Shoalrun project's root, with its package manifest and a docs/ directory containing docs.config.yaml and content/ . Adjust paths for a different layout. Set up Manni Install the optional tools Install the tested Manni version and a separate Node 24 development runtime: npm install --save-dev --save-exact @hawkeyexl/manni@4.25.0 node@24.22.1 --ignore-scripts npm rebuild node Manni requires Node 24. The launcher below uses the installed runtime, so Shoalrun can continue to run on Node 22.12 or later. The first command leaves dependency install scripts disabled; the second installs the Node binary for your platform. Commit your package manifest and lockfile according to your project's workflow. A subsequent npm ci must include development dependencies and permit the Node runtime install script. After an installation with scripts disabled, run npm rebuild node . Review and test upgrades before changing either pin. Add a command for running Manni Create docs/scripts/manni.cjs . This small script starts the installed Manni program with the Node version it needs: // CommonJS resolution also works through NODE_PATH in isolated Shoalrun checks. const { spawnSync } = require ( 'node:child_process' ); const { readFileSync } = require ( 'node:fs' ); const path = require ( 'node:path' ); try { const runtime = require .resolve ( 'node/bin/node' ); const packageFile = require .resolve ( '@hawkeyexl/manni/package.json' ); const installed = JSON .parse ( readFileSync (packageFile , 'utf8' )); const result = spawnSync (runtime , [ path .join ( path .dirname (packageFile) , installed . bin .manni) , ... process . argv .slice ( 2 )] , { cwd : path .resolve (__dirname , '..' ) , stdio : 'inherit' }); if ( result .error) throw result .error; if ( result .signal) process .kill ( process .pid , result .signal); else process .exitCode = result .status ?? 2 ; } catch (error) { console .error ( `Manni unavailable: ${ error .message } Run npm ci with development dependencies and the Node runtime install script enabled.` ); process .exitCode = 2 ; } Add this entry to the existing scripts mapping in your root package.json : \"manni\" : \"node docs/scripts/manni.cjs\" From the project root, discover the installed CLI and its built-in schemas: npm run manni -- --help npm run manni -- meta schemas npm run manni -- meta schemas show manni:core:1.0.0 Arguments, standard input, output, and exit status pass through to Manni. Every command runs from docs/ , so input paths and explicit config paths are relative to that directory. Manni's normal config discovery and --config option remain available. The launcher adds no default command, target, or flags. The script also works when Shoalrun validates a temporary copy of your docs. Missing tools produce an error and an installation message. The launcher itself does not install tools. Choose your documents and schemas Create docs/manni.config.yaml . A schema is a set of rules for the information in a page's YAML header, such as its title. This example selects Manni's built-in core schema: collections : - name : site paths : [ \"content/**/*.{md,mdx}\" ] meta : defaults : false schemas : [ \"manni:core:1.0.0\" ] The collection identifies your source pages, including drafts. meta.defaults: false applies only the schemas you select. Choose schemas using meta schemas and inspect their requirements with meta schemas show before enabling them. Each schema retains its own rules; schemas for another site generator may not fit Shoalrun content. The core schema requires nonempty title and description fields. Shoalrun's required summary does not substitute for description . I","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Manni is a toolkit for managing and checking documentation. It can validate, query, and help fill page information; manage terminology; track connections between explanations and source code; and build knowledge graphs. It also provides tools for testing documentation and running evaluations. This guide focuses on its checking tools. You choose the rules, and Manni reports pages that break them. For example: A page is missing its title or description. A tutorial gives instructions but never tells readers how to check that they worked. A page refers to a glossary term that no longer exists. Code has changed underneath an explanation, so the explanation needs another look. Shoalrun builds and delivers your docs. Here, we use Manni to add checks before publishing, while its other tools remain available through the same command. You can use either tool without the other. This guide shows how to run Manni in a Shoalrun project and add a check to shoalrun audit . That command runs the checks you configure and reports whether they passed. Start with one useful rule, then add more when you need them. For a working example, see how we use Manni on this site . Manni's documentation site describes its available tools and rules. Your choices go in manni.config.yaml ; you do not need a separate Shoalrun setting for each Manni feature. Prerequisites Start in a Shoalrun project's root, with its package manifest and a docs/ directory containing docs.config.yaml and content/ . Adjust paths for a different layout. Set up Manni Install the optional tools Install the tested Manni version and a separate Node 24 development runtime: npm install --save-dev --save-exact @hawkeyexl/manni@4.25.0 node@24.22.1 --ignore-scripts npm rebuild node Manni requires Node 24. The launcher below uses the installed runtime, so Shoalrun can continue to run on Node 22.12 or later. The first command leaves dependency install scripts disabled; the second installs the Node binary for your platform. Commit your package manifest and lockfile according to your project's workflow. A subsequent npm ci must include development dependencies and permit the Node runtime install script. After an installation with scripts disabled, run npm rebuild node . Review and test upgrades before changing either pin. Add a command for running Manni Create docs/scripts/manni.cjs . This small script starts the installed Manni program with the Node version it needs: // CommonJS resolution also works through NODE_PATH in isolated Shoalrun checks. const { spawnSync } = require('node:child_process'); const { readFileSync } = require('node:fs'); const path = require('node:path'); try { const runtime = require.resolve('node/bin/node'); const packageFile = require.resolve('@hawkeyexl/manni/package.json'); const installed = JSON.parse(readFileSync(packageFile, 'utf8')); const result = spawnSync(runtime, [path.join(path.dirname(packageFile), installed.bin.manni), ...process.argv.slice(2)], { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); if (result.error) throw result.error; if (result.signal) process.kill(process.pid, result.signal); else process.exitCode = result.status ?? 2; } catch (error) { console.error(`Manni unavailable: ${error.message} Run npm ci with development dependencies and the Node runtime install script enabled.`); process.exitCode = 2; } Add this entry to the existing scripts mapping in your root package.json : \"manni\": \"node docs/scripts/manni.cjs\" From the project root, discover the installed CLI and its built-in schemas: npm run manni -- --help npm run manni -- meta schemas npm run manni -- meta schemas show manni:core:1.0.0 Arguments, standard input, output, and exit status pass through to Manni. Every command runs from docs/ , so input paths and explicit config paths are relative to that directory. Manni's normal config discovery and --config option remain available. The launcher adds no default command, target, or flags. The script also works when Shoalrun validates a temporary copy of your docs. Missing tools produce an error and an installation message. The launcher itself does not install tools. Choose your documents and schemas Create docs/manni.config.yaml . A schema is a set of rules for the information in a page's YAML header, such as its title. This example selects Manni's built-in core schema: collections: - name: site paths: [\"content/**/*.{md,mdx}\"] meta: defaults: false schemas: [\"manni:core:1.0.0\"] The collection identifies your source pages, including drafts. meta.defaults: false applies only the schemas you select. Choose schemas using meta schemas and inspect their requirements with meta schemas show before enabling them. Each schema retains its own rules; schemas for another site generator may not fit Shoalrun content. The core schema requires nonempty title and description fields. Shoalrun's required summary does not substitute for description . If you choose this vocabulary, add a meaningful description to each page's existing fr"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14496,"markdownTokens":3194,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"prerequisites","title":"Prerequisites","markdownUrl":"/publish/manni.sections/prerequisites.md","markdownBytes":2433,"markdownTokens":591},{"id":"check-the-result","title":"Check the result","markdownUrl":"/publish/manni.sections/check-the-result.md","markdownBytes":2590,"markdownTokens":612},{"id":"how-this-site-uses-manni","title":"How this site uses Manni","markdownUrl":"/publish/manni.sections/how-this-site-uses-manni.md","markdownBytes":6467,"markdownTokens":1408},{"id":"optional-custom-policies","title":"Optional custom policies","markdownUrl":"/publish/manni.sections/optional-custom-policies.md","markdownBytes":2884,"markdownTokens":683}]},{"id":"guide.markdown-metadata","demo":false,"url":"/author/markdown-metadata","markdownUrl":"/author/markdown-metadata.md","title":"Markdown metadata","summary":"Public field projection, source paths, profiles, precedence, and required values.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-metadata","headings":[{"id":"projection-settings","title":"Projection settings"},{"id":"put-a-field-on-every-page","title":"Put a field on every page"},{"id":"published-markdown-size","title":"Published Markdown size"},{"id":"declare-sections-that-can-be-read-alone","title":"Declare sections that can be read alone"},{"id":"fetch-one-section","title":"Fetch one section"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"}],"text":"The build publishes the page metadata guide as Markdown alongside its HTML page. That .md file starts with a YAML header containing selected values from the source page header. Source headers can grow long and contain review notes or other details that do not help an agent read the page. Selecting a small set of useful fields keeps the agent's context focused and avoids exposing internal metadata in that header. Compare the two custom values in that guide's source: docs/content/frontmatter.mdx agent : intent : Help authors understand and configure page metadata. editorial : reviewNote : Check the frontmatter examples before release. The generated .md header includes agent.intent but leaves out editorial.reviewNote : docs/dist/author/frontmatter.md --- id : guide.frontmatter title : Page metadata summary : Set page identity, publication, and presentation fields before publishing. description : Learn how page metadata, project defaults, and publication choices shape the site and its Markdown output. type : reference audiences : - authors - maintainers canonical : /author/frontmatter agent : intent : Help authors understand and configure page metadata. --- The agent.intent value appears because this site's docs/docs.config.yaml selects it for reference pages. The relevant settings are: docs/docs.config.yaml outputs : markdown : metadata : format : yaml-frontmatter fields : id : frontmatter.id title : frontmatter.title summary : frontmatter.summary description : frontmatter.description type : frontmatter.type audiences : frontmatter.audiences subjectLifecycle : frontmatter.subjectLifecycle canonical : publication.canonicalUrl omitNull : true byType : reference : addFields : agent.intent : frontmatter.agent.intent Each entry under fields names an output key on the left and its source on the right. Here summary and description stay separate, while audiences comes from the page's intended-reader labels. The byType.reference rule adds agent.intent only for pages whose type is reference . subjectLifecycle is absent from the example output because that guide has no subjectLifecycle value and omitNull is true. The review note is absent because its declaration sets public: false and the output config does not select it. This controls only the generated YAML header: text written in the page body still appears in the published Markdown and HTML. Keep this header short. Include the fields an agent needs for the page, and leave out long descriptions or notes that take up its context. Projection settings format must be yaml-frontmatter to write a header. It defaults to none , so a projection with fields but no format writes no header and reports no error. format: none removes the header while leaving the full page body in Markdown. A field source is either frontmatter.<path> or one of these publication values: Source Value publication.channel The page's publication channel. publication.version The page's publication version. publication.language The page's language. publication.canonicalUrl The page route, such as /author/frontmatter . It is site-relative, not an absolute URL. Built-in public fields can be selected directly. A custom field needs a declaration with public: true . The protected roots access , seo , markdownMetadata , variables , tocDepth , private , internal , card , and displayText cannot be selected under any name. With omitNull: false , a missing value fails the build instead of being skipped. Layers apply in order. The base settings come first, then byType.<type> , then a named profile, then the page's own override. Each layer accepts format , fields , addFields , removeFields , and omitNull . fields replaces the inherited fields; addFields merges into them; removeFields drops output names and fails if a name is missing. Define named profiles under profiles , then select one from a page: docs.config.yaml outputs : markdown : metadata : format : yaml-frontmatter fields : { id : frontmatter.id , title : frontmatter.title } profiles : minimal : removeFields : [ title ] A page's frontmatter markdownMetadata : minimal A page can also write the override as a mapping, such as markdownMetadata: { profile: minimal, addFields: { language: publication.language } } . The example API project under framework/example/ uses the same declaration and projection pattern. See the generated frontmatter reference for the local project field inventory. See cards and collections for card inheritance and collection filters, and related reading for authored reading paths. Put a field on every page List the field under fields at the top level of outputs.markdown.metadata . Top-level fields apply to every page. A byType rule adds fields only for pages of that type, so use it for extras and not for a field that every page needs. To require the value as well, declare the field with required: true . A page that lacks it then fails the build, and the error names the file: docs.config.yaml frontmatter : fields : agent.intent : ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"The build publishes the page metadata guide as Markdown alongside its HTML page. That .md file starts with a YAML header containing selected values from the source page header. Source headers can grow long and contain review notes or other details that do not help an agent read the page. Selecting a small set of useful fields keeps the agent's context focused and avoids exposing internal metadata in that header. Compare the two custom values in that guide's source: agent: intent: Help authors understand and configure page metadata. editorial: reviewNote: Check the frontmatter examples before release. The generated .md header includes agent.intent but leaves out editorial.reviewNote : --- id: guide.frontmatter title: Page metadata summary: Set page identity, publication, and presentation fields before publishing. description: Learn how page metadata, project defaults, and publication choices shape the site and its Markdown output. type: reference audiences: - authors - maintainers canonical: /author/frontmatter agent: intent: Help authors understand and configure page metadata. --- The agent.intent value appears because this site's docs/docs.config.yaml selects it for reference pages. The relevant settings are: outputs: markdown: metadata: format: yaml-frontmatter fields: id: frontmatter.id title: frontmatter.title summary: frontmatter.summary description: frontmatter.description type: frontmatter.type audiences: frontmatter.audiences subjectLifecycle: frontmatter.subjectLifecycle canonical: publication.canonicalUrl omitNull: true byType: reference: addFields: agent.intent: frontmatter.agent.intent Each entry under fields names an output key on the left and its source on the right. Here summary and description stay separate, while audiences comes from the page's intended-reader labels. The byType.reference rule adds agent.intent only for pages whose type is reference . subjectLifecycle is absent from the example output because that guide has no subjectLifecycle value and omitNull is true. The review note is absent because its declaration sets public: false and the output config does not select it. This controls only the generated YAML header: text written in the page body still appears in the published Markdown and HTML. Keep this header short. Include the fields an agent needs for the page, and leave out long descriptions or notes that take up its context. Projection settings format must be yaml-frontmatter to write a header. It defaults to none , so a projection with fields but no format writes no header and reports no error. format: none removes the header while leaving the full page body in Markdown. A field source is either frontmatter.<path> or one of these publication values: Source Value publication.channel The page's publication channel. publication.version The page's publication version. publication.language The page's language. publication.canonicalUrl The page route, such as /author/frontmatter . It is site-relative, not an absolute URL. Built-in public fields can be selected directly. A custom field needs a declaration with public: true . The protected roots access , seo , markdownMetadata , variables , tocDepth , private , internal , card , and displayText cannot be selected under any name. With omitNull: false , a missing value fails the build instead of being skipped. Layers apply in order. The base settings come first, then byType.<type> , then a named profile, then the page's own override. Each layer accepts format , fields , addFields , removeFields , and omitNull . fields replaces the inherited fields; addFields merges into them; removeFields drops output names and fails if a name is missing. Define named profiles under profiles , then select one from a page: outputs: markdown: metadata: format: yaml-frontmatter fields: { id: frontmatter.id, title: frontmatter.title } profiles: minimal: removeFields: [title] markdownMetadata: minimal A page can also write the override as a mapping, such as markdownMetadata: { profile: minimal, addFields: { language: publication.language } } . The example API project under framework/example/ uses the same declaration and projection pattern. See the generated frontmatter reference for the local project field inventory. See cards and collections for card inheritance and collection filters, and related reading for authored reading paths. Put a field on every page List the field under fields at the top level of outputs.markdown.metadata . Top-level fields apply to every page. A byType rule adds fields only for pages of that type, so use it for extras and not for a field that every page needs. To require the value as well, declare the field with required: true . A page that lacks it then fails the build, and the error names the file: frontmatter: fields: agent.intent: type: string description: The reader task this page helps an agent complete. public: true required: true outputs: markdown: metadata: format: yaml-frontmatter fields: id: frontmatter.id title: fro"},{"filters":{"focus":["write"]},"text":"Frontmatter field reference — Check native fields and the current project declarations."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":15458,"markdownTokens":3079,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.mcp-analytics","demo":false,"url":"/publish/mcp-analytics","markdownUrl":"/publish/mcp-analytics.md","title":"Measure MCP tool usage","summary":"Send optional server events to your analytics service without changing the documentation tools.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-mcp","headings":[{"id":"enable-analytics","title":"Enable analytics"},{"id":"adapter-exports","title":"Adapter exports"},{"id":"event-fields-and-service-mappings","title":"Event fields and service mappings"},{"id":"optionally-identify-the-client-and-model","title":"Optionally identify the client and model"},{"id":"optionally-collect-intent-and-group-calls","title":"Optionally collect intent and group calls"},{"id":"safeguards-and-limits","title":"Safeguards and limits"},{"id":"example-posthog-mcp-analytics","title":"Example: PostHog MCP analytics"},{"id":"install-the-sdks","title":"Install the SDKs"},{"id":"create-the-server-adapter","title":"Create the server adapter"},{"id":"enable-the-adapter-and-verify-an-event","title":"Enable the adapter and verify an event"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"related-topics","title":"Related topics"}],"text":"Add a server adapter to measure calls to your HTTP MCP endpoint . Analytics is off by default. Enabling MCP does not enable tracking, and the browser analytics setting does not count tool calls. Your adapter chooses the service and sends the events. Shoalrun packages it for Node or the generated Vercel function. This setting does not instrument stdio, direct Markdown requests, or browser page views. Enable analytics Add your server adapter to the MCP configuration. Readers do not need to change their client settings: docs.config.yaml mcp : enabled : true access : public publication : { channel : production , version : current , language : en } analytics : module : ./mcp-analytics/adapter.mjs Adapter exports Create a local .js or .mjs server module. Export capture(event) and, if your service queues events, flush() : mcp-analytics/adapter.mjs export async function capture (event) { // Send event to your service using its server SDK or HTTP API. } export async function flush () { // Send queued events before the HTTP response completes. } capture runs after each tool call, including failures. flush sends queued events before the response completes. Both can be asynchronous. Each has a one-second wait limit; analytics failures leave tool results unchanged. Set network timeouts in your adapter because Shoalrun cannot cancel a timed-out operation. Module paths resolve relative to the config file. Use static imports and install SDK dependencies in your project. Keep credentials in the server environment, since adapter files are copied into the build. Event fields and service mappings Every event has the following fields. Arguments, search text, returned content, raw request headers, IP addresses, and user identity are excluded: Field Meaning name Always mcp_tool_call . tool search_docs , get_page , get_outline , or get_section . durationMs Tool execution time before analytics delivery. isError Whether the documentation tool failed. errorCode Error category when the tool failed. pageId , sectionId Published IDs when a successful read returns them. buildId Identity of the served build. publication Served channel , version , and language . client Optional normalized client name, bounded version, source, and verified: false . model Optional model label, source, and verified: false . Map these fields to your service’s event and property names. A service with native MCP analytics may require its SDK or reserved event names. A general event service can receive mcp_tool_call with these properties. The PostHog example below uses its native MCP SDK. Tool counts show usage, not comprehension. This adapter supplies no user or conversation identifier, so do not treat calls as unique people or agent sessions. Basic event capture leaves tool definitions and results unchanged. The optional SDK features below add analytics arguments and conversation handles. Optionally identify the client and model The harness is the application running the agent, such as Cursor or Claude Code. To collect available client and model labels, explicitly enable clientMetadata in your adapter config: docs.config.yaml mcp : enabled : true access : public publication : { channel : production , version : current , language : en } analytics : module : ./mcp-analytics/adapter.mjs clientMetadata : true This option defaults to false . Shoalrun recognizes a fixed set of client names from MCP identity metadata or product tokens in selected headers. It discards raw headers and unrelated metadata. Client versions must match a bounded numeric version format. Model capture currently recognizes model in Codex’s x-codex-turn-metadata . It accepts labels from a fixed model-name registry, normalizes supported provider prefixes, and drops other values. A recognized family prefix alone does not qualify; custom deployment names and unknown models are omitted. Other clients may supply no supported model field; missing labels remain absent. The harness name does not establish which model it uses. Both labels are unverified client claims. Use them for usage reports, never authentication, access control, or billing. No user fingerprint or cross-request identity cache is added. OpenCode can also be recognized by the presence of its documented session metadata marker. Shoalrun discards that identifier; it records only the client label. Client-specific markers do not establish the model. Optionally collect intent and group calls Intent describes why an agent called a tool. The PostHog adapter below supports separate intent and conversationIds switches, both off by default. Enable them alongside its module: docs.config.yaml mcp : enabled : true access : public publication : { channel : production , version : current , language : en } analytics : module : ./mcp-analytics/posthog.mjs clientMetadata : true intent : true conversationIds : true With intent enabled, the SDK adds a context argument asking for exactly one category: discovery , setup , troubleshooting , configuration , re","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Add a server adapter to measure calls to your HTTP MCP endpoint . Analytics is off by default. Enabling MCP does not enable tracking, and the browser analytics setting does not count tool calls. Your adapter chooses the service and sends the events. Shoalrun packages it for Node or the generated Vercel function. This setting does not instrument stdio, direct Markdown requests, or browser page views. Enable analytics Add your server adapter to the MCP configuration. Readers do not need to change their client settings: mcp: enabled: true access: public publication: { channel: production, version: current, language: en } analytics: module: ./mcp-analytics/adapter.mjs Adapter exports Create a local .js or .mjs server module. Export capture(event) and, if your service queues events, flush() : export async function capture(event) { // Send event to your service using its server SDK or HTTP API. } export async function flush() { // Send queued events before the HTTP response completes. } capture runs after each tool call, including failures. flush sends queued events before the response completes. Both can be asynchronous. Each has a one-second wait limit; analytics failures leave tool results unchanged. Set network timeouts in your adapter because Shoalrun cannot cancel a timed-out operation. Module paths resolve relative to the config file. Use static imports and install SDK dependencies in your project. Keep credentials in the server environment, since adapter files are copied into the build. Event fields and service mappings Every event has the following fields. Arguments, search text, returned content, raw request headers, IP addresses, and user identity are excluded: Field Meaning name Always mcp_tool_call . tool search_docs , get_page , get_outline , or get_section . durationMs Tool execution time before analytics delivery. isError Whether the documentation tool failed. errorCode Error category when the tool failed. pageId , sectionId Published IDs when a successful read returns them. buildId Identity of the served build. publication Served channel , version , and language . client Optional normalized client name, bounded version, source, and verified: false . model Optional model label, source, and verified: false . Map these fields to your service’s event and property names. A service with native MCP analytics may require its SDK or reserved event names. A general event service can receive mcp_tool_call with these properties. The PostHog example below uses its native MCP SDK. Tool counts show usage, not comprehension. This adapter supplies no user or conversation identifier, so do not treat calls as unique people or agent sessions. Basic event capture leaves tool definitions and results unchanged. The optional SDK features below add analytics arguments and conversation handles. Optionally identify the client and model The harness is the application running the agent, such as Cursor or Claude Code. To collect available client and model labels, explicitly enable clientMetadata in your adapter config: mcp: enabled: true access: public publication: { channel: production, version: current, language: en } analytics: module: ./mcp-analytics/adapter.mjs clientMetadata: true This option defaults to false . Shoalrun recognizes a fixed set of client names from MCP identity metadata or product tokens in selected headers. It discards raw headers and unrelated metadata. Client versions must match a bounded numeric version format. Model capture currently recognizes model in Codex’s x-codex-turn-metadata . It accepts labels from a fixed model-name registry, normalizes supported provider prefixes, and drops other values. A recognized family prefix alone does not qualify; custom deployment names and unknown models are omitted. Other clients may supply no supported model field; missing labels remain absent. The harness name does not establish which model it uses. Both labels are unverified client claims. Use them for usage reports, never authentication, access control, or billing. No user fingerprint or cross-request identity cache is added. OpenCode can also be recognized by the presence of its documented session metadata marker. Shoalrun discards that identifier; it records only the client label. Client-specific markers do not establish the model. Optionally collect intent and group calls Intent describes why an agent called a tool. The PostHog adapter below supports separate intent and conversationIds switches, both off by default. Enable them alongside its module: mcp: enabled: true access: public publication: { channel: production, version: current, language: en } analytics: module: ./mcp-analytics/posthog.mjs clientMetadata: true intent: true conversationIds: true With intent enabled, the SDK adds a context argument asking for exactly one category: discovery , setup , troubleshooting , configuration , reference_lookup , comparison , migration , or other . Only these values can reach analytics. The adapter trims whites"},{"filters":{"focus":["configure"]},"text":"Connect an MCP client — Enable and verify the HTTP endpoint before adding analytics. Bring your own analytics — Collect browser interactions through the separate browser adapter."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":21594,"markdownTokens":4596,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"enable-analytics","title":"Enable analytics","markdownUrl":"/publish/mcp-analytics.sections/enable-analytics.md","markdownBytes":1793,"markdownTokens":444},{"id":"adapter-exports","title":"Adapter exports","markdownUrl":"/publish/mcp-analytics.sections/adapter-exports.md","markdownBytes":2377,"markdownTokens":553},{"id":"event-fields-and-service-mappings","title":"Event fields and service mappings","markdownUrl":"/publish/mcp-analytics.sections/event-fields-and-service-mappings.md","markdownBytes":3543,"markdownTokens":706},{"id":"optionally-identify-the-client-and-model","title":"Optionally identify the client and model","markdownUrl":"/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md","markdownBytes":3021,"markdownTokens":674},{"id":"optionally-collect-intent-and-group-calls","title":"Optionally collect intent and group calls","markdownUrl":"/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md","markdownBytes":4327,"markdownTokens":950},{"id":"safeguards-and-limits","title":"Safeguards and limits","markdownUrl":"/publish/mcp-analytics.sections/safeguards-and-limits.md","markdownBytes":3537,"markdownTokens":752},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/mcp-analytics.sections/related-reading.md","markdownBytes":1592,"markdownTokens":392}]},{"id":"guide.mcp","demo":false,"url":"/publish/mcp","markdownUrl":"/publish/mcp.md","title":"Connect an MCP client","summary":"Connect read-only MCP clients over stdio or HTTP to search and read built documentation.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-mcp","headings":[{"id":"why-offer-mcp-for-public-docs","title":"Why offer MCP for public docs?"},{"id":"serve-a-public-endpoint-on-node","title":"Serve a public endpoint on Node"},{"id":"enable-a-public-publication","title":"Enable a public publication"},{"id":"build-and-serve-the-site","title":"Build and serve the site"},{"id":"connect-and-check-the-tools","title":"Connect and check the tools"},{"id":"hosts-origins-and-limits","title":"Hosts, origins, and limits"},{"id":"generate-a-vercel-endpoint","title":"Generate a Vercel endpoint"},{"id":"choose-the-documentation-source","title":"Choose the documentation source"},{"id":"configure-the-client","title":"Configure the client"},{"id":"search-then-read","title":"Search, then read"},{"id":"check-budgets-and-errors","title":"Check budgets and errors"},{"id":"verify-the-connection","title":"Verify the connection"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Connect an MCP client to built documentation through four read-only tools. Use stdio for a client-launched local process, or enable an HTTP endpoint on Node or in a generated Vercel function. Both use the same search and Markdown reading core. The HTTP endpoint currently supports one explicitly selected public publication. The generated Vercel endpoint is deployed and verified on this site. Netlify and Cloudflare adapters are not implemented. Analytics is off by default; an optional server adapter can measure tool calls. You need Node.js 22.12 or newer, the installed Shoalrun CLI, and a client that supports MCP stdio or Streamable HTTP. Follow Getting started to install the public npm package. Why offer MCP for public docs? MCP gives tool-capable agents a predictable way to search your docs and request a page or section within a token budget. For example, an agent answering “How do I configure analytics?” can search and follow the returned read instruction. The result includes relevant Markdown, its publication, and a source link. The documentation can already be public. MCP adds a tool interface; it does not grant access that public Markdown lacks. Agents that can fetch and search your Markdown may not need it. Offer both when your readers use MCP clients, and check whether the tools help them find answers with fewer requests or less content. To use Shoalrun's own live documentation endpoint, follow use this site's MCP . The setup below is for hosting your own project's tools. Serve a public endpoint on Node Use this procedure when agents should connect to a URL instead of launching the CLI themselves. Analytics is not enabled by this setting. Enable a public publication Add the endpoint and the exact channel, version, and language to your project config. The selected publication must contain public pages: docs.config.yaml mcp : enabled : true access : public path : /mcp publication : { channel : production , version : current , language : en } The endpoint supplies those publication coordinates when the client omits them. Requests for a different publication are rejected. Its lexical search index is generated even if browser search is disabled. Build and serve the site With the CLI available as shoalrun , build the output and start the Node server: shoalrun build docs.config.yaml dist shoalrun serve dist --port 8774 The server reads the MCP settings from that build. It does not need the source config. With no site base path, the local endpoint is http://127.0.0.1:8774/mcp ; a base path such as /docs makes it /docs/mcp . Set mcp: false or remove the setting and rebuild to disable the endpoint. Restart a non-watching server after replacing its build; watched preview reloads settings with each successful build. Connect and check the tools Add the endpoint URL in your client’s remote MCP settings. The client should discover the four tools listed below. Search for a known page, then follow the returned read instruction and verify its publication. The SDK integration is tested with legacy and automatic protocol negotiation using MCP TypeScript client version 2.2.0 . Compatibility with a specific desktop client or public host still needs its own check. Hosts, origins, and limits Local connections permit the configured loopback host. For a public Node deployment, site.origin supplies a trusted hostname and browser origin. Add explicit mcp.allowedHosts hostnames for other domains and mcp.allowedOrigins origins for browser-based clients. Forwarded host headers are not trusted. Native clients do not need an Origin header. The endpoint accepts JSON MCP requests through POST; it does not provide a persistent session or standalone event stream. GET and DELETE return 405. Browser preflight uses OPTIONS. Limits are 64 KiB per request, eight concurrent requests per handler, and a 15-second deadline. Excess concurrent requests return 429 with retry guidance. Tool token budgets still apply. These are process-local controls; configure deployment-level limits before exposing a public service. This is a public endpoint, not an authentication mechanism for private documentation. Generate a Vercel endpoint With the public MCP configuration above, generate deployment output from your project: shoalrun vercel build docs.config.yaml .vercel/output No extra MCP flag, Ask configuration, embeddings, or model key is required. The command packages the four tools and their selected public documentation in a Node function at the configured endpoint. Internal runtime files stay out of the public static output. Follow Publish on Vercel to deploy the complete output directory. The function trusts site.origin , explicit allowed hosts, and Vercel’s reserved deployment host variables. It does not trust arbitrary forwarded hosts or other projects’ preview domains. Deployment protection may block an MCP client from reaching a preview; check that host setting if a client cannot connect. Returned Markdown links use the URLs generated at build time.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Connect an MCP client to built documentation through four read-only tools. Use stdio for a client-launched local process, or enable an HTTP endpoint on Node or in a generated Vercel function. Both use the same search and Markdown reading core. The HTTP endpoint currently supports one explicitly selected public publication. The generated Vercel endpoint is deployed and verified on this site. Netlify and Cloudflare adapters are not implemented. Analytics is off by default; an optional server adapter can measure tool calls. You need Node.js 22.12 or newer, the installed Shoalrun CLI, and a client that supports MCP stdio or Streamable HTTP. Follow Getting started to install the public npm package. Why offer MCP for public docs? MCP gives tool-capable agents a predictable way to search your docs and request a page or section within a token budget. For example, an agent answering “How do I configure analytics?” can search and follow the returned read instruction. The result includes relevant Markdown, its publication, and a source link. The documentation can already be public. MCP adds a tool interface; it does not grant access that public Markdown lacks. Agents that can fetch and search your Markdown may not need it. Offer both when your readers use MCP clients, and check whether the tools help them find answers with fewer requests or less content. To use Shoalrun's own live documentation endpoint, follow use this site's MCP . The setup below is for hosting your own project's tools. Serve a public endpoint on Node Use this procedure when agents should connect to a URL instead of launching the CLI themselves. Analytics is not enabled by this setting. Enable a public publication Add the endpoint and the exact channel, version, and language to your project config. The selected publication must contain public pages: mcp: enabled: true access: public path: /mcp publication: { channel: production, version: current, language: en } The endpoint supplies those publication coordinates when the client omits them. Requests for a different publication are rejected. Its lexical search index is generated even if browser search is disabled. Build and serve the site With the CLI available as shoalrun , build the output and start the Node server: shoalrun build docs.config.yaml dist shoalrun serve dist --port 8774 The server reads the MCP settings from that build. It does not need the source config. With no site base path, the local endpoint is http://127.0.0.1:8774/mcp ; a base path such as /docs makes it /docs/mcp . Set mcp: false or remove the setting and rebuild to disable the endpoint. Restart a non-watching server after replacing its build; watched preview reloads settings with each successful build. Connect and check the tools Add the endpoint URL in your client’s remote MCP settings. The client should discover the four tools listed below. Search for a known page, then follow the returned read instruction and verify its publication. The SDK integration is tested with legacy and automatic protocol negotiation using MCP TypeScript client version 2.2.0 . Compatibility with a specific desktop client or public host still needs its own check. Hosts, origins, and limits Local connections permit the configured loopback host. For a public Node deployment, site.origin supplies a trusted hostname and browser origin. Add explicit mcp.allowedHosts hostnames for other domains and mcp.allowedOrigins origins for browser-based clients. Forwarded host headers are not trusted. Native clients do not need an Origin header. The endpoint accepts JSON MCP requests through POST; it does not provide a persistent session or standalone event stream. GET and DELETE return 405. Browser preflight uses OPTIONS. Limits are 64 KiB per request, eight concurrent requests per handler, and a 15-second deadline. Excess concurrent requests return 429 with retry guidance. Tool token budgets still apply. These are process-local controls; configure deployment-level limits before exposing a public service. This is a public endpoint, not an authentication mechanism for private documentation. Generate a Vercel endpoint With the public MCP configuration above, generate deployment output from your project: shoalrun vercel build docs.config.yaml .vercel/output No extra MCP flag, Ask configuration, embeddings, or model key is required. The command packages the four tools and their selected public documentation in a Node function at the configured endpoint. Internal runtime files stay out of the public static output. Follow Publish on Vercel to deploy the complete output directory. The function trusts site.origin , explicit allowed hosts, and Vercel’s reserved deployment host variables. It does not trust arbitrary forwarded hosts or other projects’ preview domains. Deployment protection may block an MCP client from reaching a preview; check that host setting if a client cannot connect. Returned Markdown links use the URLs generated at build time. Set the intended origin be"},{"filters":{"focus":["configure"]},"text":"Measure MCP tool usage — Optionally measure tool calls through a server adapter. Agent-friendly documentation — Understand the published Markdown and discovery surfaces alongside MCP."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14946,"markdownTokens":3096,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"why-offer-mcp-for-public-docs","title":"Why offer MCP for public docs?","markdownUrl":"/publish/mcp.sections/why-offer-mcp-for-public-docs.md","markdownBytes":2636,"markdownTokens":617},{"id":"serve-a-public-endpoint-on-node","title":"Serve a public endpoint on Node","markdownUrl":"/publish/mcp.sections/serve-a-public-endpoint-on-node.md","markdownBytes":4559,"markdownTokens":1025},{"id":"generate-a-vercel-endpoint","title":"Generate a Vercel endpoint","markdownUrl":"/publish/mcp.sections/generate-a-vercel-endpoint.md","markdownBytes":3146,"markdownTokens":702},{"id":"choose-the-documentation-source","title":"Choose the documentation source","markdownUrl":"/publish/mcp.sections/choose-the-documentation-source.md","markdownBytes":2446,"markdownTokens":585},{"id":"configure-the-client","title":"Configure the client","markdownUrl":"/publish/mcp.sections/configure-the-client.md","markdownBytes":2624,"markdownTokens":636},{"id":"search-then-read","title":"Search, then read","markdownUrl":"/publish/mcp.sections/search-then-read.md","markdownBytes":5101,"markdownTokens":1105},{"id":"check-budgets-and-errors","title":"Check budgets and errors","markdownUrl":"/publish/mcp.sections/check-budgets-and-errors.md","markdownBytes":4183,"markdownTokens":899},{"id":"verify-the-connection","title":"Verify the connection","markdownUrl":"/publish/mcp.sections/verify-the-connection.md","markdownBytes":2499,"markdownTokens":581},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/mcp.sections/related-reading.md","markdownBytes":2068,"markdownTokens":504}]},{"id":"guide.navigation-lifecycle","demo":false,"url":"/author/navigation","markdownUrl":"/author/navigation.md","title":"Organize site navigation","summary":"Arrange guides, reference pages, and other documents into a clear site menu.","type":"how-to","variant":"production|current|en","area":"appearance","subarea":"appearance-navigation","headings":[{"id":"arrange-authored-pages","title":"Arrange authored pages"},{"id":"split-navigation-into-tabs","title":"Split navigation into tabs"},{"id":"agent-discovery-across-tabs","title":"Agent discovery across tabs"},{"id":"reach-navigation-while-reading","title":"Reach navigation while reading"},{"id":"hide-group-page-counts","title":"Hide group page counts"},{"id":"optionally-split-a-large-menu-into-files","title":"Optionally split a large menu into files"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"mix-guides-and-api-references","title":"Mix guides and API references"},{"id":"fill-an-api-tag-group","title":"Fill an API tag group"},{"id":"local-api-preview","title":"Local API preview"},{"id":"subject-lifecycle-labels","title":"Subject lifecycle labels"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"The navigation setting controls the site's left menu. It can be a list in docs.config.yaml or import a separate YAML file. Add guides, tutorials, concepts, and reference pages by their stable document IDs. Nodes appear in the order you write them. Each node has a stable id for the menu entry. It needs exactly one of these targets: doc places any page, including a guide or API reference, by its stable document ID. label with items makes a group of pages or nested groups. operation places an API reference by stable operation ID. generated fills in API references from the registered OpenAPI source. The menu follows document IDs rather than file paths or slugs. Moving a source file or changing a page URL does not require a navigation edit. A doc node uses the page title by default; set label when the menu needs a shorter name. Pages omitted from navigation can still be built and linked from other pages. Arrange authored pages - id : overview doc : guide.overview - id : learn label : Learn items : - id : first-steps doc : guide.first-steps label : First steps - id : core-concepts doc : concept.core - id : tasks label : Tasks items : - id : create-payment doc : guide.create-payment - id : handle-errors doc : guide.handle-errors Each doc value must match a page's frontmatter ID. Groups can contain other groups, so a larger site can place task guides under a product area. Use a structure that matches the reader's tasks; the source directory layout does not control the menu. The build rejects missing document IDs and malformed groups. For a publication where a page has no matching channel, version, or language, its menu entry is omitted. An empty group is omitted too. Use search on an individual page or operation node to add terms to the reader's sidebar menu filter . The filter also matches the page label and its group labels. For example, search: refunds returns helps readers find a page whose title uses different words. This setting does not add terms to the site-wide search index; site search uses page content and search metadata. Groups and generators cannot have search . Split navigation into tabs Use navigation tabs for parallel sections such as Guides, API reference, and Recipes. Mark a top-level group with tab: true and name its landing page by stable document ID: config/nav.yaml - id : guides label : Guides tab : true landing : guide.overview items : - { id : overview , doc : guide.overview } - { id : first-page , doc : guide.add-page } - id : api label : API reference tab : true landing : guide.api-references items : - { id : api-intro , doc : guide.api-references } - { id : generated , api : notes , generated : tags } Replace the example IDs and API name with your project's values. A tab ID uses lowercase letters, digits, and hyphens and starts with a letter. Tabs require a label, nonempty items, and a landing document inside those items. Nested tabs fail the build. A published page can belong to only one tab, or to shared navigation; placing it in both fails the build. Tabs whose items have no pages in a publication are omitted. A nonempty tab whose landing page is unavailable in that publication fails the build. Each tab links to its landing page. The current page's URL selects its tab and sidebar on the server. Opening a direct link, following a search result, or navigating without JavaScript selects the same section. Groups outside tabs remain shared navigation. A page outside every tab shows the shared navigation with no tab selected. Existing navigation lists work without adding tabs. Tab placement does not change page URLs or publication routes. The section links appear below the masthead on docs and wide pages. Landing and splash pages hide them by default. Set showNavigationTabs: true or false in page frontmatter to override the layout default; see page layouts . On smaller screens, Menu opens a drawer containing these section links and the current sidebar. Closing the drawer restores focus and the article's scroll position. Without JavaScript, Menu links to navigation below the article and section links remain in a native disclosure. They inherit each theme's typography and colors. Site-wide search still includes all sections; the sidebar filter searches only the current sidebar. Reader views can filter that sidebar without changing tab membership or agent discovery. Agent discovery across tabs Both /llms.min.txt and /llms.txt keep every published page and add links to a scoped text index for each tab and publication. Follow the published indexUrl ; do not construct it from the page's URL. Each scoped index links to all of that tab's Markdown pages and back to the global index, which also includes shared pages and pages omitted from navigation. Each member page's Markdown identifies its navigation section, stable tab ID, and scoped index. Its breadcrumbs include the tab. documents.json publishes a navigationTabs catalog and a matching navigationTab record on each member page. Records contain id","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"The navigation setting controls the site's left menu. It can be a list in docs.config.yaml or import a separate YAML file. Add guides, tutorials, concepts, and reference pages by their stable document IDs. Nodes appear in the order you write them. Each node has a stable id for the menu entry. It needs exactly one of these targets: doc places any page, including a guide or API reference, by its stable document ID. label with items makes a group of pages or nested groups. operation places an API reference by stable operation ID. generated fills in API references from the registered OpenAPI source. The menu follows document IDs rather than file paths or slugs. Moving a source file or changing a page URL does not require a navigation edit. A doc node uses the page title by default; set label when the menu needs a shorter name. Pages omitted from navigation can still be built and linked from other pages. Arrange authored pages - id: overview doc: guide.overview - id: learn label: Learn items: - id: first-steps doc: guide.first-steps label: First steps - id: core-concepts doc: concept.core - id: tasks label: Tasks items: - id: create-payment doc: guide.create-payment - id: handle-errors doc: guide.handle-errors Each doc value must match a page's frontmatter ID. Groups can contain other groups, so a larger site can place task guides under a product area. Use a structure that matches the reader's tasks; the source directory layout does not control the menu. The build rejects missing document IDs and malformed groups. For a publication where a page has no matching channel, version, or language, its menu entry is omitted. An empty group is omitted too. Use search on an individual page or operation node to add terms to the reader's sidebar menu filter . The filter also matches the page label and its group labels. For example, search: refunds returns helps readers find a page whose title uses different words. This setting does not add terms to the site-wide search index; site search uses page content and search metadata. Groups and generators cannot have search . Split navigation into tabs Use navigation tabs for parallel sections such as Guides, API reference, and Recipes. Mark a top-level group with tab: true and name its landing page by stable document ID: - id: guides label: Guides tab: true landing: guide.overview items: - { id: overview, doc: guide.overview } - { id: first-page, doc: guide.add-page } - id: api label: API reference tab: true landing: guide.api-references items: - { id: api-intro, doc: guide.api-references } - { id: generated, api: notes, generated: tags } Replace the example IDs and API name with your project's values. A tab ID uses lowercase letters, digits, and hyphens and starts with a letter. Tabs require a label, nonempty items, and a landing document inside those items. Nested tabs fail the build. A published page can belong to only one tab, or to shared navigation; placing it in both fails the build. Tabs whose items have no pages in a publication are omitted. A nonempty tab whose landing page is unavailable in that publication fails the build. Each tab links to its landing page. The current page's URL selects its tab and sidebar on the server. Opening a direct link, following a search result, or navigating without JavaScript selects the same section. Groups outside tabs remain shared navigation. A page outside every tab shows the shared navigation with no tab selected. Existing navigation lists work without adding tabs. Tab placement does not change page URLs or publication routes. The section links appear below the masthead on docs and wide pages. Landing and splash pages hide them by default. Set showNavigationTabs: true or false in page frontmatter to override the layout default; see page layouts . On smaller screens, Menu opens a drawer containing these section links and the current sidebar. Closing the drawer restores focus and the article's scroll position. Without JavaScript, Menu links to navigation below the article and section links remain in a native disclosure. They inherit each theme's typography and colors. Site-wide search still includes all sections; the sidebar filter searches only the current sidebar. Reader views can filter that sidebar without changing tab membership or agent discovery. Agent discovery across tabs Both /llms.min.txt and /llms.txt keep every published page and add links to a scoped text index for each tab and publication. Follow the published indexUrl ; do not construct it from the page's URL. Each scoped index links to all of that tab's Markdown pages and back to the global index, which also includes shared pages and pages omitted from navigation. Each member page's Markdown identifies its navigation section, stable tab ID, and scoped index. Its breadcrumbs include the tab. documents.json publishes a navigationTabs catalog and a matching navigationTab record on each member page. Records contain id , label , variant , url , markdownUrl , and indexUrl . B"},{"filters":{"focus":["configure"]},"text":"Configuration reference — Look up every field a navigation item accepts. Breadcrumbs — Understand the breadcrumb trails generated from navigation groups."},{"filters":{"focus":["write"]},"text":"Generate and select API pages — Generate the API reference pages that fill a tag group in the menu."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":15444,"markdownTokens":3377,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"arrange-authored-pages","title":"Arrange authored pages","markdownUrl":"/author/navigation.sections/arrange-authored-pages.md","markdownBytes":3055,"markdownTokens":729},{"id":"split-navigation-into-tabs","title":"Split navigation into tabs","markdownUrl":"/author/navigation.sections/split-navigation-into-tabs.md","markdownBytes":5254,"markdownTokens":1158},{"id":"reach-navigation-while-reading","title":"Reach navigation while reading","markdownUrl":"/author/navigation.sections/reach-navigation-while-reading.md","markdownBytes":2354,"markdownTokens":533},{"id":"hide-group-page-counts","title":"Hide group page counts","markdownUrl":"/author/navigation.sections/hide-group-page-counts.md","markdownBytes":2261,"markdownTokens":534},{"id":"optionally-split-a-large-menu-into-files","title":"Optionally split a large menu into files","markdownUrl":"/author/navigation.sections/optionally-split-a-large-menu-into-files.md","markdownBytes":3836,"markdownTokens":918},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/navigation.sections/html-markdown-and-agents.md","markdownBytes":3185,"markdownTokens":706},{"id":"mix-guides-and-api-references","title":"Mix guides and API references","markdownUrl":"/author/navigation.sections/mix-guides-and-api-references.md","markdownBytes":3836,"markdownTokens":883},{"id":"fill-an-api-tag-group","title":"Fill an API tag group","markdownUrl":"/author/navigation.sections/fill-an-api-tag-group.md","markdownBytes":2097,"markdownTokens":512},{"id":"local-api-preview","title":"Local API preview","markdownUrl":"/author/navigation.sections/local-api-preview.md","markdownBytes":2289,"markdownTokens":532},{"id":"subject-lifecycle-labels","title":"Subject lifecycle labels","markdownUrl":"/author/navigation.sections/subject-lifecycle-labels.md","markdownBytes":2599,"markdownTokens":594},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/navigation.sections/related-reading.md","markdownBytes":2236,"markdownTokens":531}]},{"id":"guide.non-goals","demo":false,"url":"/non-goals","markdownUrl":"/non-goals.md","title":"Non-goals","summary":"Scope limits for skill generation, agent orchestration, and reader-view authorization.","type":"explanation","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"shipping-a-skill-builder-with-the-tool","title":"Shipping a skill builder with the tool"},{"id":"general-agent-orchestration","title":"General agent orchestration"},{"id":"using-reader-views-for-authorization","title":"Using reader views for authorization"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun's scope includes publishing documentation that people and agents can discover and read. This page records capabilities we deliberately exclude and the reasoning behind those decisions. Shipping a skill builder with the tool Shoalrun does not ship a non-interactive skill builder or automatically generate a reader-side skill for each site it builds. Skills need a human expert to guide their creation and maintenance. That expert brings knowledge of the domain, decides which workflows are appropriate, tests the instructions against real tasks, and keeps them accurate as the product changes. A non-interactive builder could produce something that looks complete and give users false confidence that they have “automatic agent skills.” Generating instructions alone does not establish that those instructions are useful, reliable, or kept current. We are not yet comfortable shipping a feature that implies that confidence. Shoalrun's bundled authoring skills are maintained instructions for working with Shoalrun. Published sites receive Markdown pages and discovery files during the build. Teams that create their own skills remain responsible for expert guidance, review, evaluation, and maintenance. General agent orchestration Shoalrun provides authoring tools for project discovery, documentation references, snapshot validation, and local review. The author's coding agent owns planning, evidence gathering, editing, its model, and execution permissions. General orchestration of arbitrary agents and tasks remains outside Shoalrun's scope. The evaluation task format and audit hook let teams use their own agents to run tasks and record reviewed results against a build. Shoalrun checks the report; the team owns agent execution and grading. Using reader views for authorization Reader views shape navigation and visible sections. They do not protect content: published files and Markdown twins remain available. Using a reader's selected view as an authorization boundary is outside their purpose. Exclude nonpublic pages from a public build and use host-level authorization when private content must be protected. Related reading Reference while working Bundled agent skills — See the maintained authoring skills that Shoalrun bundles. Related topics Evaluate agent tasks against your docs — Understand why agent execution remains outside Shoalrun. Agent-friendly documentation — See how published Markdown and discovery files help agents read a site. Bundled agent skills — Understand why a non-interactive skill builder is outside the tool's scope. Project status — Distinguish deliberate scope limits from deferred features.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Shoalrun's scope includes publishing documentation that people and agents can discover and read. This page records capabilities we deliberately exclude and the reasoning behind those decisions. Shipping a skill builder with the tool Shoalrun does not ship a non-interactive skill builder or automatically generate a reader-side skill for each site it builds. Skills need a human expert to guide their creation and maintenance. That expert brings knowledge of the domain, decides which workflows are appropriate, tests the instructions against real tasks, and keeps them accurate as the product changes. A non-interactive builder could produce something that looks complete and give users false confidence that they have “automatic agent skills.” Generating instructions alone does not establish that those instructions are useful, reliable, or kept current. We are not yet comfortable shipping a feature that implies that confidence. Shoalrun's bundled authoring skills are maintained instructions for working with Shoalrun. Published sites receive Markdown pages and discovery files during the build. Teams that create their own skills remain responsible for expert guidance, review, evaluation, and maintenance. General agent orchestration Shoalrun provides authoring tools for project discovery, documentation references, snapshot validation, and local review. The author's coding agent owns planning, evidence gathering, editing, its model, and execution permissions. General orchestration of arbitrary agents and tasks remains outside Shoalrun's scope. The evaluation task format and audit hook let teams use their own agents to run tasks and record reviewed results against a build. Shoalrun checks the report; the team owns agent execution and grading. Using reader views for authorization Reader views shape navigation and visible sections. They do not protect content: published files and Markdown twins remain available. Using a reader's selected view as an authorization boundary is outside their purpose. Exclude nonpublic pages from a public build and use host-level authorization when private content must be protected. Related reading Reference while working Related topics Project status — Distinguish deliberate scope limits from deferred features."},{"filters":{"focus":["write"]},"text":"Bundled agent skills — See the maintained authoring skills that Shoalrun bundles. Bundled agent skills — Understand why a non-interactive skill builder is outside the tool's scope."},{"filters":{"focus":["configure"]},"text":"Evaluate agent tasks against your docs — Understand why agent execution remains outside Shoalrun. Agent-friendly documentation — See how published Markdown and discovery files help agents read a site."}],"navigationTab":{"id":"project-updates","label":"Project updates","variant":{"channel":"production","version":"current","language":"en"},"url":"/status","markdownUrl":"/status.md","indexUrl":"/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt"},"markdownBytes":3836,"markdownTokens":823,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.openapi-extension-mappings","demo":false,"url":"/publish/openapi-extension-mappings","markdownUrl":"/publish/openapi-extension-mappings.md","title":"OpenAPI extension mappings","summary":"Map selected operation-level x-* values into Shoalrun metadata without depending on a particular authoring service.","type":"reference","variant":"production|current|en","area":"api","subarea":"api-contracts","headings":[{"id":"supported-mapping","title":"Supported mapping"},{"id":"other-extension-shapes","title":"Other extension shapes"},{"id":"choosing-a-new-mapping-target","title":"Choosing a new mapping target"}],"text":"OpenAPI permits specification extensions whose names begin with x- . Their names and values belong to the tool or team that wrote the description. Shoalrun reads standard OpenAPI fields directly and applies an extension only when the project config explicitly maps it to a supported Shoalrun field. Supported mapping Use these source locations and value shapes when mapping OpenAPI extensions to Shoalrun fields. Shoalrun target Source location Accepted source shape Shoalrun values subjectLifecycle An operation under paths or OpenAPI 3.1 webhooks A scalar x-* value, or a scalar member inside an x-* object beta , in-development , experimental , deprecated Use apis.<apiId>.mappings.subjectLifecycle . from starts with an operation-level x-* key. For an object, add a dot and the member name; further simple member names may follow. values maps exact source values to Shoalrun values. Unlisted, missing, null, array, or object values do not set a badge. For example, this fictional OpenAPI operation uses an object-shaped extension: openapi.yaml paths : /widgets : get : operationId : listWidgets x-docs-availability : status : testing note : May change before general release responses : '200' : { description : Widgets returned } Map its status member without changing the OpenAPI file: config/api.yaml catalog : source : { kind : file , path : ../apis/catalog/openapi.yaml } mappings : subjectLifecycle : from : x-docs-availability.status values : testing : beta building : in-development retired : deprecated generateReferences : true The listWidgets reference now shows Beta in its page header and navigation. Its Markdown twin and documents.json also report the mapped status. For a scalar extension such as x-docs-availability: testing , use from: x-docs-availability with the same values map. The source names are examples; the project chooses its own extension name and values. An authored reference page's subjectLifecycle takes precedence over the mapping. OpenAPI deprecated: true always makes the operation Deprecated ; a conflicting authored status fails the build. A mapping is scoped to one API registration and applies to that API's selected operations across its publications. Other extension shapes Extensions outside the supported mapping may need source changes or a different Shoalrun feature. Source extension purpose Current Shoalrun behavior Use in Shoalrun today Tag names and tag groups No automatic mapping Use OpenAPI tags for generated groups and navigation config for editorial grouping and MDX pages. Custom code samples No automatic mapping Add an authored MDX example or reusable snippet; standard OpenAPI request and response examples still appear automatically. Enum labels or descriptions No automatic mapping Standard enum values appear in schemas. Put explanatory prose in a schema or field description . Hide or internal flags No automatic mapping Select public operations with generateReferences.include or explicit operations ; set page access in authored frontmatter. Do not rely on an unrecognized extension to hide content. Explorer settings and SDK naming No automatic mapping Shoalrun does not execute API requests. Keep SDK-specific settings in their owning tool. Webhook markers in older descriptions No automatic mapping Describe inbound events with OpenAPI 3.1 webhooks . An unmapped x-* value does not change the rendered reference. A focused contract omits extension properties while retaining literal example payload keys, even when those keys begin with x- . A full OpenAPI download enabled by source.publish: true contains the source file as authored, including its extensions. Review that file before publishing it. Choosing a new mapping target The target list above is intentionally small. An extension can describe presentation, visibility, SDK behavior, or actual wire semantics, and identical names do not guarantee identical shapes. When adding a target, define its source location, accepted value shapes, Shoalrun output, precedence over authored metadata and standard OpenAPI, and behavior for unknown values. Keep the source name configurable so projects can adapt descriptions from different tools without baking a vendor vocabulary into Shoalrun.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"OpenAPI permits specification extensions whose names begin with x- . Their names and values belong to the tool or team that wrote the description. Shoalrun reads standard OpenAPI fields directly and applies an extension only when the project config explicitly maps it to a supported Shoalrun field. Supported mapping Use these source locations and value shapes when mapping OpenAPI extensions to Shoalrun fields. Shoalrun target Source location Accepted source shape Shoalrun values subjectLifecycle An operation under paths or OpenAPI 3.1 webhooks A scalar x-* value, or a scalar member inside an x-* object beta , in-development , experimental , deprecated Use apis.<apiId>.mappings.subjectLifecycle . from starts with an operation-level x-* key. For an object, add a dot and the member name; further simple member names may follow. values maps exact source values to Shoalrun values. Unlisted, missing, null, array, or object values do not set a badge. For example, this fictional OpenAPI operation uses an object-shaped extension: paths: /widgets: get: operationId: listWidgets x-docs-availability: status: testing note: May change before general release responses: '200': { description: Widgets returned } Map its status member without changing the OpenAPI file: catalog: source: { kind: file, path: ../apis/catalog/openapi.yaml } mappings: subjectLifecycle: from: x-docs-availability.status values: testing: beta building: in-development retired: deprecated generateReferences: true The listWidgets reference now shows Beta in its page header and navigation. Its Markdown twin and documents.json also report the mapped status. For a scalar extension such as x-docs-availability: testing , use from: x-docs-availability with the same values map. The source names are examples; the project chooses its own extension name and values. An authored reference page's subjectLifecycle takes precedence over the mapping. OpenAPI deprecated: true always makes the operation Deprecated ; a conflicting authored status fails the build. A mapping is scoped to one API registration and applies to that API's selected operations across its publications. Other extension shapes Extensions outside the supported mapping may need source changes or a different Shoalrun feature. Source extension purpose Current Shoalrun behavior Use in Shoalrun today Tag names and tag groups No automatic mapping Use OpenAPI tags for generated groups and navigation config for editorial grouping and MDX pages. Custom code samples No automatic mapping Add an authored MDX example or reusable snippet; standard OpenAPI request and response examples still appear automatically. Enum labels or descriptions No automatic mapping Standard enum values appear in schemas. Put explanatory prose in a schema or field description . Hide or internal flags No automatic mapping Select public operations with generateReferences.include or explicit operations ; set page access in authored frontmatter. Do not rely on an unrecognized extension to hide content. Explorer settings and SDK naming No automatic mapping Shoalrun does not execute API requests. Keep SDK-specific settings in their owning tool. Webhook markers in older descriptions No automatic mapping Describe inbound events with OpenAPI 3.1 webhooks . An unmapped x-* value does not change the rendered reference. A focused contract omits extension properties while retaining literal example payload keys, even when those keys begin with x- . A full OpenAPI download enabled by source.publish: true contains the source file as authored, including its extensions. Review that file before publishing it. Choosing a new mapping target The target list above is intentionally small. An extension can describe presentation, visibility, SDK behavior, or actual wire semantics, and identical names do not guarantee identical shapes. When adding a target, define its source location, accepted value shapes, Shoalrun output, precedence over authored metadata and standard OpenAPI, and behavior for unknown values. Keep the source name configurable so projects can adapt descriptions from different tools without baking a vendor vocabulary into Shoalrun."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6670,"markdownTokens":1236,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.openapi-support","demo":false,"url":"/api-docs/support","markdownUrl":"/api-docs/support.md","title":"OpenAPI support and limits","summary":"Check supported OpenAPI operations, schema keywords, examples, and source restrictions before importing a specification.","type":"reference","variant":"production|current|en","area":"api","subarea":"api-contracts","headings":[{"id":"compatibility","title":"Compatibility"},{"id":"supported-schema-keywords","title":"Supported schema keywords"},{"id":"features-requiring-adaptation","title":"Features requiring adaptation"},{"id":"check-a-source-before-adding-pages","title":"Check a source before adding pages"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Shoalrun renders a defined subset of OpenAPI into HTML, Markdown, and focused contracts. Check these limits before importing a large specification. A supported OpenAPI version does not mean every feature in that version can be rendered. Compatibility The supported behavior varies by OpenAPI feature and source structure. Area Supported behavior Source formats OpenAPI 3.0.x and 3.1.x in YAML or JSON. kind: file builds from local files; api import can create a pinned local snapshot from a public HTTPS URL. Operations Method and path, server alternatives, CommonMark descriptions, security alternatives and credential details, path and operation parameter overrides, request body media types, responses, and named examples. Webhooks Top-level OpenAPI 3.1 webhooks , including a document without paths ; authored and generated references describe the inbound request and acknowledgement, with no outbound cURL command. Focused contracts retain the webhooks location. Authentication API keys in headers, query strings, or cookies; HTTP schemes; OAuth2 flow names and scopes; OpenID Connect discovery; mutual TLS. These describe authentication; the site does not authenticate or execute requests. References Local $ref within the project or configured OpenAPI source directory, including multiple files. api import downloads same-origin relative references and rewrites them to local snapshot paths. Recursive schemas end with a named reference marker. Absolute file paths and references escaping those directories are rejected. Schemas Objects, arrays, titled variants, discriminators, enums, constants, required fields, defaults, examples, nullable values, supported constraints, additional properties, and read/write/deprecated labels. OpenAPI 3.1 boolean schemas are supported. The exact keyword list is below. Named examples Parameter, request, and response examples maps; reusable components.examples references; names, summaries, descriptions, values, provenance, HTML selection and deep links. All examples appear in Markdown. HTTPS externalValue is an external link, not a fetched payload. Focused contracts One-operation JSON with transitive local components, named examples, security schemes, and internal recursive references. Enabled by source.focused: true or source.publish: true . Reader layout Three columns at wide widths and a stacked order on narrow screens. JSON schemas supply type shapes even without named examples; shapes and named examples are distinct views. Extension metadata Explicit mappings from operation-level x-* values to subjectLifecycle ; OpenAPI deprecated: true takes precedence. Other extensions do not automatically become page metadata. Supported schema keywords The renderer accepts these schema keys, plus x-* extension keys: $ref, type, format, nullable, enum, const, default, minLength, maxLength, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minItems, maxItems, uniqueItems, minProperties, maxProperties, pattern, readOnly, writeOnly, deprecated, description, example, examples, allOf, oneOf, anyOf, items, properties, required, additionalProperties, title, discriminator Other schema keywords fail when encountered by the renderer. This includes valid OpenAPI or JSON Schema keywords outside this list. The compiler presents supported constraints; it is not a general validator for payloads or the entire OpenAPI specification. Exclusive bounds follow the entry document's version even when a schema lives in another local file. In OpenAPI 3.0, exclusiveMinimum and exclusiveMaximum are booleans that modify a numeric minimum or maximum . In OpenAPI 3.1, each exclusive bound is a number. The build rejects a value in the wrong form. OpenAPI 3.1 also accepts true and false as entire schemas, displayed as allowing any value or no value, and an examples array on a schema. OpenAPI 3.0 rejects boolean schemas and schema-level examples . Features requiring adaptation These features have limits that may require adapting the source or authored documentation. Feature Current limit and recovery Remote $ref in a normal build Fails with Remote $ref requires a pinned snapshot . Use api import for public HTTPS sources with same-origin relative references, then build from its local snapshot. Cross-origin references need a separately prepared local source. Local externalValue Fails with local externalValue needs a pinned adapter . Use a local inline example value, or an HTTPS external example link. Callbacks Operation callbacks fail with an unsupported feature diagnostic. Top-level 3.1 webhooks are supported separately. Response headers and links Fail with Response headers or links need an adapter . Prepare a supported documentation source while retaining the original contract separately. Parameter content Requires an adapter; use supported parameter schemas in the documentation source. Request media encoding Fails with Request encoding needs an adapter . Multipart binary fields have limited generated upload commands, bu","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Shoalrun renders a defined subset of OpenAPI into HTML, Markdown, and focused contracts. Check these limits before importing a large specification. A supported OpenAPI version does not mean every feature in that version can be rendered. Compatibility The supported behavior varies by OpenAPI feature and source structure. Area Supported behavior Source formats OpenAPI 3.0.x and 3.1.x in YAML or JSON. kind: file builds from local files; api import can create a pinned local snapshot from a public HTTPS URL. Operations Method and path, server alternatives, CommonMark descriptions, security alternatives and credential details, path and operation parameter overrides, request body media types, responses, and named examples. Webhooks Top-level OpenAPI 3.1 webhooks , including a document without paths ; authored and generated references describe the inbound request and acknowledgement, with no outbound cURL command. Focused contracts retain the webhooks location. Authentication API keys in headers, query strings, or cookies; HTTP schemes; OAuth2 flow names and scopes; OpenID Connect discovery; mutual TLS. These describe authentication; the site does not authenticate or execute requests. References Local $ref within the project or configured OpenAPI source directory, including multiple files. api import downloads same-origin relative references and rewrites them to local snapshot paths. Recursive schemas end with a named reference marker. Absolute file paths and references escaping those directories are rejected. Schemas Objects, arrays, titled variants, discriminators, enums, constants, required fields, defaults, examples, nullable values, supported constraints, additional properties, and read/write/deprecated labels. OpenAPI 3.1 boolean schemas are supported. The exact keyword list is below. Named examples Parameter, request, and response examples maps; reusable components.examples references; names, summaries, descriptions, values, provenance, HTML selection and deep links. All examples appear in Markdown. HTTPS externalValue is an external link, not a fetched payload. Focused contracts One-operation JSON with transitive local components, named examples, security schemes, and internal recursive references. Enabled by source.focused: true or source.publish: true . Reader layout Three columns at wide widths and a stacked order on narrow screens. JSON schemas supply type shapes even without named examples; shapes and named examples are distinct views. Extension metadata Explicit mappings from operation-level x-* values to subjectLifecycle ; OpenAPI deprecated: true takes precedence. Other extensions do not automatically become page metadata. Supported schema keywords The renderer accepts these schema keys, plus x-* extension keys: $ref, type, format, nullable, enum, const, default, minLength, maxLength, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minItems, maxItems, uniqueItems, minProperties, maxProperties, pattern, readOnly, writeOnly, deprecated, description, example, examples, allOf, oneOf, anyOf, items, properties, required, additionalProperties, title, discriminator Other schema keywords fail when encountered by the renderer. This includes valid OpenAPI or JSON Schema keywords outside this list. The compiler presents supported constraints; it is not a general validator for payloads or the entire OpenAPI specification. Exclusive bounds follow the entry document's version even when a schema lives in another local file. In OpenAPI 3.0, exclusiveMinimum and exclusiveMaximum are booleans that modify a numeric minimum or maximum . In OpenAPI 3.1, each exclusive bound is a number. The build rejects a value in the wrong form. OpenAPI 3.1 also accepts true and false as entire schemas, displayed as allowing any value or no value, and an examples array on a schema. OpenAPI 3.0 rejects boolean schemas and schema-level examples . Features requiring adaptation These features have limits that may require adapting the source or authored documentation. Feature Current limit and recovery Remote $ref in a normal build Fails with Remote $ref requires a pinned snapshot . Use api import for public HTTPS sources with same-origin relative references, then build from its local snapshot. Cross-origin references need a separately prepared local source. Local externalValue Fails with local externalValue needs a pinned adapter . Use a local inline example value, or an HTTPS external example link. Callbacks Operation callbacks fail with an unsupported feature diagnostic. Top-level 3.1 webhooks are supported separately. Response headers and links Fail with Response headers or links need an adapter . Prepare a supported documentation source while retaining the original contract separately. Parameter content Requires an adapter; use supported parameter schemas in the documentation source. Request media encoding Fails with Request encoding needs an adapter . Multipart binary fields have limited generated upload commands, bu"},{"filters":{"focus":["write"]},"text":"Add an OpenAPI API — Build a reference page from a supported local specification. Focused OpenAPI contracts — Check what a focused export keeps and drops."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":11000,"markdownTokens":1751,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.output","demo":false,"url":"/publish/output","markdownUrl":"/publish/output.md","title":"Publishing and agent representations","summary":"Read the published-output contract for HTML, Markdown, manifests, and incremental sync.","type":"reference","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[{"id":"published-output-contract","title":"Published-output contract"},{"id":"page-formats","title":"Page formats"},{"id":"where-files-go","title":"Where files go"},{"id":"site-files","title":"Site files"},{"id":"manifest-records-and-sections","title":"Manifest records and sections"},{"id":"navigation-section-indexes","title":"Navigation section indexes"},{"id":"response-identity","title":"Response identity"},{"id":"incremental-sync","title":"Incremental sync"},{"id":"validate-an-existing-build-locally","title":"Validate an existing build locally"},{"id":"api-contracts","title":"API contracts"},{"id":"current-limits","title":"Current limits"},{"id":"code-highlighting","title":"Code highlighting"},{"id":"reader-appearance-and-controls","title":"Reader appearance and controls"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"}],"text":"shoalrun build turns accepted source pages and local OpenAPI files into a static site. A publication is one enabled channel, version, and language combination, such as production, v1, and English. The build includes a public page only in publications matching its frontmatter. It makes no model calls or remote requests. For each included page, the build writes an HTML page for browsing. It also writes a Markdown twin , a generated .md copy that agents can read as text. The Markdown twin can start with a short YAML header. That header contains only the page metadata selected in project config, so agents get useful context without a long source header or internal notes. Shared content appears in both bodies; authors can also add content to either format alone with Only . The site also includes a document manifest , documents.json , which indexes the built pages and their URLs. Projects with an API source can publish operation pages and focused contracts , small OpenAPI files containing one operation and the definitions it needs. Published-output contract This page is the consumer reference for Shoalrun's current published output. It describes the existing producer, not a general format that other generators must implement. The manifest and sync snapshot use schemaVersion: 1 . Editorial revisions to this reference do not change that wire version. The repository maintains JSON Schema 2020-12 definitions at framework/schemas/manifest.schema.json and framework/schemas/sync.schema.json . They specify required fields and known value shapes; this reference explains their meaning. Schema identifiers are stable names for local resolution, not a promise that a site hosts the schema files. Register both schemas together when validating a sync snapshot. They remain repository validation resources and are not added to site output. Consumers must tolerate unknown properties. Optional fields may be absent; absence is not evidence of a negative claim. Removing a required field, changing a field's meaning, or making existing valid output incompatible requires a new wire version. Adding optional fields can retain version 1. Changes to a constrained value set also need compatibility review; accepting unknown properties does not mean a consumer accepts unknown enum values. Capability Availability HTML and Markdown pages Every included public page has both representations. Manifest, sync snapshot, build information, response headers, redirect inventory, and both text discovery indexes Emitted by the build. Empty inventories are allowed. Search indexes Both full and compact indexes are emitted when search indexing is enabled. Section resources Emitted only for eligible sections of sufficiently long pages. Focused contracts and published API sources Emitted when configured for an API source. Sitemap Requires a site origin and enabled indexing. Markdown negotiation, redirect responses, caching, and HTTP 404 status Hosting behavior; the Node server and Vercel adapter implement it. Other hosts need matching rules. Routes include the configured base path and publication prefixes. Start at llms.min.txt under that base path, follow a matching topic index when present, then choose a page by its ID, title, and summary and fetch its Markdown URL. Fetch the manifest when you need structured metadata. Each compact index is limited to 2,000 cl100k_base tokens; total discovery cost depends on the number of indexes you read. A document's identity is (id, channel, version, language) , not its title, URL, or array position. The same ID in two publications identifies two records. That tuple must be unique in both the manifest and sync snapshot. Cite it with the resource URL; for sections, also retain section identity and parent/section digests. A manifest array pointer is a link into that snapshot, not a permanent document identifier. indexable describes indexing, not access. demo: false means unmarked, not a verified service. Missing or null subjectLifecycle does not mean stable. verified is an author's review date, not compiler or independent verification. updated records content freshness and can be a calendar date or a timestamp with a timezone. Reader filters control presentation, not authorization. Page formats Both formats come from the same parsed content. Supported components preserve their documented shared content in Markdown: tab choices, disclosure bodies, reader-marked branches, table rows, resolved snippets, and API examples retain readable content and relevant labels. Unknown components and unsupported dynamic MDX fail compilation. Explicit format-specific branches follow author selection; authors must review equivalent task guidance and completeness. Rendering checks do not prove semantic equivalence or that a reader has every prerequisite. Tabs become labeled sections in Markdown. OpenAPI examples and schemas are expanded during the build, so their values and field details appear as readable text in the twin. A filtered or sticky t","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"shoalrun build turns accepted source pages and local OpenAPI files into a static site. A publication is one enabled channel, version, and language combination, such as production, v1, and English. The build includes a public page only in publications matching its frontmatter. It makes no model calls or remote requests. For each included page, the build writes an HTML page for browsing. It also writes a Markdown twin , a generated .md copy that agents can read as text. The Markdown twin can start with a short YAML header. That header contains only the page metadata selected in project config, so agents get useful context without a long source header or internal notes. Shared content appears in both bodies; authors can also add content to either format alone with Only . The site also includes a document manifest , documents.json , which indexes the built pages and their URLs. Projects with an API source can publish operation pages and focused contracts , small OpenAPI files containing one operation and the definitions it needs. Published-output contract This page is the consumer reference for Shoalrun's current published output. It describes the existing producer, not a general format that other generators must implement. The manifest and sync snapshot use schemaVersion: 1 . Editorial revisions to this reference do not change that wire version. The repository maintains JSON Schema 2020-12 definitions at framework/schemas/manifest.schema.json and framework/schemas/sync.schema.json . They specify required fields and known value shapes; this reference explains their meaning. Schema identifiers are stable names for local resolution, not a promise that a site hosts the schema files. Register both schemas together when validating a sync snapshot. They remain repository validation resources and are not added to site output. Consumers must tolerate unknown properties. Optional fields may be absent; absence is not evidence of a negative claim. Removing a required field, changing a field's meaning, or making existing valid output incompatible requires a new wire version. Adding optional fields can retain version 1. Changes to a constrained value set also need compatibility review; accepting unknown properties does not mean a consumer accepts unknown enum values. Capability Availability HTML and Markdown pages Every included public page has both representations. Manifest, sync snapshot, build information, response headers, redirect inventory, and both text discovery indexes Emitted by the build. Empty inventories are allowed. Search indexes Both full and compact indexes are emitted when search indexing is enabled. Section resources Emitted only for eligible sections of sufficiently long pages. Focused contracts and published API sources Emitted when configured for an API source. Sitemap Requires a site origin and enabled indexing. Markdown negotiation, redirect responses, caching, and HTTP 404 status Hosting behavior; the Node server and Vercel adapter implement it. Other hosts need matching rules. Routes include the configured base path and publication prefixes. Start at llms.min.txt under that base path, follow a matching topic index when present, then choose a page by its ID, title, and summary and fetch its Markdown URL. Fetch the manifest when you need structured metadata. Each compact index is limited to 2,000 cl100k_base tokens; total discovery cost depends on the number of indexes you read. A document's identity is (id, channel, version, language) , not its title, URL, or array position. The same ID in two publications identifies two records. That tuple must be unique in both the manifest and sync snapshot. Cite it with the resource URL; for sections, also retain section identity and parent/section digests. A manifest array pointer is a link into that snapshot, not a permanent document identifier. indexable describes indexing, not access. demo: false means unmarked, not a verified service. Missing or null subjectLifecycle does not mean stable. verified is an author's review date, not compiler or independent verification. updated records content freshness and can be a calendar date or a timestamp with a timezone. Reader filters control presentation, not authorization. Page formats Both formats come from the same parsed content. Supported components preserve their documented shared content in Markdown: tab choices, disclosure bodies, reader-marked branches, table rows, resolved snippets, and API examples retain readable content and relevant labels. Unknown components and unsupported dynamic MDX fail compilation. Explicit format-specific branches follow author selection; authors must review equivalent task guidance and completeness. Rendering checks do not prove semantic equivalence or that a reader has every prerequisite. Tabs become labeled sections in Markdown. OpenAPI examples and schemas are expanded during the build, so their values and field details appear as readable text in the twin. A filtered or sticky t"},{"filters":{"focus":["configure"]},"text":"Agent-friendly documentation — See how these files help agents discover and read the site."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":31086,"markdownTokens":6094,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"published-output-contract","title":"Published-output contract","markdownUrl":"/publish/output.sections/published-output-contract.md","markdownBytes":6623,"markdownTokens":1158},{"id":"page-formats","title":"Page formats","markdownUrl":"/publish/output.sections/page-formats.md","markdownBytes":4697,"markdownTokens":1030},{"id":"where-files-go","title":"Where files go","markdownUrl":"/publish/output.sections/where-files-go.md","markdownBytes":4309,"markdownTokens":846},{"id":"site-files","title":"Site files","markdownUrl":"/publish/output.sections/site-files.md","markdownBytes":8060,"markdownTokens":1782},{"id":"manifest-records-and-sections","title":"Manifest records and sections","markdownUrl":"/publish/output.sections/manifest-records-and-sections.md","markdownBytes":4815,"markdownTokens":1046},{"id":"navigation-section-indexes","title":"Navigation section indexes","markdownUrl":"/publish/output.sections/navigation-section-indexes.md","markdownBytes":3566,"markdownTokens":778},{"id":"response-identity","title":"Response identity","markdownUrl":"/publish/output.sections/response-identity.md","markdownBytes":2818,"markdownTokens":621},{"id":"incremental-sync","title":"Incremental sync","markdownUrl":"/publish/output.sections/incremental-sync.md","markdownBytes":6206,"markdownTokens":1255},{"id":"validate-an-existing-build-locally","title":"Validate an existing build locally","markdownUrl":"/publish/output.sections/validate-an-existing-build-locally.md","markdownBytes":3686,"markdownTokens":781},{"id":"api-contracts","title":"API contracts","markdownUrl":"/publish/output.sections/api-contracts.md","markdownBytes":3092,"markdownTokens":688},{"id":"current-limits","title":"Current limits","markdownUrl":"/publish/output.sections/current-limits.md","markdownBytes":2638,"markdownTokens":596},{"id":"code-highlighting","title":"Code highlighting","markdownUrl":"/publish/output.sections/code-highlighting.md","markdownBytes":2562,"markdownTokens":577},{"id":"reader-appearance-and-controls","title":"Reader appearance and controls","markdownUrl":"/publish/output.sections/reader-appearance-and-controls.md","markdownBytes":4080,"markdownTokens":887},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/output.sections/related-reading.md","markdownBytes":2121,"markdownTokens":484}]},{"id":"guide.page-taxonomy","demo":false,"url":"/author/taxonomy","markdownUrl":"/author/taxonomy.md","title":"Design and enforce a page taxonomy","summary":"Define page categories, validate allowed values, and enforce your project's area and subarea rules.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-metadata","headings":[{"id":"define-allowed-categories","title":"Define allowed categories"},{"id":"classify-pages-by-subject","title":"Classify pages by subject"},{"id":"allow-multiple-areas-when-needed","title":"Allow multiple areas when needed"},{"id":"choose-the-enforcement-level","title":"Choose the enforcement level"},{"id":"related-reading","title":"Related reading"}],"text":"Use area and subarea to describe a page's subject independently of its place in navigation. The same subject can appear in guides, reference pages, recipes, and change notes. Built-in taxonomy enforcement requires @shoalrun/cli@0.1.0-alpha.3 or later. Start with an existing Shoalrun project. You need access to its configuration, authored pages, and build command. Define allowed categories Choose areas that readers recognize and subareas for distinct subjects within them. Keep category IDs stable when changing display labels. Store the definitions and enforcement options in one file: config/taxonomy.yaml required : [ area , subarea ] requireExplicit : [ area , subarea ] areas : components : label : Content components subareas : api-embeds : API examples and schemas diagrams : Diagrams api : label : API documentation subareas : contracts : Contracts Load the file as the project's taxonomy: docs.config.yaml frontmatter : taxonomy : { $include : ./config/taxonomy.yaml } required makes the selected fields mandatory after defaults and enforced values are resolved. requireExplicit also requires those fields in authored source, including drafts. Generated API reference pages can inherit their categories from global frontmatter defaults. Each subarea belongs to its declared parent area. IDs do not need to share a prefix. A subarea ID must be unique across the taxonomy. Classify pages by subject Add the category IDs to a page's frontmatter: area : components subarea : api-embeds The build rejects unknown categories, missing required tags, and subareas that do not belong to the selected area. It applies the checks to authored pages and resolved generated references. The generated frontmatter schema exposes the same vocabulary and pair constraints for editors. Shoalrun publishes the definitions in documents.json under taxonomy . Individual page records and search indexes carry their resolved categories. To expose category IDs in Markdown frontmatter, add area: frontmatter.area and subarea: frontmatter.subarea to outputs.markdown.metadata.fields . Allow multiple areas when needed A site permits one area and one subarea per page by default. Enable lists only for the fields your project needs: config/taxonomy.yaml required : [ area , subarea ] requireExplicit : [ area , subarea ] multiple : [ area , subarea ] areas : components : label : Content components subareas : api-embeds : API examples and schemas api : label : API documentation subareas : contracts : Contracts A page can then belong to both subjects: area : [ components , api ] subarea : [ api-embeds , contracts ] Lists must be nonempty and contain unique IDs. Every subarea must belong to at least one selected area. Scalar values remain valid when multiple values are enabled. Use multiple: [area] if only areas may have several values; subareas then remain single-valued. A matching configured reader facet receives all selected values. See reader views for facet controls and matching. Category enforcement works without configuring reader facets. Choose the enforcement level Omit required to validate categories only where supplied. Omit requireExplicit to let authored pages inherit categories. Omit multiple to keep both fields single-valued. Omit frontmatter.taxonomy or set it to false to leave category fields optional with their existing behavior. Configured reader facets continue to validate their own choices. Run the ordinary build after editing the definitions or page tags: npx --no-install shoalrun build docs.config.yaml dist Verify that missing required fields, unknown IDs, wrong parent pairs, and disallowed lists fail. Restore valid tags and inspect a generated page and the published taxonomy. When renaming or removing a category, update the definitions and affected pages together. Related reading Page metadata describes the native category fields. Reader views explains how category values become facets. Custom metadata covers defaults and additional fields.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Use area and subarea to describe a page's subject independently of its place in navigation. The same subject can appear in guides, reference pages, recipes, and change notes. Built-in taxonomy enforcement requires @shoalrun/cli@0.1.0-alpha.3 or later. Start with an existing Shoalrun project. You need access to its configuration, authored pages, and build command. Define allowed categories Choose areas that readers recognize and subareas for distinct subjects within them. Keep category IDs stable when changing display labels. Store the definitions and enforcement options in one file: required: [area, subarea] requireExplicit: [area, subarea] areas: components: label: Content components subareas: api-embeds: API examples and schemas diagrams: Diagrams api: label: API documentation subareas: contracts: Contracts Load the file as the project's taxonomy: frontmatter: taxonomy: { $include: ./config/taxonomy.yaml } required makes the selected fields mandatory after defaults and enforced values are resolved. requireExplicit also requires those fields in authored source, including drafts. Generated API reference pages can inherit their categories from global frontmatter defaults. Each subarea belongs to its declared parent area. IDs do not need to share a prefix. A subarea ID must be unique across the taxonomy. Classify pages by subject Add the category IDs to a page's frontmatter: area: components subarea: api-embeds The build rejects unknown categories, missing required tags, and subareas that do not belong to the selected area. It applies the checks to authored pages and resolved generated references. The generated frontmatter schema exposes the same vocabulary and pair constraints for editors. Shoalrun publishes the definitions in documents.json under taxonomy . Individual page records and search indexes carry their resolved categories. To expose category IDs in Markdown frontmatter, add area: frontmatter.area and subarea: frontmatter.subarea to outputs.markdown.metadata.fields . Allow multiple areas when needed A site permits one area and one subarea per page by default. Enable lists only for the fields your project needs: required: [area, subarea] requireExplicit: [area, subarea] multiple: [area, subarea] areas: components: label: Content components subareas: api-embeds: API examples and schemas api: label: API documentation subareas: contracts: Contracts A page can then belong to both subjects: area: [components, api] subarea: [api-embeds, contracts] Lists must be nonempty and contain unique IDs. Every subarea must belong to at least one selected area. Scalar values remain valid when multiple values are enabled. Use multiple: [area] if only areas may have several values; subareas then remain single-valued. A matching configured reader facet receives all selected values. See reader views for facet controls and matching. Category enforcement works without configuring reader facets. Choose the enforcement level Omit required to validate categories only where supplied. Omit requireExplicit to let authored pages inherit categories. Omit multiple to keep both fields single-valued. Omit frontmatter.taxonomy or set it to false to leave category fields optional with their existing behavior. Configured reader facets continue to validate their own choices. Run the ordinary build after editing the definitions or page tags: npx --no-install shoalrun build docs.config.yaml dist Verify that missing required fields, unknown IDs, wrong parent pairs, and disallowed lists fail. Restore valid tags and inspect a generated page and the published taxonomy. When renaming or removing a category, update the definitions and affected pages together. Related reading Page metadata describes the native category fields. Reader views explains how category values become facets. Custom metadata covers defaults and additional fields."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5174,"markdownTokens":1166,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.palettes","demo":false,"url":"/styling/palettes","markdownUrl":"/styling/palettes.md","title":"Color palettes","summary":"Use a built-in palette or extend one with your brand colors. The build checks every palette against WCAG contrast.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-themes","headings":[{"id":"built-in-palettes","title":"Built-in palettes"},{"id":"add-brand-colors","title":"Add brand colors"},{"id":"contrast-checks","title":"Contrast checks"},{"id":"check-colors-in-ci","title":"Check colors in CI"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"related-topics","title":"Related topics"}],"text":"A palette sets every color token on the site, with one set for light mode and one for dark mode. Choose a built-in palette by name, or extend one with your own colors. Built-in palettes Choose a built-in palette as the starting point for your site colors. Palette Colors kelp Sea green on white. The light set matches the base tokens in tokens.css . coral Coral accent over cool blue-gray neutrals. ink Black ink on warm paper with a vermilion accent. harbor Navy ink, blue links, and a yellow callout rule. amethyst Violet accents over lavender neutrals. vice Flamingo pink and aqua by day, and neon on a night-purple sky after dark. docs.config.yaml theme : palette : amethyst Each preset has a default palette, so you only need palette to change it. Add brand colors Extend a built-in palette and override only the tokens you need. Write token names without the --color- prefix: docs.config.yaml theme : palette : extends : harbor light : accent : \"#0a6a48\" link : \"#0a6a48\" emphasis : \"#0a6a48\" dark : accent : \"#4fd6a4\" accent-contrast : \"#06231a\" link : \"#7fe0bd\" extends defaults to the preset's palette. light and dark are both optional. Values must be three- or six-digit hex colors such as \"#0a6a48\" . Quote them, because YAML treats # as the start of a comment. To keep the colors in their own files, include each mode's token map and keep extends in the main config: docs.config.yaml theme : palette : extends : harbor light : { $include : ./styles/brand-light.yaml } dark : { $include : ./styles/brand-dark.yaml } styles/brand-light.yaml accent : \"#0a6a48\" link : \"#0a6a48\" Don't include a file that sets extends at its top level. The config loader reads a top-level extends in any config file as a list of config presets , so extends: harbor there fails the build. Most brands need four tokens or fewer: Token Controls accent Brand mark, primary header button, and active navigation marker. accent-contrast Text on accent , such as the primary button label. link and link-hover Links at rest and on hover. emphasis Eyebrows, card icons, and search highlights. The CSS and theme reference lists every token. Contrast checks The build checks each palette against WCAG 2.2 before it writes any files. It checks the light set, the dark set, or both, depending on the mode . If a pair fails, the build stops and names it: Theme colors fail WCAG 2.2 contrast: - light: link #9fe6cc on page #ffffff is 1.40:1; needs 4.5:1 Success criterion 1.4.3 requires 4.5:1 for text against its background. Success criterion 1.4.11 requires 3:1 for focus rings, form field borders, and the accent fill against the page. The build checks these pairs: Body text, muted text, links, headings, navigation text, and summaries on the page, surface, and field backgrounds. Hovered links, callout text, and inline code on their backgrounds. Body text, links, and labels in each callout type: note, tip, important, warning, and caution. Body text, links, and labels on each custom callout tone from callouts.tones . Active navigation, subject lifecycle badges, and required and optional field badges. Code text and code labels on code blocks. accent-contrast on accent , and strong-text on strong-surface . focus , field-border , and accent against the page and surface. Every built-in palette passes in both modes. The framework tests check them on every change. Check colors in CI shoalrun config validate runs the same check without building the site. It prints the same messages and exits with status 1 when a pair fails, so a CI step can stop a change before it merges: shoalrun config validate docs.config.yaml On success, its JSON output includes \"contrast\": { \"status\": \"ok\", \"palette\": \"kelp\", \"modes\": [\"light\"] } . shoalrun audit also fails on a contrast problem, because it builds the site. The check covers palette colors only. Colors you set in project CSS , and syntax colors from a named Shiki theme, are not checked. Test those yourself. The default site code theme derives its syntax colors from the palette and replaces any that fall below 4.5:1 with plain code text. Related reading Read first Themes — Pick the preset that the palette colors. Related topics Light and dark mode — A palette has one color set for light mode and one for dark mode.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"A palette sets every color token on the site, with one set for light mode and one for dark mode. Choose a built-in palette by name, or extend one with your own colors. Built-in palettes Choose a built-in palette as the starting point for your site colors. Palette Colors kelp Sea green on white. The light set matches the base tokens in tokens.css . coral Coral accent over cool blue-gray neutrals. ink Black ink on warm paper with a vermilion accent. harbor Navy ink, blue links, and a yellow callout rule. amethyst Violet accents over lavender neutrals. vice Flamingo pink and aqua by day, and neon on a night-purple sky after dark. theme: palette: amethyst Each preset has a default palette, so you only need palette to change it. Add brand colors Extend a built-in palette and override only the tokens you need. Write token names without the --color- prefix: theme: palette: extends: harbor light: accent: \"#0a6a48\" link: \"#0a6a48\" emphasis: \"#0a6a48\" dark: accent: \"#4fd6a4\" accent-contrast: \"#06231a\" link: \"#7fe0bd\" extends defaults to the preset's palette. light and dark are both optional. Values must be three- or six-digit hex colors such as \"#0a6a48\" . Quote them, because YAML treats # as the start of a comment. To keep the colors in their own files, include each mode's token map and keep extends in the main config: theme: palette: extends: harbor light: { $include: ./styles/brand-light.yaml } dark: { $include: ./styles/brand-dark.yaml } accent: \"#0a6a48\" link: \"#0a6a48\" Don't include a file that sets extends at its top level. The config loader reads a top-level extends in any config file as a list of config presets , so extends: harbor there fails the build. Most brands need four tokens or fewer: Token Controls accent Brand mark, primary header button, and active navigation marker. accent-contrast Text on accent , such as the primary button label. link and link-hover Links at rest and on hover. emphasis Eyebrows, card icons, and search highlights. The CSS and theme reference lists every token. Contrast checks The build checks each palette against WCAG 2.2 before it writes any files. It checks the light set, the dark set, or both, depending on the mode . If a pair fails, the build stops and names it: Theme colors fail WCAG 2.2 contrast: - light: link #9fe6cc on page #ffffff is 1.40:1; needs 4.5:1 Success criterion 1.4.3 requires 4.5:1 for text against its background. Success criterion 1.4.11 requires 3:1 for focus rings, form field borders, and the accent fill against the page. The build checks these pairs: Body text, muted text, links, headings, navigation text, and summaries on the page, surface, and field backgrounds. Hovered links, callout text, and inline code on their backgrounds. Body text, links, and labels in each callout type: note, tip, important, warning, and caution. Body text, links, and labels on each custom callout tone from callouts.tones . Active navigation, subject lifecycle badges, and required and optional field badges. Code text and code labels on code blocks. accent-contrast on accent , and strong-text on strong-surface . focus , field-border , and accent against the page and surface. Every built-in palette passes in both modes. The framework tests check them on every change. Check colors in CI shoalrun config validate runs the same check without building the site. It prints the same messages and exits with status 1 when a pair fails, so a CI step can stop a change before it merges: shoalrun config validate docs.config.yaml On success, its JSON output includes \"contrast\": { \"status\": \"ok\", \"palette\": \"kelp\", \"modes\": [\"light\"] } . shoalrun audit also fails on a contrast problem, because it builds the site. The check covers palette colors only. Colors you set in project CSS , and syntax colors from a named Shiki theme, are not checked. Test those yourself. The default site code theme derives its syntax colors from the palette and replaces any that fall below 4.5:1 with plain code text. Related reading Read first Related topics"},{"filters":{"focus":["configure"]},"text":"Themes — Pick the preset that the palette colors. Light and dark mode — A palette has one color set for light mode and one for dark mode."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6300,"markdownTokens":1545,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.passage-index","demo":false,"url":"/chat/passage-index","markdownUrl":"/chat/passage-index.md","title":"Passage index","summary":"Passage file formats, chunking rules, identifiers, embedding behavior, and limits.","type":"reference","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"build-the-index","title":"Build the index"},{"id":"how-the-default-chunker-splits-a-page","title":"How the default chunker splits a page"},{"id":"what-a-passage-contains","title":"What a passage contains"},{"id":"embedding-input","title":"Embedding input"},{"id":"passage-ids-and-links","title":"Passage IDs and links"},{"id":"embed-passages","title":"Embed passages"},{"id":"choose-a-provider","title":"Choose a provider"},{"id":"embed-queries-with-a-different-model","title":"Embed queries with a different model"},{"id":"limits","title":"Limits"},{"id":"related-reading","title":"Related reading"}],"text":"A passage index splits built Markdown pages into smaller pieces for retrieval. Each passage keeps its page title, heading path, and source link. Chat and custom passage-search providers use it to find relevant parts of a page. The built-in search box uses the separate page-level search-index.json . You do not need a passage index for normal static-site search. Create the files after building the site: Command Adds Provider requests shoalrun index ai/chunks.json , the passage text and metadata. None. shoalrun index --embed Passage index plus embedding metadata and vectors. Sends embedding input to the configured provider. Indexing leaves published page content unchanged. The files sit beside the build output, and you must rebuild the index when that output changes. Build the index Build the site, then run shoalrun index on the output directory: shoalrun build docs.config.yaml site-dist shoalrun index site-dist The command prints a summary as JSON: { \"status\" : \"ok\" , \"documents\" : 77 , \"chunks\" : 725 , \"output\" : \"/path/to/site-dist/ai/chunks.json\" } The command reads three files from the build output: File Use documents.json The list of published pages, with each page's ID, URL, publication, and digest. Each page's .md twin The text to split. search-index.json The heading IDs that passage links use. Optional. It writes ai/chunks.json . Without --embed , it makes no network requests. Run it after each build. It replaces the previous file. Indexing also prepares readable paragraphs, code lines, and table rows for passage-search results. Search requests use that prepared data instead of parsing Markdown on first use. If serving search rejects an older index, rerun shoalrun index site-dist . Existing embeddings remain usable when the passage text and embedding settings are unchanged. Because it reads built output, the index holds only published pages in each publication. Drafts and pages outside enabled publications never appear. How the default chunker splits a page The default chunker follows structure. It doesn't cut text into fixed-length windows. Split at ## and ### headings. Text before the first ## heading forms an intro passage. Headings at #### and below stay inside their section's text. Keep blocks whole. A paragraph, list, table, or code block is never cut mid-block, except for large tables in step 4. Fill passages up to 2,000 characters. A section longer than that splits between blocks into a first passage and later parts. Split large tables between rows. Each part repeats the table's header rows, so every row keeps its column names. Keep large code blocks whole. A code block over the limit becomes one passage that exceeds it. Fenced code never starts a heading, so # comments inside a fence don't split a section. Merge short sections into their first subsection. A section under 200 characters with a subsection below it joins that subsection's first passage. A short section with no subsection stays a passage of its own. These limits are fixed. You can't configure the chunker or replace it yet. The number of passages changes as the documentation grows. Most passages are a few hundred characters long, and nearly all stay under 2,000. What a passage contains Each entry in chunks describes one passage: ai/chunks.json { \"id\" : \"guide.configuration#understand-the-three-stages\" , \"docId\" : \"guide.configuration\" , \"title\" : \"Organize project configuration\" , \"type\" : \"how-to\" , \"variant\" : \"production|current|en\" , \"headingPath\" : [ \"Understand the three stages\" ] , \"url\" : \"/configuration#understand-the-three-stages\" , \"markdownUrl\" : \"/configuration.md\" , \"text\" : \"Configuration takes effect in three stages:\\n\\n1. **Resolve co…\" , \"digest\" : \"be259c2f4c0c896d1fe25ed496ac642f97391744675e06ee844f09372e47767a\" , \"search\" : { \"schemaVersion\" : 1 , \"paragraphs\" : [ \"Configuration takes effect in three stages: …\" ] , \"literalLines\" : [] } } Field Value id The passage ID. See Passage IDs . docId , title , type The page's ID, title, and type. variant The page's channel, version, and language, joined by | . Passages from different publications never mix. headingPath The ## and ### headings above the passage, outermost first. Empty for an intro passage. url The page URL, plus # and the section's heading ID when one exists. markdownUrl The page's Markdown twin. readerFilters Optional. The page's reader marks, such as { \"audience\": [\"maintainers\"] } . It is present only when the page has marks. Retrieval uses it to answer for one audience. text The passage's Markdown, without its own heading. digest A SHA-256 hash of the passage's embedding input. search Prepared result content: schemaVersion: 1 , explanatory paragraphs , and code/table literalLines . Generated navigation lists are excluded from the paragraphs. The file also records schemaVersion and a sourceDigest that changes when any page's digest changes. Embedding input The heading path isn't part of text . Anything that scores or embeds a passage reads the page ","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"A passage index splits built Markdown pages into smaller pieces for retrieval. Each passage keeps its page title, heading path, and source link. Chat and custom passage-search providers use it to find relevant parts of a page. The built-in search box uses the separate page-level search-index.json . You do not need a passage index for normal static-site search. Create the files after building the site: Command Adds Provider requests shoalrun index ai/chunks.json , the passage text and metadata. None. shoalrun index --embed Passage index plus embedding metadata and vectors. Sends embedding input to the configured provider. Indexing leaves published page content unchanged. The files sit beside the build output, and you must rebuild the index when that output changes. Build the index Build the site, then run shoalrun index on the output directory: shoalrun build docs.config.yaml site-dist shoalrun index site-dist The command prints a summary as JSON: { \"status\": \"ok\", \"documents\": 77, \"chunks\": 725, \"output\": \"/path/to/site-dist/ai/chunks.json\" } The command reads three files from the build output: File Use documents.json The list of published pages, with each page's ID, URL, publication, and digest. Each page's .md twin The text to split. search-index.json The heading IDs that passage links use. Optional. It writes ai/chunks.json . Without --embed , it makes no network requests. Run it after each build. It replaces the previous file. Indexing also prepares readable paragraphs, code lines, and table rows for passage-search results. Search requests use that prepared data instead of parsing Markdown on first use. If serving search rejects an older index, rerun shoalrun index site-dist . Existing embeddings remain usable when the passage text and embedding settings are unchanged. Because it reads built output, the index holds only published pages in each publication. Drafts and pages outside enabled publications never appear. How the default chunker splits a page The default chunker follows structure. It doesn't cut text into fixed-length windows. Split at ## and ### headings. Text before the first ## heading forms an intro passage. Headings at #### and below stay inside their section's text. Keep blocks whole. A paragraph, list, table, or code block is never cut mid-block, except for large tables in step 4. Fill passages up to 2,000 characters. A section longer than that splits between blocks into a first passage and later parts. Split large tables between rows. Each part repeats the table's header rows, so every row keeps its column names. Keep large code blocks whole. A code block over the limit becomes one passage that exceeds it. Fenced code never starts a heading, so # comments inside a fence don't split a section. Merge short sections into their first subsection. A section under 200 characters with a subsection below it joins that subsection's first passage. A short section with no subsection stays a passage of its own. These limits are fixed. You can't configure the chunker or replace it yet. The number of passages changes as the documentation grows. Most passages are a few hundred characters long, and nearly all stay under 2,000. What a passage contains Each entry in chunks describes one passage: { \"id\": \"guide.configuration#understand-the-three-stages\", \"docId\": \"guide.configuration\", \"title\": \"Organize project configuration\", \"type\": \"how-to\", \"variant\": \"production|current|en\", \"headingPath\": [\"Understand the three stages\"], \"url\": \"/configuration#understand-the-three-stages\", \"markdownUrl\": \"/configuration.md\", \"text\": \"Configuration takes effect in three stages:\\n\\n1. **Resolve co…\", \"digest\": \"be259c2f4c0c896d1fe25ed496ac642f97391744675e06ee844f09372e47767a\", \"search\": { \"schemaVersion\": 1, \"paragraphs\": [\"Configuration takes effect in three stages: …\"], \"literalLines\": [] } } Field Value id The passage ID. See Passage IDs . docId , title , type The page's ID, title, and type. variant The page's channel, version, and language, joined by | . Passages from different publications never mix. headingPath The ## and ### headings above the passage, outermost first. Empty for an intro passage. url The page URL, plus # and the section's heading ID when one exists. markdownUrl The page's Markdown twin. readerFilters Optional. The page's reader marks, such as { \"audience\": [\"maintainers\"] } . It is present only when the page has marks. Retrieval uses it to answer for one audience. text The passage's Markdown, without its own heading. digest A SHA-256 hash of the passage's embedding input. search Prepared result content: schemaVersion: 1 , explanatory paragraphs , and code/table literalLines . Generated navigation lists are excluded from the paragraphs. The file also records schemaVersion and a sourceDigest that changes when any page's digest changes. Embedding input The heading path isn't part of text . Anything that scores or embeds a passage reads the page title, the heading path, and the text together: Orga"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14109,"markdownTokens":2790,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"build-the-index","title":"Build the index","markdownUrl":"/chat/passage-index.sections/build-the-index.md","markdownBytes":3584,"markdownTokens":749},{"id":"how-the-default-chunker-splits-a-page","title":"How the default chunker splits a page","markdownUrl":"/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md","markdownBytes":3322,"markdownTokens":736},{"id":"what-a-passage-contains","title":"What a passage contains","markdownUrl":"/chat/passage-index.sections/what-a-passage-contains.md","markdownBytes":5878,"markdownTokens":1123},{"id":"passage-ids-and-links","title":"Passage IDs and links","markdownUrl":"/chat/passage-index.sections/passage-ids-and-links.md","markdownBytes":3220,"markdownTokens":668},{"id":"embed-passages","title":"Embed passages","markdownUrl":"/chat/passage-index.sections/embed-passages.md","markdownBytes":5680,"markdownTokens":1179},{"id":"limits","title":"Limits","markdownUrl":"/chat/passage-index.sections/limits.md","markdownBytes":2611,"markdownTokens":577},{"id":"related-reading","title":"Related reading","markdownUrl":"/chat/passage-index.sections/related-reading.md","markdownBytes":2069,"markdownTokens":450}]},{"id":"guide.prepared-answers","demo":false,"url":"/chat/prepared-answers","markdownUrl":"/chat/prepared-answers.md","title":"Generate and refresh answer cards","summary":"Generate and review common answers ahead of time, then serve confirmed cards without a new chat-model answer.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-chat","headings":[{"id":"what-you-need","title":"What you need"},{"id":"list-the-questions","title":"List the questions"},{"id":"build-the-cards","title":"Build the cards"},{"id":"how-a-card-is-used","title":"How a card is used"},{"id":"keep-cards-current","title":"Keep cards current"},{"id":"find-questions-worth-a-card","title":"Find questions worth a card"},{"id":"where-cards-work","title":"Where cards work"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"}],"text":"An answer card stores a reviewed answer to a recurring question. Generate cards after local chat works, then review their text before serving them. Start in your documentation project root with the CLI available. A confirmed card avoids generating a new answer. Matching still calls the embedding provider and relevance scorer. Note: An answer card is not a page card. Page cards preview another page; see Cards and collections . Answer cards are stored answers. What you need A site indexed with --embed . See Passage index . A chat section with rerank: jev and a cards setting. See Retrieval and chat settings . A configured chat service and the provider keys used by shoalrun ask . Card generation can make new provider requests each time it runs. List the questions Write the questions in a YAML or JSON file. Each is a string, or a mapping with question and aliases . Aliases are other ways to ask the same thing. config/answers.yaml - question : how do I reset my password aliases : [ forgot my password , change my password ] - question : how do I export my data The file can live anywhere. You pass its path to the next command. Build the cards Card generation uses providers and can produce different wording on each run: index --embed sends new or changed passages to the embedding provider. answers calls the embedding provider and scorer, then the chat model for questions that pass the coverage gate. Fallback and escalation settings can add chat-model calls. Run the commands, then review the generated file before publishing: shoalrun index site-dist --embed shoalrun answers site-dist --questions config/answers.yaml Each question goes through the normal retrieval and answer checks. The command turns off card reuse and direct excerpts while generating cards, so an accepted card contains a freshly written answer. It also embeds each kept question and its aliases for later similarity matching. A question the docs do not cover may be declined before a chat-model call. The command writes ai/answers.json and reports kept and skipped questions. It skips a question when: The docs don't cover it. The answer was hedged. The answer cites nothing. A check flagged a sentence, some code, or a citation. A skipped question is a signal. Either the docs need a page for it, or the question is too broad for one answer. ai/answers.json is plain JSON. Each card holds its question, aliases, answer, sources, and the digest of every passage behind it. Read the answers before you ship them. The command writes the whole file each time, so to drop a card, remove its question from your list and run the command again. How a card is used With chat.cards set, a question that opens a conversation is checked against cards in two steps: The query embedding provider embeds the new question. Its vector is compared with each card's question vectors. A card at least threshold similar is shortlisted. The default is 0.75. The relevance scorer checks whether the card's stored answer really answers this question. The card is used only at confirm or higher. The default is 0.9. A confirmed card needs no new chat-model answer. Similarity alone can confuse related questions, such as turning notifications on versus turning them off. Scorer confirmation is a separate check against the stored answer. If no card is confirmed, the question follows the normal answer pipeline. A follow-up never uses a card. A card also belongs to one publication and reader view, and a question asked in another view never uses it. --no-cards on shoalrun ask turns cards off for one run. Keep cards current A card records the digest of each source passage. When a passage changes, the card stops being used without a warning. Run shoalrun answers after documentation changes to refresh the cards. If ai/answers.json is missing, or was made with a different embedding model, ask says so and carries on without cards. Find questions worth a card The question log shows what readers ask. Questions that were asked at least twice, that the model answered cleanly, and that no card covers make good candidates. shoalrun ask-log ask.jsonl --cards-out candidates.yaml --cards-out writes a new file and never replaces one. Review the list and move the questions you want into your questions file. Change the repeat count with --min-repeats . See Keep a record of questions for how to record the log. Where cards work Cards work in the terminal, the local panel, and the Vercel chat function. For Vercel, build with --chat , then run shoalrun answers against the function's private site directory before deployment. The function reads site/ai/answers.json from that directory. A plain shoalrun vercel build --chat embeds passages but does not generate cards. This repository's npm run docs:build-all performs both steps. See Publish on Vercel for the deployment workflow. Related reading Reference while working CLI reference — Look up the answers and ask-log commands and the --no-cards option. Retrieval and chat settings — L","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"An answer card stores a reviewed answer to a recurring question. Generate cards after local chat works, then review their text before serving them. Start in your documentation project root with the CLI available. A confirmed card avoids generating a new answer. Matching still calls the embedding provider and relevance scorer. Note: An answer card is not a page card. Page cards preview another page; see Cards and collections . Answer cards are stored answers. What you need A site indexed with --embed . See Passage index . A chat section with rerank: jev and a cards setting. See Retrieval and chat settings . A configured chat service and the provider keys used by shoalrun ask . Card generation can make new provider requests each time it runs. List the questions Write the questions in a YAML or JSON file. Each is a string, or a mapping with question and aliases . Aliases are other ways to ask the same thing. - question: how do I reset my password aliases: [forgot my password, change my password] - question: how do I export my data The file can live anywhere. You pass its path to the next command. Build the cards Card generation uses providers and can produce different wording on each run: index --embed sends new or changed passages to the embedding provider. answers calls the embedding provider and scorer, then the chat model for questions that pass the coverage gate. Fallback and escalation settings can add chat-model calls. Run the commands, then review the generated file before publishing: shoalrun index site-dist --embed shoalrun answers site-dist --questions config/answers.yaml Each question goes through the normal retrieval and answer checks. The command turns off card reuse and direct excerpts while generating cards, so an accepted card contains a freshly written answer. It also embeds each kept question and its aliases for later similarity matching. A question the docs do not cover may be declined before a chat-model call. The command writes ai/answers.json and reports kept and skipped questions. It skips a question when: The docs don't cover it. The answer was hedged. The answer cites nothing. A check flagged a sentence, some code, or a citation. A skipped question is a signal. Either the docs need a page for it, or the question is too broad for one answer. ai/answers.json is plain JSON. Each card holds its question, aliases, answer, sources, and the digest of every passage behind it. Read the answers before you ship them. The command writes the whole file each time, so to drop a card, remove its question from your list and run the command again. How a card is used With chat.cards set, a question that opens a conversation is checked against cards in two steps: The query embedding provider embeds the new question. Its vector is compared with each card's question vectors. A card at least threshold similar is shortlisted. The default is 0.75. The relevance scorer checks whether the card's stored answer really answers this question. The card is used only at confirm or higher. The default is 0.9. A confirmed card needs no new chat-model answer. Similarity alone can confuse related questions, such as turning notifications on versus turning them off. Scorer confirmation is a separate check against the stored answer. If no card is confirmed, the question follows the normal answer pipeline. A follow-up never uses a card. A card also belongs to one publication and reader view, and a question asked in another view never uses it. --no-cards on shoalrun ask turns cards off for one run. Keep cards current A card records the digest of each source passage. When a passage changes, the card stops being used without a warning. Run shoalrun answers after documentation changes to refresh the cards. If ai/answers.json is missing, or was made with a different embedding model, ask says so and carries on without cards. Find questions worth a card The question log shows what readers ask. Questions that were asked at least twice, that the model answered cleanly, and that no card covers make good candidates. shoalrun ask-log ask.jsonl --cards-out candidates.yaml --cards-out writes a new file and never replaces one. Review the list and move the questions you want into your questions file. Change the repeat count with --min-repeats . See Keep a record of questions for how to record the log. Where cards work Cards work in the terminal, the local panel, and the Vercel chat function. For Vercel, build with --chat , then run shoalrun answers against the function's private site directory before deployment. The function reads site/ai/answers.json from that directory. A plain shoalrun vercel build --chat embeds passages but does not generate cards. This repository's npm run docs:build-all performs both steps. See Publish on Vercel for the deployment workflow. Related reading Reference while working CLI reference — Look up the answers and ask-log commands and the --no-cards option."},{"filters":{"focus":["configure"]},"text":"Retrieval and chat settings — Look up the chat.cards settings. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6429,"markdownTokens":1485,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.publications","demo":false,"url":"/publish/publications","markdownUrl":"/publish/publications.md","title":"Share pages across documentation versions","summary":"Versioning one docs site without copying every page: share unchanged pages, vary sections, and publish changed pages separately.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-versions","headings":[{"id":"choose-which-versions-exist","title":"Choose which versions exist"},{"id":"keep-an-unchanged-page-in-one-file","title":"Keep an unchanged page in one file"},{"id":"change-just-one-part-of-a-shared-page","title":"Change just one part of a shared page"},{"id":"give-each-api-version-its-own-contract","title":"Give each API version its own contract"},{"id":"what-agents-receive","title":"What agents receive"},{"id":"add-a-language","title":"Add a language"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Say you support v1 and v2. Your setup instructions are mostly the same, but v2 has a new credential and one extra guide. You can keep the common instructions in one source file , show the right credential in each version, and publish the extra guide only in v2. Shoalrun calls each channel, version, and language combination a publication . You choose which publications a build makes. A Git branch or tag chooses which revision of the repository to build ; it does not automatically create a docs version. For separate sites such as stable and next, see publish separate docs sites from Git . For separate sites selected by audience, product, region, or another configured facet, see build sites from shared content . That workflow shares one content directory and uses a separate entry config and output directory for each site. Choose which versions exist This config publishes two versions at /v1 and /v2 : docs.config.yaml (fragment) publications : defaults : { channel : production , version : v1 , language : en } channels : production : { pathPrefix : \"\" } versions : v1 : { pathPrefix : /v1 } v2 : { pathPrefix : /v2 } enabled : - { channel : production , version : v1 , language : en } - { channel : production , version : v2 , language : en } enabled sets the combinations the build may publish. It does not create pages or fill gaps in them. The paths come from the prefixes above plus each page's slug . Keep an unchanged page in one file List the versions that should receive the page in its frontmatter. This one file creates /v1/start and /v2/start : content/start.mdx --- id : guide.start title : Get started summary : Set up your first request. type : guide slug : /start publications : - { channel : production , version : v1 } - { channel : production , version : v2 } language : en access : { policy : public } --- Install the client and create a project. The publications list is explicit: add a version when the page should appear there, and omit it when the page should not. Only enabled combinations are built. Keep the same id and slug in every publication so links and the Version menu can find the corresponding page. A shared file cannot also set page-level channel or version . Change just one part of a shared page Put version-specific content inside <ForPublication> . The rest of the page stays shared: Create a project, then choose a credential. < ForPublication version = \"v1\" > Use a legacy key. </ ForPublication > < ForPublication version = \"v2\" > Use a scoped key. [ Set permissions ](doc:guide.permissions) </ ForPublication > You can select a channel , version , language , or a combination, such as <ForPublication channel=\"sandbox\" version=\"v2\"> . Omitted attributes match any value. The block needs at least one attribute and ordinary block content. A doc: link inside a block resolves in that publication, so a v2-only target can live in a v2-only block. If a whole page changes substantially, write separate source files with the same id and slug , each with its own channel and version . If a page exists only in v2, write only its v2 file. You do not need a blank v1 copy. The Version menu shows a matching page only where one was published. Source choice Result One file listing v1 and v2 The same page appears at both paths. One file listing v1 and v2, with <ForPublication> blocks Shared text appears in both; each version gets its own selected blocks. Two files with the same ID, one for each version Each version gets different page content. One file assigned only to v2 The page appears only in v2. Run shoalrun build docs.config.yaml dist and inspect dist/documents.json for the actual pages and routes. Links, navigation, search, and the Version menu use those published variants. A link to a page missing from the current publication fails the build instead of sending readers to another version. Give each API version its own contract When API behavior differs by version, bind an OpenAPI file to each publication in apis.<name>.publications . The top-level API source belongs to publications.defaults . A shared guide can refer to the same stable operation ID in both versions; each version resolves that operation against its own API source. The build fails if a page needs an API operation but that publication has no source. See API references for the config and example configs for full projects. What agents receive Each published page has a Markdown copy at its route plus .md , such as /v1/start.md and /v2/start.md . These are separate artifacts built from the same source file. Each copy includes only its own <ForPublication> sections, so an agent reading v1 instructions does not see v2-only text. documents.json , search-index.json , and the site's agent discovery files list the published variants and their Markdown URLs. A missing version of a page has no Markdown copy or search result. Published outputs lists those files. For channel and prefix rules, see the publication config","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Say you support v1 and v2. Your setup instructions are mostly the same, but v2 has a new credential and one extra guide. You can keep the common instructions in one source file , show the right credential in each version, and publish the extra guide only in v2. Shoalrun calls each channel, version, and language combination a publication . You choose which publications a build makes. A Git branch or tag chooses which revision of the repository to build ; it does not automatically create a docs version. For separate sites such as stable and next, see publish separate docs sites from Git . For separate sites selected by audience, product, region, or another configured facet, see build sites from shared content . That workflow shares one content directory and uses a separate entry config and output directory for each site. Choose which versions exist This config publishes two versions at /v1 and /v2 : publications: defaults: { channel: production, version: v1, language: en } channels: production: { pathPrefix: \"\" } versions: v1: { pathPrefix: /v1 } v2: { pathPrefix: /v2 } enabled: - { channel: production, version: v1, language: en } - { channel: production, version: v2, language: en } enabled sets the combinations the build may publish. It does not create pages or fill gaps in them. The paths come from the prefixes above plus each page's slug . Keep an unchanged page in one file List the versions that should receive the page in its frontmatter. This one file creates /v1/start and /v2/start : --- id: guide.start title: Get started summary: Set up your first request. type: guide slug: /start publications: - { channel: production, version: v1 } - { channel: production, version: v2 } language: en access: { policy: public } --- Install the client and create a project. The publications list is explicit: add a version when the page should appear there, and omit it when the page should not. Only enabled combinations are built. Keep the same id and slug in every publication so links and the Version menu can find the corresponding page. A shared file cannot also set page-level channel or version . Change just one part of a shared page Put version-specific content inside <ForPublication> . The rest of the page stays shared: Create a project, then choose a credential. <ForPublication version=\"v1\"> Use a legacy key. </ForPublication> <ForPublication version=\"v2\"> Use a scoped key. [Set permissions](doc:guide.permissions) </ForPublication> You can select a channel , version , language , or a combination, such as <ForPublication channel=\"sandbox\" version=\"v2\"> . Omitted attributes match any value. The block needs at least one attribute and ordinary block content. A doc: link inside a block resolves in that publication, so a v2-only target can live in a v2-only block. If a whole page changes substantially, write separate source files with the same id and slug , each with its own channel and version . If a page exists only in v2, write only its v2 file. You do not need a blank v1 copy. The Version menu shows a matching page only where one was published. Source choice Result One file listing v1 and v2 The same page appears at both paths. One file listing v1 and v2, with <ForPublication> blocks Shared text appears in both; each version gets its own selected blocks. Two files with the same ID, one for each version Each version gets different page content. One file assigned only to v2 The page appears only in v2. Run shoalrun build docs.config.yaml dist and inspect dist/documents.json for the actual pages and routes. Links, navigation, search, and the Version menu use those published variants. A link to a page missing from the current publication fails the build instead of sending readers to another version. Give each API version its own contract When API behavior differs by version, bind an OpenAPI file to each publication in apis.<name>.publications . The top-level API source belongs to publications.defaults . A shared guide can refer to the same stable operation ID in both versions; each version resolves that operation against its own API source. The build fails if a page needs an API operation but that publication has no source. See API references for the config and example configs for full projects. What agents receive Each published page has a Markdown copy at its route plus .md , such as /v1/start.md and /v2/start.md . These are separate artifacts built from the same source file. Each copy includes only its own <ForPublication> sections, so an agent reading v1 instructions does not see v2-only text. documents.json , search-index.json , and the site's agent discovery files list the published variants and their Markdown URLs. A missing version of a page has no Markdown copy or search result. Published outputs lists those files. For channel and prefix rules, see the publication configuration reference . Add a language To add a language such as Japanese, add its combination to enabled , then write a translated file for each page"},{"filters":{"focus":["configure"]},"text":"Configuration reference — Look up publication defaults and route prefixes. Use Git branches for separate docs sites — Distinguish content editions from source revisions and retained builds. Build separate sites from shared content — Publish separate sites from one content source using facet selections."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":8513,"markdownTokens":1896,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.publish","demo":false,"url":"/publish","markdownUrl":"/publish.md","title":"Deploy your documentation","summary":"Build your site, choose Vercel or Node hosting, and verify the deployed HTML and Markdown.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-hosting","headings":[{"id":"prepare-a-release","title":"Prepare a release"},{"id":"choose-a-host","title":"Choose a host"},{"id":"node-hosting","title":"Node hosting"},{"id":"other-hosts","title":"Other hosts"},{"id":"verify-the-public-site","title":"Verify the public site"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"After the quickstart , your documentation project has @shoalrun/cli installed. Run the commands below from that project directory, my-docs/ . Prepare a release Set site.origin in docs.config.yaml to your public HTTPS origin. Then audit the project and build it: npx --no-install shoalrun audit docs.config.yaml npx --no-install shoalrun build docs.config.yaml dist Review the generated HTML, Markdown, and dist/documents.json . A build replaces its output directory; keep source files outside dist/ . If it fails, use troubleshooting . Choose a host Choose a hosting route based on the artifacts and server features your site needs. Hosting route What to deploy Vercel The .vercel/output/ bundle generated by the installed CLI. Node server The compiled site and the installed @shoalrun/cli package, as described below. Another host The compiled files plus routing and headers implementing the HTTP contract . For a site hosted at /docs , set site.basePath: /docs . The Node and Vercel adapters serve the prefixed routes directly. On a static host that mounts a directory at /docs , publish the build output's docs/ subtree as that directory's root. The build keeps internal manifests at the output root for local commands. Static hosts also need routing rules for Markdown content negotiation . Node hosting On a machine with Node.js 22.12 or newer and npm, check out your documentation project with its package.json and lockfile. Configure package registry access as described in the quickstart , then run these commands from the project directory: npm ci npx --no-install shoalrun build docs.config.yaml dist npx --no-install shoalrun serve dist --host 0.0.0.0 --port 8080 The last command runs the server in the foreground. Configure your host's process manager to run it from the project directory and restart it after a release. Route your public HTTPS endpoint to port 8080 using the host's proxy or load balancer. Preserve request Accept headers and response headers through that proxy. The Node server handles HTML, negotiated Markdown, explicit .md URLs, and discovery resources. For a local check, use http://localhost:8080/install/ and http://localhost:8080/install.md from the minimal starter. Replace those paths with your own pages when you change the content. Other hosts A static upload alone does not establish Markdown content negotiation. Configure the host to serve the resources and page variants described in content negotiation , including Vary: Accept , content types, Markdown alternate links, redirects, and 404 responses. Use generated outputs to identify the files to deploy. Verify the public site Replace the example origin and page path below with a published page on your site: curl -i -H 'Accept: text/html' https://your-docs.example/install/ curl -i -H 'Accept: text/markdown' https://your-docs.example/install/ curl -i https://your-docs.example/install.md Confirm that all three requests return HTTP 200. The first should return HTML; the second and third should return the page as Markdown. Check the response headers and missing-page behavior against the HTTP contract . A local build verifies files; these requests check the host's responses. Shoalrun's docs repository also has a whole-site deployment checker . That repository script is separate from the installed CLI. Before sharing a page, check its SEO and social preview metadata , including the public share-image URL. Next, put multiple versions on one site if you need several editions in one site. For branches, tags, and retained build snapshots, see use Git branches for separate docs sites . Related reading Next steps Publish on Vercel — Build the site and routing rules for Vercel. Reference while working Check a deployed site — Check deployed HTML, Markdown, and discovery responses. Related topics Add Shoalrun to another build or host — Apply the hosting contract on another platform.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"After the quickstart , your documentation project has @shoalrun/cli installed. Run the commands below from that project directory, my-docs/ . Prepare a release Set site.origin in docs.config.yaml to your public HTTPS origin. Then audit the project and build it: npx --no-install shoalrun audit docs.config.yaml npx --no-install shoalrun build docs.config.yaml dist Review the generated HTML, Markdown, and dist/documents.json . A build replaces its output directory; keep source files outside dist/ . If it fails, use troubleshooting . Choose a host Choose a hosting route based on the artifacts and server features your site needs. Hosting route What to deploy Vercel The .vercel/output/ bundle generated by the installed CLI. Node server The compiled site and the installed @shoalrun/cli package, as described below. Another host The compiled files plus routing and headers implementing the HTTP contract . For a site hosted at /docs , set site.basePath: /docs . The Node and Vercel adapters serve the prefixed routes directly. On a static host that mounts a directory at /docs , publish the build output's docs/ subtree as that directory's root. The build keeps internal manifests at the output root for local commands. Static hosts also need routing rules for Markdown content negotiation . Node hosting On a machine with Node.js 22.12 or newer and npm, check out your documentation project with its package.json and lockfile. Configure package registry access as described in the quickstart , then run these commands from the project directory: npm ci npx --no-install shoalrun build docs.config.yaml dist npx --no-install shoalrun serve dist --host 0.0.0.0 --port 8080 The last command runs the server in the foreground. Configure your host's process manager to run it from the project directory and restart it after a release. Route your public HTTPS endpoint to port 8080 using the host's proxy or load balancer. Preserve request Accept headers and response headers through that proxy. The Node server handles HTML, negotiated Markdown, explicit .md URLs, and discovery resources. For a local check, use http://localhost:8080/install/ and http://localhost:8080/install.md from the minimal starter. Replace those paths with your own pages when you change the content. Other hosts A static upload alone does not establish Markdown content negotiation. Configure the host to serve the resources and page variants described in content negotiation , including Vary: Accept , content types, Markdown alternate links, redirects, and 404 responses. Use generated outputs to identify the files to deploy. Verify the public site Replace the example origin and page path below with a published page on your site: curl -i -H 'Accept: text/html' https://your-docs.example/install/ curl -i -H 'Accept: text/markdown' https://your-docs.example/install/ curl -i https://your-docs.example/install.md Confirm that all three requests return HTTP 200. The first should return HTML; the second and third should return the page as Markdown. Check the response headers and missing-page behavior against the HTTP contract . A local build verifies files; these requests check the host's responses. Shoalrun's docs repository also has a whole-site deployment checker . That repository script is separate from the installed CLI. Before sharing a page, check its SEO and social preview metadata , including the public share-image URL. Next, put multiple versions on one site if you need several editions in one site. For branches, tags, and retained build snapshots, see use Git branches for separate docs sites . Related reading Next steps Reference while working Related topics"},{"filters":{"focus":["configure"]},"text":"Publish on Vercel — Build the site and routing rules for Vercel. Check a deployed site — Check deployed HTML, Markdown, and discovery responses. Add Shoalrun to another build or host — Apply the hosting contract on another platform."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6155,"markdownTokens":1350,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.reader-filters","demo":false,"url":"/author/reader-views","markdownUrl":"/author/reader-views.md","title":"Reader views","summary":"Reader-view configuration, page and section marks, controls, and agent-facing behavior.","type":"reference","variant":"production|current|en","area":"discovery","subarea":"discovery-reader-views","headings":[{"id":"try-the-controls-here","title":"Try the controls here"},{"id":"filter-the-navigation","title":"Filter the navigation"},{"id":"filter-examples-on-this-page","title":"Filter examples on this page"},{"id":"configure-the-choices","title":"Configure the choices"},{"id":"mark-pages","title":"Mark pages"},{"id":"mark-sections-and-add-an-entry-choice","title":"Mark sections and add an entry choice"},{"id":"place-filter-controls","title":"Place filter controls"},{"id":"how-it-works-for-agents","title":"How it works for agents"},{"id":"connect-your-own-control","title":"Connect your own control"}],"text":"A reader view changes which pages appear in navigation and search. It also controls document cards and marked sections within pages. The site still publishes one URL for each page. A first-time visitor sees all content; a choice is saved in the browser and added to the URL so it can be shared. Reader views are visibility controls, not access controls. All published page and section content remains available in site files and Markdown twins. Use access.policy to exclude a page from a public build, and host-level authorization to protect private content. To build separate sites from the same source using these facets, use build-time page selection with site.contentFilter . That selector excludes unmatched pages from the output. A browser reader view continues to affect visibility within a published site. Try the controls here Filter the navigation This site's Focus dropdown changes navigation, search, and document cards. The same control appears in the header on every page. Your choice persists across visits and can be shared in the URL. Choose Write documentation to bring forward pages about metadata, authoring, components, and API documentation. Pages about styling and deployment leave the navigation and search results. Choose Configure & publish to bring forward styling, search, chat, hosting, and deployment. Authoring-specific pages leave the navigation and search results. Choose All to see both paths. Foundational pages, such as How Shoalrun works , stay in every view. All published pages still work at their direct URLs. A focus choice is a reading aid, not an access rule. This site's focus facet has write and configure choices. Generated API references use a typeDefaults mark of write . It also retains an internal audience facet for the hosted chat's author view and a persona facet for the page-only examples below. The header shows only Focus. These machine IDs contain no spaces; the longer labels are only shown to readers. Filter examples on this page The controls below use a separate persona facet and scope=\"page\" . They change the examples below without changing this site's navigation or search. Choose a reader to see one example, or use the controls to show both. Show UI example Show developer example UI example In a dashboard guide, show the menu names and screen actions a reader needs. This section appears when UI reader is selected. Developer example In an API guide, show the request, required fields, and expected response. This section appears when Developer is selected. Show all in the multi-select keeps both sections visible on this page. Follow site view removes the page-only choice and returns to the site's current reader view. The page-only choice is shareable with Copy view link and is not saved across visits. Configure the choices Define the available reader choices once in readerFilters.facets in docs.config.yaml . The facet names and choices are yours; Shoalrun has no fixed list of reader types. Each facet and choice has a stable lowercase ID and a label for readers. Pages and sections refer to these IDs, and unknown IDs fail the build. typeDefaults is optional; it is useful when generated API references should start in the Developer view without marking every operation separately. docs.config.yaml readerFilters : facets : audience : label : Reader options : ui : Use the UI developer : Build with the API product : label : Product options : payments : Payments reports : Reports area : label : Area options : reporting : Reporting setup : Setup subarea : label : Subarea options : settlements : Settlements exports : Exports typeDefaults : api-reference : audience : [ developer ] controls : sidebar : false header : { facet : audience , display : select , label : Reader } Nothing is selected by default, so every page and section is visible. Readers can select more than one choice within a facet: a page marked for either selected choice appears. Different facets combine: a page marked audience: [ui] and product: [payments] appears when both selections match. A page with no mark for a facet is shared across that facet. Mark pages Use the existing audiences field for the audience facet. product , area , and subarea can each supply a single choice for a same-named facet. Use readerFilters for other facets or when a page needs multiple choices in one facet. All of these fields work with frontmatter defaults and enforced values. content/payments-dashboard.mdx --- id : guide.payments-dashboard title : Review payments in the dashboard type : guide slug : /payments/dashboard audiences : [ ui ] product : payments area : reporting subarea : settlements --- When a facet is configured, audiences and same-named category values must use its choice IDs. You can instead use readerFilters.audience or readerFilters.product , but do not put both forms for the same facet on one page. An explicit page value overrides a typeDefaults value for that facet. Categories without matching configured facets remain tax","readerFilters":{},"readerSegments":[{"filters":{},"text":"A reader view changes which pages appear in navigation and search. It also controls document cards and marked sections within pages. The site still publishes one URL for each page. A first-time visitor sees all content; a choice is saved in the browser and added to the URL so it can be shared. Reader views are visibility controls, not access controls. All published page and section content remains available in site files and Markdown twins. Use access.policy to exclude a page from a public build, and host-level authorization to protect private content. To build separate sites from the same source using these facets, use build-time page selection with site.contentFilter . That selector excludes unmatched pages from the output. A browser reader view continues to affect visibility within a published site. Try the controls here Filter the navigation This site's Focus dropdown changes navigation, search, and document cards. The same control appears in the header on every page. Your choice persists across visits and can be shared in the URL. Choose Write documentation to bring forward pages about metadata, authoring, components, and API documentation. Pages about styling and deployment leave the navigation and search results. Choose Configure & publish to bring forward styling, search, chat, hosting, and deployment. Authoring-specific pages leave the navigation and search results. Choose All to see both paths. Foundational pages, such as How Shoalrun works , stay in every view. All published pages still work at their direct URLs. A focus choice is a reading aid, not an access rule. This site's focus facet has write and configure choices. Generated API references use a typeDefaults mark of write . It also retains an internal audience facet for the hosted chat's author view and a persona facet for the page-only examples below. The header shows only Focus. These machine IDs contain no spaces; the longer labels are only shown to readers. Filter examples on this page The controls below use a separate persona facet and scope=\"page\" . They change the examples below without changing this site's navigation or search. Choose a reader to see one example, or use the controls to show both. Show UI example Show developer example Show all in the multi-select keeps both sections visible on this page. Follow site view removes the page-only choice and returns to the site's current reader view. The page-only choice is shareable with Copy view link and is not saved across visits. Configure the choices Define the available reader choices once in readerFilters.facets in docs.config.yaml . The facet names and choices are yours; Shoalrun has no fixed list of reader types. Each facet and choice has a stable lowercase ID and a label for readers. Pages and sections refer to these IDs, and unknown IDs fail the build. typeDefaults is optional; it is useful when generated API references should start in the Developer view without marking every operation separately. readerFilters: facets: audience: label: Reader options: ui: Use the UI developer: Build with the API product: label: Product options: payments: Payments reports: Reports area: label: Area options: reporting: Reporting setup: Setup subarea: label: Subarea options: settlements: Settlements exports: Exports typeDefaults: api-reference: audience: [developer] controls: sidebar: false header: { facet: audience, display: select, label: Reader } Nothing is selected by default, so every page and section is visible. Readers can select more than one choice within a facet: a page marked for either selected choice appears. Different facets combine: a page marked audience: [ui] and product: [payments] appears when both selections match. A page with no mark for a facet is shared across that facet. Mark pages Use the existing audiences field for the audience facet. product , area , and subarea can each supply a single choice for a same-named facet. Use readerFilters for other facets or when a page needs multiple choices in one facet. All of these fields work with frontmatter defaults and enforced values. --- id: guide.payments-dashboard title: Review payments in the dashboard type: guide slug: /payments/dashboard audiences: [ui] product: payments area: reporting subarea: settlements --- When a facet is configured, audiences and same-named category values must use its choice IDs. You can instead use readerFilters.audience or readerFilters.product , but do not put both forms for the same facet on one page. An explicit page value overrides a typeDefaults value for that facet. Categories without matching configured facets remain taxonomy metadata only. Pages with no marks remain visible in every view. The page marks control navigation, search, and cards that point to the page. They do not change its URL. A direct link to a page outside the current view opens the page in full. A notice offers actions to switch view or show all content. Mark sections and add an entry choice Use ReaderSection for content "},{"filters":{"persona":["ui"]},"text":"UI example In a dashboard guide, show the menu names and screen actions a reader needs. This section appears when UI reader is selected."},{"filters":{"persona":["developer"]},"text":"Developer example In an API guide, show the request, required fields, and expected response. This section appears when Developer is selected."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":14163,"markdownTokens":2906,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"try-the-controls-here","title":"Try the controls here","markdownUrl":"/author/reader-views.sections/try-the-controls-here.md","markdownBytes":3973,"markdownTokens":896},{"id":"configure-the-choices","title":"Configure the choices","markdownUrl":"/author/reader-views.sections/configure-the-choices.md","markdownBytes":3158,"markdownTokens":714},{"id":"mark-pages","title":"Mark pages","markdownUrl":"/author/reader-views.sections/mark-pages.md","markdownBytes":2906,"markdownTokens":665},{"id":"mark-sections-and-add-an-entry-choice","title":"Mark sections and add an entry choice","markdownUrl":"/author/reader-views.sections/mark-sections-and-add-an-entry-choice.md","markdownBytes":2551,"markdownTokens":574},{"id":"place-filter-controls","title":"Place filter controls","markdownUrl":"/author/reader-views.sections/place-filter-controls.md","markdownBytes":3008,"markdownTokens":687},{"id":"how-it-works-for-agents","title":"How it works for agents","markdownUrl":"/author/reader-views.sections/how-it-works-for-agents.md","markdownBytes":4726,"markdownTokens":830},{"id":"connect-your-own-control","title":"Connect your own control","markdownUrl":"/author/reader-views.sections/connect-your-own-control.md","markdownBytes":3951,"markdownTokens":902}]},{"id":"recipe.add-page","demo":false,"url":"/recipes/add-page","markdownUrl":"/recipes/add-page.md","title":"Add a page to this documentation site","summary":"Create a guide, add navigation, build and audit it, then refresh its agent documentation.","type":"recipe","variant":"production|current|en","area":"authoring","subarea":"authoring-pages","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"install-the-site-dependencies","title":"Install the site dependencies"},{"id":"scaffold-a-new-guide","title":"Scaffold a new guide"},{"id":"complete-the-guide-and-add-navigation","title":"Complete the guide and add navigation"},{"id":"build-the-shoalrun-docs-site","title":"Build the Shoalrun docs site"},{"id":"check-the-built-page-artifacts","title":"Check the built page artifacts"},{"id":"audit-the-shoalrun-docs-project","title":"Audit the Shoalrun docs project"},{"id":"regenerate-the-agent-documentation-bundle","title":"Regenerate the agent documentation bundle"},{"id":"check-agent-search-and-page-lookup","title":"Check agent search and page lookup"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Create a guide, add navigation, build and audit it, then refresh its agent documentation. Before you start DOC_ID : Set export DOC_ID=guide.my-new-guide for the new guide; use the same ID in navigation and every check. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install Vale 3.20 or newer for this repository's configured formatting check. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Scaffold a new guide Use DOC_ID from Before you start : The stable document ID chosen for the new guide. Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Choose a file name, title, and stable document ID for your real topic. The commands use my-new-guide as the example; replace those values together. npx --no-install shoalrun scaffold how-to -n docs/content/my-new-guide.mdx \\ --config docs/docs.config.yaml --id \"$DOC_ID\" --title 'My new guide' The command refuses to overwrite an existing file. If this guide already exists, edit it directly instead of scaffolding it again. Keep its access policy set to draft while writing. Save draftPage : The new draft at docs/content/my-new-guide.mdx with ID guide.my-new-guide. Continue when: The CLI creates the requested file with draft access and the intended document ID. Complete the guide and add navigation Use draftPage from Scaffold a new guide : The draft file and stable ID returned by the scaffold step. Open the scaffolded file and write the actual task, prerequisites, steps, and an observable success check. Set updated to today's date, replace the draft summary, and resolve every generated TODO prompt. Check every technical claim against the implementation or a tested workflow. Set a suitable card.icon , such as file-text , to meet this site's page-card audit. Once the content is ready for review in the built site, change access.policy to public and add the stable document ID under the appropriate group in docs/config/nav.yaml : - { id : my-new-guide , doc : guide.my-new-guide } For useful next steps, add edges to docs/config/relationships.yaml and put <RelatedReading /> at the end of the page. Preserve the page ID if you later change its title or slug. Setting public access includes the page in the local build; it does not deploy the site. Save authoredPage : The completed public page and its navigation entry, ready for a local build. Continue when: The summary and scaffold prompts are replaced, the guide has a card icon, and navigation references its stable ID. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID = \"${DOC_ID :- guide.recipes-overview}\" node --input-type=module << 'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(","readerFilters":{},"readerSegments":[{"filters":{},"text":"Create a guide, add navigation, build and audit it, then refresh its agent documentation. Before you start DOC_ID : Set export DOC_ID=guide.my-new-guide for the new guide; use the same ID in navigation and every check. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install Vale 3.20 or newer for this repository's configured formatting check. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Scaffold a new guide Use DOC_ID from Before you start : The stable document ID chosen for the new guide. Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Choose a file name, title, and stable document ID for your real topic. The commands use my-new-guide as the example; replace those values together. npx --no-install shoalrun scaffold how-to -n docs/content/my-new-guide.mdx \\ --config docs/docs.config.yaml --id \"$DOC_ID\" --title 'My new guide' The command refuses to overwrite an existing file. If this guide already exists, edit it directly instead of scaffolding it again. Keep its access policy set to draft while writing. Save draftPage : The new draft at docs/content/my-new-guide.mdx with ID guide.my-new-guide. Continue when: The CLI creates the requested file with draft access and the intended document ID. Complete the guide and add navigation Use draftPage from Scaffold a new guide : The draft file and stable ID returned by the scaffold step. Open the scaffolded file and write the actual task, prerequisites, steps, and an observable success check. Set updated to today's date, replace the draft summary, and resolve every generated TODO prompt. Check every technical claim against the implementation or a tested workflow. Set a suitable card.icon , such as file-text , to meet this site's page-card audit. Once the content is ready for review in the built site, change access.policy to public and add the stable document ID under the appropriate group in docs/config/nav.yaml : - { id: my-new-guide, doc: guide.my-new-guide } For useful next steps, add edges to docs/config/relationships.yaml and put <RelatedReading /> at the end of the page. Preserve the page ID if you later change its title or slug. Setting public access includes the page in the local build; it does not deploy the site. Save authoredPage : The completed public page and its navigation entry, ready for a local build. Continue when: The summary and scaffold prompts are replaced, the guide has a card icon, and navigation references its stable ID. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID=\"${DOC_ID:-guide.recipes-overview}\" node --input-type=module <<'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document "}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9971,"markdownTokens":2177,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"before-you-start","title":"Before you start","markdownUrl":"/recipes/add-page.sections/before-you-start.md","markdownBytes":1457,"markdownTokens":369},{"id":"install-the-site-dependencies","title":"Install the site dependencies","markdownUrl":"/recipes/add-page.sections/install-the-site-dependencies.md","markdownBytes":1868,"markdownTokens":431},{"id":"scaffold-a-new-guide","title":"Scaffold a new guide","markdownUrl":"/recipes/add-page.sections/scaffold-a-new-guide.md","markdownBytes":1900,"markdownTokens":468},{"id":"complete-the-guide-and-add-navigation","title":"Complete the guide and add navigation","markdownUrl":"/recipes/add-page.sections/complete-the-guide-and-add-navigation.md","markdownBytes":2244,"markdownTokens":534},{"id":"build-the-shoalrun-docs-site","title":"Build the Shoalrun docs site","markdownUrl":"/recipes/add-page.sections/build-the-shoalrun-docs-site.md","markdownBytes":1821,"markdownTokens":438},{"id":"check-the-built-page-artifacts","title":"Check the built page artifacts","markdownUrl":"/recipes/add-page.sections/check-the-built-page-artifacts.md","markdownBytes":2448,"markdownTokens":598},{"id":"audit-the-shoalrun-docs-project","title":"Audit the Shoalrun docs project","markdownUrl":"/recipes/add-page.sections/audit-the-shoalrun-docs-project.md","markdownBytes":1803,"markdownTokens":425},{"id":"regenerate-the-agent-documentation-bundle","title":"Regenerate the agent documentation bundle","markdownUrl":"/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md","markdownBytes":1876,"markdownTokens":430},{"id":"check-agent-search-and-page-lookup","title":"Check agent search and page lookup","markdownUrl":"/recipes/add-page.sections/check-agent-search-and-page-lookup.md","markdownBytes":1982,"markdownTokens":467},{"id":"check-the-outcome","title":"Check the outcome","markdownUrl":"/recipes/add-page.sections/check-the-outcome.md","markdownBytes":1268,"markdownTokens":314},{"id":"related-reading","title":"Related reading","markdownUrl":"/recipes/add-page.sections/related-reading.md","markdownBytes":1131,"markdownTokens":297}]},{"id":"recipe.audit-docs","demo":false,"url":"/recipes/audit-docs","markdownUrl":"/recipes/audit-docs.md","title":"Build and audit this documentation site","summary":"Build current documentation, check its artifacts, and run the configured audits.","type":"recipe","variant":"production|current|en","area":"quality","subarea":"quality-audits","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"install-the-site-dependencies","title":"Install the site dependencies"},{"id":"build-the-shoalrun-docs-site","title":"Build the Shoalrun docs site"},{"id":"check-the-built-page-artifacts","title":"Check the built page artifacts"},{"id":"audit-the-shoalrun-docs-project","title":"Audit the Shoalrun docs project"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Build current documentation, check its artifacts, and run the configured audits. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install Vale 3.20 or newer for this repository's configured formatting check. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID = \"${DOC_ID :- guide.recipes-overview}\" node --input-type=module << 'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly. Save checkedArtifacts : The HTML and Markdown paths reported for the selected document. Continue when: The check prints two nonempty files for the chosen document ID. Audit the Shoalrun docs project Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Run Shoalrun's configured checks. This repository's formatting check requires Vale 3.20 or newer: npx --no-install shoalrun audit docs/docs.config.yaml The audit checks configured project commands, API representations, and focused contracts. Read any reported finding and fix its source before continuing. This command does not run the complete framework test suite or replace a browser review. Framework source changes and tests belong in the framework repository. Save auditPassed : A successful audit report with no failed configured checks. Continue when: The audit exits successfully and reports status: ok with no failed checks. Check the outcome The current source builds, the selected page has both output formats, and all configured audits pass. Review the rendered change before publishing; this recipe does not deploy or run the full framework test suite. Related reading Related topics Site workflows — Choose a related Shoalrun workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Build current documentation, check its artifacts, and run the configured audits. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install Vale 3.20 or newer for this repository's configured formatting check. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID=\"${DOC_ID:-guide.recipes-overview}\" node --input-type=module <<'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly. Save checkedArtifacts : The HTML and Markdown paths reported for the selected document. Continue when: The check prints two nonempty files for the chosen document ID. Audit the Shoalrun docs project Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Run Shoalrun's configured checks. This repository's formatting check requires Vale 3.20 or newer: npx --no-install shoalrun audit docs/docs.config.yaml The audit checks configured project commands, API representations, and focused contracts. Read any reported finding and fix its source before continuing. This command does not run the complete framework test suite or replace a browser review. Framework source changes and tests belong in the framework repository. Save auditPassed : A successful audit report with no failed configured checks. Continue when: The audit exits successfully and reports status: ok with no failed checks. Check the outcome The current source builds, the selected page has both output formats, and all configured audits pass. Review the rendered change before publishing; this recipe does not deploy or run the full framework test suite. Related reading Related topics Site workflows — Choose a related Shoalrun workflow."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5797,"markdownTokens":1287,"markdownTokenEncoding":"cl100k_base"},{"id":"recipe.build-docs","demo":false,"url":"/recipes/build-docs","markdownUrl":"/recipes/build-docs.md","title":"Build this documentation site","summary":"Use the pinned Shoalrun package and confirm a chosen page has HTML and Markdown output.","type":"recipe","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"install-the-site-dependencies","title":"Install the site dependencies"},{"id":"build-the-shoalrun-docs-site","title":"Build the Shoalrun docs site"},{"id":"check-the-built-page-artifacts","title":"Check the built page artifacts"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use the pinned Shoalrun package and confirm a chosen page has HTML and Markdown output. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID = \"${DOC_ID :- guide.recipes-overview}\" node --input-type=module << 'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly. Save checkedArtifacts : The HTML and Markdown paths reported for the selected document. Continue when: The check prints two nonempty files for the chosen document ID. Check the outcome The build succeeded and the selected document has nonempty HTML and Markdown files. Use the preview recipe to inspect the rendered experience. Related reading Related topics Site workflows — Choose a related Shoalrun workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Use the pinned Shoalrun package and confirm a chosen page has HTML and Markdown output. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID=\"${DOC_ID:-guide.recipes-overview}\" node --input-type=module <<'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly. Save checkedArtifacts : The HTML and Markdown paths reported for the selected document. Continue when: The check prints two nonempty files for the chosen document ID. Check the outcome The build succeeded and the selected document has nonempty HTML and Markdown files. Use the preview recipe to inspect the rendered experience. Related reading Related topics Site workflows — Choose a related Shoalrun workflow."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4810,"markdownTokens":1088,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.recipe-drafts","demo":false,"url":"/author/recipe-drafts","markdownUrl":"/author/recipe-drafts.md","title":"Compose and maintain recipes","summary":"Use Shoalrun ingredient files and a recipe spec to produce a complete, reviewable task page.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-composition","headings":[{"id":"1-write-one-reusable-step","title":"1. Write one reusable step"},{"id":"2-list-the-steps-for-one-complete-goal","title":"2. List the steps for one complete goal"},{"id":"3-generate-a-draft-and-review-it","title":"3. Generate a draft and review it"},{"id":"4-maintain-shoalrun-s-published-recipe-snapshots","title":"4. Maintain Shoalrun's published recipe snapshots"},{"id":"start-an-ingredient-from-an-api-example","title":"Start an ingredient from an API example"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use ingredients when several recipes share instructions you want to maintain in one place. This guide follows Shoalrun's Build and audit this documentation site recipe from its source files to its published page. If you only need one task page, you can write a type: recipe page directly. Ingredients and the draft assembler are optional. Start with how the pieces fit for the distinction between authoring a recipe and choosing one in a cookbook. The built-in recipe , ingredient , and cookbook scaffolds are available in any project without registering templates. For example: shoalrun scaffold ingredient -n content/lookup-parcel.mdx shoalrun scaffold recipe -n content/track-parcel.mdx See templates for their outlines and project overrides. 1. Write one reusable step An ingredient is an MDX file with type: ingredient . Its body contains the instructions to reuse. This is a shortened version of docs/content/ingredient-build-site.mdx : docs/content/ingredient-build-site.mdx --- id : ingredient.build-site title : Build the Shoalrun docs site summary : Compile authored documentation into local HTML and Markdown. type : ingredient slug : /ingredients/build-site channel : production version : current language : en access : { policy : public } workflow : inputs : frameworkCli : The CLI compiled from this checkout. outputs : builtSite : The successful site build at docs/dist. prerequisites : - Run commands from the Shoalrun repository root. check : \"The build reports status: ok.\" --- Use the compiled CLI to build the documentation: ``` sh node framework/dist/cli.js build docs/docs.config.yaml docs/dist ``` If the build fails, fix the named source or configuration issue and rerun it. The workflow fields describe the step: Field Meaning inputs Names and descriptions of values or artifacts that must already be available. Here, an earlier step must provide frameworkCli . outputs Names and descriptions of what successful completion makes available to later steps. Here, builtSite means the successful output at docs/dist . prerequisites Setup instructions. The assembler includes identical strings once across the recipe. check An observable condition for the reader to evaluate before continuing. Required whenever workflow is present. These declarations do not run the command or create variables. The body tells the reader or agent what to do. The check tells them what result to inspect. The assembler checks names and order, so a typo such as builtDocs where the next step expects builtSite fails during assembly. An ingredient can be private draft source for a recipe, or a published page readers can inspect. It must have a literal YAML header and match the recipe's default channel, version, and language. Without workflow , the assembler copies its body without checking handoffs. 2. List the steps for one complete goal The recipe spec chooses the ingredients and their order. A shortened version of docs/recipe-specs/audit-docs.yaml is: docs/recipe-specs/audit-docs.yaml schemaVersion : 1 id : recipe.audit-docs title : Build and audit this documentation site summary : Build current documentation and run the configured audits. slug : /recipes/audit-docs inputs : repositoryCheckout : A local Shoalrun checkout with dependencies installed. DOC_ID : Set the stable ID of the page you want to check. ingredients : - ../content/ingredient-compile-framework.mdx - ../content/ingredient-build-site.mdx - ../content/ingredient-inspect-build.mdx - ../content/ingredient-audit-site.mdx outcome : The build succeeds, both page formats exist, and configured audits pass. Paths are relative to this spec file. The initial inputs are available before the first ingredient. The compile ingredient produces frameworkCli ; the build ingredient requires it and produces builtSite ; the artifact-check ingredient requires that build and DOC_ID . The assembler rejects a missing input, repeated output name, repeated ingredient ID, or publication mismatch. It does not choose an order for you or verify that an output has the described value. The outcome is the final check for the complete recipe; omitting it leaves a prompt for the author to complete. 3. Generate a draft and review it From this repository's root, compile the CLI and preview the draft using the existing spec: npm --prefix framework run build node framework/dist/cli.js recipe draft \\ --config docs/docs.config.yaml \\ --spec docs/recipe-specs/audit-docs.yaml \\ --out /tmp/shoalrun-audit-recipe.mdx --check --check prints the proposed content and reports would-create , unchanged , or would-change . Remove --check to create the file. The write command refuses to overwrite an existing file; choose a new output path for a new candidate. The output is a complete MDX draft with setup, ordered ingredient bodies, handoff descriptions, per-step checks, and the final outcome. It also contains a draft notice and a review checklist. No model or API is called, and none of the recipe's commands are executed during generatio","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Use ingredients when several recipes share instructions you want to maintain in one place. This guide follows Shoalrun's Build and audit this documentation site recipe from its source files to its published page. If you only need one task page, you can write a type: recipe page directly. Ingredients and the draft assembler are optional. Start with how the pieces fit for the distinction between authoring a recipe and choosing one in a cookbook. The built-in recipe , ingredient , and cookbook scaffolds are available in any project without registering templates. For example: shoalrun scaffold ingredient -n content/lookup-parcel.mdx shoalrun scaffold recipe -n content/track-parcel.mdx See templates for their outlines and project overrides. 1. Write one reusable step An ingredient is an MDX file with type: ingredient . Its body contains the instructions to reuse. This is a shortened version of docs/content/ingredient-build-site.mdx : --- id: ingredient.build-site title: Build the Shoalrun docs site summary: Compile authored documentation into local HTML and Markdown. type: ingredient slug: /ingredients/build-site channel: production version: current language: en access: { policy: public } workflow: inputs: frameworkCli: The CLI compiled from this checkout. outputs: builtSite: The successful site build at docs/dist. prerequisites: - Run commands from the Shoalrun repository root. check: \"The build reports status: ok.\" --- Use the compiled CLI to build the documentation: ```sh node framework/dist/cli.js build docs/docs.config.yaml docs/dist ``` If the build fails, fix the named source or configuration issue and rerun it. The workflow fields describe the step: Field Meaning inputs Names and descriptions of values or artifacts that must already be available. Here, an earlier step must provide frameworkCli . outputs Names and descriptions of what successful completion makes available to later steps. Here, builtSite means the successful output at docs/dist . prerequisites Setup instructions. The assembler includes identical strings once across the recipe. check An observable condition for the reader to evaluate before continuing. Required whenever workflow is present. These declarations do not run the command or create variables. The body tells the reader or agent what to do. The check tells them what result to inspect. The assembler checks names and order, so a typo such as builtDocs where the next step expects builtSite fails during assembly. An ingredient can be private draft source for a recipe, or a published page readers can inspect. It must have a literal YAML header and match the recipe's default channel, version, and language. Without workflow , the assembler copies its body without checking handoffs. 2. List the steps for one complete goal The recipe spec chooses the ingredients and their order. A shortened version of docs/recipe-specs/audit-docs.yaml is: schemaVersion: 1 id: recipe.audit-docs title: Build and audit this documentation site summary: Build current documentation and run the configured audits. slug: /recipes/audit-docs inputs: repositoryCheckout: A local Shoalrun checkout with dependencies installed. DOC_ID: Set the stable ID of the page you want to check. ingredients: - ../content/ingredient-compile-framework.mdx - ../content/ingredient-build-site.mdx - ../content/ingredient-inspect-build.mdx - ../content/ingredient-audit-site.mdx outcome: The build succeeds, both page formats exist, and configured audits pass. Paths are relative to this spec file. The initial inputs are available before the first ingredient. The compile ingredient produces frameworkCli ; the build ingredient requires it and produces builtSite ; the artifact-check ingredient requires that build and DOC_ID . The assembler rejects a missing input, repeated output name, repeated ingredient ID, or publication mismatch. It does not choose an order for you or verify that an output has the described value. The outcome is the final check for the complete recipe; omitting it leaves a prompt for the author to complete. 3. Generate a draft and review it From this repository's root, compile the CLI and preview the draft using the existing spec: npm --prefix framework run build node framework/dist/cli.js recipe draft \\ --config docs/docs.config.yaml \\ --spec docs/recipe-specs/audit-docs.yaml \\ --out /tmp/shoalrun-audit-recipe.mdx --check --check prints the proposed content and reports would-create , unchanged , or would-change . Remove --check to create the file. The write command refuses to overwrite an existing file; choose a new output path for a new candidate. The output is a complete MDX draft with setup, ordered ingredient bodies, handoff descriptions, per-step checks, and the final outcome. It also contains a draft notice and a review checklist. No model or API is called, and none of the recipe's commands are executed during generation. Read the complete draft and follow its instructions in a suitable environment. Check that the hand"},{"filters":{"focus":["write"]},"text":"Add an OpenAPI API — Configure the stable operation ID and review the OpenAPI source used by an API ingredient draft. CookbookChooser — Let readers assemble reviewed recipes into a path in a cookbook."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates — Use a project template when an API example is not the right starting point."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10729,"markdownTokens":2268,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"1-write-one-reusable-step","title":"1. Write one reusable step","markdownUrl":"/author/recipe-drafts.sections/1-write-one-reusable-step.md","markdownBytes":4339,"markdownTokens":915},{"id":"2-list-the-steps-for-one-complete-goal","title":"2. List the steps for one complete goal","markdownUrl":"/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md","markdownBytes":3133,"markdownTokens":747},{"id":"3-generate-a-draft-and-review-it","title":"3. Generate a draft and review it","markdownUrl":"/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md","markdownBytes":3172,"markdownTokens":758},{"id":"4-maintain-shoalrun-s-published-recipe-snapshots","title":"4. Maintain Shoalrun's published recipe snapshots","markdownUrl":"/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md","markdownBytes":3619,"markdownTokens":805},{"id":"start-an-ingredient-from-an-api-example","title":"Start an ingredient from an API example","markdownUrl":"/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md","markdownBytes":2955,"markdownTokens":688},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/recipe-drafts.sections/related-reading.md","markdownBytes":2247,"markdownTokens":557}]},{"id":"recipe.preview-hybrid-search","demo":false,"url":"/recipes/preview-hybrid-search","markdownUrl":"/recipes/preview-hybrid-search.md","title":"Preview semantic search in this checkout","summary":"Build the Shoalrun docs, index passages, and verify vector retrieval and lexical fallback locally.","type":"recipe","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"build-and-index-the-docs","title":"Build and index the docs"},{"id":"start-the-semantic-endpoint","title":"Start the semantic endpoint"},{"id":"verify-the-retrieval-mode","title":"Verify the retrieval mode"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"}],"text":"Build the Shoalrun docs, index passages, and verify vector retrieval and lexical fallback locally. Before you start repositoryCheckout : A Shoalrun checkout with dependencies installed. Run commands from its root with Node.js 22.12 or newer. embeddingCredentials : A shell-readable environment file at ~/.config/shoalrun/.env containing the key for the embedding provider configured under retrieval.embeddings . This site's current config uses Voyage; the key stays on the server. previewPort : Port 8770, available for the preview server. If occupied, use another port with the CLI and adjust the URL. Build and index the docs Use repositoryCheckout and embeddingCredentials from Before you start . npm run docs:build set -a ; . ~/.config/shoalrun/.env ; set +a npm run docs:index The build writes search-index.json . The index command sends documentation passages to the configured embedding provider and generates or reuses passage vectors. Each semantic query also calls the embedding provider. No chat model is needed for search. If indexing reports a missing key or provider error, check retrieval.embeddings and the environment file, then rerun indexing. The passage index guide explains digests and vector reuse. Save indexedSite : The successful site build and current passage index under docs/dist. Continue when: The build and index commands both succeed. Start the semantic endpoint Use indexedSite from Build and index the docs and previewPort from Before you start . npm run docs:search-preview Open http://127.0.0.1:8770/ . This command occupies the terminal. Restart it after rebuilding the passage index, because the local endpoint reads its files at startup. Vector results include only passages with current embeddings. Reindex after editing pages so semantic results include the changed passages. A literal configuration key or command flag can also recover one word-matching explanation, but this is not a substitute for refreshing vectors. The browser search provider first asks /__shoalrun/search . That endpoint ranks passages by embedding similarity and returns page or section links. Successful semantic queries keep their first two pages ranked by meaning. A question containing dotted configuration keys or command flags can include one exact-identifier prose explanation as the third result. Filenames and requests for fewer than three results keep semantic ranking. It does not call the chat model. If the endpoint has no current vectors, it returns lexical passage results. If the endpoint is missing, slow, or fails, the browser uses search-index.json for lexical page search. Save runningPreview : The local site and search endpoint while the server is running. Continue when: The homepage and its search box load. Verify the retrieval mode Use runningPreview from Start the semantic endpoint . Search for navigation , then describe a task in your own words without copying a page title or sentence. For example, ask about reusing warnings across documentation. Lexical search can now return partial matches for the sentence; returning a result alone does not prove semantic retrieval worked. In the browser Network inspector, inspect /__shoalrun/search . A successful response with \"mode\": \"vector\" confirms the endpoint used embeddings. \"mode\": \"lexical\" means the endpoint returned word-matching results. It can do this when current document vectors are missing, the embedding budget is exhausted, the provider fails, or the three-second deadline expires. The response mode alone does not tell you whether document vectors exist. A failed request followed by results demonstrates the browser provider's lexical fallback. For a preview without the endpoint, stop this server and run npm run docs:preview . Save modeEvidence : The response mode and relevant page or section links for the queries. Continue when: You can identify the active retrieval mode and open a relevant result. Check the outcome The indexed site serves local search, results open relevant documentation, and the Network inspector distinguishes vector retrieval from the lexical endpoint or browser fallback. Press Ctrl+C to stop the server. Related reading Next steps Passage index — Understand passage digests, embedding input, and vector reuse. (Status: experimental.)","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Build the Shoalrun docs, index passages, and verify vector retrieval and lexical fallback locally. Before you start repositoryCheckout : A Shoalrun checkout with dependencies installed. Run commands from its root with Node.js 22.12 or newer. embeddingCredentials : A shell-readable environment file at ~/.config/shoalrun/.env containing the key for the embedding provider configured under retrieval.embeddings . This site's current config uses Voyage; the key stays on the server. previewPort : Port 8770, available for the preview server. If occupied, use another port with the CLI and adjust the URL. Build and index the docs Use repositoryCheckout and embeddingCredentials from Before you start . npm run docs:build set -a; . ~/.config/shoalrun/.env; set +a npm run docs:index The build writes search-index.json . The index command sends documentation passages to the configured embedding provider and generates or reuses passage vectors. Each semantic query also calls the embedding provider. No chat model is needed for search. If indexing reports a missing key or provider error, check retrieval.embeddings and the environment file, then rerun indexing. The passage index guide explains digests and vector reuse. Save indexedSite : The successful site build and current passage index under docs/dist. Continue when: The build and index commands both succeed. Start the semantic endpoint Use indexedSite from Build and index the docs and previewPort from Before you start . npm run docs:search-preview Open http://127.0.0.1:8770/ . This command occupies the terminal. Restart it after rebuilding the passage index, because the local endpoint reads its files at startup. Vector results include only passages with current embeddings. Reindex after editing pages so semantic results include the changed passages. A literal configuration key or command flag can also recover one word-matching explanation, but this is not a substitute for refreshing vectors. The browser search provider first asks /__shoalrun/search . That endpoint ranks passages by embedding similarity and returns page or section links. Successful semantic queries keep their first two pages ranked by meaning. A question containing dotted configuration keys or command flags can include one exact-identifier prose explanation as the third result. Filenames and requests for fewer than three results keep semantic ranking. It does not call the chat model. If the endpoint has no current vectors, it returns lexical passage results. If the endpoint is missing, slow, or fails, the browser uses search-index.json for lexical page search. Save runningPreview : The local site and search endpoint while the server is running. Continue when: The homepage and its search box load. Verify the retrieval mode Use runningPreview from Start the semantic endpoint . Search for navigation , then describe a task in your own words without copying a page title or sentence. For example, ask about reusing warnings across documentation. Lexical search can now return partial matches for the sentence; returning a result alone does not prove semantic retrieval worked. In the browser Network inspector, inspect /__shoalrun/search . A successful response with \"mode\": \"vector\" confirms the endpoint used embeddings. \"mode\": \"lexical\" means the endpoint returned word-matching results. It can do this when current document vectors are missing, the embedding budget is exhausted, the provider fails, or the three-second deadline expires. The response mode alone does not tell you whether document vectors exist. A failed request followed by results demonstrates the browser provider's lexical fallback. For a preview without the endpoint, stop this server and run npm run docs:preview . Save modeEvidence : The response mode and relevant page or section links for the queries. Continue when: You can identify the active retrieval mode and open a relevant result. Check the outcome The indexed site serves local search, results open relevant documentation, and the Network inspector distinguishes vector retrieval from the lexical endpoint or browser fallback. Press Ctrl+C to stop the server. Related reading Next steps"},{"filters":{"focus":["configure"]},"text":"Passage index — Understand passage digests, embedding input, and vector reuse. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5401,"markdownTokens":1154,"markdownTokenEncoding":"cl100k_base"},{"id":"recipe.preview-page","demo":false,"url":"/recipes/preview-page","markdownUrl":"/recipes/preview-page.md","title":"Preview a documentation change locally","summary":"Build current documentation and inspect its HTML and Markdown over local HTTP.","type":"recipe","variant":"production|current|en","area":"publishing","subarea":"publishing-builds","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"install-the-site-dependencies","title":"Install the site dependencies"},{"id":"build-the-shoalrun-docs-site","title":"Build the Shoalrun docs site"},{"id":"check-the-built-page-artifacts","title":"Check the built page artifacts"},{"id":"serve-the-built-docs-locally","title":"Serve the built docs locally"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Build current documentation and inspect its HTML and Markdown over local HTTP. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID = \"${DOC_ID :- guide.recipes-overview}\" node --input-type=module << 'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly. Save checkedArtifacts : The HTML and Markdown paths reported for the selected document. Continue when: The check prints two nonempty files for the chosen document ID. Serve the built docs locally Use builtSite from Build the Shoalrun docs site : The successful site build at docs/dist. Serve the build from the repository root: npx --no-install shoalrun serve docs/dist --port 8770 This command occupies the terminal. Open http://127.0.0.1:8770/author/recipes/ and http://127.0.0.1:8770/author/recipes.md in a browser. For another page, use its url and markdownUrl from docs/dist/documents.json . Check the page title, navigation, links, images, code copying, and complete instructions in Markdown. Check the page at a narrow window width too. If port 8770 is occupied, select another port and use it in both URLs. Press Ctrl+C when finished. This server serves the existing build; rebuild and reload after editing. Use npm run docs:dev for ongoing work that should rebuild automatically. Save previewOrigin : The local preview at http://127.0.0.1:8770 while the server is running. Continue when: The selected HTML page and its Markdown twin load, the sidebar reaches it, and the instructions are complete. Check the outcome The page you changed works over HTTP, navigation reaches it, and its Markdown contains the complete instructions. Stop the preview server when finished. Related reading Related topics Authoring workflows — Choose a related Shoalrun workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Build current documentation and inspect its HTML and Markdown over local HTTP. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Build the Shoalrun docs site Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Use the installed CLI to build Shoalrun's documentation: npx --no-install shoalrun build docs/docs.config.yaml docs/dist The source configuration is docs/docs.config.yaml ; output goes to docs/dist . The root shortcut is npm run docs:build ; it uses the installed package. If the build fails, fix the named source or configuration issue and rerun it. A previous successful output can remain on disk after a failure, so file existence alone is not evidence of a successful new build. Save builtSite : The successful site build at docs/dist, including documents.json and each published page. Continue when: The build reports status: ok and the expected number of documents. Check the built page artifacts Use DOC_ID from Before you start : The stable ID of the page being checked. Use builtSite from Build the Shoalrun docs site : The site produced by the successful build. Choose a document by its stable ID. The default below checks the recipes overview; replace it with the ID of the page you changed. export DOC_ID=\"${DOC_ID:-guide.recipes-overview}\" node --input-type=module <<'JS' import { readFile } from 'node:fs/promises'; import path from 'node:path'; const root = 'docs/dist'; const manifest = JSON.parse(await readFile(path.join(root, 'documents.json'), 'utf8')); const doc = manifest.documents.find(item => item.id === process.env.DOC_ID); if (!doc) throw new Error(`No published document with ID ${process.env.DOC_ID}`); for (const route of [`${doc.url.replace(/\\/$/, '')}/index.html`, doc.markdownUrl]) { const file = path.join(root, route.replace(/^\\//, '')); if (!(await readFile(file, 'utf8')).trim()) throw new Error(`Empty output: ${file}`); console.log(file); } JS If the ID is missing, check the page's access policy and publication fields, then rebuild. Inspect the printed Markdown file for the expected instructions. Use a local HTTP preview for the HTML page so its assets and navigation resolve correctly. Save checkedArtifacts : The HTML and Markdown paths reported for the selected document. Continue when: The check prints two nonempty files for the chosen document ID. Serve the built docs locally Use builtSite from Build the Shoalrun docs site : The successful site build at docs/dist. Serve the build from the repository root: npx --no-install shoalrun serve docs/dist --port 8770 This command occupies the terminal. Open http://127.0.0.1:8770/author/recipes/ and http://127.0.0.1:8770/author/recipes.md in a browser. For another page, use its url and markdownUrl from docs/dist/documents.json . Check the page title, navigation, links, images, code copying, and complete instructions in Markdown. Check the page at a narrow window width too. If port 8770 is occupied, select another port and use it in both URLs. Press Ctrl+C when finished. This server serves the existing build; rebuild and reload after editing. Use npm run docs:dev for ongoing work that should rebuild automatically. Save previewOrigin : The local preview at http://127.0.0.1:8770 while the server is running. Continue when: The selected HTML page and its Markdown twin load, the sidebar reaches it, and the instructions are complete. Check the outcome The page you changed works over HTTP, navigation reaches it, and its Markdown contains the complete instructions. Stop the preview server when finished. Related reading Related topics Authoring workflows — Choose a related Shoalrun workflow."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5922,"markdownTokens":1352,"markdownTokenEncoding":"cl100k_base"},{"id":"recipe.queue-email","demo":false,"url":"/recipes/queue-email","markdownUrl":"/recipes/queue-email.md","title":"Queue a welcome email","summary":"Submit the welcome template and confirm the API accepted the request.","type":"recipe","variant":"production|current|en","area":"api","subarea":"api-examples","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"queue-the-message","title":"Queue the message"},{"id":"check-the-outcome","title":"Check the outcome"}],"text":"Use this path to check request acceptance. For delivery status and failure handling, follow the complete delivery recipe . Before you start Start the local simulation from the Shoalrun repository root in a separate terminal: node framework/example-configs/notifications/demo.mjs Keep it running. Have cURL and Node.js available, and use a scratch directory for queued.json ; the command replaces that file. The demo sends no email. Queue the message export API_BASE = http://127.0.0.1:8787/v1 curl --fail-with-body --silent --show-error \\ --request POST \"$API_BASE/messages/email\" \\ --header 'Content-Type: application/json' \\ --data '{\"to\":\"reader@example.com\",\"template\":\"welcome\",\"variables\":{\"firstName\":\"Avery\"}}' \\ --output queued.json --write-out 'HTTP %{http_code}\\n' cat queued.json MESSAGE_ID = $( node -p \"JSON.parse(require('fs').readFileSync('queued.json', 'utf8')).id\" ) printf '\\nMessage ID: %s\\n' \"$MESSAGE_ID\" Check the outcome The HTTP status is 202, the response says status: queued , and the returned id is nonempty. Keep that ID if you will check delivery later. A failed POST needs its own diagnostic; do not reuse an ID from an earlier attempt. Acceptance leaves delivery unknown.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Use this path to check request acceptance. For delivery status and failure handling, follow the complete delivery recipe . Before you start Start the local simulation from the Shoalrun repository root in a separate terminal: node framework/example-configs/notifications/demo.mjs Keep it running. Have cURL and Node.js available, and use a scratch directory for queued.json ; the command replaces that file. The demo sends no email. Queue the message export API_BASE=http://127.0.0.1:8787/v1 curl --fail-with-body --silent --show-error \\ --request POST \"$API_BASE/messages/email\" \\ --header 'Content-Type: application/json' \\ --data '{\"to\":\"reader@example.com\",\"template\":\"welcome\",\"variables\":{\"firstName\":\"Avery\"}}' \\ --output queued.json --write-out 'HTTP %{http_code}\\n' cat queued.json MESSAGE_ID=$(node -p \"JSON.parse(require('fs').readFileSync('queued.json', 'utf8')).id\") printf '\\nMessage ID: %s\\n' \"$MESSAGE_ID\" Check the outcome The HTTP status is 202, the response says status: queued , and the returned id is nonempty. Keep that ID if you will check delivery later. A failed POST needs its own diagnostic; do not reuse an ID from an earlier attempt. Acceptance leaves delivery unknown."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2061,"markdownTokens":525,"markdownTokenEncoding":"cl100k_base"},{"id":"recipe.refresh-agent-docs","demo":false,"url":"/recipes/refresh-agent-docs","markdownUrl":"/recipes/refresh-agent-docs.md","title":"Refresh Shoalrun's bundled agent docs","summary":"Regenerate offline docs, verify CLI search and read, and run project audits.","type":"recipe","variant":"production|current|en","area":"discovery","subarea":"discovery-agents","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"install-the-site-dependencies","title":"Install the site dependencies"},{"id":"regenerate-the-agent-documentation-bundle","title":"Regenerate the agent documentation bundle"},{"id":"check-agent-search-and-page-lookup","title":"Check agent search and page lookup"},{"id":"audit-the-shoalrun-docs-project","title":"Audit the Shoalrun docs project"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Regenerate offline docs, verify CLI search and read, and run project audits. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install Vale 3.20 or newer for this repository's configured formatting check. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Regenerate the agent documentation bundle Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Export the already built site for the framework’s next documentation snapshot: npm run agent-docs:build Build the site first. The export copies that output without rebuilding and records the site build identity and pinned package integrity in agent-docs/provenance.json . It does not modify the installed package. Review and transfer the export as a versioned artifact to the framework repository. Framework releases consume an explicitly selected snapshot; they must not fetch the latest site during a package build. Save agentBundle : The exported Markdown, manifest, search index, and provenance under agent-docs. Continue when: The command reports matching counts of bundled Markdown pages and search records. Check agent search and page lookup Use DOC_ID from Before you start : The stable ID of the page being checked. Use agentBundle from Regenerate the agent documentation bundle : The refreshed offline documentation bundle. Search and read the exported site snapshot explicitly: npx --no-install shoalrun docs search \"recipes and cookbooks\" --site agent-docs npx --no-install shoalrun docs read \"$DOC_ID\" --site agent-docs Confirm the returned Markdown includes your change and links. Review agent-docs/provenance.json and the export inventory before handing the artifact to the framework release process. Plain shoalrun docs read uses the installed package’s snapshot, which is independent of this working tree. Save agentLookupConfirmed : Search results and page Markdown from the refreshed bundle, plus a reviewed generated diff. Continue when: Search includes the intended topic, docs read shows the current instructions, and generated changes are understood. Audit the Shoalrun docs project Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Run Shoalrun's configured checks. This repository's formatting check requires Vale 3.20 or newer: npx --no-install shoalrun audit docs/docs.config.yaml The audit checks configured project commands, API representations, and focused contracts. Read any reported finding and fix its source before continuing. This command does not run the complete framework test suite or replace a browser review. Framework source changes and tests belong in the framework repository. Save auditPassed : A successful audit report with no failed configured checks. Continue when: The audit exits successfully and reports status: ok with no failed checks. Check the outcome The bundle contains the current authored instructions, search and read find the intended page, and configured audits pass. Hand off the reviewed snapshot as a versioned artifact. Related reading Related topics Authoring workflows — Choose a related Shoalrun workflow.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Regenerate offline docs, verify CLI search and read, and run project audits. Before you start DOC_ID : Set export DOC_ID=guide.recipes-overview , or use the stable ID of the page you changed. repositoryCheckout : This documentation repository with its pinned package and lockfile. Run commands from the documentation repository root. Use Node.js 22.12 or newer. Use Node.js 22.12 or newer and install site dependencies with npm ci if needed. Install Vale 3.20 or newer for this repository's configured formatting check. Install the site dependencies Use repositoryCheckout from Before you start : This documentation repository and its package lockfile. Install the versions pinned by this site’s lockfile: npm ci npx --no-install shoalrun config validate docs/docs.config.yaml The manifest and lockfile pin the CLI version and registry artifact. Public npm releases need no package token or framework checkout. If your checkout still pins an older GitHub Packages release, follow Getting started to migrate registries. That older dependency still needs its original registry access until upgraded. Update and validate the dependency and lockfile together. Save frameworkCli : The installed shoalrun executable in node_modules/.bin. Continue when: The dependency installation succeeds and the installed CLI validates the site configuration. Regenerate the agent documentation bundle Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Export the already built site for the framework’s next documentation snapshot: npm run agent-docs:build Build the site first. The export copies that output without rebuilding and records the site build identity and pinned package integrity in agent-docs/provenance.json . It does not modify the installed package. Review and transfer the export as a versioned artifact to the framework repository. Framework releases consume an explicitly selected snapshot; they must not fetch the latest site during a package build. Save agentBundle : The exported Markdown, manifest, search index, and provenance under agent-docs. Continue when: The command reports matching counts of bundled Markdown pages and search records. Check agent search and page lookup Use DOC_ID from Before you start : The stable ID of the page being checked. Use agentBundle from Regenerate the agent documentation bundle : The refreshed offline documentation bundle. Search and read the exported site snapshot explicitly: npx --no-install shoalrun docs search \"recipes and cookbooks\" --site agent-docs npx --no-install shoalrun docs read \"$DOC_ID\" --site agent-docs Confirm the returned Markdown includes your change and links. Review agent-docs/provenance.json and the export inventory before handing the artifact to the framework release process. Plain shoalrun docs read uses the installed package’s snapshot, which is independent of this working tree. Save agentLookupConfirmed : Search results and page Markdown from the refreshed bundle, plus a reviewed generated diff. Continue when: Search includes the intended topic, docs read shows the current instructions, and generated changes are understood. Audit the Shoalrun docs project Use frameworkCli from Install the site dependencies : The pinned Shoalrun package installed for this site. Run Shoalrun's configured checks. This repository's formatting check requires Vale 3.20 or newer: npx --no-install shoalrun audit docs/docs.config.yaml The audit checks configured project commands, API representations, and focused contracts. Read any reported finding and fix its source before continuing. This command does not run the complete framework test suite or replace a browser review. Framework source changes and tests belong in the framework repository. Save auditPassed : A successful audit report with no failed configured checks. Continue when: The audit exits successfully and reports status: ok with no failed checks. Check the outcome The bundle contains the current authored instructions, search and read find the intended page, and configured audits pass. Hand off the reviewed snapshot as a versioned artifact. Related reading Related topics Authoring workflows — Choose a related Shoalrun workflow."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5355,"markdownTokens":1150,"markdownTokenEncoding":"cl100k_base"},{"id":"recipe.send-welcome-email","demo":false,"url":"/recipes/send-welcome-email","markdownUrl":"/recipes/send-welcome-email.md","title":"Send a welcome email and confirm delivery","summary":"Follow one message from an accepted request through delivery, and inspect a simulated failure.","type":"recipe","variant":"production|current|en","area":"api","subarea":"api-examples","headings":[{"id":"before-you-start","title":"Before you start"},{"id":"queue-the-welcome-email","title":"Queue the welcome email"},{"id":"check-delivery-for-that-message","title":"Check delivery for that message"},{"id":"check-the-outcome","title":"Check the outcome"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Follow one message from an accepted request through delivery, and inspect a simulated failure. Before you start API_BASE : Set export API_BASE=http://127.0.0.1:8787/v1 in your command terminal. From the Shoalrun repository root, run node framework/example-configs/notifications/demo.mjs in a separate terminal and keep it running. If it is already running, reuse it. Use a scratch directory for queued.json and delivery.json. These commands replace those files. Have cURL and Node.js available in your command terminal. Queue the welcome email Use API_BASE from Before you start : The demo API base URL set in your terminal. Send the welcome template to the demo recipient. The demo stores a simulated message and sends no email. curl --fail-with-body --silent --show-error \\ --request POST \"$API_BASE/messages/email\" \\ --header 'Content-Type: application/json' \\ --data '{\"to\":\"reader@example.com\",\"template\":\"welcome\",\"variables\":{\"firstName\":\"Avery\"}}' \\ --output queued.json --write-out 'HTTP %{http_code}\\n' cat queued.json MESSAGE_ID = $( node -p \"JSON.parse(require('fs').readFileSync('queued.json', 'utf8')).id\" ) printf '\\nMessage ID: %s\\n' \"$MESSAGE_ID\" A successful response looks like {\"id\":\"msg_…\",\"status\":\"queued\"} . If the POST fails, inspect its HTTP status and response before continuing. Do not reuse a message ID from an earlier attempt. Save MESSAGE_ID : The id returned in queued.json; use this exact value for the delivery check. Continue when: The POST returns HTTP 202, status is queued, and MESSAGE_ID is nonempty. This confirms acceptance only. Check delivery for that message Use API_BASE from Before you start : Use the same environment as the queue request. Use MESSAGE_ID from Queue the welcome email : Put the returned ID into the status URL; do not substitute the example ID. Look up the message using the ID saved in the previous step: curl --fail-with-body --silent --show-error \\ \"$API_BASE/messages/$MESSAGE_ID\" \\ --output delivery.json --write-out 'HTTP %{http_code}\\n' cat delivery.json The local demo returns queued on the first lookup. Run the lookup once more to see its terminal status. This deterministic transition is part of the simulation; a real provider needs its own polling interval and timeout. Status or error What to do next queued The request was accepted; delivery is still pending. In this demo, repeat the lookup once. delivered Check that id matches MESSAGE_ID . The delivery check is complete. failed Inspect failureReason . Correct the cause before creating another message; do not keep polling a terminal failure. HTTP 404 Check the saved ID and API base URL. Restarting the demo clears its messages. Connection refused Start the demo and check that it is listening on port 8787. To exercise failure handling, repeat the queue step with blocked@example.com , save its new message ID, and check that ID twice. The demo returns failed with failureReason: recipient_rejected . Save deliveryStatus : The status returned for MESSAGE_ID in delivery.json. Continue when: The response id equals MESSAGE_ID and status is delivered. Queued and failed do not satisfy this recipe's goal. Check the outcome The final response contains the same message ID you saved and status: delivered . You have verified the simulated delivery flow. The local demo sends no email; a real provider reporting delivery still does not prove the recipient read it. Related reading Related topics Welcome email workflows — Compare the complete delivery path with the acceptance-only path.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Follow one message from an accepted request through delivery, and inspect a simulated failure. Before you start API_BASE : Set export API_BASE=http://127.0.0.1:8787/v1 in your command terminal. From the Shoalrun repository root, run node framework/example-configs/notifications/demo.mjs in a separate terminal and keep it running. If it is already running, reuse it. Use a scratch directory for queued.json and delivery.json. These commands replace those files. Have cURL and Node.js available in your command terminal. Queue the welcome email Use API_BASE from Before you start : The demo API base URL set in your terminal. Send the welcome template to the demo recipient. The demo stores a simulated message and sends no email. curl --fail-with-body --silent --show-error \\ --request POST \"$API_BASE/messages/email\" \\ --header 'Content-Type: application/json' \\ --data '{\"to\":\"reader@example.com\",\"template\":\"welcome\",\"variables\":{\"firstName\":\"Avery\"}}' \\ --output queued.json --write-out 'HTTP %{http_code}\\n' cat queued.json MESSAGE_ID=$(node -p \"JSON.parse(require('fs').readFileSync('queued.json', 'utf8')).id\") printf '\\nMessage ID: %s\\n' \"$MESSAGE_ID\" A successful response looks like {\"id\":\"msg_…\",\"status\":\"queued\"} . If the POST fails, inspect its HTTP status and response before continuing. Do not reuse a message ID from an earlier attempt. Save MESSAGE_ID : The id returned in queued.json; use this exact value for the delivery check. Continue when: The POST returns HTTP 202, status is queued, and MESSAGE_ID is nonempty. This confirms acceptance only. Check delivery for that message Use API_BASE from Before you start : Use the same environment as the queue request. Use MESSAGE_ID from Queue the welcome email : Put the returned ID into the status URL; do not substitute the example ID. Look up the message using the ID saved in the previous step: curl --fail-with-body --silent --show-error \\ \"$API_BASE/messages/$MESSAGE_ID\" \\ --output delivery.json --write-out 'HTTP %{http_code}\\n' cat delivery.json The local demo returns queued on the first lookup. Run the lookup once more to see its terminal status. This deterministic transition is part of the simulation; a real provider needs its own polling interval and timeout. Status or error What to do next queued The request was accepted; delivery is still pending. In this demo, repeat the lookup once. delivered Check that id matches MESSAGE_ID . The delivery check is complete. failed Inspect failureReason . Correct the cause before creating another message; do not keep polling a terminal failure. HTTP 404 Check the saved ID and API base URL. Restarting the demo clears its messages. Connection refused Start the demo and check that it is listening on port 8787. To exercise failure handling, repeat the queue step with blocked@example.com , save its new message ID, and check that ID twice. The demo returns failed with failureReason: recipient_rejected . Save deliveryStatus : The status returned for MESSAGE_ID in delivery.json. Continue when: The response id equals MESSAGE_ID and status is delivered. Queued and failed do not satisfy this recipe's goal. Check the outcome The final response contains the same message ID you saved and status: delivered . You have verified the simulated delivery flow. The local demo sends no email; a real provider reporting delivery still does not prove the recipient read it. Related reading Related topics Welcome email workflows — Compare the complete delivery path with the acceptance-only path."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5053,"markdownTokens":1092,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.recipes-overview","demo":false,"url":"/author/recipes","markdownUrl":"/author/recipes.md","title":"Understand ingredients, recipes, and cookbooks","summary":"See how reusable source instructions become complete recipe pages that a cookbook helps readers choose.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-composition","headings":[{"id":"use-recipes-for-task-oriented-how-tos","title":"Use recipes for task-oriented how-tos"},{"id":"one-example-from-shoalrun","title":"One example from Shoalrun"},{"id":"what-each-file-does","title":"What each file does"},{"id":"what-happens-and-when","title":"What happens, and when"},{"id":"what-changing-an-ingredient-updates","title":"What changing an ingredient updates"},{"id":"how-agents-use-this","title":"How agents use this"},{"id":"try-a-complete-workflow","title":"Try a complete workflow"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"}],"text":"A recipe is the complete page someone follows to finish a task. An ingredient is a reusable piece of source documentation used to write that page. A cookbook is a page that helps readers choose a recipe. Readers can open a recipe directly. Ingredients help authors maintain instructions shared by several recipes. A cookbook becomes useful when readers need help choosing which complete task to follow. Use recipes for task-oriented how-tos Use the built-in how-to template for a task page, or recipe when the page should participate in Shoalrun's recipe and cookbook features. Both take a reader from a known starting state to a verifiable result. Give it prerequisites, ordered actions, failure guidance, and a final success check. A recipe can be a short, directly authored page; it does not require ingredients, a YAML composition spec, or a cookbook. Use the built-in explanation template to explain a concept or help readers understand a system. Use a reference page to describe fields, commands, or API behavior. Existing how-tos can keep their current type, stable ID, and route until a deliberate content revision calls for a change. A page's type does not prove its instructions have been tested. Writing task Starting format Build this site and verify its output A recipe. Explain how the compiler produces HTML and Markdown An explanation page. Look up CLI flags or configuration fields A reference page. Reuse the same build instructions across several recipes An ingredient included by those recipes. Help a reader choose build, audit, or preview A cookbook pointing to complete recipes. The bundled shoalrun-recipes skill follows these choices. See use the agent skills for a copyable authoring request. One example from Shoalrun Suppose you need two sets of instructions: Build and check a page. Compile the CLI, build the docs, and check the HTML and Markdown files. Build and audit the site. Do those same three steps, then run the project audits. Both recipes need the same build instructions. We keep those instructions in ingredient files and use them in both recipe specs: copied into draft copied into draft added to draft Shared ingredients Compile CLI → Build docs → Check artifacts Audit ingredient Run project audits Recipe page Build and check a page Recipe page Build and audit the site Two recipes reuse the same source instructions — The compile, build, and artifact-check ingredients are used in both recipes. The build-and-audit recipe also includes the audit ingredient. These arrows describe authoring reuse; they do not run commands. The Site workflows cookbook offers these two finished recipes. Choosing the audit path displays all four steps. The reader does not have to find or assemble the ingredients. What each file does These are real files in this checkout: File What the author puts there What it contributes docs/content/ingredient-build-site.mdx The build command, explanation, required inputs, expected outputs, and a success check. Reusable source instructions for one step. docs/recipe-specs/audit-docs.yaml An ordered list of ingredient files, starting inputs, and the final goal. Instructions to the recipe assembler about which steps to copy and how to order them. docs/content/recipe-audit-docs.mdx The assembled, reviewed recipe. The complete page a person or agent follows. docs/config/cookbooks.yaml Choice labels and the published recipe ID for each option. The chooser's options and descriptions. docs/content/cookbook-site-workflows.mdx An introduction and <CookbookChooser id=\"site-checks\" /> . The page where readers choose their task. What happens, and when An author prepares ingredients and a recipe spec. Ingredients contain prose and commands. Their optional workflow metadata names the values or artifacts each step needs and produces. The author runs recipe draft . The assembler copies ingredient bodies into a new MDX draft, combines identical prerequisites, and writes the declared handoffs and checks. It checks that each named input is available from setup or an earlier step. The author reviews and tests the recipe, then publishes it. A normal site build turns the recipe page into HTML and Markdown. It also builds the cookbook page and its choice list. A reader chooses a recipe in the cookbook. The browser fetches the already-published recipe and displays its instructions. The reader or their agent runs the commands and checks the results. Selecting a cookbook option does not assemble ingredients or run a task. It loads finished recipe content. The cookbook's own introduction and choice descriptions come from its page and configuration. What changing an ingredient updates A generated recipe is a snapshot of its ingredients. Editing an ingredient does not immediately change a published recipe. Regenerate the affected recipe, review the changes, and rebuild the site. Shoalrun's five repository recipes have a maintenance script that updates their snapshots together and a test that detects stale snapshots","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A recipe is the complete page someone follows to finish a task. An ingredient is a reusable piece of source documentation used to write that page. A cookbook is a page that helps readers choose a recipe. Readers can open a recipe directly. Ingredients help authors maintain instructions shared by several recipes. A cookbook becomes useful when readers need help choosing which complete task to follow. Use recipes for task-oriented how-tos Use the built-in how-to template for a task page, or recipe when the page should participate in Shoalrun's recipe and cookbook features. Both take a reader from a known starting state to a verifiable result. Give it prerequisites, ordered actions, failure guidance, and a final success check. A recipe can be a short, directly authored page; it does not require ingredients, a YAML composition spec, or a cookbook. Use the built-in explanation template to explain a concept or help readers understand a system. Use a reference page to describe fields, commands, or API behavior. Existing how-tos can keep their current type, stable ID, and route until a deliberate content revision calls for a change. A page's type does not prove its instructions have been tested. Writing task Starting format Build this site and verify its output A recipe. Explain how the compiler produces HTML and Markdown An explanation page. Look up CLI flags or configuration fields A reference page. Reuse the same build instructions across several recipes An ingredient included by those recipes. Help a reader choose build, audit, or preview A cookbook pointing to complete recipes. The bundled shoalrun-recipes skill follows these choices. See use the agent skills for a copyable authoring request. One example from Shoalrun Suppose you need two sets of instructions: Build and check a page. Compile the CLI, build the docs, and check the HTML and Markdown files. Build and audit the site. Do those same three steps, then run the project audits. Both recipes need the same build instructions. We keep those instructions in ingredient files and use them in both recipe specs: Two recipes reuse the same source instructions — The compile, build, and artifact-check ingredients are used in both recipes. The build-and-audit recipe also includes the audit ingredient. These arrows describe authoring reuse; they do not run commands. The Site workflows cookbook offers these two finished recipes. Choosing the audit path displays all four steps. The reader does not have to find or assemble the ingredients. What each file does These are real files in this checkout: File What the author puts there What it contributes docs/content/ingredient-build-site.mdx The build command, explanation, required inputs, expected outputs, and a success check. Reusable source instructions for one step. docs/recipe-specs/audit-docs.yaml An ordered list of ingredient files, starting inputs, and the final goal. Instructions to the recipe assembler about which steps to copy and how to order them. docs/content/recipe-audit-docs.mdx The assembled, reviewed recipe. The complete page a person or agent follows. docs/config/cookbooks.yaml Choice labels and the published recipe ID for each option. The chooser's options and descriptions. docs/content/cookbook-site-workflows.mdx An introduction and <CookbookChooser id=\"site-checks\" /> . The page where readers choose their task. What happens, and when An author prepares ingredients and a recipe spec. Ingredients contain prose and commands. Their optional workflow metadata names the values or artifacts each step needs and produces. The author runs recipe draft . The assembler copies ingredient bodies into a new MDX draft, combines identical prerequisites, and writes the declared handoffs and checks. It checks that each named input is available from setup or an earlier step. The author reviews and tests the recipe, then publishes it. A normal site build turns the recipe page into HTML and Markdown. It also builds the cookbook page and its choice list. A reader chooses a recipe in the cookbook. The browser fetches the already-published recipe and displays its instructions. The reader or their agent runs the commands and checks the results. Selecting a cookbook option does not assemble ingredients or run a task. It loads finished recipe content. The cookbook's own introduction and choice descriptions come from its page and configuration. What changing an ingredient updates A generated recipe is a snapshot of its ingredients. Editing an ingredient does not immediately change a published recipe. Regenerate the affected recipe, review the changes, and rebuild the site. Shoalrun's five repository recipes have a maintenance script that updates their snapshots together and a test that detects stale snapshots. The composition guide shows that workflow. Other projects can keep generated recipes as drafts and edit them independently. For example, if the docs build command changes, update the build ingredient once and regenerate the "},{"filters":{"focus":["write"]},"text":"Compose and maintain recipes — Follow the actual ingredient files and spec that produce Shoalrun's audit recipe."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10542,"markdownTokens":2017,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"use-recipes-for-task-oriented-how-tos","title":"Use recipes for task-oriented how-tos","markdownUrl":"/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md","markdownBytes":3623,"markdownTokens":773},{"id":"one-example-from-shoalrun","title":"One example from Shoalrun","markdownUrl":"/author/recipes.sections/one-example-from-shoalrun.md","markdownBytes":3339,"markdownTokens":769},{"id":"what-each-file-does","title":"What each file does","markdownUrl":"/author/recipes.sections/what-each-file-does.md","markdownBytes":3543,"markdownTokens":689},{"id":"what-happens-and-when","title":"What happens, and when","markdownUrl":"/author/recipes.sections/what-happens-and-when.md","markdownBytes":2969,"markdownTokens":662},{"id":"what-changing-an-ingredient-updates","title":"What changing an ingredient updates","markdownUrl":"/author/recipes.sections/what-changing-an-ingredient-updates.md","markdownBytes":2646,"markdownTokens":592},{"id":"how-agents-use-this","title":"How agents use this","markdownUrl":"/author/recipes.sections/how-agents-use-this.md","markdownBytes":3573,"markdownTokens":707},{"id":"try-a-complete-workflow","title":"Try a complete workflow","markdownUrl":"/author/recipes.sections/try-a-complete-workflow.md","markdownBytes":2365,"markdownTokens":555},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/recipes.sections/related-reading.md","markdownBytes":1860,"markdownTokens":441}]},{"id":"guide.related-reading","demo":false,"url":"/author/related-reading","markdownUrl":"/author/related-reading.md","title":"Related reading","summary":"Relationship fields, purposes, ordering, validation, and rendered reading paths.","type":"reference","variant":"production|current|en","area":"components","subarea":"components-navigation","headings":[{"id":"declare-relationships","title":"Declare relationships"},{"id":"where-relationship-explanations-come-from","title":"Where relationship explanations come from"},{"id":"display-related-documents","title":"Display related documents"},{"id":"reading-paths-in-section-markdown","title":"Reading paths in section Markdown"},{"id":"automatic-footers","title":"Automatic footers"},{"id":"inspect-output-and-changes","title":"Inspect output and changes"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"often-confused-with","title":"Often confused with"}],"text":"A relationship is an authored connection between two pages, with a reason to follow the link. Use related reading for prerequisites, next steps, references, and distinctions that help readers choose where to go. The links use stable document IDs and remain in the current publication. For curated cards and filtered collections, see cards and collections . Declare relationships A relationship is an explicit connection between two pages, with a reason to follow the link. For example, a guide can point to the task readers should do next, a prerequisite they should read first, or a useful reference. These connections express your intended reading path; sidebar position and shared operation IDs do not establish that order. Keep the connections in a central config fragment so pages can display them without repeating the target IDs and reasons in their content: docs.config.yaml relationships : { $include : ./config/relationships.yaml } config/relationships.yaml - id : cards-to-output from : guide.related-reading to : guide.output type : next-step reason : Inspect the HTML, Markdown, and manifests produced by the build. order : 10 Field Meaning id Unique relationship ID. from , to Stable document IDs. type A relationship purpose from the table below. reason Required text explaining why the target is useful. order Optional finite number; smaller values come first, with relationship ID as the tie-breaker. Default is 0 . Relationship types describe why a reader should follow the link: Type Purpose / default group heading Direction prerequisite Read first — knowledge needed before this page. From source to target. next-step Next steps — continue the workflow. From source to target. reference Reference while working — look up details. From source to target. advanced Go deeper — explore a more advanced topic. From source to target. see-also Related topics — parallel or complementary material. Both directions. not-confused-with Often confused with — distinguish two topics. Both directions. Declare symmetric pairs only once and write a reason that makes sense from either page. For not-confused-with , explain the actual distinction in the reason. A prerequisite target is something to read before the source. Unknown document IDs, self-links, duplicate IDs, duplicate edges of the same type, and prerequisite cycles within a public publication fail. Different relationship types can connect the same pair. Next-step cycles are allowed for workflows with a return step; provide meaningful reasons. A relationship is published only where both documents have public variants in the same channel, version, and language. Edges to drafts or unavailable variants are omitted from related reading and the public manifest. A relationship does not publish its target or create a cross-version link. Where relationship explanations come from The Why they’re connected text in this site's documentation explorer comes directly from the relationship's authored reason field. Authors maintain that text in docs/config/relationships.yaml . The build validates each relationship and publishes its reason in the relationships array in documents.json . The explorer reads that manifest and displays the explanation. Opening the graph, selecting a page, or inspecting a matrix cell makes no model calls. The explorer does not infer connections or generate explanations from page content. Relationship types, direction, and reasons come from the declared configuration; page titles and summaries come from document metadata. Write a reason that tells readers what the connected page helps them do or understand. Prefer a concrete explanation such as “Inspect the HTML, Markdown, and manifests produced by the build” over “These pages are related.” For two-way relationships, write text that works from either page. The reason field is required by relationship validation. To change an explanation, edit its reason in the relationship configuration and rebuild the site. The same authored reason is available to humans in related-reading views and to agents through documents.json . Display related documents Related reading presents centrally maintained connections as lists of links grouped by purpose. Cards are a visual presentation for page previews. The same relationship data can drive either presentation; declaring a relationship does not require a card. Place this under a level-two heading where related reading belongs: ## Related reading < RelatedReading /> This renders nonempty groups in the order shown in the relationship-type table, with level-three headings. Within each group, links follow order , then relationship ID. Each list item uses the target's page title and the relationship reason. Card titles, descriptions, eyebrows, and icons do not change the default link list. Subject lifecycle status remains visible. Titles and URLs come from the target page; maintain only IDs, relationship purposes, and reasons in the central mapping. To show one kind of relationship und","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A relationship is an authored connection between two pages, with a reason to follow the link. Use related reading for prerequisites, next steps, references, and distinctions that help readers choose where to go. The links use stable document IDs and remain in the current publication. For curated cards and filtered collections, see cards and collections . Declare relationships A relationship is an explicit connection between two pages, with a reason to follow the link. For example, a guide can point to the task readers should do next, a prerequisite they should read first, or a useful reference. These connections express your intended reading path; sidebar position and shared operation IDs do not establish that order. Keep the connections in a central config fragment so pages can display them without repeating the target IDs and reasons in their content: relationships: { $include: ./config/relationships.yaml } - id: cards-to-output from: guide.related-reading to: guide.output type: next-step reason: Inspect the HTML, Markdown, and manifests produced by the build. order: 10 Field Meaning id Unique relationship ID. from , to Stable document IDs. type A relationship purpose from the table below. reason Required text explaining why the target is useful. order Optional finite number; smaller values come first, with relationship ID as the tie-breaker. Default is 0 . Relationship types describe why a reader should follow the link: Type Purpose / default group heading Direction prerequisite Read first — knowledge needed before this page. From source to target. next-step Next steps — continue the workflow. From source to target. reference Reference while working — look up details. From source to target. advanced Go deeper — explore a more advanced topic. From source to target. see-also Related topics — parallel or complementary material. Both directions. not-confused-with Often confused with — distinguish two topics. Both directions. Declare symmetric pairs only once and write a reason that makes sense from either page. For not-confused-with , explain the actual distinction in the reason. A prerequisite target is something to read before the source. Unknown document IDs, self-links, duplicate IDs, duplicate edges of the same type, and prerequisite cycles within a public publication fail. Different relationship types can connect the same pair. Next-step cycles are allowed for workflows with a return step; provide meaningful reasons. A relationship is published only where both documents have public variants in the same channel, version, and language. Edges to drafts or unavailable variants are omitted from related reading and the public manifest. A relationship does not publish its target or create a cross-version link. Where relationship explanations come from The Why they’re connected text in this site's documentation explorer comes directly from the relationship's authored reason field. Authors maintain that text in docs/config/relationships.yaml . The build validates each relationship and publishes its reason in the relationships array in documents.json . The explorer reads that manifest and displays the explanation. Opening the graph, selecting a page, or inspecting a matrix cell makes no model calls. The explorer does not infer connections or generate explanations from page content. Relationship types, direction, and reasons come from the declared configuration; page titles and summaries come from document metadata. Write a reason that tells readers what the connected page helps them do or understand. Prefer a concrete explanation such as “Inspect the HTML, Markdown, and manifests produced by the build” over “These pages are related.” For two-way relationships, write text that works from either page. The reason field is required by relationship validation. To change an explanation, edit its reason in the relationship configuration and rebuild the site. The same authored reason is available to humans in related-reading views and to agents through documents.json . Display related documents Related reading presents centrally maintained connections as lists of links grouped by purpose. Cards are a visual presentation for page previews. The same relationship data can drive either presentation; declaring a relationship does not require a card. Place this under a level-two heading where related reading belongs: ## Related reading <RelatedReading /> This renders nonempty groups in the order shown in the relationship-type table, with level-three headings. Within each group, links follow order , then relationship ID. Each list item uses the target's page title and the relationship reason. Card titles, descriptions, eyebrows, and icons do not change the default link list. Subject lifecycle status remains visible. Titles and URLs come from the target page; maintain only IDs, relationship purposes, and reasons in the central mapping. To show one kind of relationship under your own heading: ## Next steps <RelatedReading relati"},{"filters":{"focus":["write"]},"text":"RelatedReading — Look up every RelatedReading attribute. Cards and collections — Related reading follows authored relationships with reasons; cards and collections show pages you pick by ID or filter by metadata."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":11022,"markdownTokens":2110,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"declare-relationships","title":"Declare relationships","markdownUrl":"/author/related-reading.sections/declare-relationships.md","markdownBytes":4659,"markdownTokens":894},{"id":"where-relationship-explanations-come-from","title":"Where relationship explanations come from","markdownUrl":"/author/related-reading.sections/where-relationship-explanations-come-from.md","markdownBytes":2562,"markdownTokens":546},{"id":"display-related-documents","title":"Display related documents","markdownUrl":"/author/related-reading.sections/display-related-documents.md","markdownBytes":2663,"markdownTokens":589},{"id":"reading-paths-in-section-markdown","title":"Reading paths in section Markdown","markdownUrl":"/author/related-reading.sections/reading-paths-in-section-markdown.md","markdownBytes":2556,"markdownTokens":540},{"id":"automatic-footers","title":"Automatic footers","markdownUrl":"/author/related-reading.sections/automatic-footers.md","markdownBytes":1948,"markdownTokens":442},{"id":"inspect-output-and-changes","title":"Inspect output and changes","markdownUrl":"/author/related-reading.sections/inspect-output-and-changes.md","markdownBytes":2365,"markdownTokens":508},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/related-reading.sections/related-reading.md","markdownBytes":1634,"markdownTokens":383}]},{"id":"guide.release-notes","demo":false,"url":"/author/release-notes","markdownUrl":"/author/release-notes.md","title":"Write release notes and changelog entries","summary":"Write flexible release summaries and changelog entries identified by date or version.","type":"how-to","variant":"production|current|en","area":"project","subarea":"project-releases","headings":[{"id":"write-a-release-note","title":"Write a release note"},{"id":"write-a-changelog-entry","title":"Write a changelog entry"},{"id":"set-the-identifier-rule","title":"Set the identifier rule"},{"id":"describe-what-changed","title":"Describe what changed"},{"id":"collect-updates","title":"Collect updates"},{"id":"check-the-published-entries","title":"Check the published entries"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"Release notes and changelog entries serve different reading needs. A release note summarizes a named release, quarter, or other period. A changelog entry records a change identified by date, release version, or both. Both are ordinary Markdown or MDX pages with HTML and Markdown outputs and stable IDs. Write a release note Use type: release-note . Its title and content define the scope; neither a date nor a release version is required. This example covers a quarter without claiming one publication day: content/releases/q3-summary.mdx --- id : release.q3-summary title : Q3 2026 summary summary : Changes grouped for the quarter. type : release-note slug : /releases/q3-summary channel : production version : current access : { policy : public } --- channel and version must name an enabled publication, or come from global frontmatter . A note for one release can instead use releaseVersion: \"2.4\" and a version in its title. releaseVersion identifies the product release; the ordinary version field selects a documentation publication. The two fields are independent. Add date only when the note has a meaningful publication date. Write a changelog entry Use type: changelog-entry and identify the change with date , releaseVersion , or both. The project sets which field is required. The default accepts either. A date must be a real YYYY-MM-DD calendar date; a release version must be nonempty text. content/changelog/example.mdx --- id : change.example title : Example change summary : A short description of the change. type : changelog-entry date : 2026-09-24 slug : /changelog/example channel : production version : current access : { policy : public } tags : [ api-reference ] --- The build shows supplied dates and release versions on pages and cards, and includes them in Markdown twins. Dated changelog entries show their publication date without a separate Updated label in the page header or Markdown body. Revision dates remain in the document manifest and configured Markdown metadata. This site's Markdown metadata also projects the date and release version when present. Set the identifier rule Configure frontmatter.changelogIdentifier in project config: docs.config.yaml frontmatter : changelogIdentifier : either Value Required on each changelog entry either A date, a release version, or both. Default. date A date. A release version is optional. version A release version. A date is optional. This rule does not apply to release notes. It also does not change the documentation publication's version axis. Describe what changed On a changelog-entry , add an optional change block to distinguish an editorial correction from a changed procedure or behavior. This fictional example describes a breaking API change: change : kind : breaking affects : [ reference.create-payment , guide.create-payment ] migration : guide.migrate-payments Replace these IDs with public pages in the entry's channel, version, and language. Use stable IDs without the doc: prefix. Targets resolve to their current titles and URLs. Missing, draft, self, and other-publication targets fail the build; external URLs and references to removed pages are not supported in this increment. Field Required Meaning kind Yes One author-declared classification from the table below. affects Yes Nonempty list of unique document IDs that describe the affected subjects or instructions. Order is preserved. migration No Document ID of the guide explaining how to adapt. Kind Use when editorial Correcting wording or presentation without changing the documented instructions or behavior. procedure Changing instructions, setup steps, or a recommended workflow. behavior Describing a feature or behavior change that the author has not classified as breaking. breaking Existing clients or workflows need adaptation because of the change. Choose the kind deliberately and explain scope and limitations in the entry body. behavior is not a compiler guarantee of compatibility. A missing migration link does not mean migration is unnecessary. When one release contains several distinct changes, agree on the grouping before drafting: one combined entry with clearly scoped sections, or separate entries collected in a release note. Use one change classification only when it accurately describes the combined entry; otherwise leave the entry unclassified and explain each change in its body. change is page-specific: global defaults and enforced metadata cannot set it. It is accepted only on changelog-entry pages, not release summaries or ordinary guides. Unknown keys fail. Use the entry's existing date and releaseVersion fields for its date and release label; this block does not add an effective-date schedule or prove deployment. HTML, full Markdown, and every published section of the entry show an Authored change notice with the kind, affected pages, and migration link when supplied. HTML links open pages; Markdown links open their twins. The corresponding documents.json record includes change.kind , r","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Release notes and changelog entries serve different reading needs. A release note summarizes a named release, quarter, or other period. A changelog entry records a change identified by date, release version, or both. Both are ordinary Markdown or MDX pages with HTML and Markdown outputs and stable IDs. Write a release note Use type: release-note . Its title and content define the scope; neither a date nor a release version is required. This example covers a quarter without claiming one publication day: --- id: release.q3-summary title: Q3 2026 summary summary: Changes grouped for the quarter. type: release-note slug: /releases/q3-summary channel: production version: current access: { policy: public } --- channel and version must name an enabled publication, or come from global frontmatter . A note for one release can instead use releaseVersion: \"2.4\" and a version in its title. releaseVersion identifies the product release; the ordinary version field selects a documentation publication. The two fields are independent. Add date only when the note has a meaningful publication date. Write a changelog entry Use type: changelog-entry and identify the change with date , releaseVersion , or both. The project sets which field is required. The default accepts either. A date must be a real YYYY-MM-DD calendar date; a release version must be nonempty text. --- id: change.example title: Example change summary: A short description of the change. type: changelog-entry date: 2026-09-24 slug: /changelog/example channel: production version: current access: { policy: public } tags: [api-reference] --- The build shows supplied dates and release versions on pages and cards, and includes them in Markdown twins. Dated changelog entries show their publication date without a separate Updated label in the page header or Markdown body. Revision dates remain in the document manifest and configured Markdown metadata. This site's Markdown metadata also projects the date and release version when present. Set the identifier rule Configure frontmatter.changelogIdentifier in project config: frontmatter: changelogIdentifier: either Value Required on each changelog entry either A date, a release version, or both. Default. date A date. A release version is optional. version A release version. A date is optional. This rule does not apply to release notes. It also does not change the documentation publication's version axis. Describe what changed On a changelog-entry , add an optional change block to distinguish an editorial correction from a changed procedure or behavior. This fictional example describes a breaking API change: change: kind: breaking affects: [reference.create-payment, guide.create-payment] migration: guide.migrate-payments Replace these IDs with public pages in the entry's channel, version, and language. Use stable IDs without the doc: prefix. Targets resolve to their current titles and URLs. Missing, draft, self, and other-publication targets fail the build; external URLs and references to removed pages are not supported in this increment. Field Required Meaning kind Yes One author-declared classification from the table below. affects Yes Nonempty list of unique document IDs that describe the affected subjects or instructions. Order is preserved. migration No Document ID of the guide explaining how to adapt. Kind Use when editorial Correcting wording or presentation without changing the documented instructions or behavior. procedure Changing instructions, setup steps, or a recommended workflow. behavior Describing a feature or behavior change that the author has not classified as breaking. breaking Existing clients or workflows need adaptation because of the change. Choose the kind deliberately and explain scope and limitations in the entry body. behavior is not a compiler guarantee of compatibility. A missing migration link does not mean migration is unnecessary. When one release contains several distinct changes, agree on the grouping before drafting: one combined entry with clearly scoped sections, or separate entries collected in a release note. Use one change classification only when it accurately describes the combined entry; otherwise leave the entry unclassified and explain each change in its body. change is page-specific: global defaults and enforced metadata cannot set it. It is accepted only on changelog-entry pages, not release summaries or ordinary guides. Unknown keys fail. Use the entry's existing date and releaseVersion fields for its date and release label; this block does not add an effective-date schedule or prove deployment. HTML, full Markdown, and every published section of the entry show an Authored change notice with the kind, affected pages, and migration link when supplied. HTML links open pages; Markdown links open their twins. The corresponding documents.json record includes change.kind , resolved change.affects targets, and optional change.migration . Each target has id , title , url , and markdow"},{"filters":{"focus":["write"]},"text":"Cards and collections — Filter and order a collection of changelog entries."},{"filters":{"focus":["write"],"audience":["authors","maintainers"]},"text":"Page metadata — Look up the date and releaseVersion fields that order entries."},{"filters":{"focus":["configure"]},"text":"Use Git branches for separate docs sites — Release notes tell readers what changed; release revisions choose which Git revision of the docs to build and deploy."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9499,"markdownTokens":1946,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.release-revisions","demo":false,"url":"/publish/revisions","markdownUrl":"/publish/revisions.md","title":"Use Git branches for separate docs sites","summary":"Build a chosen Git branch for each docs address, add links between sites, and verify the deployed commit.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-versions","headings":[{"id":"build-and-deploy-each-source","title":"Build and deploy each source"},{"id":"add-another-site-to-the-version-menu","title":"Add another site to the Version menu"},{"id":"what-agents-receive","title":"What agents receive"},{"id":"check-the-deployed-source","title":"Check the deployed source"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"A deployment takes the docs files from a Git branch or commit, builds them, and serves the result at an address you choose. Your host or CI service chooses the source and destination. Branch names have no special meaning to Shoalrun. For example, either of these mappings can work: Workflow Source Docs address Sandbox and production sandbox sandbox-docs.example.com Sandbox and production main docs.example.com Next and stable next next-docs.example.com Next and stable stable docs.example.com You can use another branch name, a tag, or a fixed commit. You can also use path-based versions within one build instead of separate sites. Branches choose which files to build ; publications choose which editions those files produce . Build and deploy each source Set site.origin in each site's config to its public HTTPS origin. A site at next-docs.example.com , for example, uses site.origin: https://next-docs.example.com . Commit the pages, API sources, and publication settings for that site. After the deployment job checks out its chosen source, build it with the full commit hash: shoalrun build docs.config.yaml site-dist --source-commit \"$( git rev-parse HEAD )\" Deploy all of site-dist/ to the address assigned to that source. Configure this source-to-address rule in your host or CI service; Shoalrun does not deploy files or infer a branch from channel . See deploy your documentation for hosting options. If two separate domains should both serve /start , use an empty channel pathPrefix in each site's config. Add another site to the Version menu Add an external site when readers should be able to move between addresses. In the current site's publications section, keep its existing defaults , channels , versions , and enabled entries, and add: docs.config.yaml (fragment) publications : externalSites : - label : Next docs baseUrl : https://next-docs.example.com This adds Next docs to the Version menu on every page. The link opens that site's root. Add the corresponding link in the other site's config if readers should be able to switch back. baseUrl can be another domain or an address with a path, such as https://docs.example.com/next/ . To keep a reader on the matching page , provide a local snapshot of the other site's built documents.json : docs.config.yaml (fragment) publications : externalSites : - label : Next docs baseUrl : https://next-docs.example.com manifest : ./config/next-documents.json Shoalrun matches stable document IDs and uses the other site's published paths. Only pages in that manifest appear in the menu. Copy or refresh the manifest as part of your release process when pages change. This extra step is optional; the direct site link above is enough for a simple branch switcher. A baseUrl with a path changes where the menu points. Hosting a whole standalone build under a path also requires the host to handle Shoalrun's root-level assets and discovery files. Path prefixes inside one build already work without that hosting setup. What agents receive Each deployed site has its own Markdown pages, documents.json , search index, and agent discovery files, built from that site's selected Git revision. An agent using the stable site reads its stable artifacts; an agent using the next site reads its next artifacts. The external Version menu helps human readers navigate between sites, but it does not combine their manifests or Markdown copies. Preserve a built release or its tagged source if agents must be able to consult it later. See published outputs for the file list. Check the deployed source Each build writes its source commit to /build-info.json . Run the post-deploy checker with the full hash selected by that site's deployment job: npm --prefix framework run deploy:check -- https://next-docs.example.com/ --source-commit \"$DEPLOYED_COMMIT\" The checker fails if the address serves a different commit or if its published HTML and Markdown routes fail their HTTP checks. Run it for each site. For a durable release record, tag the source commit and retain the built output with /build-info.json ; a branch moves as new commits arrive. Related reading Read first How Shoalrun works — Understand publications, channels, and versions. Next steps Check a deployed site — Check each deployed revision before you release it. Related topics Share pages across documentation versions — Distinguish content editions from source revisions and retained builds. Often confused with Write release notes and changelog entries — Release notes tell readers what changed; release revisions choose which Git revision of the docs to build and deploy.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"A deployment takes the docs files from a Git branch or commit, builds them, and serves the result at an address you choose. Your host or CI service chooses the source and destination. Branch names have no special meaning to Shoalrun. For example, either of these mappings can work: Workflow Source Docs address Sandbox and production sandbox sandbox-docs.example.com Sandbox and production main docs.example.com Next and stable next next-docs.example.com Next and stable stable docs.example.com You can use another branch name, a tag, or a fixed commit. You can also use path-based versions within one build instead of separate sites. Branches choose which files to build ; publications choose which editions those files produce . Build and deploy each source Set site.origin in each site's config to its public HTTPS origin. A site at next-docs.example.com , for example, uses site.origin: https://next-docs.example.com . Commit the pages, API sources, and publication settings for that site. After the deployment job checks out its chosen source, build it with the full commit hash: shoalrun build docs.config.yaml site-dist --source-commit \"$(git rev-parse HEAD)\" Deploy all of site-dist/ to the address assigned to that source. Configure this source-to-address rule in your host or CI service; Shoalrun does not deploy files or infer a branch from channel . See deploy your documentation for hosting options. If two separate domains should both serve /start , use an empty channel pathPrefix in each site's config. Add another site to the Version menu Add an external site when readers should be able to move between addresses. In the current site's publications section, keep its existing defaults , channels , versions , and enabled entries, and add: publications: externalSites: - label: Next docs baseUrl: https://next-docs.example.com This adds Next docs to the Version menu on every page. The link opens that site's root. Add the corresponding link in the other site's config if readers should be able to switch back. baseUrl can be another domain or an address with a path, such as https://docs.example.com/next/ . To keep a reader on the matching page , provide a local snapshot of the other site's built documents.json : publications: externalSites: - label: Next docs baseUrl: https://next-docs.example.com manifest: ./config/next-documents.json Shoalrun matches stable document IDs and uses the other site's published paths. Only pages in that manifest appear in the menu. Copy or refresh the manifest as part of your release process when pages change. This extra step is optional; the direct site link above is enough for a simple branch switcher. A baseUrl with a path changes where the menu points. Hosting a whole standalone build under a path also requires the host to handle Shoalrun's root-level assets and discovery files. Path prefixes inside one build already work without that hosting setup. What agents receive Each deployed site has its own Markdown pages, documents.json , search index, and agent discovery files, built from that site's selected Git revision. An agent using the stable site reads its stable artifacts; an agent using the next site reads its next artifacts. The external Version menu helps human readers navigate between sites, but it does not combine their manifests or Markdown copies. Preserve a built release or its tagged source if agents must be able to consult it later. See published outputs for the file list. Check the deployed source Each build writes its source commit to /build-info.json . Run the post-deploy checker with the full hash selected by that site's deployment job: npm --prefix framework run deploy:check -- https://next-docs.example.com/ --source-commit \"$DEPLOYED_COMMIT\" The checker fails if the address serves a different commit or if its published HTML and Markdown routes fail their HTTP checks. Run it for each site. For a durable release record, tag the source commit and retain the built output with /build-info.json ; a branch moves as new commits arrive. Related reading Read first How Shoalrun works — Understand publications, channels, and versions. Next steps Related topics Often confused with"},{"filters":{"focus":["configure"]},"text":"Check a deployed site — Check each deployed revision before you release it. Share pages across documentation versions — Distinguish content editions from source revisions and retained builds."},{"filters":{"focus":["write"]},"text":"Write release notes and changelog entries — Release notes tell readers what changed; release revisions choose which Git revision of the docs to build and deploy."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6255,"markdownTokens":1419,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.retrieval-chat","demo":false,"url":"/chat","markdownUrl":"/chat.md","title":"How documentation answers work","summary":"Understand how passages, embeddings, scoring, and a chat model produce cited answers.","type":"explanation","variant":"production|current|en","area":"discovery","subarea":"discovery-chat","headings":[{"id":"how-the-layers-fit","title":"How the layers fit"},{"id":"how-a-question-is-answered","title":"How a question is answered"},{"id":"put-the-model-into-practice","title":"Put the model into practice"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Documentation chat reads a site you have already built. It is optional: a normal shoalrun build does not call the retrieval or chat providers. Chat first finds relevant passages, then uses them to produce a cited answer. A passage is a short part of a built Markdown page with a link back to its source. Some configurations can return an existing answer or an excerpt instead of generating new text. For commands, start with local chat setup . Search and chat compares chat with the page-search box. How the layers fit Each layer adds a retrieval or answer capability and has its own prerequisites. Layer What it adds It needs Keyword matching Finds the most relevant passages by their words. It is what the chat uses when there are no vectors, or the embedding service is unavailable. The passage index. No key. Semantic search Finds passages by meaning, so a question matches even when it shares no words with the page. An embedding service and key. Relevance scorer Reorders the results and declines a question the docs don't cover. It checks each sentence of an answer, and shows a passage word for word when one is clearly the answer. A scorer service that speaks the Jev protocol. Chat model Writes a cited answer from the best passages. A chat service and key. Hosting Runs the chat beside your site with spending caps and an off switch. Vercel, and a key-value store. The site-search box returns links from its own page index. Chat retrieves passages to answer a question. An embedding service helps match different wording; a scorer rates whether the passages support an answer. The settings reference describes supported providers and the Jev scoring protocol. Choose services and models in config. Keep their keys in the environment variables named by that config. How a question is answered The diagram shows a chat with optional reuse and scoring enabled. A question stops at an existing answer or direct excerpt when the configured checks accept one. asked before new question docs do not cover it one clear winner anything else flagged: ask a second model passes Question Cached answer or answer card Find passages by keyword, and by meaning if set up Answer Relevance scorer decides Not covered List the closest pages One clear passage Show it word for word Chat model Write a cited answer Check citations, code, and claims How a question is answered — A question first looks for a cached answer or an answer card. Otherwise passages are found by keyword and meaning, and the relevance scorer decides. A question the docs don't cover gets a list of pages. One clear passage is shown as an excerpt. Everything else goes to the chat model, whose answer is checked before it is shown. The minimal setup uses keyword retrieval, a chat model, and citation and code checks. Caching, answer cards, scoring, and claim verification need extra configuration. Without a scorer, there is no score-based coverage gate. For an explicit request with up to three action clauses, retrieval can find evidence for each part and include page introductions. This helps keep one topic from filling the passage budget. Answer checks explains that behavior and its limits. Put the model into practice Add optional layers after testing the minimal setup with questions your readers actually ask. Check source coverage and response quality before choosing scoring thresholds or enabling answer reuse. Use set up local documentation chat for commands and verification. The retrieval and chat settings define provider fields and defaults. Passage index describes the files used by retrieval. Related reading Next steps Passage index — See how a built site is split into passages and embedded. (Status: experimental.) Check and speed up answers — Decline questions the docs don't cover and check what the model writes. (Status: experimental.) Host and limit documentation chat — Run the chat beside your site with spending caps and an off switch. (Status: experimental.) Reference while working CLI reference — Look up the index, ask, answers, ask-log, chat, and serve commands. Retrieval and chat settings — Look up every retrieval and chat setting. (Status: experimental.) Related topics Set up local documentation chat — Understand the layers behind cited answers before choosing additional services. (Status: experimental.) Site search — Use retrieved passages to produce cited answers instead of page links.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Documentation chat reads a site you have already built. It is optional: a normal shoalrun build does not call the retrieval or chat providers. Chat first finds relevant passages, then uses them to produce a cited answer. A passage is a short part of a built Markdown page with a link back to its source. Some configurations can return an existing answer or an excerpt instead of generating new text. For commands, start with local chat setup . Search and chat compares chat with the page-search box. How the layers fit Each layer adds a retrieval or answer capability and has its own prerequisites. Layer What it adds It needs Keyword matching Finds the most relevant passages by their words. It is what the chat uses when there are no vectors, or the embedding service is unavailable. The passage index. No key. Semantic search Finds passages by meaning, so a question matches even when it shares no words with the page. An embedding service and key. Relevance scorer Reorders the results and declines a question the docs don't cover. It checks each sentence of an answer, and shows a passage word for word when one is clearly the answer. A scorer service that speaks the Jev protocol. Chat model Writes a cited answer from the best passages. A chat service and key. Hosting Runs the chat beside your site with spending caps and an off switch. Vercel, and a key-value store. The site-search box returns links from its own page index. Chat retrieves passages to answer a question. An embedding service helps match different wording; a scorer rates whether the passages support an answer. The settings reference describes supported providers and the Jev scoring protocol. Choose services and models in config. Keep their keys in the environment variables named by that config. How a question is answered The diagram shows a chat with optional reuse and scoring enabled. A question stops at an existing answer or direct excerpt when the configured checks accept one. How a question is answered — A question first looks for a cached answer or an answer card. Otherwise passages are found by keyword and meaning, and the relevance scorer decides. A question the docs don't cover gets a list of pages. One clear passage is shown as an excerpt. Everything else goes to the chat model, whose answer is checked before it is shown. The minimal setup uses keyword retrieval, a chat model, and citation and code checks. Caching, answer cards, scoring, and claim verification need extra configuration. Without a scorer, there is no score-based coverage gate. For an explicit request with up to three action clauses, retrieval can find evidence for each part and include page introductions. This helps keep one topic from filling the passage budget. Answer checks explains that behavior and its limits. Put the model into practice Add optional layers after testing the minimal setup with questions your readers actually ask. Check source coverage and response quality before choosing scoring thresholds or enabling answer reuse. Use set up local documentation chat for commands and verification. The retrieval and chat settings define provider fields and defaults. Passage index describes the files used by retrieval. Related reading Next steps Reference while working CLI reference — Look up the index, ask, answers, ask-log, chat, and serve commands. Related topics"},{"filters":{"focus":["configure"]},"text":"Passage index — See how a built site is split into passages and embedded. (Status: experimental.) Check and speed up answers — Decline questions the docs don't cover and check what the model writes. (Status: experimental.) Host and limit documentation chat — Run the chat beside your site with spending caps and an off switch. (Status: experimental.) Retrieval and chat settings — Look up every retrieval and chat setting. (Status: experimental.) Set up local documentation chat — Understand the layers behind cited answers before choosing additional services. (Status: experimental.) Site search — Use retrieved passages to produce cited answers instead of page links."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":7275,"markdownTokens":1472,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.search-chat-overview","demo":false,"url":"/search-and-chat","markdownUrl":"/search-and-chat.md","title":"Search and chat","summary":"Choose page search, meaning-based search, or cited answers for your documentation.","type":"explanation","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"choose-the-result-you-want","title":"Choose the result you want"},{"id":"start-with-a-local-chat","title":"Start with a local chat"},{"id":"which-index-does-each-feature-use","title":"Which index does each feature use?"},{"id":"when-an-optional-service-is-unavailable","title":"When an optional service is unavailable"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"}],"text":"Start with site search if readers need links to pages and sections. It is built in, works on a static host, and needs no provider account. Add chat when readers need answers written from your documentation. Choose the result you want These features have different setup and hosting needs. Passage retrieval and chat are experimental. Reader needs Feature Requirements Page and section links Site search A normal site build and a browser with JavaScript. Links that can match different wording Semantic search preview A passage index, embeddings, and a local search endpoint. The provider can fall back to keyword search. An answer with source citations Documentation chat A passage index, a configured chat service, and a terminal or server. Embeddings and a scorer are optional additions. The sidebar's navigation filter only narrows the menu. Its search words do not change site-search results. The search dropdown returns links; it does not call a chat model. Start with a local chat Follow Set up local documentation chat to configure a service, index your pages, and inspect an answer with sources. Once that works, choose the next capability you need: Answer checks explain coverage, citations, code checks, and answer reuse. Answer cards prepare reviewed answers to recurring questions. Hosting adds a Vercel function, shared limits, and an off switch. Settings define the provider fields and optional layers. Which index does each feature use? Shoalrun keeps page search and passage retrieval separate. File Created by Used for search-index.json The normal site build when search indexing is enabled. Browser page search and local documentation search. Contains titles, summaries, headings, and text excerpts. ai/chunks.json shoalrun index after the build. Passage retrieval for semantic search and chat. Contains text from built Markdown pages, with source links. ai/embeddings.json and .bin shoalrun index --embed Comparing the meaning of queries and passages. Requires an embedding provider. An embedding represents text as numbers. Keyword, or lexical , retrieval compares words. Semantic retrieval compares embeddings; hybrid retrieval combines word-based and meaning-based rankings. Neither requires a chat model just to return search links. The passage reference describes these files in detail. The glossary defines the related terms. When an optional service is unavailable Fallback behavior depends on the configured feature. Situation Result Built-in search has no server or provider key Browser keyword search still works. This site's custom search provider cannot reach its endpoint It uses the browser keyword index. A search endpoint has no current vectors, or embeddings fail It returns keyword passage results. Chat has no current vectors Retrieval uses keywords. A configured chat model can still write an answer. A deployment has no chat function The site remains available, but has no chat endpoint. A Vercel build with --chat includes search and answer endpoints. Semantic queries have shared rate and daily limits. When the embedding budget is exhausted, search returns keyword results. A static deployment can use browser search without those endpoints. Related reading Next steps How documentation answers work — Turn passage retrieval into cited answers. (Status: experimental.) Site search — Configure the masthead box, its provider, and searchable index fields. Reference while working Glossary — Look up the search and retrieval terms used in this section. Passage index — Compare the page index with the passage and vector files. (Status: experimental.)","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Start with site search if readers need links to pages and sections. It is built in, works on a static host, and needs no provider account. Add chat when readers need answers written from your documentation. Choose the result you want These features have different setup and hosting needs. Passage retrieval and chat are experimental. Reader needs Feature Requirements Page and section links Site search A normal site build and a browser with JavaScript. Links that can match different wording Semantic search preview A passage index, embeddings, and a local search endpoint. The provider can fall back to keyword search. An answer with source citations Documentation chat A passage index, a configured chat service, and a terminal or server. Embeddings and a scorer are optional additions. The sidebar's navigation filter only narrows the menu. Its search words do not change site-search results. The search dropdown returns links; it does not call a chat model. Start with a local chat Follow Set up local documentation chat to configure a service, index your pages, and inspect an answer with sources. Once that works, choose the next capability you need: Answer checks explain coverage, citations, code checks, and answer reuse. Answer cards prepare reviewed answers to recurring questions. Hosting adds a Vercel function, shared limits, and an off switch. Settings define the provider fields and optional layers. Which index does each feature use? Shoalrun keeps page search and passage retrieval separate. File Created by Used for search-index.json The normal site build when search indexing is enabled. Browser page search and local documentation search. Contains titles, summaries, headings, and text excerpts. ai/chunks.json shoalrun index after the build. Passage retrieval for semantic search and chat. Contains text from built Markdown pages, with source links. ai/embeddings.json and .bin shoalrun index --embed Comparing the meaning of queries and passages. Requires an embedding provider. An embedding represents text as numbers. Keyword, or lexical , retrieval compares words. Semantic retrieval compares embeddings; hybrid retrieval combines word-based and meaning-based rankings. Neither requires a chat model just to return search links. The passage reference describes these files in detail. The glossary defines the related terms. When an optional service is unavailable Fallback behavior depends on the configured feature. Situation Result Built-in search has no server or provider key Browser keyword search still works. This site's custom search provider cannot reach its endpoint It uses the browser keyword index. A search endpoint has no current vectors, or embeddings fail It returns keyword passage results. Chat has no current vectors Retrieval uses keywords. A configured chat model can still write an answer. A deployment has no chat function The site remains available, but has no chat endpoint. A Vercel build with --chat includes search and answer endpoints. Semantic queries have shared rate and daily limits. When the embedding budget is exhausted, search returns keyword results. A static deployment can use browser search without those endpoints. Related reading Next steps Reference while working Glossary — Look up the search and retrieval terms used in this section."},{"filters":{"focus":["configure"]},"text":"How documentation answers work — Turn passage retrieval into cited answers. (Status: experimental.) Site search — Configure the masthead box, its provider, and searchable index fields. Passage index — Compare the page index with the passage and vector files. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6825,"markdownTokens":1258,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.search","demo":false,"url":"/author/search","markdownUrl":"/author/search.md","title":"Site search","summary":"Search settings, keyboard behavior, provider interfaces, and index fields.","type":"reference","variant":"production|current|en","area":"discovery","subarea":"discovery-search","headings":[{"id":"choose-a-provider","title":"Choose a provider"},{"id":"use-the-search-box","title":"Use the search box"},{"id":"lexical-search","title":"Lexical search"},{"id":"synonyms","title":"Synonyms"},{"id":"result-ordering-and-limits","title":"Result ordering and limits"},{"id":"hosted-semantic-search-limits","title":"Hosted semantic search limits"},{"id":"write-a-custom-provider","title":"Write a custom provider"},{"id":"search-context","title":"Search context"},{"id":"search-results","title":"Search results"},{"id":"module-limits","title":"Module limits"},{"id":"reuse-the-lexical-index","title":"Reuse the lexical index"},{"id":"turn-search-off","title":"Turn search off"},{"id":"local-semantic-preview","title":"Local semantic preview"},{"id":"cli-and-mcp-ranking-details","title":"CLI and MCP ranking details"},{"id":"partial-matches","title":"Partial matches"},{"id":"title-plurals","title":"Title plurals"},{"id":"mixed-matches","title":"Mixed matches"},{"id":"read-a-search-result-with-an-agent","title":"Read a search result with an agent"},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Site search returns links to pages and sections. It is enabled by default and matches words in the browser, with no provider account or server required. Shoalrun supplies the search box and keyboard controls. A search provider supplies results; you can replace the built-in provider with your own module. Search and chat explains when to add semantic search or cited answers. Choose a provider Set the provider under outputs.html.search : docs.config.yaml outputs : html : search : provider : lexical Provider Behavior lexical The default. Builds /search-index.json and matches it in the browser. custom Loads your browser module. Needs module ; index is optional. none Removes the search box. Writes no index or provider file. The build copies the provider module to /assets/search-provider.js . The search box imports that file when a reader first focuses the box or types. Use the search box Press / or Ctrl + K ( ⌘ + K on macOS) to focus the box. Use the arrow keys to move through results, Enter to open one, and Escape to close the list. When a match falls inside a section, the result names the section and links to its heading. The box needs JavaScript. Without it, both the search box and sidebar filter stay hidden; the published navigation links still work. Lexical search The built-in provider matches words rather than meaning. It lowercases the query and recognizes phrases declared in search.synonyms . The browser provider ranks matches in this order: Pages containing every query term or its mapped synonym. If none match completely, partial results ordered by matched term count, then field score. Common filler words such as “how,” “do,” and “the” do not count toward partial-match coverage. A partial result must match at least one remaining term. This helps sentence-shaped queries but does not infer meaning or handle typos and general stemming. The local search command shares the base index and weights, with additional CLI/MCP ranking rules described below. Synonyms Projects can define their own synonym groups of words and phrases. Put them in a YAML file and include it from the site config: docs.config.yaml search : synonyms : { $include : ./config/search-synonyms.yaml } The included file lists equivalent words or phrases: config/search-synonyms.yaml - [ walkthrough , \"walk through\" , \"code tutorial\" , tutorial ] Each group works in both directions. Exact word or phrase matches rank above synonym matches. A term can belong to only one group; groups need at least two distinct terms. Phrase matching respects word boundaries, so walk through is treated as one term. Shoalrun validates the file during config loading and includes its mapping in /search-index.json and ai/chunks.json . Browser search, shoalrun search , and lexical passage retrieval for chat share that vocabulary. Rebuild the site and passage index after editing the file. Custom search providers must read the mapping from /search-index.json if they want to apply it to their own results. Result ordering and limits Pages rank by where the terms appear: Title, highest when the title starts with the term. Summary. Section headings. Body text. The built-in lexical provider returns at most one result per page. It adds a section link when every query term matches one section heading and the query is not already a title match. With a reader view selected, it returns page links because the unfiltered heading list may include hidden sections. Custom providers can return multiple section results from the same page. The list shows the top eight results. The provider downloads the index once, on first focus, and searches only pages in the reader's channel, version, and language. When reader views are configured, it also excludes pages and marked section text outside the selected view. The local CLI search command reads the full index and does not apply a browser's saved view. The navigation sidebar has a separate filter. Its optional node-level search terms help readers find menu items; they do not change /search-index.json or masthead results. See Organize site navigation . Hosted semantic search limits Shoalrun's hosted search endpoint accepts site-specific limits, separate from the Ask budget: docs.config.yaml search : limits : perCallerPerDay : 100 perDay : 1000 perCallerPerMinute : 10 These are the defaults. Each value must be a positive whole number. They apply to Shoalrun's hosted semantic search handler; the built-in browser keyword provider and third-party search services manage their own limits. The Vercel adapter wires these settings into the generated search function when hosted search is included in the build. Configure the embedding provider and shared Redis/KV credentials in the hosting environment. See Publish on Vercel . Other hosting platforms need an adapter that runs Shoalrun's hosted search handler, passes the site's settings, and connects the shared counter store. Shoalrun does not automatically apply these limits to another host or a customer's se","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Site search returns links to pages and sections. It is enabled by default and matches words in the browser, with no provider account or server required. Shoalrun supplies the search box and keyboard controls. A search provider supplies results; you can replace the built-in provider with your own module. Search and chat explains when to add semantic search or cited answers. Choose a provider Set the provider under outputs.html.search : outputs: html: search: provider: lexical Provider Behavior lexical The default. Builds /search-index.json and matches it in the browser. custom Loads your browser module. Needs module ; index is optional. none Removes the search box. Writes no index or provider file. The build copies the provider module to /assets/search-provider.js . The search box imports that file when a reader first focuses the box or types. Use the search box Press / or Ctrl + K ( ⌘ + K on macOS) to focus the box. Use the arrow keys to move through results, Enter to open one, and Escape to close the list. When a match falls inside a section, the result names the section and links to its heading. The box needs JavaScript. Without it, both the search box and sidebar filter stay hidden; the published navigation links still work. Lexical search The built-in provider matches words rather than meaning. It lowercases the query and recognizes phrases declared in search.synonyms . The browser provider ranks matches in this order: Pages containing every query term or its mapped synonym. If none match completely, partial results ordered by matched term count, then field score. Common filler words such as “how,” “do,” and “the” do not count toward partial-match coverage. A partial result must match at least one remaining term. This helps sentence-shaped queries but does not infer meaning or handle typos and general stemming. The local search command shares the base index and weights, with additional CLI/MCP ranking rules described below. Synonyms Projects can define their own synonym groups of words and phrases. Put them in a YAML file and include it from the site config: search: synonyms: { $include: ./config/search-synonyms.yaml } The included file lists equivalent words or phrases: - [walkthrough, \"walk through\", \"code tutorial\", tutorial] Each group works in both directions. Exact word or phrase matches rank above synonym matches. A term can belong to only one group; groups need at least two distinct terms. Phrase matching respects word boundaries, so walk through is treated as one term. Shoalrun validates the file during config loading and includes its mapping in /search-index.json and ai/chunks.json . Browser search, shoalrun search , and lexical passage retrieval for chat share that vocabulary. Rebuild the site and passage index after editing the file. Custom search providers must read the mapping from /search-index.json if they want to apply it to their own results. Result ordering and limits Pages rank by where the terms appear: Title, highest when the title starts with the term. Summary. Section headings. Body text. The built-in lexical provider returns at most one result per page. It adds a section link when every query term matches one section heading and the query is not already a title match. With a reader view selected, it returns page links because the unfiltered heading list may include hidden sections. Custom providers can return multiple section results from the same page. The list shows the top eight results. The provider downloads the index once, on first focus, and searches only pages in the reader's channel, version, and language. When reader views are configured, it also excludes pages and marked section text outside the selected view. The local CLI search command reads the full index and does not apply a browser's saved view. The navigation sidebar has a separate filter. Its optional node-level search terms help readers find menu items; they do not change /search-index.json or masthead results. See Organize site navigation . Hosted semantic search limits Shoalrun's hosted search endpoint accepts site-specific limits, separate from the Ask budget: search: limits: perCallerPerDay: 100 perDay: 1000 perCallerPerMinute: 10 These are the defaults. Each value must be a positive whole number. They apply to Shoalrun's hosted semantic search handler; the built-in browser keyword provider and third-party search services manage their own limits. The Vercel adapter wires these settings into the generated search function when hosted search is included in the build. Configure the embedding provider and shared Redis/KV credentials in the hosting environment. See Publish on Vercel . Other hosting platforms need an adapter that runs Shoalrun's hosted search handler, passes the site's settings, and connects the shared counter store. Shoalrun does not automatically apply these limits to another host or a customer's search service. A static-only deployment can use the built-in browser keyword provider without a s"},{"filters":{"focus":["configure"]},"text":"Preview semantic search in this checkout — Build the passage index and verify hybrid search and lexical fallback in this checkout. Header links — The search box sits in the site header, before your header links. How documentation answers work — Use retrieved passages to produce cited answers instead of page links. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":20080,"markdownTokens":4104,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"choose-a-provider","title":"Choose a provider","markdownUrl":"/author/search.sections/choose-a-provider.md","markdownBytes":2231,"markdownTokens":513},{"id":"use-the-search-box","title":"Use the search box","markdownUrl":"/author/search.sections/use-the-search-box.md","markdownBytes":1886,"markdownTokens":467},{"id":"lexical-search","title":"Lexical search","markdownUrl":"/author/search.sections/lexical-search.md","markdownBytes":4539,"markdownTokens":1007},{"id":"hosted-semantic-search-limits","title":"Hosted semantic search limits","markdownUrl":"/author/search.sections/hosted-semantic-search-limits.md","markdownBytes":3344,"markdownTokens":745},{"id":"write-a-custom-provider","title":"Write a custom provider","markdownUrl":"/author/search.sections/write-a-custom-provider.md","markdownBytes":5285,"markdownTokens":1050,"standalone":true},{"id":"reuse-the-lexical-index","title":"Reuse the lexical index","markdownUrl":"/author/search.sections/reuse-the-lexical-index.md","markdownBytes":3897,"markdownTokens":912},{"id":"turn-search-off","title":"Turn search off","markdownUrl":"/author/search.sections/turn-search-off.md","markdownBytes":2125,"markdownTokens":506,"standalone":true},{"id":"local-semantic-preview","title":"Local semantic preview","markdownUrl":"/author/search.sections/local-semantic-preview.md","markdownBytes":2560,"markdownTokens":565},{"id":"cli-and-mcp-ranking-details","title":"CLI and MCP ranking details","markdownUrl":"/author/search.sections/cli-and-mcp-ranking-details.md","markdownBytes":3253,"markdownTokens":708},{"id":"read-a-search-result-with-an-agent","title":"Read a search result with an agent","markdownUrl":"/author/search.sections/read-a-search-result-with-an-agent.md","markdownBytes":3255,"markdownTokens":723},{"id":"html-markdown-and-agents","title":"HTML, Markdown, and agents","markdownUrl":"/author/search.sections/html-markdown-and-agents.md","markdownBytes":1980,"markdownTokens":469},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/search.sections/related-reading.md","markdownBytes":2059,"markdownTokens":500}]},{"id":"guide.seo","demo":false,"url":"/publish/seo","markdownUrl":"/publish/seo.md","title":"SEO and social previews","summary":"Give each page a useful title and summary, generate share cards, and verify public preview URLs.","type":"how-to","variant":"production|current|en","area":"appearance","subarea":"appearance-branding","headings":[{"id":"set-the-public-address","title":"Set the public address"},{"id":"write-the-page-title-and-summary","title":"Write the page title and summary"},{"id":"what-the-build-adds","title":"What the build adds"},{"id":"check-the-deployed-page","title":"Check the deployed page"},{"id":"derive-revision-dates-from-content-changes","title":"Derive revision dates from content changes"},{"id":"record-verification-separately","title":"Record verification separately"},{"id":"what-agents-receive","title":"What agents receive"},{"id":"related-reading","title":"Related reading"}],"text":"When someone shares a docs link, Slack and other services fetch the page's HTML and look for a title, description, and image. Shoalrun writes these tags at build time from page metadata and can generate a share image for every page. Start with a clear page title and a one-sentence summary ; you do not need to hand-write Open Graph or Twitter tags. Set the public address Put the address readers actually use in site.origin . This is where crawlers will fetch the page and its image: docs.config.yaml site : title : Acme API docs origin : https://docs.acme.com Check the domain in the built og:image URL. A page may display in a browser while its social preview cannot load an image from that domain. Preview deployments behind sign-in cannot be unfurled by a public crawler. Publish on Vercel explains the production and preview origins for this site's build. Write the page title and summary content/start.mdx (frontmatter) title : Getting started summary : Create your first project and make a request. The title becomes the page heading and browser title. The summary is the default preview description and appears on the generated share image. For short titles, Shoalrun adds site.title to the Open Graph and Twitter titles when the result fits within 70 characters. The browser title and page heading remain unchanged. If a page needs a different browser and social title, or a different description, use seo.title and seo.description in its frontmatter : seo : title : Getting started with Acme API description : Create a project, choose a credential, and make your first request. seo.title sets the exact browser and social title; it skips the automatic site-name suffix. seo.description sets the browser and social description unless the page selects a separate displayText.socialCard . The generated image uses the same selected description, so its copy agrees with the tags. You can configure the text choices site-wide under outputs.text ; see text surfaces for precedence. What the build adds The build derives these metadata and discovery outputs from your site and page settings. Output Default source HTML <title> seo.title , then page title HTML name=\"description\" seo.description , then configured HTML description og:title and twitter:title Browser title, with site.title added for short titles when it fits og:description and twitter:description Selected social description, falling back to the page summary og:url site.origin plus the published page route Canonical URL site.origin plus the published page route XML sitemap lastmod Page updated , then optional site.updated og:image and twitter:image Absolute URL of that page's share image twitter:card summary_large_image when a share image exists The default image is a 1200×630 PNG with the page type, title, summary, site name, and URL. Share images and favicon shows how to replace a page image or the site-wide design. Turning off share images removes image tags on pages without their own image. Check the deployed page Build and deploy, then run the deployment checker with the public origin: npm --prefix framework run deploy:check -- https://docs.acme.com/ It checks page responses, compares og:url and og:image with that origin, and fetches a share image. To inspect one page directly, view its HTML source and open the absolute og:image URL in a private browser window. On Vercel, the deployment's Open Graph tab can show a preview for Slack and other services. When site.origin is set, the build writes /sitemap.xml from public, indexable page routes and advertises it in /robots.txt . Every page gets a self-referencing canonical URL. A page with seo.noindex: true stays public, gets a noindex tag, and is omitted from the sitemap. Set site.indexing: false for a preview: every page gets noindex and the build omits the sitemap. Crawlers can still reach those pages to read noindex. Set updated in a page's frontmatter to the date of a meaningful content update, such as 2026-09-27 . A timezone-qualified ISO timestamp is also accepted. Shoalrun copies it to sitemap lastmod ; it never substitutes build time. site.updated is an optional date fallback for generated pages and other pages without updated . Change it only when the material it covers changes. Dates may repeat across pages when they really changed together. Without site.freshness , the build uses declared dates. It never reads file modification times to determine content updates. Derive revision dates from content changes Opt into a content-digest history: docs.config.yaml site : freshness : history : ./config/content-updates.json The history file must be inside the project and its parent directory must already exist. The first successful build seeds each page with its declared updated , then site.updated , then today's UTC date. Later builds compare the resolved HTML and Markdown content plus displayed page metadata. Unchanged content keeps its recorded Updated date; changed content receives today's UTC date. File touches, AST s","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"When someone shares a docs link, Slack and other services fetch the page's HTML and look for a title, description, and image. Shoalrun writes these tags at build time from page metadata and can generate a share image for every page. Start with a clear page title and a one-sentence summary ; you do not need to hand-write Open Graph or Twitter tags. Set the public address Put the address readers actually use in site.origin . This is where crawlers will fetch the page and its image: site: title: Acme API docs origin: https://docs.acme.com Check the domain in the built og:image URL. A page may display in a browser while its social preview cannot load an image from that domain. Preview deployments behind sign-in cannot be unfurled by a public crawler. Publish on Vercel explains the production and preview origins for this site's build. Write the page title and summary title: Getting started summary: Create your first project and make a request. The title becomes the page heading and browser title. The summary is the default preview description and appears on the generated share image. For short titles, Shoalrun adds site.title to the Open Graph and Twitter titles when the result fits within 70 characters. The browser title and page heading remain unchanged. If a page needs a different browser and social title, or a different description, use seo.title and seo.description in its frontmatter : seo: title: Getting started with Acme API description: Create a project, choose a credential, and make your first request. seo.title sets the exact browser and social title; it skips the automatic site-name suffix. seo.description sets the browser and social description unless the page selects a separate displayText.socialCard . The generated image uses the same selected description, so its copy agrees with the tags. You can configure the text choices site-wide under outputs.text ; see text surfaces for precedence. What the build adds The build derives these metadata and discovery outputs from your site and page settings. Output Default source HTML <title> seo.title , then page title HTML name=\"description\" seo.description , then configured HTML description og:title and twitter:title Browser title, with site.title added for short titles when it fits og:description and twitter:description Selected social description, falling back to the page summary og:url site.origin plus the published page route Canonical URL site.origin plus the published page route XML sitemap lastmod Page updated , then optional site.updated og:image and twitter:image Absolute URL of that page's share image twitter:card summary_large_image when a share image exists The default image is a 1200×630 PNG with the page type, title, summary, site name, and URL. Share images and favicon shows how to replace a page image or the site-wide design. Turning off share images removes image tags on pages without their own image. Check the deployed page Build and deploy, then run the deployment checker with the public origin: npm --prefix framework run deploy:check -- https://docs.acme.com/ It checks page responses, compares og:url and og:image with that origin, and fetches a share image. To inspect one page directly, view its HTML source and open the absolute og:image URL in a private browser window. On Vercel, the deployment's Open Graph tab can show a preview for Slack and other services. When site.origin is set, the build writes /sitemap.xml from public, indexable page routes and advertises it in /robots.txt . Every page gets a self-referencing canonical URL. A page with seo.noindex: true stays public, gets a noindex tag, and is omitted from the sitemap. Set site.indexing: false for a preview: every page gets noindex and the build omits the sitemap. Crawlers can still reach those pages to read noindex. Set updated in a page's frontmatter to the date of a meaningful content update, such as 2026-09-27 . A timezone-qualified ISO timestamp is also accepted. Shoalrun copies it to sitemap lastmod ; it never substitutes build time. site.updated is an optional date fallback for generated pages and other pages without updated . Change it only when the material it covers changes. Dates may repeat across pages when they really changed together. Without site.freshness , the build uses declared dates. It never reads file modification times to determine content updates. Derive revision dates from content changes Opt into a content-digest history: site: freshness: history: ./config/content-updates.json The history file must be inside the project and its parent directory must already exist. The first successful build seeds each page with its declared updated , then site.updated , then today's UTC date. Later builds compare the resolved HTML and Markdown content plus displayed page metadata. Unchanged content keeps its recorded Updated date; changed content receives today's UTC date. File touches, AST source positions, and changes to verification dates do not change the content diges"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9165,"markdownTokens":1946,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.set-up-chat","demo":false,"url":"/chat/setup","markdownUrl":"/chat/setup.md","title":"Set up local documentation chat","summary":"Build a passage index, configure a chat service, and verify cited answers locally.","type":"how-to","variant":"production|current|en","area":"discovery","subarea":"discovery-chat","headings":[{"id":"set-up-and-try-the-chat","title":"Set up and try the chat"},{"id":"configure-the-providers","title":"Configure the providers"},{"id":"build-and-index-the-documentation","title":"Build and index the documentation"},{"id":"ask-a-question-from-the-terminal","title":"Ask a question from the terminal"},{"id":"open-the-local-panel","title":"Open the local panel"},{"id":"if-something-goes-wrong","title":"If something goes wrong"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Set up a local chat panel, then check that its answers cite the right documentation. Start in the root of a Shoalrun project that already builds, with the CLI available in your terminal. You need a chat-service account and its API key. Meaning-based retrieval also needs an embedding provider and key. These commands make provider requests; they do not deploy your site. For keyword-only retrieval, omit retrieval from the example below and omit --embed from the indexing command. You still need the passage index and a chat service. Set up and try the chat This example uses Voyage for embeddings and an OpenAI-compatible chat endpoint through OpenRouter. Choose providers and model IDs available to your accounts. Configure the providers Add these sections to docs.config.yaml . Store VOYAGE_API_KEY and OPENROUTER_API_KEY in your terminal environment, not in the YAML file. docs.config.yaml retrieval : embeddings : provider : voyage model : voyage-4-large dimension : 1024 queryModel : voyage-4-lite chat : provider : openai model : deepseek/deepseek-v4-flash baseUrl : https://openrouter.ai/api/v1 keyEnv : OPENROUTER_API_KEY Build and index the documentation Build the site, then split its Markdown pages into passages. --embed sends those passages to the configured embedding provider. shoalrun build docs.config.yaml site-dist shoalrun index site-dist --embed --config docs.config.yaml Ask a question from the terminal Replace the sample question with one that your own pages answer. shoalrun ask site-dist \"how do I reset my password\" --config docs.config.yaml Check the answer's citations and open the source pages. Confirm that the sources support the answer, rather than accepting citations alone as proof. Open the local panel Start the server and open the address it prints. Ask the same question in the panel and follow its source links. Stop the server with Ctrl+C when finished. shoalrun serve site-dist --ask --config docs.config.yaml If something goes wrong A missing-key error names the environment variable to set in the same terminal. For missing or stale sources, rebuild the site and run index again. Keyword-only retrieval can miss questions that use different wording from the pages. This minimal setup has no relevance scorer to decline out-of-scope questions. Before broader use, review answer checks and hosting limits . To record local questions, add --log with a path outside the site output. Logging is optional; read question logging before enabling it. The CLI reference defines the other flags and report fields. Related reading Reference while working Retrieval and chat settings — Look up provider fields, environment variables, and answer settings. (Status: experimental.) Related topics How documentation answers work — Understand the layers behind cited answers before choosing additional services. (Status: experimental.)","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Set up a local chat panel, then check that its answers cite the right documentation. Start in the root of a Shoalrun project that already builds, with the CLI available in your terminal. You need a chat-service account and its API key. Meaning-based retrieval also needs an embedding provider and key. These commands make provider requests; they do not deploy your site. For keyword-only retrieval, omit retrieval from the example below and omit --embed from the indexing command. You still need the passage index and a chat service. Set up and try the chat This example uses Voyage for embeddings and an OpenAI-compatible chat endpoint through OpenRouter. Choose providers and model IDs available to your accounts. Configure the providers Add these sections to docs.config.yaml . Store VOYAGE_API_KEY and OPENROUTER_API_KEY in your terminal environment, not in the YAML file. retrieval: embeddings: provider: voyage model: voyage-4-large dimension: 1024 queryModel: voyage-4-lite chat: provider: openai model: deepseek/deepseek-v4-flash baseUrl: https://openrouter.ai/api/v1 keyEnv: OPENROUTER_API_KEY Build and index the documentation Build the site, then split its Markdown pages into passages. --embed sends those passages to the configured embedding provider. shoalrun build docs.config.yaml site-dist shoalrun index site-dist --embed --config docs.config.yaml Ask a question from the terminal Replace the sample question with one that your own pages answer. shoalrun ask site-dist \"how do I reset my password\" --config docs.config.yaml Check the answer's citations and open the source pages. Confirm that the sources support the answer, rather than accepting citations alone as proof. Open the local panel Start the server and open the address it prints. Ask the same question in the panel and follow its source links. Stop the server with Ctrl+C when finished. shoalrun serve site-dist --ask --config docs.config.yaml If something goes wrong A missing-key error names the environment variable to set in the same terminal. For missing or stale sources, rebuild the site and run index again. Keyword-only retrieval can miss questions that use different wording from the pages. This minimal setup has no relevance scorer to decline out-of-scope questions. Before broader use, review answer checks and hosting limits . To record local questions, add --log with a path outside the site output. Logging is optional; read question logging before enabling it. The CLI reference defines the other flags and report fields. Related reading Reference while working Related topics"},{"filters":{"focus":["configure"]},"text":"Retrieval and chat settings — Look up provider fields, environment variables, and answer settings. (Status: experimental.) How documentation answers work — Understand the layers behind cited answers before choosing additional services. (Status: experimental.)"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4171,"markdownTokens":975,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.share-images","demo":false,"url":"/styling/share-images","markdownUrl":"/styling/share-images.md","title":"Share images and favicon","summary":"Generated social images, metadata precedence, SVG placeholders, fonts, and favicon settings.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-branding","headings":[{"id":"what-the-build-writes","title":"What the build writes"},{"id":"use-your-own-image-for-a-page","title":"Use your own image for a page"},{"id":"replace-the-design","title":"Replace the design"},{"id":"replace-the-favicon","title":"Replace the favicon"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"}],"text":"When someone pastes a page link into Slack, LinkedIn, or X, the preview shows an image. Shoalrun draws one for every page at build time and adds the tags those apps read. It also generates a favicon. Both follow the site's preset and palette, so they need no setup. For the author workflow around page titles, summaries, public URLs, and social metadata, start with SEO and social previews . What the build writes A 1200×630 PNG per page at /assets/share/<page path>.png , such as /assets/share/styling/themes.png . It shows the page type, title, and summary, the site title, and the page URL. og:title , og:description , and og:image tags, plus explicit twitter:title , twitter:description , twitter:image , and twitter:card tags. The description uses the same page text as the image. /favicon.svg , drawn from the preset's brand mark in the accent color, and a 180×180 /apple-touch-icon.png . Set site.origin to the public site address so image and page URLs in the tags are absolute and publicly reachable. A browser can load a page even when a link-preview crawler cannot fetch an image hosted at a different or private address. Run the deployment checker against the public origin to catch a mismatched og:image or a missing image. docs.config.yaml site : title : Acme API docs origin : https://docs.acme.com The preview description comes from the page's displayText.socialCard , seo.description , configured HTML description, or summary , in that order. The same text appears in og:description and on the generated image. Long titles wrap to three lines and long summaries to two, ending in an ellipsis. For a short page title such as Getting started , the social title adds the site name when the result fits within 70 characters. The page heading and browser title stay as authored. Set seo.title on a page when you want to choose its exact social title instead. The build caches rendered images in .shoalrun/cache/share-images/ beside the config file and redraws only pages whose card changed. Add .shoalrun/ to .gitignore . Use your own image for a page Set image in frontmatter to a local .png or .jpg , relative to the page file. It replaces the generated card for that page. 1200×630 works best. Frontmatter image : ./images/launch.png Replace the design Point outputs.html.shareImages.template at a 1200×630 SVG file. The build fills these placeholders on each page: Placeholder Value {{title}} , {{summary}} The full title and summary. {{title.1}} , {{title.2}} , {{title.3}} The title split into lines of about 30 characters. {{summary.1}} , {{summary.2}} The summary split into lines of about 60 characters. {{site}} site.title . {{type}} The page type as words, such as API reference . {{url}} The page URL without https:// , when site.origin is set. docs.config.yaml outputs : html : shareImages : template : ./share/card.svg fonts : [ ./share/AcmeSans-Bold.ttf ] share/card.svg < svg xmlns = \"http://www.w3.org/2000/svg\" width = \"1200\" height = \"630\" > < rect width = \"1200\" height = \"630\" fill = \"#0b3d2e\" /> < text x = \"80\" y = \"220\" font-family = \"Acme Sans\" font-weight = \"700\" font-size = \"64\" fill = \"#ffffff\" >{{title.1}}</ text > < text x = \"80\" y = \"296\" font-family = \"Acme Sans\" font-weight = \"700\" font-size = \"64\" fill = \"#ffffff\" >{{title.2}}</ text > < text x = \"80\" y = \"560\" font-family = \"Inter\" font-size = \"26\" fill = \"#cfe8dd\" >{{site}}</ text > </ svg > An unknown placeholder fails the build, so a typo can't publish raw braces. The renderer doesn't load system fonts. It can use Inter, Figtree, Source Serif 4, JetBrains Mono, and Jost, plus any .ttf or .otf files listed in fonts or in theme.fonts . The renderer reads TrueType and OpenType files only. WOFF2 files from theme.fonts still work on the site, but not in share images. To turn generated images off, set shareImages: false . Pages with their own image keep it. Replace the favicon Set site.favicon to a local .svg or .png . An SVG favicon also becomes the touch icon, placed on the palette's inked surface. A PNG favicon is used as is, with no separate touch icon. docs.config.yaml site : favicon : ./brand/mark.svg A missing file or another format fails the build. Related reading Read first Themes — Set the theme that generated share images and the favicon take their look from.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"When someone pastes a page link into Slack, LinkedIn, or X, the preview shows an image. Shoalrun draws one for every page at build time and adds the tags those apps read. It also generates a favicon. Both follow the site's preset and palette, so they need no setup. For the author workflow around page titles, summaries, public URLs, and social metadata, start with SEO and social previews . What the build writes A 1200×630 PNG per page at /assets/share/<page path>.png , such as /assets/share/styling/themes.png . It shows the page type, title, and summary, the site title, and the page URL. og:title , og:description , and og:image tags, plus explicit twitter:title , twitter:description , twitter:image , and twitter:card tags. The description uses the same page text as the image. /favicon.svg , drawn from the preset's brand mark in the accent color, and a 180×180 /apple-touch-icon.png . Set site.origin to the public site address so image and page URLs in the tags are absolute and publicly reachable. A browser can load a page even when a link-preview crawler cannot fetch an image hosted at a different or private address. Run the deployment checker against the public origin to catch a mismatched og:image or a missing image. site: title: Acme API docs origin: https://docs.acme.com The preview description comes from the page's displayText.socialCard , seo.description , configured HTML description, or summary , in that order. The same text appears in og:description and on the generated image. Long titles wrap to three lines and long summaries to two, ending in an ellipsis. For a short page title such as Getting started , the social title adds the site name when the result fits within 70 characters. The page heading and browser title stay as authored. Set seo.title on a page when you want to choose its exact social title instead. The build caches rendered images in .shoalrun/cache/share-images/ beside the config file and redraws only pages whose card changed. Add .shoalrun/ to .gitignore . Use your own image for a page Set image in frontmatter to a local .png or .jpg , relative to the page file. It replaces the generated card for that page. 1200×630 works best. image: ./images/launch.png Replace the design Point outputs.html.shareImages.template at a 1200×630 SVG file. The build fills these placeholders on each page: Placeholder Value {{title}} , {{summary}} The full title and summary. {{title.1}} , {{title.2}} , {{title.3}} The title split into lines of about 30 characters. {{summary.1}} , {{summary.2}} The summary split into lines of about 60 characters. {{site}} site.title . {{type}} The page type as words, such as API reference . {{url}} The page URL without https:// , when site.origin is set. outputs: html: shareImages: template: ./share/card.svg fonts: [./share/AcmeSans-Bold.ttf] <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1200\" height=\"630\"> <rect width=\"1200\" height=\"630\" fill=\"#0b3d2e\"/> <text x=\"80\" y=\"220\" font-family=\"Acme Sans\" font-weight=\"700\" font-size=\"64\" fill=\"#ffffff\">{{title.1}}</text> <text x=\"80\" y=\"296\" font-family=\"Acme Sans\" font-weight=\"700\" font-size=\"64\" fill=\"#ffffff\">{{title.2}}</text> <text x=\"80\" y=\"560\" font-family=\"Inter\" font-size=\"26\" fill=\"#cfe8dd\">{{site}}</text> </svg> An unknown placeholder fails the build, so a typo can't publish raw braces. The renderer doesn't load system fonts. It can use Inter, Figtree, Source Serif 4, JetBrains Mono, and Jost, plus any .ttf or .otf files listed in fonts or in theme.fonts . The renderer reads TrueType and OpenType files only. WOFF2 files from theme.fonts still work on the site, but not in share images. To turn generated images off, set shareImages: false . Pages with their own image keep it. Replace the favicon Set site.favicon to a local .svg or .png . An SVG favicon also becomes the touch icon, placed on the palette's inked surface. A PNG favicon is used as is, with no separate touch icon. site: favicon: ./brand/mark.svg A missing file or another format fails the build. Related reading Read first"},{"filters":{"focus":["configure"]},"text":"Themes — Set the theme that generated share images and the favicon take their look from."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5909,"markdownTokens":1447,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.single-source-sites","demo":false,"url":"/publish/single-source-sites","markdownUrl":"/publish/single-source-sites.md","title":"Build separate sites from shared content","summary":"Publish separate sites from shared content using optional facet selection.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-configuration","headings":[{"id":"share-the-base-configuration","title":"Share the base configuration"},{"id":"select-the-pages-for-each-site","title":"Select the pages for each site"},{"id":"build-and-check-each-output","title":"Build and check each output"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"You can keep one content directory and build separate sites for any configured facet: audience, product, area, subarea, or a custom facet such as region. Each entry config can have its own origin, base path, branding, navigation, and output directory. A developer portal is one example; the same workflow applies to an operations site, a product site, or regional resources. Share the base configuration Keep entry configs beside the base file so they resolve contentDir from the same directory: resources/ base.yaml docs.config.yaml developers.config.yaml europe.config.yaml content/ home.md api.md operations.md Start with Shoalrun installed in your project. The base declares the content, publication, and available facet choices: base.yaml schemaVersion : 1 site : title : Acme resources contentDir : content publications : defaults : { channel : production , version : current , language : en } channels : production : { pathPrefix : \"\" } versions : current : { pathPrefix : \"\" } enabled : - { channel : production , version : current } frontmatter : defaults : type : guide channel : production version : current access : { policy : public } readerFilters : facets : audience : label : Audience options : { developer : Developers , operator : Operators } region : label : Region options : { eu : Europe , us : United States } Each page needs its ordinary identity fields and the facet values for the sites that should receive it. This overview belongs to both audiences and both regions: content/home.md frontmatter --- id : guide.home title : Resource overview summary : Shared setup for all resource sites. slug : / audiences : [ developer , operator ] readerFilters : { region : [ eu , us ] } --- Give content/api.md the ID guide.api , a unique slug such as /api-requests , audiences: [developer] , and readerFilters: { region: [us] } . Give content/operations.md the ID guide.operations , slug /operations , audiences: [operator] , and readerFilters: { region: [eu] } . Add a title, summary, and body to both files. Link either page to the overview with [Shared setup](doc:guide.home) . The audience facet reads the page's audiences field. Configured product , area , and subarea facets read their corresponding category fields. Other facets use page-level readerFilters . Resolved readerFilters.typeDefaults also participate. See reader views for these marks. Select the pages for each site The main site omits contentFilter and publishes all otherwise eligible pages: docs.config.yaml extends : [ ./base.yaml ] site : origin : https://docs.example.com navigation : - { id : home , doc : guide.home } - { id : api , doc : guide.api } - { id : operations , doc : guide.operations } A developer site selects the audience facet and supplies navigation for its selected pages: developers.config.yaml extends : [ ./base.yaml ] site : title : Acme developer resources origin : https://developers.example.com contentFilter : { audience : [ developer ] } navigation : - { id : home , doc : guide.home } - { id : api , doc : guide.api } A regional site selects the custom region facet independently of audience: europe.config.yaml extends : [ ./base.yaml ] site : title : Acme Europe resources origin : https://eu.example.com basePath : /resources contentFilter : { region : [ eu ] } navigation : - { id : home , doc : guide.home } - { id : operations , doc : guide.operations } Every selected facet must match. Choices within one facet are alternatives: { audience: [developer, operator], region: [eu] } requires either audience and the European region. A page without a mark for a selected facet is excluded. Mark shared pages with all applicable values rather than leaving them unmarked. Unknown facets or choices, empty selections, and selections with no published pages fail the build. The selector does not rewrite publication metadata. Public access, enabled publications, and language still determine eligibility. Keep explicit navigation and page links within the selected set; missing targets fail validation rather than copying excluded pages into the output. Separate entry configs can replace inherited navigation lists. Build and check each output From resources/ , build each site into its own directory: shoalrun build docs.config.yaml dist/main shoalrun build developers.config.yaml dist/developers shoalrun build europe.config.yaml dist/europe Check each output's documents.json for its page IDs and routes. The main site contains all three pages. The developer site contains the overview and API guide. The European site contains the overview and operations guide beneath /resources . Inspect HTML, Markdown, search indexes, llms.min.txt , and the sitemap to confirm that excluded pages have no published entries or files. The runnable faceted-sites example ships with the framework's example configurations. Deploy each output separately to its configured host. Building one site does not update the others. After editing shared content, rebuild and deploy every affected site. ","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"You can keep one content directory and build separate sites for any configured facet: audience, product, area, subarea, or a custom facet such as region. Each entry config can have its own origin, base path, branding, navigation, and output directory. A developer portal is one example; the same workflow applies to an operations site, a product site, or regional resources. Share the base configuration Keep entry configs beside the base file so they resolve contentDir from the same directory: resources/ base.yaml docs.config.yaml developers.config.yaml europe.config.yaml content/ home.md api.md operations.md Start with Shoalrun installed in your project. The base declares the content, publication, and available facet choices: schemaVersion: 1 site: title: Acme resources contentDir: content publications: defaults: { channel: production, version: current, language: en } channels: production: { pathPrefix: \"\" } versions: current: { pathPrefix: \"\" } enabled: - { channel: production, version: current } frontmatter: defaults: type: guide channel: production version: current access: { policy: public } readerFilters: facets: audience: label: Audience options: { developer: Developers, operator: Operators } region: label: Region options: { eu: Europe, us: United States } Each page needs its ordinary identity fields and the facet values for the sites that should receive it. This overview belongs to both audiences and both regions: --- id: guide.home title: Resource overview summary: Shared setup for all resource sites. slug: / audiences: [developer, operator] readerFilters: { region: [eu, us] } --- Give content/api.md the ID guide.api , a unique slug such as /api-requests , audiences: [developer] , and readerFilters: { region: [us] } . Give content/operations.md the ID guide.operations , slug /operations , audiences: [operator] , and readerFilters: { region: [eu] } . Add a title, summary, and body to both files. Link either page to the overview with [Shared setup](doc:guide.home) . The audience facet reads the page's audiences field. Configured product , area , and subarea facets read their corresponding category fields. Other facets use page-level readerFilters . Resolved readerFilters.typeDefaults also participate. See reader views for these marks. Select the pages for each site The main site omits contentFilter and publishes all otherwise eligible pages: extends: [./base.yaml] site: origin: https://docs.example.com navigation: - { id: home, doc: guide.home } - { id: api, doc: guide.api } - { id: operations, doc: guide.operations } A developer site selects the audience facet and supplies navigation for its selected pages: extends: [./base.yaml] site: title: Acme developer resources origin: https://developers.example.com contentFilter: { audience: [developer] } navigation: - { id: home, doc: guide.home } - { id: api, doc: guide.api } A regional site selects the custom region facet independently of audience: extends: [./base.yaml] site: title: Acme Europe resources origin: https://eu.example.com basePath: /resources contentFilter: { region: [eu] } navigation: - { id: home, doc: guide.home } - { id: operations, doc: guide.operations } Every selected facet must match. Choices within one facet are alternatives: { audience: [developer, operator], region: [eu] } requires either audience and the European region. A page without a mark for a selected facet is excluded. Mark shared pages with all applicable values rather than leaving them unmarked. Unknown facets or choices, empty selections, and selections with no published pages fail the build. The selector does not rewrite publication metadata. Public access, enabled publications, and language still determine eligibility. Keep explicit navigation and page links within the selected set; missing targets fail validation rather than copying excluded pages into the output. Separate entry configs can replace inherited navigation lists. Build and check each output From resources/ , build each site into its own directory: shoalrun build docs.config.yaml dist/main shoalrun build developers.config.yaml dist/developers shoalrun build europe.config.yaml dist/europe Check each output's documents.json for its page IDs and routes. The main site contains all three pages. The developer site contains the overview and API guide. The European site contains the overview and operations guide beneath /resources . Inspect HTML, Markdown, search indexes, llms.min.txt , and the sitemap to confirm that excluded pages have no published entries or files. The runnable faceted-sites example ships with the framework's example configurations. Deploy each output separately to its configured host. Building one site does not update the others. After editing shared content, rebuild and deploy every affected site. Keep output directories separate from sources and from one another because a successful build replaces its output directory. Selection applies to whole authored and generated pages before rendering. A s"},{"filters":{"focus":["configure"]},"text":"Deploy your documentation — Deploy each reviewed site output to its own destination. Configuration reference — Look up content selection and configuration inheritance settings. Share pages across documentation versions — Publish separate sites from one content source using facet selections. Export content into your application — Reuse the same authored content inside an application."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":8004,"markdownTokens":1768,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.snippets","demo":false,"url":"/author/snippets","markdownUrl":"/author/snippets.md","title":"Reuse prose across pages","summary":"Share validated prose across pages with typed variables.","type":"how-to","variant":"production|current|en","area":"authoring","subarea":"authoring-composition","headings":[{"id":"register-a-snippet","title":"Register a snippet"},{"id":"see-a-variable-resolve","title":"See a variable resolve"},{"id":"component-attributes","title":"Component attributes"},{"id":"check-the-shared-text","title":"Check the shared text"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"often-confused-with","title":"Often confused with"}],"text":"A snippet is a shared Markdown or MDX fragment that the build expands into each page that includes it. Use one when the wording must stay in sync across pages. A template creates a draft once; editing a template does not change existing pages. Register a snippet Import a snippets mapping in project config. Snippet IDs are dot-separated names, such as authoring.build-check . Each entry points to a plain .md or .mdx file and declares its variables: docs/config/snippets.yaml authoring.build-check : file : ../snippets/build-check.mdx variables : command : { type : string , required : true } The snippet file uses <Var name=\"command\" /> in prose: docs/snippets/build-check.mdx < Callout label = \"Check the result\" >Run < Var name = \"command\" /> after editing. Confirm the HTML page and Markdown twin contain the same resolved snippet text.</ Callout > A page includes it with literal values: docs/content/snippets.mdx < Snippet id = \"authoring.build-check\" values = {{ command : \"npm test\" }} /> See a variable resolve The example project has a second snippet with two variables: example/config/snippets.yaml payment.request-prep : file : ../snippets/request-prep.mdx variables : product : { type : string , required : true } header : { type : string , default : Idempotency-Key } Its source file contains ordinary MDX prose: example/snippets/request-prep.mdx For < Var name = \"product\" /> requests, choose a unique < Var name = \"header\" /> and provide the amount in minor currency units. The guide supplies product and leaves header at its declared default: example/content/create-payment-guide.mdx < Snippet id = \"payment.request-prep\" values = {{ product : \"Payments\" }} /> Readers and agents get resolved text in their respective page formats: For Payments requests, choose a unique Idempotency-Key and provide the amount in minor currency units. The real snippet also includes a nested retry note. It inherits product from the outer snippet. See example/snippets/request-prep.mdx and example/content/create-payment-guide.mdx in the repository. This page uses that snippet below, so the published HTML and Markdown exercise the same expansion. Check the result: Run npm test after editing. Confirm the HTML page and Markdown twin contain the same resolved snippet text. Values can be strings, numbers, or booleans. A variable can also list allowed values with enum , such as tier: { type: string, enum: [free, pro] } ; its default must be one of them. Snippet defaults, project variables, page variables, and invocation values apply in that order. Set project variables in the top-level variables mapping of docs.config.yaml , and page variables in a page's variables frontmatter: docs.config.yaml variables : product : Payments Unknown names, missing required values, wrong types, and recursive includes stop the build. The document manifest lists snippet IDs used by each page. For this slice, snippets use inline <Var /> in prose. Code blocks are never changed by string replacement. Put headings in the page, and use absolute or doc: links inside snippets. These limits avoid ambiguous anchors and broken relative links until their adapters are built. Component attributes <Snippet> is a standalone empty element in a page or registered snippet. <Var> is an inline empty element inside a snippet file; using it directly in a page fails the build. Element Attribute Required Meaning <Snippet> id Yes Registered snippet ID. <Snippet> values No Literal mapping of invocation values. <Var> name Yes Variable declared for that snippet. The included Markdown and supported MDX components render in both HTML and Markdown. Nested snippets work, but recursive includes fail. API embeds need page-level headings and cannot be placed inside snippets. Keep headings in the page, and use absolute or doc: links in snippets. Check the shared text Build your project and open each page that includes the snippet. Confirm that HTML and Markdown both contain the resolved text and that no variable tags remain. Change the snippet source and rebuild; every including page should receive that change. If validation fails, correct the named variable, include, or type before publishing. Related reading Reference while working Configuration reference — Look up the snippets and variables settings. Often confused with Templates — A template is copied into a new page once; a snippet is shared prose that stays in sync on every page that includes it.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"A snippet is a shared Markdown or MDX fragment that the build expands into each page that includes it. Use one when the wording must stay in sync across pages. A template creates a draft once; editing a template does not change existing pages. Register a snippet Import a snippets mapping in project config. Snippet IDs are dot-separated names, such as authoring.build-check . Each entry points to a plain .md or .mdx file and declares its variables: authoring.build-check: file: ../snippets/build-check.mdx variables: command: { type: string, required: true } The snippet file uses <Var name=\"command\" /> in prose: <Callout label=\"Check the result\">Run <Var name=\"command\" /> after editing. Confirm the HTML page and Markdown twin contain the same resolved snippet text.</Callout> A page includes it with literal values: <Snippet id=\"authoring.build-check\" values={{ command: \"npm test\" }} /> See a variable resolve The example project has a second snippet with two variables: payment.request-prep: file: ../snippets/request-prep.mdx variables: product: { type: string, required: true } header: { type: string, default: Idempotency-Key } Its source file contains ordinary MDX prose: For <Var name=\"product\" /> requests, choose a unique <Var name=\"header\" /> and provide the amount in minor currency units. The guide supplies product and leaves header at its declared default: <Snippet id=\"payment.request-prep\" values={{ product: \"Payments\" }} /> Readers and agents get resolved text in their respective page formats: For Payments requests, choose a unique Idempotency-Key and provide the amount in minor currency units. The real snippet also includes a nested retry note. It inherits product from the outer snippet. See example/snippets/request-prep.mdx and example/content/create-payment-guide.mdx in the repository. This page uses that snippet below, so the published HTML and Markdown exercise the same expansion. Check the result: Run npm test after editing. Confirm the HTML page and Markdown twin contain the same resolved snippet text. Values can be strings, numbers, or booleans. A variable can also list allowed values with enum , such as tier: { type: string, enum: [free, pro] } ; its default must be one of them. Snippet defaults, project variables, page variables, and invocation values apply in that order. Set project variables in the top-level variables mapping of docs.config.yaml , and page variables in a page's variables frontmatter: variables: product: Payments Unknown names, missing required values, wrong types, and recursive includes stop the build. The document manifest lists snippet IDs used by each page. For this slice, snippets use inline <Var /> in prose. Code blocks are never changed by string replacement. Put headings in the page, and use absolute or doc: links inside snippets. These limits avoid ambiguous anchors and broken relative links until their adapters are built. Component attributes <Snippet> is a standalone empty element in a page or registered snippet. <Var> is an inline empty element inside a snippet file; using it directly in a page fails the build. Element Attribute Required Meaning <Snippet> id Yes Registered snippet ID. <Snippet> values No Literal mapping of invocation values. <Var> name Yes Variable declared for that snippet. The included Markdown and supported MDX components render in both HTML and Markdown. Nested snippets work, but recursive includes fail. API embeds need page-level headings and cannot be placed inside snippets. Keep headings in the page, and use absolute or doc: links in snippets. Check the shared text Build your project and open each page that includes the snippet. Confirm that HTML and Markdown both contain the resolved text and that no variable tags remain. Change the snippet source and rebuild; every including page should receive that change. If validation fails, correct the named variable, include, or type before publishing. Related reading Reference while working Often confused with"},{"filters":{"focus":["configure"]},"text":"Configuration reference — Look up the snippets and variables settings."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Templates — A template is copied into a new page once; a snippet is shared prose that stays in sync on every page that includes it."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5746,"markdownTokens":1303,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.overview","demo":false,"url":"/start","markdownUrl":"/start.md","title":"Getting started","summary":"Create a site, publish a page, and check both formats.","type":"tutorial","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"prerequisites","title":"Prerequisites"},{"id":"start-your-own-project","title":"Start your own project"},{"id":"create-a-page","title":"Create a page"},{"id":"add-the-page-to-navigation","title":"Add the page to navigation"},{"id":"build-and-check-both-outputs","title":"Build and check both outputs"},{"id":"make-it-yours","title":"Make it yours"},{"id":"build-this-site","title":"Build this site"},{"id":"check-writing-style","title":"Check writing style"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"This quickstart takes you from installing Shoalrun to your own working documentation site. You will scaffold a page from a template, complete its draft, put it in the sidebar, and read its HTML and Markdown output. Alpha: Pin an exact version and review release notes before upgrading. Configuration and output formats may change between alpha releases. Prerequisites Install Node.js 22.12 or newer and npm. Use the npm that comes with Node.js; Shoalrun sets no separate npm version. The commands below use a POSIX shell, such as Bash or Zsh. The public npm package needs no account or token. If you used the earlier GitHub Packages alpha, run npm config get @shoalrun:registry . Remove or replace any @shoalrun:registry=https://npm.pkg.github.com entry in your project or user .npmrc . To explicitly select npm during migration, add --@shoalrun:registry=https://registry.npmjs.org to the install command below. Commit the updated manifest and lockfile together, and check that Shoalrun resolves from registry.npmjs.org . Start your own project Install an exact version of the alpha and initialize the minimal starter: mkdir my-docs cd my-docs npm init -y npm install --save-exact @shoalrun/cli@0.1.0-alpha.11 npx --no-install shoalrun init . Diagrams build without Chrome. The starter puts docs.config.yaml and content/ in your project. Initialization refuses to overwrite starter files, and preserves unrelated files such as the package manifest and lockfile. Preview the starter: npx --no-install shoalrun dev docs.config.yaml site-dist --port 8765 Open http://127.0.0.1:8765/ . You should see the Acme handbook example with a welcome page and an installation page. Press Ctrl+C to stop the preview before continuing. Create a page Start new pages from a template. From the same my-docs/ directory, scaffold the built-in how-to template: npx --no-install shoalrun scaffold how-to -n content/first-page.mdx \\ --id guide.first-page --title 'Your first page' The command creates draft frontmatter and a body with prompts for outcomes, steps, checks, and recovery. It derives the slug /first-page and refuses to overwrite existing files. Use a registered project template when your team has one; create a page explains the choices. Open content/first-page.mdx . Set updated to today's date in YYYY-MM-DD format. Replace its generated summary with Find the installation guide and check its Markdown page. Keep access.policy set to draft while completing the prompts. For this example, replace the generated YAML header with the following completed header. It omits the optional description and tags fields, whose template prompts would otherwise prevent publication. Use today's date for updated : Completed page frontmatter id : guide.first-page title : Your first page summary : Find the installation guide and check its Markdown page. type : how-to slug : /first-page channel : production version : current language : en updated : 2026-10-24 access : { policy : draft } card : { icon : book-open } For this small walkthrough, replace the template body below the closing frontmatter delimiter with this completed example. It keeps the introduction, actions, and verification together: Completed template body Find this handbook's installation instructions and their Markdown copy. This page is for readers exploring the example documentation site. ## Before you begin Run the local documentation preview and open its home page. No account or credentials are needed. ## Complete the task 1. Open Setup in the sidebar. 2. Choose Install Acme to open the [ installation guide ](doc:guide.install) . 3. Read the example version command. Acme is fictional; do not run it. ## Check the result The installation page shows an example command: `acme --version` . Open `/install.md` on the same local server and find that command there too. ## Handle common failures If the page does not load, restart the preview and check its printed address. If the installation page is missing, restore the minimal starter's install file. ## How it works for agents The Markdown page contains the same instructions and version command. Its installation link points to `/install.md` . ## Next steps Read the [ installation guide ](doc:guide.install) in either format. ## Editorial evidence The minimal starter's `content/install.mdx` supplies the page and example command. Review the content and replace every remaining template prompt before setting access: { policy: public } in the header. The build rejects unfinished public drafts, including the generated draft summary. id is the stable target used by navigation and doc: links. slug sets the page URL. Keep the generated publication fields; the minimal starter enables their combination. Add the page to navigation In docs.config.yaml , replace the existing navigation block with this block. Keep the rest of the file: docs.config.yaml navigation : - id : welcome doc : guide.welcome - id : setup label : Setup items : - id : install doc : guide.install - id : first-","readerFilters":{},"readerSegments":[{"filters":{},"text":"This quickstart takes you from installing Shoalrun to your own working documentation site. You will scaffold a page from a template, complete its draft, put it in the sidebar, and read its HTML and Markdown output. Alpha: Pin an exact version and review release notes before upgrading. Configuration and output formats may change between alpha releases. Prerequisites Install Node.js 22.12 or newer and npm. Use the npm that comes with Node.js; Shoalrun sets no separate npm version. The commands below use a POSIX shell, such as Bash or Zsh. The public npm package needs no account or token. If you used the earlier GitHub Packages alpha, run npm config get @shoalrun:registry . Remove or replace any @shoalrun:registry=https://npm.pkg.github.com entry in your project or user .npmrc . To explicitly select npm during migration, add --@shoalrun:registry=https://registry.npmjs.org to the install command below. Commit the updated manifest and lockfile together, and check that Shoalrun resolves from registry.npmjs.org . Start your own project Install an exact version of the alpha and initialize the minimal starter: mkdir my-docs cd my-docs npm init -y npm install --save-exact @shoalrun/cli@0.1.0-alpha.11 npx --no-install shoalrun init . Diagrams build without Chrome. The starter puts docs.config.yaml and content/ in your project. Initialization refuses to overwrite starter files, and preserves unrelated files such as the package manifest and lockfile. Preview the starter: npx --no-install shoalrun dev docs.config.yaml site-dist --port 8765 Open http://127.0.0.1:8765/ . You should see the Acme handbook example with a welcome page and an installation page. Press Ctrl+C to stop the preview before continuing. Create a page Start new pages from a template. From the same my-docs/ directory, scaffold the built-in how-to template: npx --no-install shoalrun scaffold how-to -n content/first-page.mdx \\ --id guide.first-page --title 'Your first page' The command creates draft frontmatter and a body with prompts for outcomes, steps, checks, and recovery. It derives the slug /first-page and refuses to overwrite existing files. Use a registered project template when your team has one; create a page explains the choices. Open content/first-page.mdx . Set updated to today's date in YYYY-MM-DD format. Replace its generated summary with Find the installation guide and check its Markdown page. Keep access.policy set to draft while completing the prompts. For this example, replace the generated YAML header with the following completed header. It omits the optional description and tags fields, whose template prompts would otherwise prevent publication. Use today's date for updated : id: guide.first-page title: Your first page summary: Find the installation guide and check its Markdown page. type: how-to slug: /first-page channel: production version: current language: en updated: 2026-10-24 access: { policy: draft } card: { icon: book-open } For this small walkthrough, replace the template body below the closing frontmatter delimiter with this completed example. It keeps the introduction, actions, and verification together: Find this handbook's installation instructions and their Markdown copy. This page is for readers exploring the example documentation site. ## Before you begin Run the local documentation preview and open its home page. No account or credentials are needed. ## Complete the task 1. Open Setup in the sidebar. 2. Choose Install Acme to open the [installation guide](doc:guide.install). 3. Read the example version command. Acme is fictional; do not run it. ## Check the result The installation page shows an example command: `acme --version`. Open `/install.md` on the same local server and find that command there too. ## Handle common failures If the page does not load, restart the preview and check its printed address. If the installation page is missing, restore the minimal starter's install file. ## How it works for agents The Markdown page contains the same instructions and version command. Its installation link points to `/install.md`. ## Next steps Read the [installation guide](doc:guide.install) in either format. ## Editorial evidence The minimal starter's `content/install.mdx` supplies the page and example command. Review the content and replace every remaining template prompt before setting access: { policy: public } in the header. The build rejects unfinished public drafts, including the generated draft summary. id is the stable target used by navigation and doc: links. slug sets the page URL. Keep the generated publication fields; the minimal starter enables their combination. Add the page to navigation In docs.config.yaml , replace the existing navigation block with this block. Keep the rest of the file: navigation: - id: welcome doc: guide.welcome - id: setup label: Setup items: - id: install doc: guide.install - id: first-page doc: guide.first-page Creating a page does not add it to navigation automatically. This entr"},{"filters":{"focus":["write"]},"text":"Create a page — Create another page and add it to navigation. Use the bundled agent skills — Give an agent the same setup and authoring workflow as a bundled skill."},{"filters":{"focus":["configure"]},"text":"Example configs — Start from a complete config for a common kind of site."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":9092,"markdownTokens":2175,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"prerequisites","title":"Prerequisites","markdownUrl":"/start.sections/prerequisites.md","markdownBytes":1955,"markdownTokens":488},{"id":"start-your-own-project","title":"Start your own project","markdownUrl":"/start.sections/start-your-own-project.md","markdownBytes":2070,"markdownTokens":529},{"id":"create-a-page","title":"Create a page","markdownUrl":"/start.sections/create-a-page.md","markdownBytes":4407,"markdownTokens":995},{"id":"add-the-page-to-navigation","title":"Add the page to navigation","markdownUrl":"/start.sections/add-the-page-to-navigation.md","markdownBytes":1801,"markdownTokens":451},{"id":"build-and-check-both-outputs","title":"Build and check both outputs","markdownUrl":"/start.sections/build-and-check-both-outputs.md","markdownBytes":2343,"markdownTokens":592},{"id":"make-it-yours","title":"Make it yours","markdownUrl":"/start.sections/make-it-yours.md","markdownBytes":1952,"markdownTokens":493},{"id":"build-this-site","title":"Build this site","markdownUrl":"/start.sections/build-this-site.md","markdownBytes":1473,"markdownTokens":379},{"id":"check-writing-style","title":"Check writing style","markdownUrl":"/start.sections/check-writing-style.md","markdownBytes":1404,"markdownTokens":355},{"id":"related-reading","title":"Related reading","markdownUrl":"/start.sections/related-reading.md","markdownBytes":1925,"markdownTokens":489}]},{"id":"guide.status","demo":false,"url":"/status","markdownUrl":"/status.md","title":"Project status","summary":"Current capabilities, planned features, and known limits.","type":"reference","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"what-works-today","title":"What works today"},{"id":"what-i-want-to-add-next","title":"What I want to add next"},{"id":"current-limits","title":"Current limits"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun is an alpha for publishing documentation for people and agents from the same source. This site is built with it. Install the public @shoalrun/cli npm package through Getting started . No account or package token is needed. What works today One source, two reading formats. Markdown and supported MDX components produce a browser site and a Markdown copy of every page . Generated indexes, manifests, and section resources help agents discover and read the content without running the site’s JavaScript. Structured authoring. Templates, reusable snippets, custom metadata, and composable configuration support guides and reference pages. Stable page IDs connect links, cards, navigation, and related reading. Recipes and cookbooks combine reusable instructions into complete workflows. Agent authoring tools provide project discovery, source context, draft previews, and local validation for your existing coding agent. Rich documentation pages. Built-in components include tabs, callouts, tables, code walkthroughs, steps, timelines, and API embeds, with defined Markdown output. Diagrams render D2 and Mermaid syntax as SVG during the build; Pele renders the Mermaid diagrams. Markdown retains the diagram source and explanation. Reader controls. File trees have expandable folders and keyboard navigation. Collapsible groups join related disclosures without gaps. Authors can synchronize related tabs and add captions or expanded viewing to images . Configurable sites. Themes, palettes, layouts, headers, and footers shape the presentation. Navigation tabs organize larger sites into sections. Explicit versions and languages publish separate page variants, while reader views tailor navigation and marked content to different audiences. API documentation. OpenAPI sources supply reference pages, named examples, request samples, and contracts for individual operations. Authors can combine generated references with guides and review imported API content before publishing it. Search and documentation tools. Built-in search works in the browser without a model key. Optional semantic search and cited answers use your configured providers. Read-only Model Context Protocol (MCP) tools let agents search and read pages or sections. They run through a local stdio process or a public HTTP endpoint on Node or Vercel. Publishing and measurement. Local previews and checks support static publishing, with Node and Vercel serving options. Optional browser analytics and HTTP MCP analytics send events through adapters to your chosen service. Both are off by default; their guides describe the event fields, filtering, and configuration. Experimental visual navigation. Explore the docs offers circles, expandable branches, arcs, a relationship matrix, and a force layout. The views use declared page categories and reading relationships, including authored explanations. Agents can read the same metadata and relationships through the document manifest without running the visualization. What I want to add next Optional vector-store connections. Add adapters for customers’ own vector stores for semantic search. Keep file-based indexes as the default, and preserve document identity, publication filtering, updates, and deletions across storage options. Content exports should remain usable without a vector store. Improve visual navigation. Refine layout sizing, label collisions, dense graph views, filtering, relationship explanations, and accessibility as we try the experimental explorer on larger documentation sets. Custom access control. Add connectors for customers’ own role-based access control (RBAC) systems, with consistent access decisions across HTML, Markdown, search, downloads, and MCP. These are intended additions, without a promised release date. Current limits Alpha stability. Configuration, extension points, and output formats can still change. There is no stable release or compatibility promise yet. Component extensibility. Trusted custom components lower into shared content, with a portable authoring skill. Arbitrary executable MDX remains unsupported. Project CSS, browser modules, and configured build extensions are trusted project code. API coverage. OpenAPI and JSON Schema support is partial; check the support reference against your source. Request examples are copyable, but Shoalrun does not provide a live API explorer that sends requests. Private content. Reader views do not restrict access to published files. Shoalrun has no built-in reader authentication, and its HTTP MCP endpoint currently serves one selected public publication. Host-level authorization is a separate responsibility. Managed services. Shoalrun does not provide managed hosting, translation, or chat. Versions and translations need explicit authored variants. Optional model and analytics services need your own configuration and accounts. Automatic skill generation and general agent orchestration are deliberate non-goals . Authors remain responsible for the accuracy and","readerFilters":{},"readerSegments":[{"filters":{},"text":"Shoalrun is an alpha for publishing documentation for people and agents from the same source. This site is built with it. Install the public @shoalrun/cli npm package through Getting started . No account or package token is needed. What works today One source, two reading formats. Markdown and supported MDX components produce a browser site and a Markdown copy of every page . Generated indexes, manifests, and section resources help agents discover and read the content without running the site’s JavaScript. Structured authoring. Templates, reusable snippets, custom metadata, and composable configuration support guides and reference pages. Stable page IDs connect links, cards, navigation, and related reading. Recipes and cookbooks combine reusable instructions into complete workflows. Agent authoring tools provide project discovery, source context, draft previews, and local validation for your existing coding agent. Rich documentation pages. Built-in components include tabs, callouts, tables, code walkthroughs, steps, timelines, and API embeds, with defined Markdown output. Diagrams render D2 and Mermaid syntax as SVG during the build; Pele renders the Mermaid diagrams. Markdown retains the diagram source and explanation. Reader controls. File trees have expandable folders and keyboard navigation. Collapsible groups join related disclosures without gaps. Authors can synchronize related tabs and add captions or expanded viewing to images . Configurable sites. Themes, palettes, layouts, headers, and footers shape the presentation. Navigation tabs organize larger sites into sections. Explicit versions and languages publish separate page variants, while reader views tailor navigation and marked content to different audiences. API documentation. OpenAPI sources supply reference pages, named examples, request samples, and contracts for individual operations. Authors can combine generated references with guides and review imported API content before publishing it. Search and documentation tools. Built-in search works in the browser without a model key. Optional semantic search and cited answers use your configured providers. Read-only Model Context Protocol (MCP) tools let agents search and read pages or sections. They run through a local stdio process or a public HTTP endpoint on Node or Vercel. Publishing and measurement. Local previews and checks support static publishing, with Node and Vercel serving options. Optional browser analytics and HTTP MCP analytics send events through adapters to your chosen service. Both are off by default; their guides describe the event fields, filtering, and configuration. Experimental visual navigation. Explore the docs offers circles, expandable branches, arcs, a relationship matrix, and a force layout. The views use declared page categories and reading relationships, including authored explanations. Agents can read the same metadata and relationships through the document manifest without running the visualization. What I want to add next Optional vector-store connections. Add adapters for customers’ own vector stores for semantic search. Keep file-based indexes as the default, and preserve document identity, publication filtering, updates, and deletions across storage options. Content exports should remain usable without a vector store. Improve visual navigation. Refine layout sizing, label collisions, dense graph views, filtering, relationship explanations, and accessibility as we try the experimental explorer on larger documentation sets. Custom access control. Add connectors for customers’ own role-based access control (RBAC) systems, with consistent access decisions across HTML, Markdown, search, downloads, and MCP. These are intended additions, without a promised release date. Current limits Alpha stability. Configuration, extension points, and output formats can still change. There is no stable release or compatibility promise yet. Component extensibility. Trusted custom components lower into shared content, with a portable authoring skill. Arbitrary executable MDX remains unsupported. Project CSS, browser modules, and configured build extensions are trusted project code. API coverage. OpenAPI and JSON Schema support is partial; check the support reference against your source. Request examples are copyable, but Shoalrun does not provide a live API explorer that sends requests. Private content. Reader views do not restrict access to published files. Shoalrun has no built-in reader authentication, and its HTTP MCP endpoint currently serves one selected public publication. Host-level authorization is a separate responsibility. Managed services. Shoalrun does not provide managed hosting, translation, or chat. Versions and translations need explicit authored variants. Optional model and analytics services need your own configuration and accounts. Automatic skill generation and general agent orchestration are deliberate non-goals . Authors remain responsible for the accuracy and"},{"filters":{"focus":["configure"]},"text":"Evaluate agent tasks against your docs — Evaluate realistic tasks against the built documentation. Connect an MCP client — Configure and test the implemented stdio documentation tools."}],"navigationTab":{"id":"project-updates","label":"Project updates","variant":{"channel":"production","version":"current","language":"en"},"url":"/status","markdownUrl":"/status.md","indexUrl":"/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt"},"markdownBytes":7692,"markdownTokens":1653,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.templates","demo":false,"url":"/author/templates","markdownUrl":"/author/templates.md","title":"Templates","summary":"Create and edit page starting points, then scaffold drafts from them.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-templates","headings":[{"id":"built-in-templates","title":"Built-in templates"},{"id":"built-in-feature-templates","title":"Built-in feature templates"},{"id":"project-added-templates","title":"Project-added templates"},{"id":"keep-the-four-shapes-distinct","title":"Keep the four shapes distinct"},{"id":"what-every-template-gives-you","title":"What every template gives you"},{"id":"scaffold-a-page","title":"Scaffold a page"},{"id":"create-or-edit-a-project-template","title":"Create or edit a project template"},{"id":"write-the-frontmatter","title":"Write the frontmatter"},{"id":"write-the-body","title":"Write the body"},{"id":"choose-formatting-enforcement-for-your-project","title":"Choose formatting enforcement for your project"},{"id":"short-cli-and-derived-values","title":"Short CLI and derived values"},{"id":"related-reading","title":"Related reading"},{"id":"read-first","title":"Read first"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"},{"id":"often-confused-with","title":"Often confused with"}],"text":"A template supplies the starting page for a new one: commented frontmatter and a body of prompts. It tells authors and agents what to write, in what order, and what to delete. scaffold copies the template once and fills in the draft fields. The result is an ordinary page that authors can change. Editing a template later affects future drafts, not pages already scaffolded. Use a snippet when the same prose must stay shared across several pages. Templates guide the initial draft; they do not enforce a permanent page structure. Built-in templates These ship with the CLI and require no templates configuration. Their names are available in every project unless a project overrides them. Template Page type Use it for tutorial tutorial Learn by following one guided exercise that builds something. Built in. how-to how-to Complete a specific task from a known starting state and verify the result. Built in. reference reference Look up exact syntax, fields, options, errors, and limits. Built in. explanation explanation Understand a concept, its context, design choices, and tradeoffs. Built in. The four primary built-in templates are inspired by the Diátaxis documentation framework : tutorial, how-to, reference, and explanation. Choose by the reader's need. A tutorial teaches through a controlled exercise; a how-to helps someone accomplish their own task; reference supplies facts; explanation develops understanding. The older guide and troubleshooting templates remain available for compatibility. Existing pages keep their types, IDs, and routes. Shoalrun also includes feature templates for recipes, ingredients, and cookbooks, described below. Built-in feature templates These also ship with the CLI and need no project registration. They support Shoalrun's API and workflow features rather than adding new Diátaxis categories. A recipe is a specialized how-to; an ingredient is reusable source for an action or check; a cookbook helps readers choose complete recipes. Template Page type Use it for api-reference api-reference The authored text above a generated operation page. Built in; requires exactly one known operation ID. recipe recipe A complete task page with instructions and a final success check; it can be written directly or assembled from ingredients. Built in; see recipe drafts . ingredient ingredient Reusable source instructions for one action or check, copied into recipe drafts. Built in; see recipe drafts . cookbook cookbook An authored page that lists complete recipe pages or offers them in a chooser. Built in; see recipe drafts . shoalrun scaffold recipe -n content/track-parcel.mdx shoalrun scaffold ingredient -n content/lookup-parcel.mdx shoalrun scaffold cookbook -n content/parcel-workflows.mdx A recipe can be written directly; ingredients and composition specs are optional. An ingredient can declare workflow metadata for handoff checks during recipe draft . A cookbook can use ordinary document links or the configured chooser. Project-added templates Project templates are named entries under templates in config. They are available only in projects that register them; installing the CLI does not provide these names. Use a custom name to add an outline, or a built-in name to override its starting content. A project template with the same name as a built-in takes precedence. For example, registering how-to replaces its starting outline in that project. Use a distinct name to add a choice instead. Neither registration nor overriding rewrites existing pages. Keep the four shapes distinct Each template gives the page a different writing purpose and boundary. Shape Writing boundary Tutorial Choose one reliable exercise and sample values. Show results early and at each step, offer repetition, and keep explanation brief. Link out for deeper reasoning and alternatives. How-to Address the reader's specific goal. Assume practical competence, allow conditional paths for real situations, and link out for background or complete reference facts. Reference Organize facts to mirror the product, with consistent sections and neutral descriptions. Examples illustrate behavior without becoming task walkthroughs. Explanation Develop a bounded topic through context, connections, design reasons, and perspectives. Discuss alternatives and tradeoffs without prescribing a task or cataloging fields. These boundaries are based on Diátaxis's guidance for tutorials , how-to guides , reference , and explanation . The templates are editable starting points, not a claim that a page conforms merely because its type is set. What every template gives you The primary Diátaxis templates use these authoring conventions; workflow templates keep the sections useful to their role: Commented frontmatter. Comments explain fields and give examples where useful. Fields you must fill in hold a placeholder. Optional fields are commented out, each with the case where it applies. A short introduction. One paragraph of 150 words or fewer sits under the title wi","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"A template supplies the starting page for a new one: commented frontmatter and a body of prompts. It tells authors and agents what to write, in what order, and what to delete. scaffold copies the template once and fills in the draft fields. The result is an ordinary page that authors can change. Editing a template later affects future drafts, not pages already scaffolded. Use a snippet when the same prose must stay shared across several pages. Templates guide the initial draft; they do not enforce a permanent page structure. Built-in templates These ship with the CLI and require no templates configuration. Their names are available in every project unless a project overrides them. Template Page type Use it for tutorial tutorial Learn by following one guided exercise that builds something. Built in. how-to how-to Complete a specific task from a known starting state and verify the result. Built in. reference reference Look up exact syntax, fields, options, errors, and limits. Built in. explanation explanation Understand a concept, its context, design choices, and tradeoffs. Built in. The four primary built-in templates are inspired by the Diátaxis documentation framework : tutorial, how-to, reference, and explanation. Choose by the reader's need. A tutorial teaches through a controlled exercise; a how-to helps someone accomplish their own task; reference supplies facts; explanation develops understanding. The older guide and troubleshooting templates remain available for compatibility. Existing pages keep their types, IDs, and routes. Shoalrun also includes feature templates for recipes, ingredients, and cookbooks, described below. Built-in feature templates These also ship with the CLI and need no project registration. They support Shoalrun's API and workflow features rather than adding new Diátaxis categories. A recipe is a specialized how-to; an ingredient is reusable source for an action or check; a cookbook helps readers choose complete recipes. Template Page type Use it for api-reference api-reference The authored text above a generated operation page. Built in; requires exactly one known operation ID. recipe recipe A complete task page with instructions and a final success check; it can be written directly or assembled from ingredients. Built in; see recipe drafts . ingredient ingredient Reusable source instructions for one action or check, copied into recipe drafts. Built in; see recipe drafts . cookbook cookbook An authored page that lists complete recipe pages or offers them in a chooser. Built in; see recipe drafts . shoalrun scaffold recipe -n content/track-parcel.mdx shoalrun scaffold ingredient -n content/lookup-parcel.mdx shoalrun scaffold cookbook -n content/parcel-workflows.mdx A recipe can be written directly; ingredients and composition specs are optional. An ingredient can declare workflow metadata for handoff checks during recipe draft . A cookbook can use ordinary document links or the configured chooser. Project-added templates Project templates are named entries under templates in config. They are available only in projects that register them; installing the CLI does not provide these names. Use a custom name to add an outline, or a built-in name to override its starting content. A project template with the same name as a built-in takes precedence. For example, registering how-to replaces its starting outline in that project. Use a distinct name to add a choice instead. Neither registration nor overriding rewrites existing pages. Keep the four shapes distinct Each template gives the page a different writing purpose and boundary. Shape Writing boundary Tutorial Choose one reliable exercise and sample values. Show results early and at each step, offer repetition, and keep explanation brief. Link out for deeper reasoning and alternatives. How-to Address the reader's specific goal. Assume practical competence, allow conditional paths for real situations, and link out for background or complete reference facts. Reference Organize facts to mirror the product, with consistent sections and neutral descriptions. Examples illustrate behavior without becoming task walkthroughs. Explanation Develop a bounded topic through context, connections, design reasons, and perspectives. Discuss alternatives and tradeoffs without prescribing a task or cataloging fields. These boundaries are based on Diátaxis's guidance for tutorials , how-to guides , reference , and explanation . The templates are editable starting points, not a claim that a page conforms merely because its type is set. What every template gives you The primary Diátaxis templates use these authoring conventions; workflow templates keep the sections useful to their role: Commented frontmatter. Comments explain fields and give examples where useful. Fields you must fill in hold a placeholder. Optional fields are commented out, each with the case where it applies. A short introduction. One paragraph of 150 words or fewer sits under the title wi"},{"filters":{"focus":["write"],"audience":["authors","maintainers"]},"text":"Page metadata — Know which fields a new page needs before you pre-fill them."},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Design templates — Choose structures and prompts that serve the reader."},{"filters":{"focus":["write"]},"text":"Compose and maintain recipes — Use a project template when an API example is not the right starting point. Reuse prose across pages — A template is copied into a new page once; a snippet is shared prose that stays in sync on every page that includes it."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":19145,"markdownTokens":3929,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"built-in-templates","title":"Built-in templates","markdownUrl":"/author/templates.sections/built-in-templates.md","markdownBytes":3057,"markdownTokens":671},{"id":"built-in-feature-templates","title":"Built-in feature templates","markdownUrl":"/author/templates.sections/built-in-feature-templates.md","markdownBytes":3793,"markdownTokens":772},{"id":"project-added-templates","title":"Project-added templates","markdownUrl":"/author/templates.sections/project-added-templates.md","markdownBytes":2116,"markdownTokens":492},{"id":"keep-the-four-shapes-distinct","title":"Keep the four shapes distinct","markdownUrl":"/author/templates.sections/keep-the-four-shapes-distinct.md","markdownBytes":3219,"markdownTokens":649},{"id":"what-every-template-gives-you","title":"What every template gives you","markdownUrl":"/author/templates.sections/what-every-template-gives-you.md","markdownBytes":2985,"markdownTokens":673},{"id":"scaffold-a-page","title":"Scaffold a page","markdownUrl":"/author/templates.sections/scaffold-a-page.md","markdownBytes":2697,"markdownTokens":651},{"id":"create-or-edit-a-project-template","title":"Create or edit a project template","markdownUrl":"/author/templates.sections/create-or-edit-a-project-template.md","markdownBytes":4886,"markdownTokens":1125},{"id":"choose-formatting-enforcement-for-your-project","title":"Choose formatting enforcement for your project","markdownUrl":"/author/templates.sections/choose-formatting-enforcement-for-your-project.md","markdownBytes":4728,"markdownTokens":1043},{"id":"short-cli-and-derived-values","title":"Short CLI and derived values","markdownUrl":"/author/templates.sections/short-cli-and-derived-values.md","markdownBytes":3636,"markdownTokens":813},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/templates.sections/related-reading.md","markdownBytes":2206,"markdownTokens":536}]},{"id":"guide.theme-preview","demo":false,"url":"/styling/try","markdownUrl":"/styling/try.md","title":"Try a theme","summary":"Preview every preset, palette, and color mode on this page, then copy the config.","type":"how-to","variant":"production|current|en","area":"appearance","subarea":"appearance-themes","headings":[{"id":"sample-content","title":"Sample content"},{"id":"a-table","title":"A table"},{"id":"a-code-block","title":"A code block"},{"id":"tabs","title":"Tabs"},{"id":"add-the-previewer-to-a-page","title":"Add the previewer to a page"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Pick a shape, a palette, and a mode. This page restyles itself as you choose. Scroll down to see how each option styles the sample content, then copy the config into docs.config.yaml . Every preset works with every palette, in light or dark mode. Browse themes and palettes Preset Shape Default palette shoal Flat page with a ruled sidebar and square-cornered controls. kelp reef Rounded panels on a tinted page, with pill navigation and controls. coral ledger Technical manual with an inked masthead, monospace headings, and numbered sections. ink vice Night masthead with a sunset stripe, bold italic type, and neon rules. vice Palette Colors kelp Sea green on white. coral Coral accent over cool blue-gray neutrals. ink Black ink on warm paper with a vermilion accent. harbor Navy ink, blue links, and a yellow callout rule. amethyst Violet accents over lavender neutrals. vice Flamingo pink and aqua by day, neon on night purple after dark. docs.config.yaml theme : preset : vice palette : harbor mode : system The preview lasts until you leave the page or press Reset . It does not change the site for other readers. Your site's project CSS still applies on top of the preview. Sample content A guide page mixes prose, links , inline code , and components. Each preset styles them in its own way. Tip: Try the vice shape in dark mode. A table Use this sample to inspect table headers, cell spacing, and inline values in the selected theme. Setting Default Values preset shoal shoal , reef , ledger , vice palette Preset default Any built-in name, or a custom palette mode light light , dark , system A code block docs.config.yaml theme : preset : reef palette : amethyst mode : system Tabs Light Dark System Light Readers always see the light set. Dark Readers always see the dark set. System The site follows each reader's system setting, with an optional toggle. Add the previewer to a page Place the component on its own line in any MDX page: < ThemePreview /> The component takes no attributes. The build then publishes every preset and palette under /assets/themes/ , so the previewer works on a static host. Sites that don't use the component don't publish those files. Without JavaScript, and in the Markdown twin, the component shows the preset and palette tables and an example config. Related reading Related topics Themes — Preview every preset, palette, and color mode on a live page.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Pick a shape, a palette, and a mode. This page restyles itself as you choose. Scroll down to see how each option styles the sample content, then copy the config into docs.config.yaml . Every preset works with every palette, in light or dark mode. Browse themes and palettes Preset Shape Default palette shoal Flat page with a ruled sidebar and square-cornered controls. kelp reef Rounded panels on a tinted page, with pill navigation and controls. coral ledger Technical manual with an inked masthead, monospace headings, and numbered sections. ink vice Night masthead with a sunset stripe, bold italic type, and neon rules. vice Palette Colors kelp Sea green on white. coral Coral accent over cool blue-gray neutrals. ink Black ink on warm paper with a vermilion accent. harbor Navy ink, blue links, and a yellow callout rule. amethyst Violet accents over lavender neutrals. vice Flamingo pink and aqua by day, neon on night purple after dark. theme: preset: vice palette: harbor mode: system The preview lasts until you leave the page or press Reset . It does not change the site for other readers. Your site's project CSS still applies on top of the preview. Sample content A guide page mixes prose, links , inline code , and components. Each preset styles them in its own way. Tip: Try the vice shape in dark mode. A table Use this sample to inspect table headers, cell spacing, and inline values in the selected theme. Setting Default Values preset shoal shoal , reef , ledger , vice palette Preset default Any built-in name, or a custom palette mode light light , dark , system A code block theme: preset: reef palette: amethyst mode: system Tabs Light Dark System Light Readers always see the light set. Dark Readers always see the dark set. System The site follows each reader's system setting, with an optional toggle. Add the previewer to a page Place the component on its own line in any MDX page: <ThemePreview /> The component takes no attributes. The build then publishes every preset and palette under /assets/themes/ , so the previewer works on a static host. Sites that don't use the component don't publish those files. Without JavaScript, and in the Markdown twin, the component shows the preset and palette tables and an example config. Related reading Related topics"},{"filters":{"focus":["configure"]},"text":"Themes — Preview every preset, palette, and color mode on a live page."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":4208,"markdownTokens":981,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.themes","demo":false,"url":"/styling/themes","markdownUrl":"/styling/themes.md","title":"Themes","summary":"Pick a site shape, pair it with a color palette, and choose how light and dark mode behave.","type":"reference","variant":"production|current|en","area":"appearance","subarea":"appearance-themes","headings":[{"id":"presets","title":"Presets"},{"id":"fonts","title":"Fonts"},{"id":"use-your-own-fonts","title":"Use your own fonts"},{"id":"load-order","title":"Load order"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"go-deeper","title":"Go deeper"},{"id":"related-topics","title":"Related topics"}],"text":"The theme setting controls how the HTML site looks. It has five keys, and each has a default: docs.config.yaml theme : preset : reef # site shape palette : harbor # colors mode : system # light, dark, or system toggle : true # reader switch for light and dark mode fonts : system # optional: turn off the preset's bundled fonts Omit theme to keep the default: the shoal preset, the kelp palette, the preset's fonts, and light mode only. An unknown value fails the build. To see every combination on a real page, open Try a theme . Start with a preset. Change the palette if its colors don't fit your brand. Set the mode if readers need dark mode. Use project CSS for anything else. Presets A preset sets the shape of the site. It controls layout, corner radii, and type, and how panels, navigation, and cards look. Each preset has a default palette. Any palette works with any preset. Preset Shape Default palette shoal Flat page with a ruled sidebar and square-cornered controls. kelp reef Rounded panels float on a tinted page. Navigation items and controls are pills. coral ledger A technical manual with an inked masthead, serif body text, monospace headings, numbered sections, and hard-edged cards. ink vice A night masthead with a sunset stripe, bold italic display type, neon section rules, and cards that glow on hover. vice Presets change CSS only. Page markup, URLs, and Markdown twins stay the same. Fonts Each preset ships its own fonts, so the site looks the same on every operating system: Preset Body Headings Code shoal Inter Inter System monospace reef Figtree Figtree System monospace ledger Source Serif 4 JetBrains Mono JetBrains Mono vice Figtree Jost System monospace The fonts are Latin variable fonts under the SIL Open Font License. The build copies them to /assets/fonts/ with their license files. A browser downloads only the faces a page uses, and the page preloads its body font. Characters outside the Latin set use the system fallback. Until a font arrives, the page uses a local font resized to match it. Text doesn't shift when the bundled font loads. Agents read the Markdown twins, which load no fonts. To use system fonts only, set fonts: system . Each preset then falls back to its system font stack. Use your own fonts Set any of body , headings , and code . A role you leave out keeps the preset's font. headings defaults to the body font. docs.config.yaml theme : preset : reef fonts : body : family : Acme Sans files : - ./fonts/AcmeSans.woff2 - { file : ./fonts/AcmeSans-Italic.woff2 , style : italic } headings : Acme Display code : family : Berkeley Mono files : [ ./fonts/BerkeleyMono.woff2 ] family is the name CSS uses. A plain string, such as headings: Acme Display , names a font without shipping files. Use it for a font that project CSS loads, or one installed on readers' machines. files lists local .woff2 , .woff , .ttf , or .otf files, relative to the config file that declares them. The build copies them to /assets/fonts/project/ . File names can use letters, numbers, dots, dashes, and underscores, and two files can't share a name. Each file can set style ( normal or italic ) and weight , such as 400 or \"100 900\" . The default weight, \"100 900\" , suits variable fonts; give each static file its own weight. A missing file, an unsupported format, or an unknown key fails the build. Check that your font license allows web embedding. Fonts set here become the --font-body , --font-heading , and --font-code CSS tokens , each followed by a system fallback. Load order The HTML page links stylesheets in this order. Later files override earlier ones. /assets/site.css , which imports the base tokens and header styles. /assets/theme-preview.css follows it, on pages that use the theme previewer . /assets/theme.css , for a preset other than shoal . /assets/palette.css , generated for any palette or mode other than kelp in light mode. /assets/fonts.css , generated from theme.fonts , unless it's system and sets nothing. /assets/project.css , from site.customCss . When a site uses a non-default preset, palette, or mode, the html element carries data-theme and data-palette . The ledger and vice presets also set data-masthead=\"inked\" , which switches header tools to light text on a dark masthead. Project CSS can target one combination: styles/project.css [ data-theme = \"ledger\" ] .page-head h1 { letter-spacing : 0 ; } Related reading Next steps Color palettes — Choose the colors the preset uses. Light and dark mode — Decide whether readers get light mode, dark mode, or a toggle. Go deeper CSS and theme reference — Customize tokens and selectors beyond what presets and palettes offer. Related topics Try a theme — Preview every preset, palette, and color mode on a live page.","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"The theme setting controls how the HTML site looks. It has five keys, and each has a default: theme: preset: reef # site shape palette: harbor # colors mode: system # light, dark, or system toggle: true # reader switch for light and dark mode fonts: system # optional: turn off the preset's bundled fonts Omit theme to keep the default: the shoal preset, the kelp palette, the preset's fonts, and light mode only. An unknown value fails the build. To see every combination on a real page, open Try a theme . Start with a preset. Change the palette if its colors don't fit your brand. Set the mode if readers need dark mode. Use project CSS for anything else. Presets A preset sets the shape of the site. It controls layout, corner radii, and type, and how panels, navigation, and cards look. Each preset has a default palette. Any palette works with any preset. Preset Shape Default palette shoal Flat page with a ruled sidebar and square-cornered controls. kelp reef Rounded panels float on a tinted page. Navigation items and controls are pills. coral ledger A technical manual with an inked masthead, serif body text, monospace headings, numbered sections, and hard-edged cards. ink vice A night masthead with a sunset stripe, bold italic display type, neon section rules, and cards that glow on hover. vice Presets change CSS only. Page markup, URLs, and Markdown twins stay the same. Fonts Each preset ships its own fonts, so the site looks the same on every operating system: Preset Body Headings Code shoal Inter Inter System monospace reef Figtree Figtree System monospace ledger Source Serif 4 JetBrains Mono JetBrains Mono vice Figtree Jost System monospace The fonts are Latin variable fonts under the SIL Open Font License. The build copies them to /assets/fonts/ with their license files. A browser downloads only the faces a page uses, and the page preloads its body font. Characters outside the Latin set use the system fallback. Until a font arrives, the page uses a local font resized to match it. Text doesn't shift when the bundled font loads. Agents read the Markdown twins, which load no fonts. To use system fonts only, set fonts: system . Each preset then falls back to its system font stack. Use your own fonts Set any of body , headings , and code . A role you leave out keeps the preset's font. headings defaults to the body font. theme: preset: reef fonts: body: family: Acme Sans files: - ./fonts/AcmeSans.woff2 - { file: ./fonts/AcmeSans-Italic.woff2, style: italic } headings: Acme Display code: family: Berkeley Mono files: [./fonts/BerkeleyMono.woff2] family is the name CSS uses. A plain string, such as headings: Acme Display , names a font without shipping files. Use it for a font that project CSS loads, or one installed on readers' machines. files lists local .woff2 , .woff , .ttf , or .otf files, relative to the config file that declares them. The build copies them to /assets/fonts/project/ . File names can use letters, numbers, dots, dashes, and underscores, and two files can't share a name. Each file can set style ( normal or italic ) and weight , such as 400 or \"100 900\" . The default weight, \"100 900\" , suits variable fonts; give each static file its own weight. A missing file, an unsupported format, or an unknown key fails the build. Check that your font license allows web embedding. Fonts set here become the --font-body , --font-heading , and --font-code CSS tokens , each followed by a system fallback. Load order The HTML page links stylesheets in this order. Later files override earlier ones. /assets/site.css , which imports the base tokens and header styles. /assets/theme-preview.css follows it, on pages that use the theme previewer . /assets/theme.css , for a preset other than shoal . /assets/palette.css , generated for any palette or mode other than kelp in light mode. /assets/fonts.css , generated from theme.fonts , unless it's system and sets nothing. /assets/project.css , from site.customCss . When a site uses a non-default preset, palette, or mode, the html element carries data-theme and data-palette . The ledger and vice presets also set data-masthead=\"inked\" , which switches header tools to light text on a dark masthead. Project CSS can target one combination: [data-theme=\"ledger\"] .page-head h1 { letter-spacing: 0; } Related reading Next steps Go deeper Related topics"},{"filters":{"focus":["configure"]},"text":"Color palettes — Choose the colors the preset uses. Light and dark mode — Decide whether readers get light mode, dark mode, or a toggle. CSS and theme reference — Customize tokens and selectors beyond what presets and palettes offer. Try a theme — Preview every preset, palette, and color mode on a live page."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6903,"markdownTokens":1698,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.troubleshooting","demo":false,"url":"/publish/troubleshooting","markdownUrl":"/publish/troubleshooting.md","title":"Troubleshooting","summary":"Resolve build and publishing errors.","type":"how-to","variant":"production|current|en","area":"quality","subarea":"quality-audits","headings":[{"id":"a-page-is-missing","title":"A page is missing"},{"id":"why-it-happens","title":"Why it happens"},{"id":"what-to-do","title":"What to do"},{"id":"an-internal-link-fails","title":"An internal link fails"},{"id":"why-it-happens-2","title":"Why it happens"},{"id":"what-to-do-2","title":"What to do"},{"id":"two-pages-claim-one-identity-or-route","title":"Two pages claim one identity or route"},{"id":"mdx-cannot-compile","title":"MDX cannot compile"},{"id":"an-api-review-digest-is-missing-or-stale","title":"An API review digest is missing or stale"},{"id":"a-diagram-fails-to-render","title":"A diagram fails to render"},{"id":"local-output-works-but-the-deployed-site-fails","title":"Local output works but the deployed site fails"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"},{"id":"related-topics","title":"Related topics"}],"text":"Run these commands from your documentation project, with Shoalrun installed as in the quickstart . Start by rebuilding so the error names the current source file: npx --no-install shoalrun config validate docs.config.yaml npx --no-install shoalrun build docs.config.yaml dist Config validation checks configuration; a full build also resolves content, links, routes, and API reviews. The messages below are compiler message fragments; file paths and document IDs vary by project. A page is missing Why it happens Drafts and pages outside enabled publications can be excluded without a build error. What to do Inspect both the effective config and the built page list: npx --no-install shoalrun config resolve docs.config.yaml node -e 'const m = require(\"./dist/documents.json\"); console.log(JSON.stringify(m.documents, null, 2))' Check the page's resolved access.policy is public and its channel, version, and language match an entry in publications.enabled . frontmatter.enforced overrides page values; a draft enforced there keeps even an explicitly public page out of the build. See versions and languages . If the manifest contains the page but the menu does not, add its exact document ID to navigation (or the YAML file included there): navigation : - id : my-page doc : guide.my-page Append that entry to the existing list. Scaffolding a file does not add it to navigation. A navigation reference to an unavailable page is omitted for that publication. If publishing instead fails with unresolved scaffold placeholders cannot be published , finish every scaffold TODO and replace the draft summary before setting access: { policy: public } . An internal link fails Why it happens unknown document link doc:guide.install means the target is unavailable in the linking page's publication. What to do Check spelling against the target's id , its public access, and its publication fields. A source file in another version or language does not satisfy the link. Add the corresponding variant or link to an available page. Use doc: plus a document ID for internal links, for example [Install](doc:guide.install) . File paths are not document IDs. Rebuild after correcting the source and target. Two pages claim one identity or route Duplicate document identity means two files have the same ID and publication combination. Keep one file per variant, or assign a distinct ID to a different page. Route collision /install means different pages produce the same final URL. Check their slugs together with language, channel, and version prefixes. Output artifact collision can also mean a page conflicts with a generated resource or another output file. Resolve the source configuration; changing the output directory does not fix conflicting URLs. Versions and languages shows how prefixes distinguish editions. MDX cannot compile dynamic MDX expression has no semantic adapter means the page contains JavaScript expressions that Shoalrun cannot project into its published formats. Replace executable MDX with Markdown or one of the supported components . Put code intended for readers inside a fenced code block so it remains literal text. Component validation errors name the source file and component. Check the component's documented attributes and nesting. Ordinary MDX syntax errors can also come from unescaped braces or angle brackets in prose; use inline code for literal syntax. An API review digest is missing or stale apis.payments.publicReview.digest is missing or apis.payments.publicReview.digest is stale means the published API content needs review. Generate a local candidate: API_REVIEW_DIR = \"$( mktemp -d )\" npx --no-install shoalrun api review docs.config.yaml --output \"$API_REVIEW_DIR\" Inspect the candidate pages, contracts, source downloads, and input hashes. Copy the reported digest into that API's publicReview.digest , then run the normal build again. Source changes, selections, embeds, and source-publication choices can change the digest. Do not copy a digest from another project or bypass the review by publishing the candidate output. See Add an OpenAPI API . A diagram fails to render failed to render mermaid diagram \"Review flow\" (or d2 ) includes the source file and the renderer's underlying error. If it names diagram syntax, fix the code fence and rebuild. Errors such as <Diagram> needs exactly one nonempty mermaid code fence concern component structure; follow the diagram reference . Mermaid syntax renders with Pele; it does not need Chrome or Mermaid CLI. Check Pele’s compatibility guide if source from another Mermaid renderer fails. D2 uses the installed @d2lang/d2 runtime. Reinstall framework dependencies if either renderer is missing. Include the source file, diagram title, and complete underlying error when reporting a failure. Local output works but the deployed site fails A successful local build does not check the host's routing or headers. Use Check a deployed site for wrong Markdown content types, missing negotiation, discovery ","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Run these commands from your documentation project, with Shoalrun installed as in the quickstart . Start by rebuilding so the error names the current source file: npx --no-install shoalrun config validate docs.config.yaml npx --no-install shoalrun build docs.config.yaml dist Config validation checks configuration; a full build also resolves content, links, routes, and API reviews. The messages below are compiler message fragments; file paths and document IDs vary by project. A page is missing Why it happens Drafts and pages outside enabled publications can be excluded without a build error. What to do Inspect both the effective config and the built page list: npx --no-install shoalrun config resolve docs.config.yaml node -e 'const m = require(\"./dist/documents.json\"); console.log(JSON.stringify(m.documents, null, 2))' Check the page's resolved access.policy is public and its channel, version, and language match an entry in publications.enabled . frontmatter.enforced overrides page values; a draft enforced there keeps even an explicitly public page out of the build. See versions and languages . If the manifest contains the page but the menu does not, add its exact document ID to navigation (or the YAML file included there): navigation: - id: my-page doc: guide.my-page Append that entry to the existing list. Scaffolding a file does not add it to navigation. A navigation reference to an unavailable page is omitted for that publication. If publishing instead fails with unresolved scaffold placeholders cannot be published , finish every scaffold TODO and replace the draft summary before setting access: { policy: public } . An internal link fails Why it happens unknown document link doc:guide.install means the target is unavailable in the linking page's publication. What to do Check spelling against the target's id , its public access, and its publication fields. A source file in another version or language does not satisfy the link. Add the corresponding variant or link to an available page. Use doc: plus a document ID for internal links, for example [Install](doc:guide.install) . File paths are not document IDs. Rebuild after correcting the source and target. Two pages claim one identity or route Duplicate document identity means two files have the same ID and publication combination. Keep one file per variant, or assign a distinct ID to a different page. Route collision /install means different pages produce the same final URL. Check their slugs together with language, channel, and version prefixes. Output artifact collision can also mean a page conflicts with a generated resource or another output file. Resolve the source configuration; changing the output directory does not fix conflicting URLs. Versions and languages shows how prefixes distinguish editions. MDX cannot compile dynamic MDX expression has no semantic adapter means the page contains JavaScript expressions that Shoalrun cannot project into its published formats. Replace executable MDX with Markdown or one of the supported components . Put code intended for readers inside a fenced code block so it remains literal text. Component validation errors name the source file and component. Check the component's documented attributes and nesting. Ordinary MDX syntax errors can also come from unescaped braces or angle brackets in prose; use inline code for literal syntax. An API review digest is missing or stale apis.payments.publicReview.digest is missing or apis.payments.publicReview.digest is stale means the published API content needs review. Generate a local candidate: API_REVIEW_DIR=\"$(mktemp -d)\" npx --no-install shoalrun api review docs.config.yaml --output \"$API_REVIEW_DIR\" Inspect the candidate pages, contracts, source downloads, and input hashes. Copy the reported digest into that API's publicReview.digest , then run the normal build again. Source changes, selections, embeds, and source-publication choices can change the digest. Do not copy a digest from another project or bypass the review by publishing the candidate output. See Add an OpenAPI API . A diagram fails to render failed to render mermaid diagram \"Review flow\" (or d2 ) includes the source file and the renderer's underlying error. If it names diagram syntax, fix the code fence and rebuild. Errors such as <Diagram> needs exactly one nonempty mermaid code fence concern component structure; follow the diagram reference . Mermaid syntax renders with Pele; it does not need Chrome or Mermaid CLI. Check Pele’s compatibility guide if source from another Mermaid renderer fails. D2 uses the installed @d2lang/d2 runtime. Reinstall framework dependencies if either renderer is missing. Include the source file, diagram title, and complete underlying error when reporting a failure. Local output works but the deployed site fails A successful local build does not check the host's routing or headers. Use Check a deployed site for wrong Markdown content types, missing negotiation, discovery resources, o"},{"filters":{"focus":["write"]},"text":"Create a page — Find why a page is missing or a build fails."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":6622,"markdownTokens":1463,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.vercel","demo":false,"url":"/publish/vercel","markdownUrl":"/publish/vercel.md","title":"Publish on Vercel","summary":"Build a Vercel deployment with Markdown negotiation and correct discovery headers.","type":"how-to","variant":"production|current|en","area":"publishing","subarea":"publishing-hosting","headings":[{"id":"prepare-your-project","title":"Prepare your project"},{"id":"configure-the-project","title":"Configure the project"},{"id":"deploy-shoalrun-s-own-documentation","title":"Deploy Shoalrun's own documentation"},{"id":"deploy-without-connecting-github","title":"Deploy without connecting GitHub"},{"id":"include-an-mcp-endpoint","title":"Include an MCP endpoint"},{"id":"check-the-deployment","title":"Check the deployment"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun can produce a Vercel Build Output API directory. It contains the compiled static site and routing rules for each published page. Vercel serves HTML to browsers and the generated Markdown twin when a request includes Accept: text/markdown . The route rules also set Vary: Accept and an HTTP Link header to the .md page. Explicit .md URLs remain available. The content negotiation guide explains the same HTTP contract for any host. This page shows how to configure Vercel specifically. Prepare your project Start with the quickstart . Your documentation repository installs the public npm package and keeps its own content and configuration. It needs no framework source checkout: package.json package-lock.json docs.config.yaml content/ vercel.json Set site.origin in docs.config.yaml to your intended public HTTPS origin before release. This controls canonical and share-image URLs. Generate deployment output locally: npx --no-install shoalrun vercel build docs.config.yaml .vercel/output Generating output does not deploy it. Configure the project Public Shoalrun packages install with npm ci using your committed manifest and lockfile; no registry token is needed. If you previously used GitHub Packages, follow the migration instructions in Getting started and commit the updated lockfile before deploying. Keep credentials required by any other private dependencies. Set the Vercel project root to the documentation repository root and choose the Other framework preset. Add: vercel.json { \"$schema\" : \"https://openapi.vercel.sh/vercel.json\" , \"framework\" : null , \"installCommand\" : \"npm ci\" , \"buildCommand\" : \"npx --no-install shoalrun vercel build docs.config.yaml .vercel/output\" } Keep the build output directory setting unset: this command produces the Build Output API directory directly. If your config lives under docs/ , adjust its path. Connecting the Git repository can trigger builds on pushes; check your build budget before enabling that integration. Deploy Shoalrun's own documentation The docs repository's root vercel.json serves the site under docs/ . It runs npm ci and npm run docs:vercel using the installed package. Production and local builds use the public https://www.shoalrun.com origin in docs/docs.config.yaml for absolute page and share-image URLs. Preview builds use their VERCEL_URL instead. Public link previews require the shared page and its image to be accessible without sign-in. Vercel deployment protection can prevent crawlers from reading preview deployments. The Vercel output puts pages and discovery files in .vercel/output/static/ . Its config.json defines page routes and content types, including text/markdown for .md files and the linkset type for /.well-known/api-catalog when that file exists. Keep the entire .vercel/output/ directory together for deployment. The API catalog is optional and appears only when the project declares a public API endpoint and publishes its source. For Shoalrun's own site, npm run docs:build-all makes a complete prebuilt bundle: it compiles the pages and embeds the passages for hosted chat and search. Repeat builds reuse private passage vectors when retrieval settings and passage digests match. Only new or changed passages need embedding. The build reports embedded and reused counts. It generates answer cards from docs/config/answers.yaml when the passages, questions, chat settings, or generator code have changed; otherwise it reuses the previous verified cards. It checks passage coverage and card digests before returning. The index and cards stay inside private functions. New embeddings call the configured provider; generating cards also calls the relevance scorer and chat model. Review answers.json in the function before deployment. Deleting .vercel/output removes the local vector and card caches. The docs repository's README has the local command sequence. The hosted search endpoint uses embeddings within shared rate and daily budgets, then returns lexical results when its embedding budget is exhausted. The card cache lives in the previous local .vercel/output bundle. The command compares a fingerprint of its passage index, embedding metadata, question list, chat and retrieval settings, and compiled generator code with the new bundle. When they match, it copies the prior cards into the new private function and checks their source digests again. If the inputs changed, the old bundle is missing, or validation fails, it regenerates all cards. The final line says reused or generated . This saves card model and scorer calls on an unchanged rebuild. A fresh checkout or deleted .vercel/output has no local card or passage vector cache. Deploy without connecting GitHub You can keep building locally and deploy the Build Output API directory with the Vercel CLI --prebuilt option . Use vercel link to connect the local directory to the existing Vercel project; this does not require importing your source repository. From the docs repository root, use npm run docs:build-all ","readerFilters":{"focus":["configure"]},"readerSegments":[{"filters":{},"text":"Shoalrun can produce a Vercel Build Output API directory. It contains the compiled static site and routing rules for each published page. Vercel serves HTML to browsers and the generated Markdown twin when a request includes Accept: text/markdown . The route rules also set Vary: Accept and an HTTP Link header to the .md page. Explicit .md URLs remain available. The content negotiation guide explains the same HTTP contract for any host. This page shows how to configure Vercel specifically. Prepare your project Start with the quickstart . Your documentation repository installs the public npm package and keeps its own content and configuration. It needs no framework source checkout: package.json package-lock.json docs.config.yaml content/ vercel.json Set site.origin in docs.config.yaml to your intended public HTTPS origin before release. This controls canonical and share-image URLs. Generate deployment output locally: npx --no-install shoalrun vercel build docs.config.yaml .vercel/output Generating output does not deploy it. Configure the project Public Shoalrun packages install with npm ci using your committed manifest and lockfile; no registry token is needed. If you previously used GitHub Packages, follow the migration instructions in Getting started and commit the updated lockfile before deploying. Keep credentials required by any other private dependencies. Set the Vercel project root to the documentation repository root and choose the Other framework preset. Add: { \"$schema\": \"https://openapi.vercel.sh/vercel.json\", \"framework\": null, \"installCommand\": \"npm ci\", \"buildCommand\": \"npx --no-install shoalrun vercel build docs.config.yaml .vercel/output\" } Keep the build output directory setting unset: this command produces the Build Output API directory directly. If your config lives under docs/ , adjust its path. Connecting the Git repository can trigger builds on pushes; check your build budget before enabling that integration. Deploy Shoalrun's own documentation The docs repository's root vercel.json serves the site under docs/ . It runs npm ci and npm run docs:vercel using the installed package. Production and local builds use the public https://www.shoalrun.com origin in docs/docs.config.yaml for absolute page and share-image URLs. Preview builds use their VERCEL_URL instead. Public link previews require the shared page and its image to be accessible without sign-in. Vercel deployment protection can prevent crawlers from reading preview deployments. The Vercel output puts pages and discovery files in .vercel/output/static/ . Its config.json defines page routes and content types, including text/markdown for .md files and the linkset type for /.well-known/api-catalog when that file exists. Keep the entire .vercel/output/ directory together for deployment. The API catalog is optional and appears only when the project declares a public API endpoint and publishes its source. For Shoalrun's own site, npm run docs:build-all makes a complete prebuilt bundle: it compiles the pages and embeds the passages for hosted chat and search. Repeat builds reuse private passage vectors when retrieval settings and passage digests match. Only new or changed passages need embedding. The build reports embedded and reused counts. It generates answer cards from docs/config/answers.yaml when the passages, questions, chat settings, or generator code have changed; otherwise it reuses the previous verified cards. It checks passage coverage and card digests before returning. The index and cards stay inside private functions. New embeddings call the configured provider; generating cards also calls the relevance scorer and chat model. Review answers.json in the function before deployment. Deleting .vercel/output removes the local vector and card caches. The docs repository's README has the local command sequence. The hosted search endpoint uses embeddings within shared rate and daily budgets, then returns lexical results when its embedding budget is exhausted. The card cache lives in the previous local .vercel/output bundle. The command compares a fingerprint of its passage index, embedding metadata, question list, chat and retrieval settings, and compiled generator code with the new bundle. When they match, it copies the prior cards into the new private function and checks their source digests again. If the inputs changed, the old bundle is missing, or validation fails, it regenerates all cards. The final line says reused or generated . This saves card model and scorer calls on an unchanged rebuild. A fresh checkout or deleted .vercel/output has no local card or passage vector cache. Deploy without connecting GitHub You can keep building locally and deploy the Build Output API directory with the Vercel CLI --prebuilt option . Use vercel link to connect the local directory to the existing Vercel project; this does not require importing your source repository. From the docs repository root, use npm run docs:build-all for Shoalrun's own "},{"filters":{"focus":["configure"]},"text":"Check a deployed site — Confirm the deployed site returns the right content and headers. Host and limit documentation chat — Deploy the site itself to Vercel before you add the chat function. (Status: experimental.) Add Shoalrun to another build or host — The Vercel build generates its own HTTP rules; other hosts need them supplied."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":10091,"markdownTokens":2294,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"prepare-your-project","title":"Prepare your project","markdownUrl":"/publish/vercel.sections/prepare-your-project.md","markdownBytes":2222,"markdownTokens":547},{"id":"include-an-mcp-endpoint","title":"Include an MCP endpoint","markdownUrl":"/publish/vercel.sections/include-an-mcp-endpoint.md","markdownBytes":2230,"markdownTokens":546},{"id":"check-the-deployment","title":"Check the deployment","markdownUrl":"/publish/vercel.sections/check-the-deployment.md","markdownBytes":3221,"markdownTokens":812},{"id":"related-reading","title":"Related reading","markdownUrl":"/publish/vercel.sections/related-reading.md","markdownBytes":1934,"markdownTokens":495}]},{"id":"guide.what-is-shoalrun","demo":false,"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","title":"What is Shoalrun?","summary":"A one-page introduction to Shoalrun's document-first approach, its outputs, and the current prototype.","type":"overview","variant":"production|current|en","area":"project","subarea":"project-overview","headings":[{"id":"documents-have-an-identity","title":"Documents have an identity"},{"id":"one-source-serves-different-readers","title":"One source serves different readers"},{"id":"authors-control-the-connections","title":"Authors control the connections"},{"id":"where-it-stands","title":"Where it stands"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-topics","title":"Related topics"}],"text":"Shoalrun is a documentation compiler for product and API docs. It reads project configuration, Markdown and supported MDX pages, and optional local OpenAPI files. From those sources, it builds a site for people and readable Markdown pages for agents. The normal build is deterministic: it makes no model calls or network requests. Documents have an identity In Shoalrun, a document is more than a file at a path. It has a stable ID, metadata, and relationships to other documents. Navigation, page cards, and links can refer to that ID. You can move a source file without reconnecting those parts of the site. The published URL is a separate choice: changing a page's slug changes its URL and may need a redirect. That identity lets information connect across the site. A guide can link to an exact API operation, a related page, or a complete workflow without relying on where its source file lives. One source serves different readers Shoalrun builds HTML and a Markdown twin from the same accepted content. Browser components can give people tabs, diagrams, and other ways to explore an idea; their Markdown form keeps the useful content readable without browser scripts. Authors can also write a section for just one output when people and agents need different explanations. The build publishes a document manifest and discovery files so software can find the pages and their relationships. Authors control the connections Shoalrun also supports AI-assisted writing with human review. Use your existing coding agent with project guidance and checked edit tools. Authoring tools provide project-wide discovery and isolated snapshot validation for ordinary working-tree edits. You accept the content, inspect its HTML and Markdown, and decide when to publish. The normal compiler build remains independent of the models. Project-owned YAML can define navigation, relationships, templates, and API sources in separate files. Shoalrun combines the files and can trace where a setting came from. Public builds check links and publication variants, and changes to imported OpenAPI content require a renewed review digest. Optional ingredients, recipes, and cookbooks extend the same idea to tasks. An ingredient is a reusable action; a reviewed recipe completes one goal. A cookbook helps readers choose the complete recipes they need. Where it stands The public documentation site shows output built by Shoalrun. Install the alpha CLI from npm using Getting started . The project status lists implemented capabilities and current limits. Related reading Next steps How Shoalrun works — Follow a document through the compiler and see how IDs and routes work. Getting started — Follow the getting-started workflow if you have access to the prototype. Related topics About Shoalrun — Read the author's motivation and design philosophy.","readerFilters":{},"readerSegments":[{"filters":{},"text":"Shoalrun is a documentation compiler for product and API docs. It reads project configuration, Markdown and supported MDX pages, and optional local OpenAPI files. From those sources, it builds a site for people and readable Markdown pages for agents. The normal build is deterministic: it makes no model calls or network requests. Documents have an identity In Shoalrun, a document is more than a file at a path. It has a stable ID, metadata, and relationships to other documents. Navigation, page cards, and links can refer to that ID. You can move a source file without reconnecting those parts of the site. The published URL is a separate choice: changing a page's slug changes its URL and may need a redirect. That identity lets information connect across the site. A guide can link to an exact API operation, a related page, or a complete workflow without relying on where its source file lives. One source serves different readers Shoalrun builds HTML and a Markdown twin from the same accepted content. Browser components can give people tabs, diagrams, and other ways to explore an idea; their Markdown form keeps the useful content readable without browser scripts. Authors can also write a section for just one output when people and agents need different explanations. The build publishes a document manifest and discovery files so software can find the pages and their relationships. Authors control the connections Shoalrun also supports AI-assisted writing with human review. Use your existing coding agent with project guidance and checked edit tools. Authoring tools provide project-wide discovery and isolated snapshot validation for ordinary working-tree edits. You accept the content, inspect its HTML and Markdown, and decide when to publish. The normal compiler build remains independent of the models. Project-owned YAML can define navigation, relationships, templates, and API sources in separate files. Shoalrun combines the files and can trace where a setting came from. Public builds check links and publication variants, and changes to imported OpenAPI content require a renewed review digest. Optional ingredients, recipes, and cookbooks extend the same idea to tasks. An ingredient is a reusable action; a reviewed recipe completes one goal. A cookbook helps readers choose the complete recipes they need. Where it stands The public documentation site shows output built by Shoalrun. Install the alpha CLI from npm using Getting started . The project status lists implemented capabilities and current limits. Related reading Next steps How Shoalrun works — Follow a document through the compiler and see how IDs and routes work. Getting started — Follow the getting-started workflow if you have access to the prototype. Related topics About Shoalrun — Read the author's motivation and design philosophy."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3875,"markdownTokens":855,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.example-note","demo":true,"url":"/example-api/write-note","markdownUrl":"/example-api/write-note.md","title":"Prepare a note request","summary":"Prepare a fictional note payload and follow its linked operation contracts.","type":"how-to","variant":"production|current|en","area":"api","subarea":"api-examples","headings":[{"id":"prepare-a-note","title":"Prepare a note"},{"id":"check-the-request","title":"Check the request"},{"id":"related-reading","title":"Related reading"},{"id":"next-steps","title":"Next steps"},{"id":"related-api-references","title":"Related API references"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. The Notes API is fictional. This short guide demonstrates how a task page can point readers to an API reference without hard-coding the reference's URL. Prepare a note Choose a short message and save this JSON as request.json . The fictional create operation accepts this body at POST /notes : request.json { \"text\" : \"Hello from Shoalrun!\" } The API references linked below cover creating and reading a note. The links on this page and on each reference are generated from relatedApiReferences in this guide's frontmatter. The Create a note page has an authored introduction; the Get a note page is generated from the spec without an MDX source page. Check the request From the directory containing request.json , check that the message is a nonempty string: node -e 'const note = require(\"./request.json\"); if (typeof note.text !== \"string\" || !note.text.trim()) process.exit(1); console.log(note.text)' The example prints Hello from Shoalrun! and exits successfully. If parsing fails or the command exits with code 1, correct the JSON or supply a nonempty message. Compare the payload with the Create a note contract before adapting it to a real API. This check validates the local example; the fixture has no live endpoint to receive a request. Related reading Next steps Create a note — Read the generated API reference this guide links to. Related API references Create a note — Preview an API operation page built from a small, fictional OpenAPI file. Get a note — GET /notes/{id}","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. The Notes API is fictional. This short guide demonstrates how a task page can point readers to an API reference without hard-coding the reference's URL. Prepare a note Choose a short message and save this JSON as request.json . The fictional create operation accepts this body at POST /notes : {\"text\":\"Hello from Shoalrun!\"} The API references linked below cover creating and reading a note. The links on this page and on each reference are generated from relatedApiReferences in this guide's frontmatter. The Create a note page has an authored introduction; the Get a note page is generated from the spec without an MDX source page. Check the request From the directory containing request.json , check that the message is a nonempty string: node -e 'const note = require(\"./request.json\"); if (typeof note.text !== \"string\" || !note.text.trim()) process.exit(1); console.log(note.text)' The example prints Hello from Shoalrun! and exits successfully. If parsing fails or the command exits with code 1, correct the JSON or supply a nonempty message. Compare the payload with the Create a note contract before adapting it to a real API. This check validates the local example; the fixture has no live endpoint to receive a request. Related reading Next steps Related API references Create a note — Preview an API operation page built from a small, fictional OpenAPI file. Get a note — GET /notes/{id}"},{"filters":{"focus":["write"]},"text":"Create a note — Read the generated API reference this guide links to."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2681,"markdownTokens":640,"markdownTokenEncoding":"cl100k_base"},{"id":"guide.write-with-agents","demo":false,"url":"/author/agents","markdownUrl":"/author/agents.md","title":"Write with agents","summary":"Use your existing coding agent with project guidance, templates, and provider-free documentation tools.","type":"explanation","variant":"production|current|en","area":"authoring","subarea":"authoring-writing","headings":[{"id":"choose-a-writing-task","title":"Choose a writing task"},{"id":"review-the-result","title":"Review the result"},{"id":"shared-writing-guidance","title":"Shared writing guidance"},{"id":"related-reading","title":"Related reading"},{"id":"related-topics","title":"Related topics"}],"text":"Use your existing coding agent to write and revise Shoalrun documentation. Start with the workflow that matches your task. Choose a writing task Each guide below describes a different starting point: Task Start here Draft a new page Use your coding agent Check edits in your working tree Check working-tree documentation edits Apply a plan from an existing checked-plan client Apply a checked edit plan Give your agent the bundled workflow instructions Use agent skills Authoring tools for your coding agent explains project discovery, isolated validation, and the division of work between Shoalrun and your agent. No additional authoring provider key is required. Review the result Review the diff, supporting sources, and built HTML and Markdown before accepting an edit. For coverage, skipped checks, and result freshness, follow snapshot validation . You decide when the result is ready to publish. Shared writing guidance Design templates and Design a writing guide explain how to give your agent useful project conventions. The example writing guide is a starting point to adapt. Related reading Related topics Apply a checked edit plan — Start with the agent authoring workflow. (Status: experimental.) Use your coding agent — Choose the authoring workflow that fits how you work.","readerFilters":{"focus":["write"],"audience":["authors"]},"readerSegments":[{"filters":{},"text":"Use your existing coding agent to write and revise Shoalrun documentation. Start with the workflow that matches your task. Choose a writing task Each guide below describes a different starting point: Task Start here Draft a new page Use your coding agent Check edits in your working tree Check working-tree documentation edits Apply a plan from an existing checked-plan client Apply a checked edit plan Give your agent the bundled workflow instructions Use agent skills Authoring tools for your coding agent explains project discovery, isolated validation, and the division of work between Shoalrun and your agent. No additional authoring provider key is required. Review the result Review the diff, supporting sources, and built HTML and Markdown before accepting an edit. For coverage, skipped checks, and result freshness, follow snapshot validation . You decide when the result is ready to publish. Shared writing guidance Design templates and Design a writing guide explain how to give your agent useful project conventions. The example writing guide is a starting point to adapt. Related reading Related topics"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Apply a checked edit plan — Start with the agent authoring workflow. (Status: experimental.) Use your coding agent — Choose the authoring workflow that fits how you work."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3085,"markdownTokens":680,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.writing-style","demo":false,"url":"/author/writing-style","markdownUrl":"/author/writing-style.md","title":"Example writing guide","summary":"Adapt this site's writing guide for your own documentation and agent instructions.","type":"reference","variant":"production|current|en","area":"authoring","subarea":"authoring-writing","headings":[{"id":"adapt-this-example","title":"Adapt this example"},{"id":"example-audience-and-scope","title":"Example audience and scope"},{"id":"page-purpose-and-structure","title":"Page purpose and structure"},{"id":"voice-and-explanations","title":"Voice and explanations"},{"id":"procedures-and-examples","title":"Procedures and examples"},{"id":"ingredients-recipes-and-cookbooks","title":"Ingredients, recipes, and cookbooks"},{"id":"choose-components-by-reader-need","title":"Choose components by reader need"},{"id":"evidence-and-uncertainty","title":"Evidence and uncertainty"},{"id":"reviewed-writing-examples","title":"Reviewed writing examples"},{"id":"review-a-draft","title":"Review a draft"},{"id":"related-reading","title":"Related reading"},{"id":"reference-while-working","title":"Reference while working"}],"text":"This page is an example of a project writing guide. The rules below are the house style for Shoalrun's own documentation site, and authors and agents use them through project instructions. Shoalrun does not automatically apply these rules to other projects. Adapt this example Save your team's writing guide in the project and give your agent its path in project instructions. Include reviewed examples appropriate to the page type. Configure your own Vale rules for automated checks. Design a writing guide explains how to choose useful rules and examples. Example audience and scope Write for someone trying to understand or complete a task in Shoalrun. Assume they can edit a text file; introduce framework-specific concepts before relying on them. State prerequisites when a task needs terminal, Git, API, or deployment knowledge. Page purpose and structure Choose the page type by the reader's goal and the actual content. Keep one primary purpose per page. Split substantial conceptual discussion from a procedure and connect the pages with related reading. Page type Reader goal Useful structure Tutorial Learn through a guided exercise. Outcome, prerequisites, one reliable path with sample values, visible results, and a final check. Explain only what the exercise needs; link to deeper discussion. How-to Complete a specific task. Starting state, necessary prerequisites, actions in execution order, success check, and likely failures. Put decisions before the steps they affect. Reference Look up an exact fact. When the feature applies, syntax or fields, defaults, constraints, examples, and errors. Organize facts for lookup. Explanation Understand a concept or design. The question being explained, definitions, a concrete example, reasons and tradeoffs, and links to practical tasks. Ingredient Reuse one task step in several recipes. Required inputs and prerequisites, one action with its instructions, named outputs, and an observable check. Keep the step independent of any recipe's position or neighboring wording. Recipe Complete one task from a known starting state. Outcome, prerequisites, ordered actions, failure guidance, and a final success check. Include everything needed to follow the published page on its own. Cookbook Choose between complete recipes. Explain who each path is for, what it needs, and what it produces; link to the published recipe pages. State whether choices are alternatives or can be combined. Changelog entry Understand a dated change. User-visible behavior, scope, migration when needed, and limitations. Say when a change concerns the private prototype; claim a release only with release evidence. These are editorial shapes, not mandatory heading names. Follow the template rules and adapt the outline to the reader's need. Headings in a page body start at level two because the renderer supplies the title. Do not add step numbers to authored headings. For a procedure with titled steps, use the Steps component ; it supplies the numbering in HTML and Markdown. Voice and explanations Address the reader as “you.” Use active voice and concrete verbs. Start a paragraph with its main point, then supply the reason or example needed to understand it. Keep sentences short enough to follow without breaking every thought into a separate paragraph. Name the action and its result. Replace claims such as “powerful,” “seamless,” and “easy” with behavior the reader can observe. Avoid inflated words, ceremonial introductions, repeated summaries, and invented terminology. Before Better Reason Utilize the configuration to leverage publication capabilities. “Set the channel and version in the page's frontmatter.” Names the fields and action. It is important to note that a Markdown twin is generated. “The build creates a Markdown copy of each published page.” Identifies the actor and defines the result. “Run CI to validate it.” “Run the project's automated checks. Continuous integration (CI) runs those checks when code changes.” Explains the acronym and mechanism. “Hybrid improves relevance.” “Hybrid search combines word matching and vector rankings. Whether it helps depends on the queries and ranking settings.” Defines the term and limits the claim. Define an unfamiliar term at its first useful appearance, even when the glossary also defines it. Explain acronyms before using them repeatedly. Prefer one small example to a chain of new terms. Preserve exact command, field, model, and component names in code formatting. Procedures and examples Show the starting directory, required inputs, and expected result when a command depends on them. Say which values readers must replace. Keep commands supported by source or verified behavior; do not invent flags to make an example look complete. Give each procedure step one purpose. Put the explanation beside the action it supports. Include a check that readers can perform and describe what success looks like. Troubleshooting should identify a symptom, likely cause, and concrete next a","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"This page is an example of a project writing guide. The rules below are the house style for Shoalrun's own documentation site, and authors and agents use them through project instructions. Shoalrun does not automatically apply these rules to other projects. Adapt this example Save your team's writing guide in the project and give your agent its path in project instructions. Include reviewed examples appropriate to the page type. Configure your own Vale rules for automated checks. Design a writing guide explains how to choose useful rules and examples. Example audience and scope Write for someone trying to understand or complete a task in Shoalrun. Assume they can edit a text file; introduce framework-specific concepts before relying on them. State prerequisites when a task needs terminal, Git, API, or deployment knowledge. Page purpose and structure Choose the page type by the reader's goal and the actual content. Keep one primary purpose per page. Split substantial conceptual discussion from a procedure and connect the pages with related reading. Page type Reader goal Useful structure Tutorial Learn through a guided exercise. Outcome, prerequisites, one reliable path with sample values, visible results, and a final check. Explain only what the exercise needs; link to deeper discussion. How-to Complete a specific task. Starting state, necessary prerequisites, actions in execution order, success check, and likely failures. Put decisions before the steps they affect. Reference Look up an exact fact. When the feature applies, syntax or fields, defaults, constraints, examples, and errors. Organize facts for lookup. Explanation Understand a concept or design. The question being explained, definitions, a concrete example, reasons and tradeoffs, and links to practical tasks. Ingredient Reuse one task step in several recipes. Required inputs and prerequisites, one action with its instructions, named outputs, and an observable check. Keep the step independent of any recipe's position or neighboring wording. Recipe Complete one task from a known starting state. Outcome, prerequisites, ordered actions, failure guidance, and a final success check. Include everything needed to follow the published page on its own. Cookbook Choose between complete recipes. Explain who each path is for, what it needs, and what it produces; link to the published recipe pages. State whether choices are alternatives or can be combined. Changelog entry Understand a dated change. User-visible behavior, scope, migration when needed, and limitations. Say when a change concerns the private prototype; claim a release only with release evidence. These are editorial shapes, not mandatory heading names. Follow the template rules and adapt the outline to the reader's need. Headings in a page body start at level two because the renderer supplies the title. Do not add step numbers to authored headings. For a procedure with titled steps, use the Steps component ; it supplies the numbering in HTML and Markdown. Voice and explanations Address the reader as “you.” Use active voice and concrete verbs. Start a paragraph with its main point, then supply the reason or example needed to understand it. Keep sentences short enough to follow without breaking every thought into a separate paragraph. Name the action and its result. Replace claims such as “powerful,” “seamless,” and “easy” with behavior the reader can observe. Avoid inflated words, ceremonial introductions, repeated summaries, and invented terminology. Before Better Reason Utilize the configuration to leverage publication capabilities. “Set the channel and version in the page's frontmatter.” Names the fields and action. It is important to note that a Markdown twin is generated. “The build creates a Markdown copy of each published page.” Identifies the actor and defines the result. “Run CI to validate it.” “Run the project's automated checks. Continuous integration (CI) runs those checks when code changes.” Explains the acronym and mechanism. “Hybrid improves relevance.” “Hybrid search combines word matching and vector rankings. Whether it helps depends on the queries and ranking settings.” Defines the term and limits the claim. Define an unfamiliar term at its first useful appearance, even when the glossary also defines it. Explain acronyms before using them repeatedly. Prefer one small example to a chain of new terms. Preserve exact command, field, model, and component names in code formatting. Procedures and examples Show the starting directory, required inputs, and expected result when a command depends on them. Say which values readers must replace. Keep commands supported by source or verified behavior; do not invent flags to make an example look complete. Give each procedure step one purpose. Put the explanation beside the action it supports. Include a check that readers can perform and describe what success looks like. Troubleshooting should identify a symptom, likely cause, and concrete next a"},{"filters":{"focus":["write"],"audience":["authors"]},"text":"Design a writing guide — Adapt editorial rules to your own readers. Templates — Look up page types, starter structures, and formatting checks."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":16766,"markdownTokens":2839,"markdownTokenEncoding":"cl100k_base","sections":[{"id":"adapt-this-example","title":"Adapt this example","markdownUrl":"/author/writing-style.sections/adapt-this-example.md","markdownBytes":1488,"markdownTokens":351},{"id":"example-audience-and-scope","title":"Example audience and scope","markdownUrl":"/author/writing-style.sections/example-audience-and-scope.md","markdownBytes":1405,"markdownTokens":332},{"id":"page-purpose-and-structure","title":"Page purpose and structure","markdownUrl":"/author/writing-style.sections/page-purpose-and-structure.md","markdownBytes":4377,"markdownTokens":789},{"id":"voice-and-explanations","title":"Voice and explanations","markdownUrl":"/author/writing-style.sections/voice-and-explanations.md","markdownBytes":3395,"markdownTokens":610},{"id":"procedures-and-examples","title":"Procedures and examples","markdownUrl":"/author/writing-style.sections/procedures-and-examples.md","markdownBytes":1944,"markdownTokens":424},{"id":"ingredients-recipes-and-cookbooks","title":"Ingredients, recipes, and cookbooks","markdownUrl":"/author/writing-style.sections/ingredients-recipes-and-cookbooks.md","markdownBytes":3258,"markdownTokens":691},{"id":"choose-components-by-reader-need","title":"Choose components by reader need","markdownUrl":"/author/writing-style.sections/choose-components-by-reader-need.md","markdownBytes":3493,"markdownTokens":628},{"id":"evidence-and-uncertainty","title":"Evidence and uncertainty","markdownUrl":"/author/writing-style.sections/evidence-and-uncertainty.md","markdownBytes":1940,"markdownTokens":428},{"id":"reviewed-writing-examples","title":"Reviewed writing examples","markdownUrl":"/author/writing-style.sections/reviewed-writing-examples.md","markdownBytes":3617,"markdownTokens":648},{"id":"review-a-draft","title":"Review a draft","markdownUrl":"/author/writing-style.sections/review-a-draft.md","markdownBytes":1707,"markdownTokens":384},{"id":"related-reading","title":"Related reading","markdownUrl":"/author/writing-style.sections/related-reading.md","markdownBytes":1433,"markdownTokens":349}]},{"id":"reference.notes.getNote","demo":true,"url":"/example-api/generated/get-note-cbedb319","markdownUrl":"/example-api/generated/get-note-cbedb319.md","title":"Get a note","summary":"GET /notes/{id}","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"get-notes-id","title":"GET /notes/{id}"},{"id":"servers","title":"Servers"},{"id":"parameters","title":"Parameters"},{"id":"id-path","title":"id (path)"},{"id":"responses","title":"Responses"},{"id":"200-ok","title":"200: OK"},{"id":"404-not-found","title":"404: Not Found"},{"id":"related-guides","title":"Related guides"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /notes/{id} Get a note Read a saved note from this fictional API. Servers https://api.example.test Parameters id (path) Required string Known note ID : \"note_123\" Responses 200: OK application/json The saved note. A saved note with its author, labels, and display metadata. 7 properties id string always present ⓘ The generated note ID. text string always present ⓘ maxLength: 280 The saved text. createdAt string always present ⓘ format: date-time When the note was created. archivedAt string always present nullable ⓘ format: date-time When the note was archived, or null while active. author object always present ⓘ The person who created the note. 2 properties id string always present ⓘ The author's user ID. displayName string always present ⓘ The author's display name. tags list of string may be absent ⓘ Labels used to organize the note. Array items: string metadata object may be absent ⓘ Optional display information for a note. 2 properties source string may be absent ⓘ Where the note came from. pinned boolean may be absent ⓘ Whether the note stays at the top. 404: Not Found application/json No note has that ID. object 2 properties code string always present ⓘ message string always present ⓘ Related guides Prepare a note request — Prepare a fictional note payload and follow its linked operation contracts.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /notes/{id} Get a note Read a saved note from this fictional API. Servers https://api.example.test Parameters id (path) Required string Known note ID : \"note_123\" Responses 200: OK application/json The saved note. A saved note with its author, labels, and display metadata. 7 properties id string always present ⓘ The generated note ID. text string always present ⓘ maxLength: 280 The saved text. createdAt string always present ⓘ format: date-time When the note was created. archivedAt string always present nullable ⓘ format: date-time When the note was archived, or null while active. author object always present ⓘ The person who created the note. 2 properties id string always present ⓘ The author's user ID. displayName string always present ⓘ The author's display name. tags list of string may be absent ⓘ Labels used to organize the note. Array items: string metadata object may be absent ⓘ Optional display information for a note. 2 properties source string may be absent ⓘ Where the note came from. pinned boolean may be absent ⓘ Whether the note stays at the top. 404: Not Found application/json No note has that ID. object 2 properties code string always present ⓘ message string always present ⓘ Related guides Prepare a note request — Prepare a fictional note payload and follow its linked operation contracts."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":3441,"markdownTokens":967,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.cedar.createEnrollment","demo":true,"url":"/example-api/cedar/create-enrollment-7af3e5d2","markdownUrl":"/example-api/cedar/create-enrollment-7af3e5d2.md","title":"Create a parcel enrollment","summary":"POST /Enrollments","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"post-enrollments","title":"POST /Enrollments"},{"id":"servers","title":"Servers"},{"id":"authentication","title":"Authentication"},{"id":"request-body","title":"Request body"},{"id":"application-json","title":"application/json"},{"id":"responses","title":"Responses"},{"id":"201-created","title":"201: Created"},{"id":"400-bad-request","title":"400: Bad Request"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . POST /Enrollments Create a parcel enrollment Create one of four enrollment shapes. The service accepts different required fields for each program; the examples illustrate the shapes but have not been sent to a server. Servers https://sandbox.api.cedar-parcel.example/v1 — Enrollment sandbox only Authentication API key API key in header X-Application-Key. Enrollment-only key. Request body Required. Choose the program that matches the parcels you will dispatch. application/json Use exactly one of these shapes: Local pickup · 6 properties A shop with ordinary pickup windows. 6 properties program string required ⓘ const: \"local\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ pickupWindows list of object required ⓘ The windows when parcels can be collected. Array items: 3 properties day enum<string> required ⓘ Available options: \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\" opensAt string required ⓘ Local time in HH:mm format. closesAt string required ⓘ Local time in HH:mm format. fragileHandling boolean optional ⓘ default: false notes string optional nullable ⓘ Chilled goods · 6 properties Requires a temperature range and handling instructions. 6 properties program string required ⓘ const: \"chilled\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ temperatureRange object required ⓘ 2 properties minimumCelsius number required ⓘ maximumCelsius number required ⓘ handlingNotes string optional ⓘ Instructions printed for handlers. sensorRequired boolean optional ⓘ default: true Bulk dispatch · 7 properties Requires an estimated volume and manifest format. 7 properties program string required ⓘ const: \"bulk\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ monthlyParcelEstimate integer required ⓘ exclusiveMinimum: 0 Example 1 (authored in OpenAPI): 8000 Example 2 (authored in OpenAPI): 12000 manifestFormat enum<string> required ⓘ Available options: \"csv\", \"json\" callbackUrl string optional nullable ⓘ format: uri customMetadata any value optional nullable ⓘ Any value is allowed. Combined program · 8 properties Supplies pickup, temperature, and volume details. 8 properties program string required ⓘ const: \"combined\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ pickupWindows list of object required ⓘ Array items: 3 properties day enum<string> required ⓘ Available options: \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\" opensAt string required ⓘ Local time in HH:mm format. closesAt string required ⓘ Local time in HH:mm format. temperatureRange object required ⓘ 2 properties minimumCelsius number required ⓘ maximumCelsius number required ⓘ monthlyParcelEstimate integer required ⓘ minimum: 1 manifestFormat enum<string> required ⓘ Available ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . POST /Enrollments Create a parcel enrollment Create one of four enrollment shapes. The service accepts different required fields for each program; the examples illustrate the shapes but have not been sent to a server. Servers https://sandbox.api.cedar-parcel.example/v1 — Enrollment sandbox only Authentication API key API key in header X-Application-Key. Enrollment-only key. Request body Required. Choose the program that matches the parcels you will dispatch. application/json Use exactly one of these shapes: Local pickup · 6 properties A shop with ordinary pickup windows. 6 properties program string required ⓘ const: \"local\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ pickupWindows list of object required ⓘ The windows when parcels can be collected. Array items: 3 properties day enum<string> required ⓘ Available options: \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\" opensAt string required ⓘ Local time in HH:mm format. closesAt string required ⓘ Local time in HH:mm format. fragileHandling boolean optional ⓘ default: false notes string optional nullable ⓘ Chilled goods · 6 properties Requires a temperature range and handling instructions. 6 properties program string required ⓘ const: \"chilled\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ temperatureRange object required ⓘ 2 properties minimumCelsius number required ⓘ maximumCelsius number required ⓘ handlingNotes string optional ⓘ Instructions printed for handlers. sensorRequired boolean optional ⓘ default: true Bulk dispatch · 7 properties Requires an estimated volume and manifest format. 7 properties program string required ⓘ const: \"bulk\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ monthlyParcelEstimate integer required ⓘ exclusiveMinimum: 0 Example 1 (authored in OpenAPI): 8000 Example 2 (authored in OpenAPI): 12000 manifestFormat enum<string> required ⓘ Available options: \"csv\", \"json\" callbackUrl string optional nullable ⓘ format: uri customMetadata any value optional nullable ⓘ Any value is allowed. Combined program · 8 properties Supplies pickup, temperature, and volume details. 8 properties program string required ⓘ const: \"combined\" organization object required ⓘ 3 properties displayName string required ⓘ Name shown on parcel labels. address object required ⓘ 5 properties line1 string required ⓘ Street and number. line2 string optional nullable ⓘ Additional address line, if present. city string required ⓘ region string required ⓘ postalCode string required ⓘ registrationCode string optional nullable ⓘ Optional local registration code. contact object required ⓘ 3 properties name string required ⓘ email string required ⓘ format: email phone string optional nullable ⓘ pickupWindows list of object required ⓘ Array items: 3 properties day enum<string> required ⓘ Available options: \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\" opensAt string required ⓘ Local time in HH:mm format. closesAt string required ⓘ Local time in HH:mm format. temperatureRange object required ⓘ 2 properties minimumCelsius number required ⓘ maximumCelsius number required ⓘ monthlyParcelEstimate integer required ⓘ minimum: 1 manifestFormat enum<string> required ⓘ Available options: \"csv\", \"jso"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":13434,"markdownTokens":3844,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.cedar.listParcels","demo":true,"url":"/example-api/cedar/list-parcels-0345fb5f","markdownUrl":"/example-api/cedar/list-parcels-0345fb5f.md","title":"List parcel records","summary":"GET /Search/parcels/{scope}","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"get-search-parcels-scope","title":"GET /Search/parcels/{scope}"},{"id":"servers","title":"Servers"},{"id":"authentication","title":"Authentication"},{"id":"parameters","title":"Parameters"},{"id":"scope-path","title":"scope (path)"},{"id":"filters-query","title":"Filters (query)"},{"id":"downloadas-query","title":"downloadAs (query)"},{"id":"skiprows-query","title":"skipRows (query)"},{"id":"maxrows-query","title":"maxRows (query)"},{"id":"responses","title":"Responses"},{"id":"200-ok","title":"200: OK"},{"id":"400-bad-request","title":"400: Bad Request"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /Search/parcels/{scope} List parcel records List records for an account or region. Use downloadAs to request a file; the same successful status can return JSON, CSV, or a spreadsheet. Servers https://sandbox.api.cedar-parcel.example/v1 — Sandbox https://api.cedar-parcel.example/v1 — Production Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Parameters scope (path) Required The account or region identifier. string Default example : \"region-demo\" Filters (query) Optional OpenAPI calls this placeholder parameters . Send a filter expression directly in the query string, without parameters= . Query form: ?declaredValue(gt)=100 . Replace the field, operator, and value for your filter. Source notes, accepted fields, and operators Placeholder for field/operator filters. Do not send parameters= . Put each expression directly in the URL, for example declaredValue(gt)=100 . Accepted fields: createdAt (gt, ge, lt, le, eq), declaredValue (gt, ge, lt, le, eq), carrier (eq, ne, in), recipientCity (eq, ct), and status (eq, ne, in). in values are separated by | . object Additional-key schema: string High declared value : declaredValue(gt)=100 City contains text : recipientCity(ct)=port downloadAs (query) Optional Return a file instead of JSON when specified. string Available options: \"csv\", \"xlsx\" skipRows (query) Optional Number of records to skip. integer; default: 0 maxRows (query) Optional Maximum records to return. Zero or a negative value requests all records. integer; default: 20 Responses 200: OK application/json text/csv application/vnd.openxmlformats-officedocument.spreadsheetml.sheet A page of records, or a downloadable file if downloadAs is set. The response format depends on the query value. application/json minProperties: 3; maxProperties: 3 3 properties records list of object always present ⓘ uniqueItems: true Array items: 5 properties parcelId string always present ⓘ status enum<string> always present ⓘ Available options: \"label_created\", \"in_transit\", \"delivered\", \"exception\" declaredValue number always present ⓘ minimum: 0; multipleOf: 0.01 Value in currency units, to the nearest cent. recipient object always present ⓘ 2 properties city string always present ⓘ postalCode string always present ⓘ events list of object may be absent ⓘ Tracking history in chronological order. Array items: object 3 properties kind enum<string> always present ⓘ Available options: \"pickup\", \"scan\", \"delivery\" at string always present ⓘ format: date-time details string may be absent nullable ⓘ totalRecords integer always present ⓘ minimum: 0 nextCursor string always present nullable ⓘ Always present; null on the last page. Additional properties: not allowed. text/csv string CSV rows with a header line. application/vnd.openxmlformats-officedocument.spreadsheetml.sheet string; format: binary A spreadsheet download. 400: Bad Request application/problem+json A field name or comparison operator is unsupported. 4 properties type string always present ⓘ format: uri title string always present ⓘ status integer always present ⓘ detail string may be absent ⓘ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /Search/parcels/{scope} List parcel records List records for an account or region. Use downloadAs to request a file; the same successful status can return JSON, CSV, or a spreadsheet. Servers https://sandbox.api.cedar-parcel.example/v1 — Sandbox https://api.cedar-parcel.example/v1 — Production Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Parameters scope (path) Required The account or region identifier. string Default example : \"region-demo\" Filters (query) Optional OpenAPI calls this placeholder parameters . Send a filter expression directly in the query string, without parameters= . Query form: ?declaredValue(gt)=100 . Replace the field, operator, and value for your filter. Source notes, accepted fields, and operators Placeholder for field/operator filters. Do not send parameters= . Put each expression directly in the URL, for example declaredValue(gt)=100 . Accepted fields: createdAt (gt, ge, lt, le, eq), declaredValue (gt, ge, lt, le, eq), carrier (eq, ne, in), recipientCity (eq, ct), and status (eq, ne, in). in values are separated by | . object Additional-key schema: string High declared value : declaredValue(gt)=100 City contains text : recipientCity(ct)=port downloadAs (query) Optional Return a file instead of JSON when specified. string Available options: \"csv\", \"xlsx\" skipRows (query) Optional Number of records to skip. integer; default: 0 maxRows (query) Optional Maximum records to return. Zero or a negative value requests all records. integer; default: 20 Responses 200: OK application/json text/csv application/vnd.openxmlformats-officedocument.spreadsheetml.sheet A page of records, or a downloadable file if downloadAs is set. The response format depends on the query value. application/json minProperties: 3; maxProperties: 3 3 properties records list of object always present ⓘ uniqueItems: true Array items: 5 properties parcelId string always present ⓘ status enum<string> always present ⓘ Available options: \"label_created\", \"in_transit\", \"delivered\", \"exception\" declaredValue number always present ⓘ minimum: 0; multipleOf: 0.01 Value in currency units, to the nearest cent. recipient object always present ⓘ 2 properties city string always present ⓘ postalCode string always present ⓘ events list of object may be absent ⓘ Tracking history in chronological order. Array items: object 3 properties kind enum<string> always present ⓘ Available options: \"pickup\", \"scan\", \"delivery\" at string always present ⓘ format: date-time details string may be absent nullable ⓘ totalRecords integer always present ⓘ minimum: 0 nextCursor string always present nullable ⓘ Always present; null on the last page. Additional properties: not allowed. text/csv string CSV rows with a header line. application/vnd.openxmlformats-officedocument.spreadsheetml.sheet string; format: binary A spreadsheet download. 400: Bad Request application/problem+json A field name or comparison operator is unsupported. 4 properties type string always present ⓘ format: uri title string always present ⓘ status integer always present ⓘ detail string may be absent ⓘ"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":5850,"markdownTokens":1570,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.cedar.getParcel","demo":true,"url":"/example-api/cedar/get-parcel-edee10e6","markdownUrl":"/example-api/cedar/get-parcel-edee10e6.md","title":"Get a parcel","summary":"GET /parcels/{parcelId}","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"get-parcels-parcelid","title":"GET /parcels/{parcelId}"},{"id":"servers","title":"Servers"},{"id":"authentication","title":"Authentication"},{"id":"parameters","title":"Parameters"},{"id":"parcelid-path","title":"parcelId (path)"},{"id":"responses","title":"Responses"},{"id":"200-ok","title":"200: OK"},{"id":"404-not-found","title":"404: Not Found"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /parcels/{parcelId} Get a parcel This lookup route does not use the API's default authentication. Servers https://lookup.api.cedar-parcel.example/v1 — Public lookup host Authentication No authentication required. Parameters parcelId (path) Required string Responses 200: OK application/json Parcel found. 5 properties parcelId string always present ⓘ status enum<string> always present ⓘ Available options: \"label_created\", \"in_transit\", \"delivered\", \"exception\" declaredValue number always present ⓘ minimum: 0; multipleOf: 0.01 Value in currency units, to the nearest cent. recipient object always present ⓘ 2 properties city string always present ⓘ postalCode string always present ⓘ events list of object may be absent ⓘ Tracking history in chronological order. Array items: object 3 properties kind enum<string> always present ⓘ Available options: \"pickup\", \"scan\", \"delivery\" at string always present ⓘ format: date-time details string may be absent nullable ⓘ 404: Not Found application/problem+json No parcel has that identifier. 4 properties type string always present ⓘ format: uri title string always present ⓘ status integer always present ⓘ detail string may be absent ⓘ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /parcels/{parcelId} Get a parcel This lookup route does not use the API's default authentication. Servers https://lookup.api.cedar-parcel.example/v1 — Public lookup host Authentication No authentication required. Parameters parcelId (path) Required string Responses 200: OK application/json Parcel found. 5 properties parcelId string always present ⓘ status enum<string> always present ⓘ Available options: \"label_created\", \"in_transit\", \"delivered\", \"exception\" declaredValue number always present ⓘ minimum: 0; multipleOf: 0.01 Value in currency units, to the nearest cent. recipient object always present ⓘ 2 properties city string always present ⓘ postalCode string always present ⓘ events list of object may be absent ⓘ Tracking history in chronological order. Array items: object 3 properties kind enum<string> always present ⓘ Available options: \"pickup\", \"scan\", \"delivery\" at string always present ⓘ format: date-time details string may be absent nullable ⓘ 404: Not Found application/problem+json No parcel has that identifier. 4 properties type string always present ⓘ format: uri title string always present ⓘ status integer always present ⓘ detail string may be absent ⓘ"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2855,"markdownTokens":810,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.cedar.uploadManifest","demo":true,"url":"/example-api/cedar/upload-manifest-1af17891","markdownUrl":"/example-api/cedar/upload-manifest-1af17891.md","title":"Upload a manifest","summary":"POST /manifests","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"post-manifests","title":"POST /manifests"},{"id":"servers","title":"Servers"},{"id":"authentication","title":"Authentication"},{"id":"request-body","title":"Request body"},{"id":"multipart-form-data","title":"multipart/form-data"},{"id":"responses","title":"Responses"},{"id":"202-accepted","title":"202: Accepted"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . POST /manifests Upload a manifest Servers https://sandbox.api.cedar-parcel.example/v1 — Sandbox https://api.cedar-parcel.example/v1 — Production Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Request body Required. multipart/form-data object 2 properties manifest string required ⓘ format: binary Dispatch data file. checksum string required ⓘ format: binary Separate checksum file. Responses 202: Accepted application/json Upload accepted for validation. object 2 properties jobId string always present ⓘ status enum<string> always present ⓘ Available options: \"queued\", \"validating\"","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . POST /manifests Upload a manifest Servers https://sandbox.api.cedar-parcel.example/v1 — Sandbox https://api.cedar-parcel.example/v1 — Production Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Request body Required. multipart/form-data object 2 properties manifest string required ⓘ format: binary Dispatch data file. checksum string required ⓘ format: binary Separate checksum file. Responses 202: Accepted application/json Upload accepted for validation. object 2 properties jobId string always present ⓘ status enum<string> always present ⓘ Available options: \"queued\", \"validating\""}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2333,"markdownTokens":621,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.cedar.getLegacyParcel","demo":true,"url":"/example-api/cedar/get-legacy-parcel-6758d051","markdownUrl":"/example-api/cedar/get-legacy-parcel-6758d051.md","title":"Get a parcel through the old route","summary":"GET /legacy/parcels/{parcelId}","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"get-legacy-parcels-parcelid","title":"GET /legacy/parcels/{parcelId}"},{"id":"servers","title":"Servers"},{"id":"authentication","title":"Authentication"},{"id":"parameters","title":"Parameters"},{"id":"parcelid-path","title":"parcelId (path)"},{"id":"responses","title":"Responses"},{"id":"200-ok","title":"200: OK"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /legacy/parcels/{parcelId} Get a parcel through the old route Deprecated operation. Servers https://sandbox.api.cedar-parcel.example/v1 — Sandbox https://api.cedar-parcel.example/v1 — Production Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Parameters parcelId (path) Required string Responses 200: OK application/json Parcel found. Use the current lookup route for new integrations. 5 properties parcelId string always present ⓘ status enum<string> always present ⓘ Available options: \"label_created\", \"in_transit\", \"delivered\", \"exception\" declaredValue number always present ⓘ minimum: 0; multipleOf: 0.01 Value in currency units, to the nearest cent. recipient object always present ⓘ 2 properties city string always present ⓘ postalCode string always present ⓘ events list of object may be absent ⓘ Tracking history in chronological order. Array items: object 3 properties kind enum<string> always present ⓘ Available options: \"pickup\", \"scan\", \"delivery\" at string always present ⓘ format: date-time details string may be absent nullable ⓘ","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context. OpenAPI for this operation: Download JSON . GET /legacy/parcels/{parcelId} Get a parcel through the old route Deprecated operation. Servers https://sandbox.api.cedar-parcel.example/v1 — Sandbox https://api.cedar-parcel.example/v1 — Production Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Parameters parcelId (path) Required string Responses 200: OK application/json Parcel found. Use the current lookup route for new integrations. 5 properties parcelId string always present ⓘ status enum<string> always present ⓘ Available options: \"label_created\", \"in_transit\", \"delivered\", \"exception\" declaredValue number always present ⓘ minimum: 0; multipleOf: 0.01 Value in currency units, to the nearest cent. recipient object always present ⓘ 2 properties city string always present ⓘ postalCode string always present ⓘ events list of object may be absent ⓘ Tracking history in chronological order. Array items: object 3 properties kind enum<string> always present ⓘ Available options: \"pickup\", \"scan\", \"delivery\" at string always present ⓘ format: date-time details string may be absent nullable ⓘ"}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2996,"markdownTokens":821,"markdownTokenEncoding":"cl100k_base"},{"id":"reference.cedar.parcelDelivered","demo":true,"url":"/example-api/cedar/parcel-delivered-7d1ba6db","markdownUrl":"/example-api/cedar/parcel-delivered-7d1ba6db.md","title":"Parcel delivered event","summary":"Webhook event: parcel.delivered","type":"api-reference","variant":"production|current|en","area":"api","subarea":"api-reference","headings":[{"id":"webhook-parcel-delivered","title":"Webhook: parcel.delivered"},{"id":"authentication","title":"Authentication"},{"id":"request-body","title":"Request body"},{"id":"application-json","title":"application/json"},{"id":"responses","title":"Responses"},{"id":"204-no-content","title":"204: No Content"}],"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This webhook reference is generated from the OpenAPI description. The provider sends this event to the receiver. OpenAPI for this operation: Download JSON . Webhook: parcel.delivered The provider sends a POST request for this event to the receiver's webhook URL. Parcel delivered event The service sends this event to the receiver's webhook URL. Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Request body Required. application/json 5 properties eventId string required ⓘ parcelId string required ⓘ occurredAt string required ⓘ format: date-time outcome enum<string> required ⓘ Available options: \"delivered\", \"returned\" proof one of several types required ⓘ Use exactly one of these shapes: Photo proof · 2 properties object 2 properties kind string required ⓘ const: \"photo\" url string required ⓘ format: uri Signature proof · 2 properties object 2 properties kind string required ⓘ const: \"signature\" signedBy string required ⓘ Responses 204: No Content Receiver accepted the event.","readerFilters":{"focus":["write"]},"readerSegments":[{"filters":{},"text":"Fictional API example. This page demonstrates documentation features; its operations do not describe a live service. This webhook reference is generated from the OpenAPI description. The provider sends this event to the receiver. OpenAPI for this operation: Download JSON . Webhook: parcel.delivered The provider sends a POST request for this event to the receiver's webhook URL. Parcel delivered event The service sends this event to the receiver's webhook URL. Authentication Use one of these authentication options: Bearer token HTTP bearer (JWT). Short-lived service token. API key API key in header X-Parcel-Key. Long-lived account key. Request body Required. application/json 5 properties eventId string required ⓘ parcelId string required ⓘ occurredAt string required ⓘ format: date-time outcome enum<string> required ⓘ Available options: \"delivered\", \"returned\" proof one of several types required ⓘ Use exactly one of these shapes: Photo proof · 2 properties object 2 properties kind string required ⓘ const: \"photo\" url string required ⓘ format: uri Signature proof · 2 properties object 2 properties kind string required ⓘ const: \"signature\" signedBy string required ⓘ Responses 204: No Content Receiver accepted the event."}],"navigationTab":{"id":"docs","label":"Docs","variant":{"channel":"production","version":"current","language":"en"},"url":"/what-is-shoalrun","markdownUrl":"/what-is-shoalrun.md","indexUrl":"/.well-known/shoalrun/navigation/docs-50f26fe22670.txt"},"markdownBytes":2787,"markdownTokens":782,"markdownTokenEncoding":"cl100k_base"}]}
|