{
  "id": "docs-markdown-checks",
  "type": "loadout",
  "title": "Markdown docs with markdownlint and offline link checks",
  "summary": "Agent-written READMEs and docs checked offline: markdownlint-cli2, relative links and #anchors resolve, and every npm run command in the docs exists.",
  "description": "Agents write docs that read well and are quietly wrong. A link points to a page that was renamed. An anchor no longer matches its heading after an edit. A quick start says npm run deploy when there is no deploy script. This loadout gives your agent two checks that need no network. markdownlint-cli2 enforces style, with code block languages and in-file link fragments required. A small script checks that relative links and images resolve and that #fragments match GitHub-style heading slugs, across files too. It also checks that every npm, pnpm, yarn or bun run command in the docs names a real script. External URLs are left to a scheduled checker, so a flaky site never blocks a change. The verifier runs both on a clean docs tree and on a broken sample, with markdownlint-cli2 0.23.3.\n",
  "highlights": [
    "Relative links, images and #anchors checked offline, across files",
    "GitHub heading slug rules, including repeated headings",
    "Catches npm run commands in docs that have no script",
    "markdownlint-cli2 with code block languages and link fragments enforced",
    "Verified with markdownlint-cli2 0.23.3 on a clean tree and a broken sample"
  ],
  "version": "1.0.0",
  "license": "MIT",
  "author": {
    "name": "Agent Loadout",
    "url": "https://loadout.jnw-it.com"
  },
  "credits": [
    {
      "title": "DavidAnson/markdownlint-cli2",
      "url": "https://github.com/DavidAnson/markdownlint-cli2"
    },
    {
      "title": "markdownlint rules (MD040, MD051)",
      "url": "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md"
    },
    {
      "title": "GitHub docs: section links in Markdown",
      "url": "https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#section-links"
    },
    {
      "title": "lycheeverse/lychee (scheduled external link checks)",
      "url": "https://github.com/lycheeverse/lychee"
    }
  ],
  "categories": [
    "workflow"
  ],
  "stacks": [
    "markdown",
    "nodejs"
  ],
  "files": [
    {
      "path": "AGENTS.md",
      "role": "instructions",
      "description": "Rules for Markdown docs whose links, anchors and commands are checked before a change is done.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": "AGENTS.md",
        "codex": "AGENTS.md",
        "cursor": "AGENTS.md",
        "gemini-cli": "AGENTS.md",
        "antigravity-cli": "AGENTS.md",
        "copilot": "AGENTS.md"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/latest/AGENTS.md",
      "bytes": 1023,
      "lang": "markdown",
      "content": "# AGENTS.md: Markdown docs that stay correct\n\nThis repository keeps its documentation in Markdown: the root README and pages under `docs/`. Docs are reviewed\nlike code: links, anchors and commands must be right, not just readable.\n\n## Commands\n\n- Style: `npx markdownlint-cli2` (config in `.markdownlint-cli2.jsonc`).\n- Links, anchors and script commands: `node .agents/skills/docs-check/scripts/check_docs.mjs` (offline).\n- Done means: both are clean.\n\n## Rules\n\n- Use the `docs-check` skill whenever you add or edit Markdown.\n- Every command in the docs is one you ran or copied from `package.json`. Never invent a script, flag or\n  environment variable.\n- Fenced code blocks name their language.\n- When a heading or file is renamed, fix every link to it in the same change.\n- Relative links between docs pages. External links only to official or primary sources.\n- Do not add markdownlint disable comments to get a clean run.\n- Keep the README short: what it is, quick start, where the docs are. Detail goes in `docs/`.\n"
    },
    {
      "path": "CLAUDE.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Claude Code.",
      "skill": null,
      "agent": "claude-code",
      "install_to": {
        "claude-code": "CLAUDE.md",
        "codex": null,
        "cursor": null,
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/CLAUDE.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/latest/CLAUDE.md",
      "bytes": 407,
      "lang": "markdown",
      "content": "# CLAUDE.md\n\n@AGENTS.md\n\n## Claude Code notes\n\n- Skills from this loadout live in `.claude/skills/`: `docs-check`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From the Agent Loadout \"Markdown docs with markdownlint and offline link checks\" v1.0.0 — https://loadout.jnw-it.com/loadouts/docs-markdown-checks/ -->\n"
    },
    {
      "path": "GEMINI.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Gemini CLI.",
      "skill": null,
      "agent": "gemini-cli",
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": null,
        "gemini-cli": "GEMINI.md",
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/GEMINI.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/latest/GEMINI.md",
      "bytes": 408,
      "lang": "markdown",
      "content": "# GEMINI.md\n\n@./AGENTS.md\n\n## Gemini CLI notes\n\n- Skills from this loadout live in `.agents/skills/`: `docs-check`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From the Agent Loadout \"Markdown docs with markdownlint and offline link checks\" v1.0.0 — https://loadout.jnw-it.com/loadouts/docs-markdown-checks/ -->\n"
    },
    {
      "path": "skills/docs-check/SKILL.md",
      "role": "skill",
      "description": "Both checks, the config, and writing rules for docs.",
      "skill": "docs-check",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/docs-check/SKILL.md",
        "codex": ".agents/skills/docs-check/SKILL.md",
        "cursor": ".agents/skills/docs-check/SKILL.md",
        "gemini-cli": ".agents/skills/docs-check/SKILL.md",
        "antigravity-cli": ".agents/skills/docs-check/SKILL.md",
        "copilot": ".agents/skills/docs-check/SKILL.md"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/latest/skills/docs-check/SKILL.md",
      "bytes": 2696,
      "lang": "markdown",
      "content": "---\nname: docs-check\ndescription: Check Markdown docs before calling a docs change done - markdownlint-cli2 for style, and an offline check that relative links, images and #anchors resolve and that npm run commands in the docs exist. Use when writing or editing README files, docs/ pages, or anything that links between Markdown files.\n---\n\n# Docs check\n\nAgents write docs that read well and are wrong in small ways: a link to a page that was renamed, an anchor\nthat no longer matches its heading, `npm run deploy` when there is no deploy script. Two checks catch these\nwithout the network.\n\n## Run both\n\n```bash\nnpx markdownlint-cli2                                         # style; config in .markdownlint-cli2.jsonc\nnode .agents/skills/docs-check/scripts/check_docs.mjs         # links, anchors, script commands\n```\n\n`check_docs.mjs` takes paths (files or folders); with none it checks the root README and `docs/`.\nOutput is `file:line: problem` and a summary line; exit 1 means fix before finishing.\n\n## What check_docs.mjs checks\n\n- Relative links, images and reference definitions point at files that exist. A leading `/` means the\n  repository root.\n- A `#fragment` matches a heading in the target file, using GitHub's slug rules: lower case, punctuation\n  dropped, spaces to hyphens, `-1`, `-2` for repeated headings. Explicit `<a id=\"...\">` anchors count too.\n- Every `npm run`, `pnpm run`, `yarn run` or `bun run` command in a code block or inline code names a script\n  in the nearest `package.json`.\n- External URLs are not fetched. Leave those to a scheduled link checker so a flaky site never blocks a change.\n\n## Markdownlint config\n\nStart from `references/markdownlint-cli2.jsonc` (copy it to the repository root as\n`.markdownlint-cli2.jsonc`). It keeps the defaults and adds:\n\n- MD040: every fenced block names its language (`bash`, `json`, `text` ...), so readers and highlighters know\n  what it is.\n- MD051: link fragments in the same file must match a heading.\n- MD013 off (no hard wrapping of prose), MD024 only for sibling headings, a small HTML allow-list.\n\n## Writing rules\n\n- Commands in docs are commands you ran. Copy them from `package.json` scripts or your terminal, not memory.\n- When you rename a heading or move a file, search for links to it (`rg -n 'old-slug|old-file.md'`) and fix\n  them in the same change.\n- Link with relative paths between docs files, never to the rendered GitHub URL of the same repository.\n- Do not disable a markdownlint rule inline to get a clean run. Fix the Markdown, or change the shared config\n  with a reason in the pull request.\n\n## Done means\n\nBoth commands are clean, and the summary line from `check_docs.mjs` is in your report.\n"
    },
    {
      "path": "skills/docs-check/scripts/check_docs.mjs",
      "role": "reference",
      "description": "Offline link, anchor and script-command check.",
      "skill": "docs-check",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/docs-check/scripts/check_docs.mjs",
        "codex": ".agents/skills/docs-check/scripts/check_docs.mjs",
        "cursor": ".agents/skills/docs-check/scripts/check_docs.mjs",
        "gemini-cli": ".agents/skills/docs-check/scripts/check_docs.mjs",
        "antigravity-cli": ".agents/skills/docs-check/scripts/check_docs.mjs",
        "copilot": ".agents/skills/docs-check/scripts/check_docs.mjs"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/latest/skills/docs-check/scripts/check_docs.mjs",
      "bytes": 5093,
      "lang": "markdown",
      "content": "#!/usr/bin/env node\n// Offline docs check for Markdown: relative links and images resolve, #fragments match a heading\n// (GitHub-style slugs, including in other files), and `npm run <script>` style commands exist in package.json.\n// No network: external URLs are left to a scheduled link checker.\n//\n//   node check_docs.mjs [paths...]     default: README.md and docs/ (when present)\n// Exit 0 when clean, 1 when there are problems.\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nconst SKIP_DIRS = new Set([\"node_modules\", \".git\", \"dist\", \"build\", \".next\", \"vendor\", \".venv\"]);\nconst args = process.argv.slice(2);\nconst roots = args.length ? args : [\"README.md\", \"docs\"].filter((p) => fs.existsSync(p));\n\nfunction walk(p, out) {\n  const st = fs.statSync(p);\n  if (st.isDirectory()) {\n    for (const e of fs.readdirSync(p)) if (!SKIP_DIRS.has(e)) walk(path.join(p, e), out);\n  } else if (/\\.mdx?$/i.test(p)) out.push(path.normalize(p));\n  return out;\n}\nconst files = roots.flatMap((r) => (fs.existsSync(r) ? walk(r, []) : (console.log(`${r}: not found`), process.exitCode = 1, [])));\n\n// Strip inline Markdown from a heading, then slug it the way GitHub does.\nfunction slug(text) {\n  return text\n    .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n    .replace(/`([^`]*)`/g, \"$1\")\n    .replace(/<[^>]+>/g, \"\")\n    .replace(/[*_~]{1,3}(\\S[^*_~]*?)[*_~]{1,3}/g, \"$1\")\n    .trim()\n    .toLowerCase()\n    .replace(/[^\\p{L}\\p{N}\\p{M}\\s_-]/gu, \"\")\n    .replace(/\\s/g, \"-\");\n}\n\n// Lines outside fenced code blocks, plus the fenced blocks themselves (for command checks).\nfunction parse(file) {\n  const lines = fs.readFileSync(file, \"utf8\").split(/\\r?\\n/);\n  const prose = [];\n  const code = [];\n  let fence = null;\n  lines.forEach((line, i) => {\n    const m = line.match(/^\\s{0,3}(`{3,}|~{3,})/);\n    if (m && !fence) { fence = m[1]; return; }\n    if (fence && line.trim().startsWith(fence)) { fence = null; return; }\n    (fence ? code : prose).push({ n: i + 1, text: line });\n  });\n  return { prose, code };\n}\n\nconst anchorCache = new Map();\nfunction anchors(file) {\n  if (anchorCache.has(file)) return anchorCache.get(file);\n  const set = new Set();\n  const seen = new Map();\n  for (const { text } of parse(file).prose) {\n    const h = text.match(/^\\s{0,3}#{1,6}\\s+(.*?)\\s*#*\\s*$/);\n    for (const m of text.matchAll(/<a\\s+(?:name|id)=\"([^\"]+)\"/g)) set.add(m[1]);\n    if (!h) continue;\n    const base = slug(h[1]);\n    const count = seen.get(base) ?? 0;\n    seen.set(base, count + 1);\n    set.add(count ? `${base}-${count}` : base);\n  }\n  anchorCache.set(file, set);\n  return set;\n}\n\nfunction nearestPackageJson(file) {\n  let dir = path.resolve(path.dirname(file));\n  for (;;) {\n    const p = path.join(dir, \"package.json\");\n    if (fs.existsSync(p)) return p;\n    const up = path.dirname(dir);\n    if (up === dir) return null;\n    dir = up;\n  }\n}\n\nconst problems = [];\nlet linksChecked = 0;\nlet commandsChecked = 0;\nconst report = (file, n, msg) => problems.push(`${file}:${n}: ${msg}`);\n\nfor (const file of files) {\n  const { prose, code } = parse(file);\n  for (const { n, text } of prose) {\n    const noCode = text.replace(/`[^`]*`/g, \"\");\n    const targets = [\n      ...[...noCode.matchAll(/!?\\[[^\\]]*\\]\\(\\s*<?([^)\\s>]+)>?(?:\\s+\"[^\"]*\")?\\s*\\)/g)].map((m) => m[1]),\n      ...[...noCode.matchAll(/^\\s{0,3}\\[[^\\]]+\\]:\\s*<?(\\S+?)>?(?:\\s+.*)?$/g)].map((m) => m[1]),\n      ...[...noCode.matchAll(/<(?:img|a)\\s[^>]*(?:src|href)=\"([^\"]+)\"/g)].map((m) => m[1]),\n    ];\n    for (const t of targets) {\n      if (/^[a-z][a-z0-9+.-]*:/i.test(t) || t.startsWith(\"//\")) continue; // external, mailto:, etc.\n      linksChecked++;\n      const [rawPath, frag] = t.split(\"#\");\n      const decoded = decodeURIComponent(rawPath);\n      const target = decoded === \"\" ? file : decoded.startsWith(\"/\") ? path.normalize(decoded.slice(1)) : path.normalize(path.join(path.dirname(file), decoded));\n      if (!fs.existsSync(target)) { report(file, n, `broken link: ${t} (${target} does not exist)`); continue; }\n      if (frag !== undefined && /\\.mdx?$/i.test(target) && !anchors(target).has(decodeURIComponent(frag).toLowerCase())) {\n        report(file, n, `missing anchor: ${t} (no heading \"#${frag}\" in ${target})`);\n      }\n    }\n  }\n  const pkgPath = nearestPackageJson(file);\n  const scripts = pkgPath ? Object.keys(JSON.parse(fs.readFileSync(pkgPath, \"utf8\")).scripts ?? {}) : null;\n  const inlineCode = prose.flatMap(({ n, text }) => [...text.matchAll(/`([^`]+)`/g)].map((m) => ({ n, text: m[1] })));\n  for (const { n, text } of [...code, ...inlineCode]) {\n    for (const m of text.matchAll(/\\b(npm|pnpm|yarn|bun)\\s+run\\s+([\\w:.-]+)/g)) {\n      commandsChecked++;\n      if (!scripts) report(file, n, `\"${m[0]}\" but no package.json above ${file}`);\n      else if (!scripts.includes(m[2])) report(file, n, `\"${m[0]}\": no \"${m[2]}\" script in ${path.relative(\".\", pkgPath)}`);\n    }\n  }\n}\n\nfor (const p of problems) console.log(p);\nconsole.log(`docs: ${files.length} files, ${linksChecked} local links, ${commandsChecked} script commands, ${problems.length} problems`);\nif (problems.length) process.exitCode = 1;\n"
    },
    {
      "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
      "role": "reference",
      "description": "Repository markdownlint-cli2 config.",
      "skill": "docs-check",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/docs-check/references/markdownlint-cli2.jsonc",
        "codex": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
        "cursor": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
        "gemini-cli": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
        "antigravity-cli": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
        "copilot": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/latest/skills/docs-check/references/markdownlint-cli2.jsonc",
      "bytes": 733,
      "lang": "markdown",
      "content": "// .markdownlint-cli2.jsonc at the repository root. Run: npx markdownlint-cli2\n{\n  \"config\": {\n    \"default\": true,\n    // Long lines are fine in prose; wrapping makes diffs noisy.\n    \"MD013\": false,\n    // Same heading text is fine under different parents (e.g. \"Usage\" per command).\n    \"MD024\": { \"siblings_only\": true },\n    // Allow the small amount of HTML GitHub renders well.\n    \"MD033\": { \"allowed_elements\": [\"details\", \"summary\", \"kbd\", \"br\", \"img\", \"a\"] },\n    // Fenced code blocks must say their language.\n    \"MD040\": true,\n    // Link fragments must match a heading in the same file.\n    \"MD051\": true\n  },\n  \"globs\": [\"**/*.md\"],\n  \"ignores\": [\"node_modules/**\", \"**/node_modules/**\", \"CHANGELOG.md\", \"dist/**\"]\n}\n"
    }
  ],
  "requires": {
    "tools": [
      "node",
      "npm"
    ],
    "env": [],
    "mcp": []
  },
  "tested": {
    "status": "untested",
    "last_run": null,
    "fixture": null,
    "per_agent": {
      "claude-code": "untested",
      "codex": "untested",
      "cursor": "untested",
      "gemini-cli": "untested",
      "antigravity-cli": "untested",
      "copilot": "untested"
    }
  },
  "security": {
    "scanned": true,
    "scanner": "intake-precheck/1",
    "verdict": "clean",
    "network": true,
    "scripts": [
      "check_docs.mjs"
    ],
    "notes": "npx markdownlint-cli2 runs the version pinned in package.json (installed from npm). check_docs.mjs reads local files only and makes no network calls."
  },
  "featured": false,
  "deprecated": false,
  "last_checked": "2026-10-17",
  "published": "2026-10-17",
  "updated": "2026-10-17",
  "compatibility": {
    "claude-code": "native",
    "codex": "native",
    "cursor": "native",
    "gemini-cli": "native",
    "antigravity-cli": "native",
    "copilot": "native"
  },
  "counts": {
    "rules": 1,
    "skills": 1,
    "mcp": 0
  },
  "url": "https://loadout.jnw-it.com/loadouts/docs-markdown-checks/",
  "api_url": "https://loadout.jnw-it.com/api/loadouts/docs-markdown-checks.json",
  "verification": {
    "level": "verified-install",
    "status": "verified",
    "label": "Verified install",
    "verified": true,
    "checked_at": "2026-10-17T20:59:33Z",
    "commit": "08c3710727a4d6fc320a98ecf32bdc0a780eaa6c",
    "content_current": true,
    "agent_tests": "not-run",
    "counts": {
      "pass": 9,
      "fail": 0,
      "skip": 0,
      "not_applicable": 1
    },
    "meaning": "Level 1: automated checks on the files (parse, install paths, MCP config, safety scan, references, size, licence, starter build). No AI agent was run.",
    "checks": [
      {
        "id": "listing",
        "name": "Listing",
        "status": "pass",
        "summary": "Schema valid; 6 files declared, none missing or extra",
        "details": [
          "tested.status: untested (agent tests are separate from Level 1)"
        ]
      },
      {
        "id": "parse",
        "name": "Files parse",
        "status": "pass",
        "summary": "All 6 files parse; front matter valid",
        "details": []
      },
      {
        "id": "adapters",
        "name": "Adapters",
        "status": "pass",
        "summary": "CLAUDE.md and GEMINI.md import AGENTS.md and are up to date",
        "details": [
          "CLAUDE.md: matches the generator",
          "GEMINI.md: matches the generator"
        ]
      },
      {
        "id": "install-paths",
        "name": "Install paths",
        "status": "pass",
        "summary": "Correct paths for all 6 agents; layouts re-discovered",
        "details": [
          "Claude Code: 5 files, 1 skill in .claude/skills/",
          "Codex CLI: 4 files, 1 skill in .agents/skills/",
          "Cursor: 4 files, 1 skill in .agents/skills/",
          "Gemini CLI: 5 files, 1 skill in .agents/skills/",
          "Antigravity CLI: 4 files, 1 skill in .agents/skills/",
          "GitHub Copilot: 4 files, 1 skill in .agents/skills/"
        ]
      },
      {
        "id": "mcp",
        "name": "MCP config",
        "status": "n/a",
        "summary": "No MCP servers in this loadout",
        "details": []
      },
      {
        "id": "safety",
        "name": "Safety scan",
        "status": "pass",
        "summary": "Clean: no credentials, risky shell or hidden text",
        "details": [
          "Scanner intake-precheck/1: verdict clean; network no (listing says yes)"
        ]
      },
      {
        "id": "references",
        "name": "References",
        "status": "pass",
        "summary": "1 reference between files resolves for every agent",
        "details": []
      },
      {
        "id": "size",
        "name": "Size limits",
        "status": "pass",
        "summary": "6 files, 10.1 KB total; largest skills/docs-check/scripts/check_docs.mjs 5.0 KB",
        "details": [
          "Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule"
        ]
      },
      {
        "id": "licence",
        "name": "Licence",
        "status": "pass",
        "summary": "MIT, by Agent Loadout; text in the repository LICENSE",
        "details": []
      },
      {
        "id": "starter-build",
        "name": "Starter build",
        "status": "pass",
        "summary": "The docs-check skill's markdownlint-cli2 config (0.23.3) and check_docs.mjs pass on a README and docs tree with cross-file anchors, an image and four npm script commands; a sample with a broken link, two wrong anchors, an invented npm script and an unlabelled code fence fails both tools.",
        "details": [
          "Applied 9 loadout files at every agent's paths",
          "✓ npm ci (markdownlint-cli2 pinned): npm ci --no-audit --no-fund --ignore-scripts",
          "✓ place the markdownlint config: bash -c cp .agents/skills/docs-check/references/markdownlint-cli2.jsonc .markdownlint-cli2.jsonc && echo placed",
          "✓ markdownlint-cli2 is clean (README, docs, and the loadout's own AGENTS.md): npx markdownlint-cli2",
          "✓ check_docs.mjs is clean: npm run -s docs:check",
          "✓ the bad sample fails both: bash -c mkdir -p bad && cp samples/bad-readme.md.txt bad/README.md && npx markdownlint-cli2 'bad/**/*.md' 2>&1; a=$?; node .agents/skills/docs-check/scripts/check_docs.mjs bad; b=$?; test $a -ne 0 && test $b -eq 1 && echo both failed",
          "Covers: Relative links and images resolve; #fragments match GitHub-style heading slugs in the same or another file",
          "Covers: npm/pnpm/yarn/bun run commands in code blocks and inline code exist in the nearest package.json",
          "Covers: markdownlint-cli2 with fenced-code languages (MD040) and link fragments (MD051) enforced"
        ]
      }
    ]
  },
  "install": {
    "claude-code": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "CLAUDE.md",
          "target": "CLAUDE.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/CLAUDE.md",
          "role": "adapter"
        },
        {
          "path": "skills/docs-check/SKILL.md",
          "target": ".claude/skills/docs-check/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/docs-check/scripts/check_docs.mjs",
          "target": ".claude/skills/docs-check/scripts/check_docs.mjs",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
          "role": "reference"
        },
        {
          "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
          "target": ".claude/skills/docs-check/references/markdownlint-cli2.jsonc",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/claude-code.zip"
    },
    "codex": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/docs-check/SKILL.md",
          "target": ".agents/skills/docs-check/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/docs-check/scripts/check_docs.mjs",
          "target": ".agents/skills/docs-check/scripts/check_docs.mjs",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
          "role": "reference"
        },
        {
          "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
          "target": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/codex.zip"
    },
    "cursor": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/docs-check/SKILL.md",
          "target": ".agents/skills/docs-check/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/docs-check/scripts/check_docs.mjs",
          "target": ".agents/skills/docs-check/scripts/check_docs.mjs",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
          "role": "reference"
        },
        {
          "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
          "target": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/cursor.zip"
    },
    "gemini-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "GEMINI.md",
          "target": "GEMINI.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/GEMINI.md",
          "role": "adapter"
        },
        {
          "path": "skills/docs-check/SKILL.md",
          "target": ".agents/skills/docs-check/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/docs-check/scripts/check_docs.mjs",
          "target": ".agents/skills/docs-check/scripts/check_docs.mjs",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
          "role": "reference"
        },
        {
          "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
          "target": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/gemini-cli.zip"
    },
    "antigravity-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/docs-check/SKILL.md",
          "target": ".agents/skills/docs-check/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/docs-check/scripts/check_docs.mjs",
          "target": ".agents/skills/docs-check/scripts/check_docs.mjs",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
          "role": "reference"
        },
        {
          "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
          "target": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/antigravity-cli.zip"
    },
    "copilot": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/docs-check/SKILL.md",
          "target": ".agents/skills/docs-check/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/docs-check/scripts/check_docs.mjs",
          "target": ".agents/skills/docs-check/scripts/check_docs.mjs",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/scripts/check_docs.mjs",
          "role": "reference"
        },
        {
          "path": "skills/docs-check/references/markdownlint-cli2.jsonc",
          "target": ".agents/skills/docs-check/references/markdownlint-cli2.jsonc",
          "raw_url": "https://loadout.jnw-it.com/raw/docs-markdown-checks/1.0.0/skills/docs-check/references/markdownlint-cli2.jsonc",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/copilot.zip"
    }
  },
  "source_zip_url": "https://loadout.jnw-it.com/download/docs-markdown-checks/source.zip"
}