SpecMD - Conditional Markdown
Markdown with variables and conditional blocks for specification documents. Create a single source document and generate multiple variants for different products, versions, or regions.
Features
Variable Substitution
Variables defined in config.yaml are substituted in the document.

---
config: ./config.yaml
---
# ${productName} Specification
Operating Voltage: ${voltage}V
Conditional Blocks
Conditional blocks show/hide content based on expressions.

@x > y
x is bigger than y
@elif x < y
x is smaller than y
@else
x equals y
@end
Switch/Case
Switch blocks select content based on a variable value.

@switch language
@case "en"
Hello!
@case "ja"
こんにちは!
@default
(default)
@end
File Includes
Content from external files can be included.

@include ./common/header.smd
@include ./common/footer.smd
Table of Contents
# Document Title
[TOC]
## Section 1
## Section 2
Syntax Reference
.smd File Syntax
Variables
Use ${variableName} to insert a variable value.
Product: ${productName}
Version: ${version}
Conditions (@if / @elif / @else / @end)
@condition
Content shown when condition is true
@end
@condition1
Content for condition1
@elif condition2
Content for condition2
@else
Content when all conditions are false
@end
Supported Operators:
| Operator |
Description |
Example |
== |
Equal |
@version == 2 |
!= |
Not equal |
@type != "basic" |
> |
Greater than |
@level > 1 |
>= |
Greater or equal |
@level >= 2 |
< |
Less than |
@level < 3 |
<= |
Less or equal |
@level <= 2 |
and |
Logical AND |
@isPro and hasFeature |
or |
Logical OR |
@isBasic or isStandard |
not |
Logical NOT |
@not isDisabled |
() |
Grouping |
@(a or b) and c |
Boolean Variables:
A variable name alone evaluates as a boolean condition.
@isPremium
Premium content here
@end
@not isDisabled
Enabled content here
@end
Switch/Case (@switch / @case / @default / @end)
@switch variableName
@case "value1"
Content for value1
@case "value2"
Content for value2
@case "value3" or "value4"
Content for value3 or value4
@default
Default content
@end
@case supports multiple values with or separator
@default is optional
Include (@include)
@include ./path/to/file.smd
@include ../common/header.smd
- Paths are relative to the current file
- Included files can also contain variables and conditions
- Ctrl+Click to jump to the included file
Table of Contents ([TOC])
# Title
[TOC]
## Chapter 1
### Section 1.1
## Chapter 2
Generates a linked table of contents from all headings in the document.
config.yaml Syntax
Basic Variables
# String
productName: "Widget Pro"
# Number
version: 2
voltage: 100
# Boolean
isPremium: true
hasAdvancedFeatures: false
Computed Values ($expr)
Use $expr: to compute values from expressions.
voltage: 100
# Ternary operator
displayVoltage:
$expr: "voltage == 100 ? '100V (Asia)' : '200V (Global)'"
# Boolean expression
isHighVoltage:
$expr: "voltage >= 200"
# Compound conditions
isPowerUser:
$expr: "isPremium and level >= 3"
$expr Operators:
- Comparison:
==, !=, >, >=, <, <=
- Logical:
and, or, not
- Ternary:
condition ? trueValue : falseValue
- Nested ternary:
a ? x : b ? y : z
Switch in Config ($switch)
Use $switch to select values based on another variable.
region: "asia"
voltage:
$switch: region
asia: 100
europe: 230
us: 120
$default: 100
plugType:
$switch: region
asia: "Type A"
europe: "Type C"
us: "Type B"
$default: "Type A"
$switch Format:
variableName:
$switch: switchVariable
value1: result1
value2: result2
"value3 or value4": result3 # Multiple values
$default: defaultResult # Optional
$switch: The variable name to switch on
- Each key is a possible value, each value is the result
- Use
"value1 or value2" for multiple matching values
$default: Optional default value when no case matches
Nested/Derived Variables
Variables can depend on other variables. They are evaluated in multiple passes.
level: 3
# Depends on level
isPro:
$expr: "level >= 3"
# Depends on isPro
features:
$expr: "isPro ? 'All features' : 'Basic features'"
Configuration
Inline (Front Matter)
Define variables directly in the .smd file:
---
productName: "Widget Pro"
version: 2
isPremium: true
---
# ${productName} v${version}
External File
Reference an external config file:
---
config: ./config.yaml
---
# ${productName} Specification
Combined (External + Inline Override)
Inline values override external file values:
---
config: ./config.yaml
productName: "Widget Pro MAX"
---
Multiple Config Files
Switch between config files using the status bar selector at the bottom of VS Code. Create different configs for different product variants:
project/
├── spec.smd
├── config-basic.yaml
├── config-standard.yaml
└── config-pro.yaml
Editor Features
- Highlighting - True conditions in green, false in gray
- Inline values - See variable values and condition results
- Hover - Details on variables and expressions
- Autocompletion - Variables after
${, keywords after @
- Outline - Navigate headings (including from @include files)
- Go to Definition - Ctrl+Click on variables or @include
- Live Preview - Alt+D to open
- Diagnostics - Warnings for undefined variables and missing include files
Keyboard Shortcuts
| Key |
Command |
| Alt+D |
Open Preview |
| Alt+Shift+D |
Export to Markdown |
| Ctrl+Click |
Go to Definition |
CLI
# Basic conversion
specmd convert spec.smd -o output.md
# With specific config file
specmd convert spec.smd -c config-pro.yaml -o spec-pro.md
# Watch mode (auto-convert on changes)
specmd watch spec.smd -o output.md
Snippets
| Prefix |
Description |
| @if |
Condition block |
| @ifelse |
Condition with else |
| @switch |
Switch/case block |
| @include |
File include |
| toc |
Table of Contents |
| $var |
Variable ${name} |
| frontmatter |
YAML front matter |
Examples
Multi-Product Specification
config-basic.yaml:
productName: "Widget Basic"
gradeLevel: 1
hasPremiumFeatures: false
hasApiAccess: false
config-pro.yaml:
productName: "Widget Pro"
gradeLevel: 3
hasPremiumFeatures: true
hasApiAccess: true
spec.smd:
---
config: ./config-basic.yaml
---
# ${productName} Specification
## Features
@hasPremiumFeatures
### Premium Features
- Advanced analytics
- Custom reports
@end
@hasApiAccess
### API Access
Full REST API access is available.
@end
@gradeLevel >= 2
### Extended Support
Priority support included.
@end
Multi-Region Documentation
config.yaml:
region: "asia"
voltage:
$switch: region
asia: 100
europe: 230
us: 120
$default: 100
plugType:
$switch: region
asia: "Type A"
europe: "Type C"
us: "Type B"
$default: "Type A"
voltageNote:
$expr: "voltage == 100 ? 'Low voltage region' : 'High voltage region'"
spec.smd:
# Electrical Specifications
- Operating Voltage: ${voltage}V
- Plug Type: ${plugType}
- Note: ${voltageNote}
License
MIT