Tips & Tricks (Aktualisiert: 2.6.2026)

Markdown und MDX sicher mit Claude Code verarbeiten

Markdown/MDX mit Claude Code sicher verarbeiten: AST, Frontmatter, XSS-Schutz, Links und Locale-QA.

Markdown und MDX sicher mit Claude Code verarbeiten

Markdown ist kein einfacher Textblock

Ein veröffentlichter Markdown- oder MDX-Artikel besteht nicht nur aus Absätzen. Er enthält Frontmatter, SEO-Description, Überschriftenhierarchie, generierte Anker, Code-Fences, interne Links, offizielle externe Quellen, Sprachrouten und manchmal rohes HTML. Wenn Claude Code nur den Auftrag “verbessere diesen Artikel” bekommt, kann der Text besser klingen und trotzdem den Slug ändern, den CTA entfernen, das Hero-Bild anfassen oder eine Locale als dünne Zusammenfassung zurücklassen.

Der robuste Ansatz trennt Schreiben und Prüfen. Claude Code darf formulieren, lokalisieren und erweitern. Die Struktur muss maschinell überprüfbar sein. Markdown und MDX liest man mit einem AST, also einem abstrakten Syntaxbaum. Frontmatter wird wie strukturierte Daten validiert. HTML-Ausgabe braucht eine klare Sanitization-Grenze. Die zehn Locale-Dateien müssen als ein Set geprüft werden.

Die wichtigsten Quellen wurden am 2. Juni 2026 geprüft. Der unified guide erklärt die Pipeline aus parse, transform und stringify. Die Seite zu syntax trees zeigt, warum ein AST stabiler ist als Zeilen-Regex. Für Markdown sind remark und remark-parse relevant. MDX steht in der MDX-Dokumentation. Frontmatter kann mit gray-matter gelesen werden. Für HTML-Sicherheit vergleiche rehype-sanitize mit dem OWASP XSS Prevention Cheat Sheet. Für Claude-Code-Grenzen helfen Claude Code overview und settings.

flowchart LR
  A["MDX-Datei"] --> B["Frontmatter"]
  B --> C["Schema-Validierung"]
  A --> D["remark / MDX AST"]
  D --> E["Headings, Fences, Links"]
  D --> F["rehype Pipeline"]
  F --> G["Sanitization"]
  C --> H["Locale- und Build-Checks"]
  E --> H
  G --> H

Parser passend zur Aufgabe wählen

Die erste Anweisung an Claude Code sollte die Toolchain nennen. “Parse Markdown” ist zu ungenau. Für kleine Dateien entsteht dann oft eine Regex, die in echten Artikeln falsche Treffer liefert.

BedarfBessere WahlRiskanter Kurzweg
Überschriften, Links und Code-Fences lesenremark-parse mit AST Traversal^## Regex auf Rohtext
JSX in .mdx behandelnremark-mdx oder MDX CompilerReiner Markdown Parser
HTML rendernremark-rehype in rehypeHTML-Strings zusammenbauen
Rohes HTML erlaubenrehype-raw plus rehype-sanitizeNur allowDangerousHtml
Frontmatter lesengray-matter und Schema-ChecksYAML per split lesen

Ein AST trennt Bedeutung. Ein ## Fake Heading im Codeblock darf nicht im Inhaltsverzeichnis landen. Eine URL in MDX-Props ist nicht immer ein redaktioneller Link. tags: Claude Code, Markdown ist in YAML ein String und kein Array. Solche Fehler sieht ein Parser plus Schema deutlich früher als ein menschlicher Diff-Review.

Vier konkrete Use Cases

Der erste Use Case ist die Aktualisierung eines veröffentlichten Blogartikels. Title, description, updatedDate, offizielle Links, interne Links, Codebeispiele und CTA müssen zusammen passen. Bei ClaudeCodeLab verlinkt man passend auf CLAUDE.md Best Practices und Web Scraping mit Claude Code, ohne andere Slugs zu ändern.

Der zweite Use Case ist eine Dokumentationsseite mit MDX-Komponenten. Callouts, Tabs, Pricing Cards, FAQ und Live-Beispiele sind nützlich, mischen aber Markdown und JSX. Ein Checker ohne MDX-Verständnis wird Komponenten falsch lesen oder wichtige Links übersehen.

Der dritte Use Case ist mehrsprachige Veröffentlichung. Ein starker japanischer Canonical-Artikel reicht nicht, wenn Deutsch, Spanisch, Französisch oder Indonesisch nur kurze Zusammenfassungen sind. Jede Locale braucht Beispiele, Fehlermodi, ausführbare Snippets, offizielle Links, interne Links, CTA und Verifikationsnotiz.

Der vierte Use Case ist kommerzieller Content. Gumroad-Seiten, Training-Seiten, kostenlose Ressourcen und E-Mail-Materialien verwenden oft Markdown. Je näher die Seite an Kauf oder Beratung liegt, desto wichtiger sind überprüfbare Code-Fences, Links und HTML-Regeln.

Minimales Copy-Paste-Setup

Die Beispiele verwenden Node.js 18 oder neuer und ESM. Starte in einem Testordner, bevor du die Skripte ins echte Repository übernimmst.

mkdir mdx-audit-demo
cd mdx-audit-demo
npm init -y
npm pkg set type=module
npm install unified remark-parse remark-mdx remark-gfm gray-matter
npm install unist-util-visit github-slugger
npm install remark-rehype rehype-raw rehype-sanitize rehype-stringify
mkdir tools

Dieses Skript liest Frontmatter mit gray-matter, parsed den Body mit remark und MDX-Support und meldet fehlende Felder, zu lange description, Code-Fences ohne Sprache sowie fehlende interne oder externe Links.

// tools/audit-mdx.mjs
import fs from "node:fs/promises";
import matter from "gray-matter";
import GithubSlugger from "github-slugger";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkMdx from "remark-mdx";
import remarkGfm from "remark-gfm";
import { visit } from "unist-util-visit";

const file = process.argv[2];
if (!file) {
  throw new Error("Usage: node tools/audit-mdx.mjs article.mdx");
}

const source = await fs.readFile(file, "utf8");
const { data, content } = matter(source);
const errors = [];
const links = { internal: [], external: [] };
const headings = [];
const codeBlocks = [];

for (const key of ["title", "description", "pubDate", "heroImage", "lang"]) {
  if (typeof data[key] !== "string" || data[key].trim() === "") {
    errors.push(`frontmatter.${key} is required`);
  }
}

if ([...String(data.description ?? "")].length > 120) {
  errors.push("description must be 120 characters or fewer");
}

if (!Array.isArray(data.tags) || data.tags.length === 0) {
  errors.push("frontmatter.tags must be a non-empty array");
}

const tree = unified()
  .use(remarkParse)
  .use(remarkMdx)
  .use(remarkGfm)
  .parse(content);

const slugger = new GithubSlugger();

visit(tree, (node) => {
  if (node.type === "heading") {
    const text = plainText(node);
    headings.push({ depth: node.depth, text, slug: slugger.slug(text) });
  }

  if (node.type === "code") {
    codeBlocks.push({ lang: node.lang || "", meta: node.meta || "" });
    if (!node.lang) errors.push("code fence is missing a language");
  }

  if (node.type === "link") {
    const url = String(node.url || "");
    if (url.startsWith("http")) links.external.push(url);
    if (url.startsWith("/")) links.internal.push(url);
  }
});

if (links.internal.length === 0) errors.push("missing internal link");
if (links.external.length === 0) errors.push("missing external link");

if (errors.length > 0) {
  console.error(errors.map((error) => `- ${error}`).join("\n"));
  process.exit(1);
}

console.log(JSON.stringify({ headings, codeBlocks, links }, null, 2));

function plainText(node) {
  if (typeof node.value === "string") return node.value;
  if (!Array.isArray(node.children)) return "";
  return node.children.map(plainText).join("");
}
node tools/audit-mdx.mjs site/src/content/blog-de/example.mdx

Beispiel 2: Markdown in sicheres HTML wandeln

Wenn rohes HTML nicht nötig ist, aktiviere es nicht. Wenn es nötig ist, parse es und sanitize direkt danach. allowDangerousHtml allein ist keine Sicherheitsmaßnahme.

// tools/markdown-to-safe-html.mjs
import fs from "node:fs/promises";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import rehypeRaw from "rehype-raw";
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
import rehypeStringify from "rehype-stringify";

const file = process.argv[2];
const markdown = await fs.readFile(file, "utf8");
const schema = {
  ...defaultSchema,
  attributes: {
    ...defaultSchema.attributes,
    code: [["className", /^language-/]],
  },
};

const html = await unified()
  .use(remarkParse)
  .use(remarkGfm)
  .use(remarkRehype, { allowDangerousHtml: true })
  .use(rehypeRaw)
  .use(rehypeSanitize, schema)
  .use(rehypeStringify)
  .process(markdown);

console.log(String(html));

Die Reihenfolge ist entscheidend. rehype-raw bringt rohes HTML zurück in den HTML-Baum. rehype-sanitize entfernt danach nicht erlaubte Tags und Attribute. Ohne diesen zweiten Schritt kann gefährlicher Inhalt im gerenderten DOM landen.

Beispiel 3: Alle zehn Locales prüfen

Dieses Skript bestätigt, dass derselbe Slug in allen Sprachen existiert, heroImage erhalten bleibt, updatedDate stimmt und jeder Body interne und externe Links enthält.

// tools/check-locales.mjs
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";

const slug = "claude-code-markdown-processing.mdx";
const expectedHero = "/images/hero/hero-077.png";
const locales = [
  ["ja", "site/src/content/blog"],
  ["en", "site/src/content/blog-en"],
  ["zh", "site/src/content/blog-zh"],
  ["ko", "site/src/content/blog-ko"],
  ["es", "site/src/content/blog-es"],
  ["fr", "site/src/content/blog-fr"],
  ["de", "site/src/content/blog-de"],
  ["pt", "site/src/content/blog-pt"],
  ["hi", "site/src/content/blog-hi"],
  ["id", "site/src/content/blog-id"],
];

const errors = [];

for (const [lang, dir] of locales) {
  const file = path.join(dir, slug);
  const source = fs.readFileSync(file, "utf8");
  const { data, content } = matter(source);
  if (data.lang !== lang) errors.push(`${lang}: lang mismatch`);
  if (data.heroImage !== expectedHero) errors.push(`${lang}: hero changed`);
  if (data.updatedDate !== "2026-06-02") {
    errors.push(`${lang}: updatedDate mismatch`);
  }
  if ([...String(data.description ?? "")].length > 120) {
    errors.push(`${lang}: description too long`);
  }
  if (!content.includes("https://")) errors.push(`${lang}: no external link`);
  if (!content.includes("](/")) errors.push(`${lang}: no internal link`);
}

if (errors.length > 0) {
  console.error(errors.map((error) => `- ${error}`).join("\n"));
  process.exit(1);
}

console.log("locale set is consistent");

Konkrete Fehlerbilder

FehlerFolgeSchutz
Headings per Regex lesenPseudo-Headings aus Codeblöcken landen im TOCNur heading Nodes lesen
tags als StringFilter und Related Posts brechenFrontmatter-Typen prüfen
Unterschiedliche SlugsAnchor-Links brechen je SpracheEinheitlichen Slugger nutzen
Rohes HTML vertrauenXSS-Risiko über Tags oder AttributeMit Schema sanitizen
Externe Links nicht testenOffizielle Docs ziehen unbemerkt umVor Veröffentlichung prüfen
Prompt zu breitDateien anderer Worker werden geändertowned_files fixieren

Diese Fehler gehören in den Prompt. Claude Code arbeitet besser mit überprüfbaren Grenzen als mit subjektiven Sätzen wie “mach es hochwertiger”.

Sicherer Prompt für Claude Code

task: "Refresh one published MDX article"
owned_files:
  - "site/src/content/blog-de/claude-code-markdown-processing.mdx"
preserve:
  - "slug path"
  - "heroImage"
  - "unrelated dirty files"
required:
  - "updatedDate: 2026-06-02"
  - "description <= 120 characters"
  - "AST-based Markdown checks"
  - "official external links"
  - "internal links and monetization CTA"
forbidden:
  - "regex-only heading parsing"
  - "raw HTML without sanitization"
  - "thin locale summaries"
verification:
  - "node scripts/check-code-fences.mjs"
  - "node scripts/check-updated-article-quality.mjs"

Vor dem Publizieren und CTA

Vor Veröffentlichung braucht es lokale Skripte und menschliche Prüfung. Die Skripte prüfen Struktur, Metadaten, Fences, Links und Tiefe. Der Mensch prüft natürliche Sprache, Suchintention, mobile Lesbarkeit und CTA.

node tools/audit-mdx.mjs site/src/content/blog-de/claude-code-markdown-processing.mdx
node tools/check-locales.mjs
node scripts/check-code-fences.mjs
node scripts/check-updated-article-quality.mjs

Einzelpersonen starten mit der kostenlosen Claude Code Cheatsheet. Wer wiederverwendbare Review- und Schreibprompts braucht, nutzt die Claude Code Prompt Templates. Teams, die Berechtigungen, CI, Locale-Workflow und Editorial Review einführen wollen, gehen zu Claude Code Training und Beratung.

Ergebnis der praktischen Prüfung

Für dieses Update behandelte Masa den Artikel als echten Content-Pipeline-Fall: kurze description, updatedDate, erhaltenes heroImage, Sprachen in Code-Fences, offizielle Links, vollständige Locales und CTA. Der AST-basierte Audit deckt Fehler ab, die Regex leicht übersieht, vor allem Headings in Codeblöcken und MDX-Syntax nahe Komponenten. Am Ende wurden node scripts/check-code-fences.mjs und node scripts/check-updated-article-quality.mjs ausgeführt. Die wichtigste Erkenntnis: Claude Code wird zuverlässig, wenn der Artikelvertrag ausführbar ist, nicht nur wenn der Prompt bessere Texte fordert.

#Claude Code #Markdown #MDX #remark #Content Ops
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.