web-meta-framework-docusaurus-a2c82a — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited web-meta-framework-docusaurus-a2c82a (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Quick Guide: Docusaurus 3.x is a React-powered static site generator for documentation. Everything is configured indocusaurus.config.js(ESM), and@docusaurus/preset-classicbundles docs, blog, pages, sitemap and theme in one entry. Sidebars are autogenerated from the filesystem, ordered bysidebar_positionfront matter and_category_.json. Theme components are customised by swizzling. Content is MDX v3, which is stricter than Markdown.docusaurus docs:versionsnapshots the wholedocs/tree, anddocusaurus buildemits a staticbuild/directory.
Detailed Resources:
<critical_requirements>
Keep all site configuration in `docusaurus.config.js` (or `.ts`). It is the single entry point the build reads, and config split across files has no mechanism to be merged.
Start from `@docusaurus/preset-classic`. It wires docs, blog, pages, sitemap and the theme together; decompose into individual plugins only when you need something the preset cannot express, such as a second docs instance.
Swizzle with `--wrap` unless the change genuinely needs the component's internals. A wrapped component keeps receiving upstream fixes; an ejected one is a snapshot you now own.
Order autogenerated sidebars with `sidebar_position` front matter and `_category_.json`. The filesystem drives routing and sidebar structure, so ordering stays next to the content it orders.
Give each doc set its own plugin instance when it needs its own versioning. One instance holding both versioned and unversioned docs has no way to keep them apart.
</critical_requirements>
Auto-detection: Docusaurus, docusaurus.config.js, docusaurus.config.ts, @docusaurus/preset-classic, @docusaurus/core, sidebars.js, docs:version, docusaurus build, docusaurus start, docusaurus deploy, docusaurus swizzle, MDX, _category_.json, sidebar_position, @site, @theme, @theme-original, plugin-content-docs, plugin-content-blog
Applies to:
docusaurus.config.js — site metadata, presets, plugins, themeConfig, navbar, footersrc/pages/, in React or MDXauthors.ymlHandled elsewhere:
docusaurus build emits static files, so anything needing a server at request time lives outside the site.<philosophy>
Docusaurus is an opinionated documentation framework that trades flexibility for convention. It decides routing (filesystem), content format (MDX) and structure (docs, blog, pages) so the work left is writing.
is fighting the framework.
preset-classic is the common plugin set already wired together; individualplugins are for setups it cannot express.
sidebar_position, slug, tags andcustom_edit_url live in the document rather than in a separate index.
snapshot with your name on it.
</philosophy>
<decision_framework>
Which sidebar strategy? Autogenerated, ordered by sidebar_position and _category_.json, is right for almost everything — including large sites, as long as the sections map onto directories. A manual sidebar in sidebars.js earns its maintenance only when the navigation has to group documents the filesystem keeps apart, and the choice is not all-or-nothing: one sidebar array can hold an autogenerated item alongside hand-written entries. Independent doc sets (an API reference beside a guide) want separate plugin instances, each with its own sidebar, rather than either strategy stretched.
Wrap, eject, or neither? Adding content around a component is --wrap. Changing colours or spacing is neither — set the Infima CSS variables in custom.css. Changing internal logic means checking the component's safety level first: "Safe" makes ejecting acceptable, "Unsafe" means wrap or find another route, and "Forbidden" means the component is not swizzlable at all.
Which content format? A documentation article or blog post is .md or .mdx in docs/ or blog/. A standalone page that is mostly prose is .mdx in src/pages/; one that is mostly interactive is .tsx in the same place. Embedding React components in documentation means .mdx with imports.
Version, or not? Versioning copies the entire docs/ tree, so each version costs its own build time and output size. Cut a version when the documentation genuinely differs between releases — not on every release.
</decision_framework>
<patterns>
docusaurus.config.jsOne ESM file: site metadata, the preset (which brings the plugins and theme), and themeConfig for navbar, footer and theme behaviour.
export default {
title: "My Docs",
url: "https://docs.example.com",
baseUrl: "/",
onBrokenLinks: "throw",
presets: [
[
"@docusaurus/preset-classic",
{
docs: {
sidebarPath: "./sidebars.js",
editUrl: "...",
showLastUpdateTime: true,
},
blog: { showReadingTime: true },
theme: { customCss: ["./src/css/custom.css"] },
},
],
],
themeConfig: {
navbar: {
/* ... */
},
footer: {
/* ... */
},
},
};onBrokenLinks: "throw" is what makes a broken internal link fail the build rather than ship.
Full code: examples/core.md
An autogenerated sidebar reads the filesystem; ordering and labels come from front matter and _category_.json beside the content.
// sidebars.js
export default { docs: [{ type: "autogenerated", dirName: "." }] };// docs/guides/_category_.json
{
"label": "Guides",
"position": 2,
"collapsed": false,
"link": { "type": "generated-index" }
}Without sidebar_position, items sort alphabetically by filename. Number prefixes (01-intro.md) are the alternative and are stripped from the URL slug — pick one mechanism, not both.
Full code: examples/core.md
A wrapper renders the original and adds around it. The import is @theme-original/ — @theme/ would resolve to the wrapper itself.
npx docusaurus swizzle --list
npx docusaurus swizzle @docusaurus/theme-classic Footer -- --wrap// src/theme/Footer/index.js
import Footer from "@theme-original/Footer";
export default function FooterWrapper(props) {
return (
<>
<Footer {...props} />
<div className="custom-banner">Custom content below footer</div>
</>
);
}Full code: examples/customization.md
MDX v3 is Markdown with JSX. Admonitions, tabs and code block metadata are the Docusaurus-specific additions.
---
title: My Document
sidebar_position: 1
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
:::tip[Pro Tip]
`note`, `tip`, `info`, `warning` and `danger`; the bracket sets a custom title.
:::
<Tabs groupId="package-manager">
<TabItem value="npm" label="npm" default>
...
</TabItem>
</Tabs>MDX v3 is stricter than Markdown: an unclosed HTML tag, a bare {, or a < used as a comparison in prose all fail the build.
Full code: examples/content.md
docs:version snapshots the whole docs/ directory. What remains in docs/ becomes the unreleased current version.
npx docusaurus docs:version 1.0.0docs: {
lastVersion: "current",
versions: {
current: { label: "2.0.0-beta", path: "next", banner: "unreleased" },
"1.0.0": { label: "1.0.0", path: "1.0.0", banner: "none" },
},
onlyIncludeVersions: ["current", "1.0.0"],
}Versions are full copies rather than diffs, so onlyIncludeVersions is how you keep development builds fast.
Full code: examples/customization.md
</patterns>
<red_flags>
Breaks at runtime:
{ or an unclosed tag in MDX — MDX v3 fails the build; escape with \{ and \<, or use a code fence.@theme/ComponentName imported inside a swizzle wrapper — the wrapper resolves to itself, and the import loops.baseUrl without a leading and trailing / — asset resolution breaks._category_.json written with name or order instead of label and position — the fields are ignored and the category falls back to defaults.@docusaurus/-package import inside MDX — reach for the @theme/ and @site/ aliases instead.routeBasePath: "/" but blog left enabled, or src/pages/index.js left in place — the routes collide.Surprising behaviour:
onBrokenLinks set to "ignore" or "log" ships dead links; "throw" is what a production config wants, with onBrokenMarkdownLinks at least at "warn".sidebars.js where autogeneration would work drifts out of step with the docs it describes.editUrl means no "Edit this page" link, and no showLastUpdateTime means a reader cannot tell how stale a page is.docusaurus.config.js are not hot-reloaded — restart the dev server.format: "detect" configured, only .mdx files process JSX; the default mode processes both extensions.static/ are served from the site root rather than from baseUrl — use require() or useBaseUrl() for a path-safe reference.blog/authors.yml, not in the site config.slug front matter field overrides the URL derived from the filename, which is how a rename keeps its URL.src/pages/ takes its route from its file path — src/pages/support.tsx becomes /support.<Tabs> instances do not sync until they share a groupId.</red_flags>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.