Help us improve
Share bugs, ideas, or general feedback.
From md-publisher
This skill should be used when the user asks to "preprocess doc.md", "tag mermaid for theming", "add classDef tags to my mermaid", "annotate diagrams", "prepare doc for theming", or invokes /md-publisher:preprocess. Scans a markdown document for mermaid flowcharts, decides a universal-tag class (ingress/core/transform/bridge) for each untagged node, rewrites the source in place, and backs up the original. Optionally adds YAML front matter for richer cover-page metadata.
npx claudepluginhub ehartye/md-publisher --plugin md-publisherHow this skill is triggered — by the user, by Claude, or both
Slash command
/md-publisher:preprocessThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Add the four universal tag classes (`:::ingress`, `:::core`, `:::transform`, `:::bridge`) to mermaid flowchart nodes so themes can color them by semantic role. The annotated source becomes the new authoring baseline; the original is backed up to `<source-dir>/.md-publisher/<timestamp>/original.md` before the rewrite.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Grills users relentlessly on plans or designs by interviewing branch-by-branch through decision trees to reach shared understanding. Use for stress-testing ideas or 'grill me'.
Share bugs, ideas, or general feedback.
Add the four universal tag classes (:::ingress, :::core, :::transform, :::bridge) to mermaid flowchart nodes so themes can color them by semantic role. The annotated source becomes the new authoring baseline; the original is backed up to <source-dir>/.md-publisher/<timestamp>/original.md before the rewrite.
Trigger on any of:
doc.md" / "tag the mermaid in doc.md"doc.md for theming"/md-publisher:preprocess <markdown-file>The four universal classes correspond to a node's role in the diagram's data flow:
| Tag | Meaning |
|---|---|
:::ingress | Entry / exit / source / sink — terminals in the data flow |
:::core | Primary processing — the "main thing" the diagram is about |
:::transform | Auxiliary processing — projections, conversions, preprocessing |
:::bridge | Connector / aggregator / intermediate — joins, splits, glue |
These map per-theme to specific colors via each theme's classDef rules (e.g., ATLAS makes ingress nodes red-bordered, ARCADE makes them neon-green). No coloring is applied at preprocess time — only the class assignments. Themes do the visual work at publish time.
For classDiagram blocks, the preprocess skill also detects misplaced :::tag markers — :::tag placed inside a method/attribute line (e.g. +method():::core) instead of on the class header. Mermaid silently ignores these. The skill auto-promotes them to the class header using priority-wins precedence (ingress > core > transform > bridge) and strips the misplaced markers from the body. See Step 2.5.
Mermaid blocks that are NOT flowchart/graph (sequenceDiagram, classDiagram, etc.) are left alone — classDef only applies to flowcharts. They still get themed at publish time, just at the diagram-level palette rather than per-node.
Two-script pipeline. The skill orchestrates between them and supplies the per-node tag decisions.
Invoke ${CLAUDE_PLUGIN_ROOT}/skills/preprocess/scripts/scan-mermaid.py <doc.md>. It emits JSON describing every mermaid block:
{
"source": "/abs/path/to/doc.md",
"blocks": [
{
"index": 0,
"line_start": 38,
"line_end": 46,
"diagram_type": "flowchart",
"supports_classdef": true,
"tagged": false,
"node_count": 12,
"node_ids": ["A", "B", ...],
"untagged_node_ids": ["A", "B", ...],
"snippet": "flowchart TD\\n A[Input tokens] --> ..."
}
]
}
line_start and line_end are 1-based line numbers in the source — useful when you need to read prose around a diagram for context. snippet is the first 12 lines of the block (truncated for brevity in the scan output; the full source is at the line range above).
For each block where supports_classdef: true and there are untagged_node_ids:
Read the snippet to understand what the diagram represents (the file body around line_start may also help — read context if the snippet is ambiguous).
For each untagged node, decide which of the four classes fits:
:::ingress for entry/exit nodes — typically the source of input or destination of output. Look for words like "input", "output", "request", "response", "start", "end", "source", "sink", "result", "next-token".:::core for the diagram's main subject — the steps that are the thing being explained. Encoder/decoder blocks, attention heads, processing stages, business logic.:::transform for auxiliary steps — projections, conversions, preprocessing, formatting. Things that prepare input for or convert output from the core.:::bridge for connectors and intermediates — concatenations, joins, splits, things that route or combine but aren't the primary work.When in doubt, prefer :::core — it is the "neutral default" and themes color it as the most prominent role.
If a node's role genuinely doesn't fit any of the four, leave it untagged. Themes color untagged nodes with the diagram-level palette, which is a fine fallback.
For each block where misplaced_tags is non-empty:
class_name.ingress > core > transform > bridge.class_tag_promotions entry into the decisions JSON: {index, class_name, winning_tag}. apply-tags will rewrite the header and strip body markers.class_name: null (orphan — no class Foo header line in the source), do NOT emit a promotion. Tell the user: "Class <name> has misplaced :::tag markers but no explicit class <name> header in the diagram. Add a header line so the auto-fix can attach the tag." apply-tags will warn and skip if a null-class promotion ever lands in the decisions doc.The promotions are independent of the tags array — they touch only classDiagram blocks via class_tag_promotions.
If the user passes --add-frontmatter (or asks for richer cover-page metadata), prompt for:
Skip this step by default. YAML front matter changes how OTHER markdown tools (not in this plugin) parse the file — it is opt-in for that reason.
Write the decisions to a temp JSON file, then invoke:
${CLAUDE_PLUGIN_ROOT}/skills/preprocess/scripts/apply-tags.py --decisions <temp.json>
The apply script:
<source-dir>/.md-publisher/<YYYYMMDD-HHMMSS>/original.md.:::<tag> to the FIRST occurrence of each tagged node ID's definition.Do NOT pass --no-backup. The flag exists in apply-tags.py as an escape hatch but using it removes the only safety net against an accidental destructive rewrite. The default backup behavior is the load-bearing safety property of this skill.
Tell the user:
/md-publisher:publish <doc.md> for theme-aware coloring{
"source": "/abs/path/to/doc.md",
"tags": [
{"index": 0, "node_id": "A", "tag": "ingress"},
{"index": 0, "node_id": "B", "tag": "core"},
{"index": 1, "node_id": "X", "tag": "ingress"}
],
"frontmatter": {
"title": "Document Title",
"subtitle": "...",
"author": "...",
"date": "2026-05-03"
}
}
frontmatter is optional. Tags with index referencing a non-existent block are silently dropped.
Re-running preprocess on an already-tagged document is safe:
untagged_node_ids for already-fully-tagged blocks:::class patterns and treats them as already-done)A document may be preprocessed multiple times — each run produces a new timestamped backup but the source converges.
# Step 1: scan
${CLAUDE_PLUGIN_ROOT}/skills/preprocess/scripts/scan-mermaid.py docs/intro.md > /tmp/scan.json
# (skill reads /tmp/scan.json, decides tags, writes /tmp/decisions.json)
# Step 2: apply
${CLAUDE_PLUGIN_ROOT}/skills/preprocess/scripts/apply-tags.py --decisions /tmp/decisions.json
0 blocks scanned, nothing to tag and exit cleanly.:::tag marker appears on or near a class identifier that has no explicit class Foo declaration in the diagram. apply-tags emits a stderr warning and leaves the source untouched; ask the user to add the class Foo declaration so the auto-fix can attach the tag.scripts/scan-mermaid.py — the scan helperscripts/apply-tags.py — the rewriter + backup${CLAUDE_PLUGIN_ROOT}/lib/output_paths.py — backup-path conventions