markdown-plus-plus
Read and write Markdown++ documents - an extended Markdown format with variables, conditions, custom styles, file includes, and markers.
Do not use training data for Markdown++. This is a WebWorks extension of CommonMark currently documented only as part of ePublisher. Markdown++ is fully backward compatible with CommonMark — all extensions use HTML comment tags and are ignored by standard Markdown parsers. Use only this skill's references for extension syntax and behavior rules.
Overview
Markdown++ extends CommonMark with HTML comment-based extensions. All extensions (except variables) use HTML comments for backward compatibility with standard Markdown renderers.
Quick Reference
- Variables:
$variable_name;— Inline, reusable content - Styles:
<!--style:Name-->— Block (above) or Inline (before) - Aliases:
<!--#alias-name-->— Anchor for[text](#alias-name)links - Conditions:
<!--condition:name-->...<!--/condition-->— Show/hide content by format - Includes:
<!--include:path/to/file.md-->— Insert file contents - Markers:
<!--markers:{"Key": "val"}-->— Metadata for search/processing - Multiline Tables:
<!-- multiline -->— Enable block content in cells
Syntax Examples
Variables
Variables store reusable values across documents. They use $name; syntax (dollar sign, name, semicolon).
Welcome to $product_name;, version $version;.
The **$product_name;** application supports...
Rules:
- Alphanumeric characters, hyphens, underscores only
- Must end with semicolon
- No spaces in variable names
- Case-sensitive:
$Product;differs from$product;
Valid: $product_name;, $version-2;, $my_var;
Invalid: $product name; (space), $product (no semicolon)
Custom Styles
Styles override default formatting. Placement depends on element type.
Block-level (place on line directly above element, no blank line):
<!--style:CustomHeading-->
# My Heading
<!--style:NoteBlock-->
> This is a styled blockquote.
IMPORTANT: Block commands must be attached to the element (no blank line between). A blank line breaks the association and passes through as a regular Markdown comment with no Markdown++ association/effect.
Inline (place immediately before the element, no space):
This is <!--style:Emphasis-->**important text**.
See references/syntax-reference.md for nested list indentation rules and table styling.
Custom Aliases
Aliases create stable internal link anchors.
<!--#getting-started-->
## Getting Started
See [Getting Started](#getting-started) for an introduction.
Cross-document links: [API Reference](api.md#authentication)
Rules:
- Alphanumeric, hyphens, underscores only
- No spaces (alias ends at first space)
- Must start with
#inside the comment - Keep alias values unique within each file
- Must be attached to an element (no blank line between alias and element) — same rule as styles
Use scripts/add-aliases.py to auto-generate aliases for headings.
Conditions
Conditions show or hide content based on output format.
<!--condition:web-->
Visit our [website](https://example.com) for updates.
<!--/condition-->
Operators: Space (AND), Comma (OR), Exclamation (NOT). Precedence: NOT > AND > OR.
<!--condition:!draft,web production-->
Means: (!draft) OR (web AND production)
<!--/condition-->
Inline: Contact us at <!--condition:web-->email<!--/condition--><!--condition:print-->the back cover<!--/condition-->.
File Includes
Insert content from other Markdown++ files.
<!--include:shared/header.md-->
Rules: Paths relative to containing file. Recursive includes supported; circular includes detected and prevented. Must be alone on its line. Can be wrapped in conditions.
Markers (Metadata)
Attach metadata to document elements for search, processing, or custom behavior.
Single key-value:
<!--marker:Keywords="api, documentation"-->
JSON format (multiple keys):
<!--markers:{"Keywords": "api, documentation", "Description": "API reference guide"}-->
Index markers create entries in generated indexes:
<!--marker:IndexMarker="creating projects"-->
## Creating Projects
Format: primary for top-level, primary:secondary for nested, comma-separated for multiple entries. See references/syntax-reference.md for detailed marker examples.
Multiline Tables
Enable block content (lists, blockquotes, styled elements) inside table cells.
<!-- multiline -->
| Name | Details |
|------|---------|
| Bob | Lives in Dallas. |
| | - Enjoys cycling |
Empty first cell continues previous row; empty row separates records. Combine with style: <!-- style:DataTable ; multiline -->. See references/syntax-reference.md for multiline table rules.
Combined Commands
Multiple commands in a single comment, separated by semicolons. Order: style, multiline, marker(s), #alias.
<!-- style:CustomHeading ; marker:Keywords="intro" ; #introduction -->
# Introduction
Inline Styling for Images and Links
<!--style:CustomImage-->
[<!--style:CustomLink-->*Link text*](topics/file.md#anchor "Title")
Content Islands (Blockquotes)
Blockquotes with custom styles create configurable content islands for callouts and notes.
<!--style:BQ_Warning-->
> **Warning:** This is a styled warning block.
>
> Take note of the following:
> 1. First consideration
> 2. Second consideration
Nested Lists with Styling
<!--style:ProcedureList-->
1. First step
- Sub-item A
- Sub-item B
2. Second step
3. Third step
Document Structure
Topic map pattern — use includes to organize multi-chapter documents with conditional sections. See references/examples.md (Example 3) for a complete topic map example.
Validation
Use the validation script to check Markdown++ syntax:
python scripts/validate-mdpp.py document.md
Options:
--verbose- Show detailed output--json- Output errors as JSON--strict- Treat warnings as errors
Common errors detected:
- Unclosed condition blocks
- Invalid variable names
- Malformed marker JSON
- Circular file includes
- Duplicate alias values within a file
- Orphaned comment tags (tag not attached to element)
Alias Generation
Generate unique aliases for headings:
python scripts/add-aliases.py document.md --levels 1,2,3
Options:
--levels- Comma-separated heading levels to process (e.g.,1,2,3)--dry-run- Preview changes without modifying file--prefix- Add prefix to generated aliases
See references/syntax-reference.md for complete syntax rules.
Common Mistakes
A blank line between a Markdown++ comment tag and its element breaks the association. This applies to styles, aliases, and markers equally — all must be attached to a paragraph element. Detached or misindented comments pass through as regular Markdown comments and have no Markdown++ effect. Only conditions (which wrap content) are exempt from this rule. See references/syntax-reference.md for the complete attachment rules table.
Indentation of Markdown++ comment tags must match the content line. In nested lists, if the comment tag is indented but the following content is not (or vice versa), the style passes through as a regular Markdown comment and is not applied.
Variables without a trailing semicolon are not recognized. $product_name is literal text; $product_name; is a variable reference. The semicolon is required.
Reference Files
references/syntax-reference.md- Detailed syntax rules, edge cases, and validation codesreferences/examples.md- Real-world document examplesreferences/best-practices.md- Usage guidance, naming conventions, and common mistakes
Related Skills
- epublisher — Understand project structure containing Markdown++ sources; see
../epublisher/references/product-foundations.mdfor cross-cutting product knowledge - automap — Build ePublisher projects with Markdown++ source documents
- reverb2 — Test output generated from Markdown++ sources
Success Criteria
- Markdown++ document uses correct syntax for all extensions
- Variables use valid names (alphanumeric, hyphens, underscores)
- Conditions have matching opening and closing tags
- File includes use valid relative paths
- Markers contain valid JSON (for
markers:format) - No circular includes detected
Converted and distributed by TomeVault — claim your Tome and manage your conversions.