RedQuilt
A modern Markdown document processor in pure Ruby, with an arena-style AST. Passes the full CommonMark spec test suite, and generally faster than kramdown.
Installation
Add this line to Gemfile:
gem "red_quilt"
Quick Start
Parsing and rendering
require "red_quilt"
# Parse Markdown to a document
doc = RedQuilt.parse("# Hello\n\nThis is **bold**.")
html = doc.to_html
# => "<h1>Hello</h1>\n<p>This is <strong>bold</strong>.</p>\n"
# Or render directly (without building AST)
html = RedQuilt.render_html("# Hello\n\n**bold**")
HTML is safe by default
RedQuilt.render_html("Hi <em>tag</em>")
# => "<p>Hi <em>tag</em></p>\n"
RedQuilt.render_html("Hi <em>tag</em>", allow_html: true)
# => "<p>Hi <em>tag</em></p>\n"
Options
RedQuilt.parse and RedQuilt.render_html accept:
| Option | Default | Effect |
|---|---|---|
allow_html: |
false |
Pass raw HTML through instead of escaping it |
disallow_raw_html: |
false |
With allow_html, still neutralize GFM's dangerous tags (<script>, <iframe>, …) |
extended_autolinks: |
false |
GFM: linkify bare http(s):// / www. / email addresses |
footnotes: |
false |
GFM footnotes (see below) |
lint: |
false |
Collect lint diagnostics (empty links, missing image alt, heading-level skips) |
Footnotes (opt-in)
RedQuilt.render_html(<<~MD, footnotes: true)
Here is a reference.[^1]
[^1]: And the footnote text.
MD
# The reference becomes a superscript link, and a trailing
# <section class="footnotes"> lists the referenced definitions (in
# first-reference order) with backrefs.
Diagnostics
Parsing never raises on malformed input; warnings are collected on the document.
doc = RedQuilt.parse("[x](javascript:alert(1))", lint: true)
doc.diagnostics.map(&:rule) # => [:unsafe_url]
doc.diagnostics.first.severity # => :warning
Heading anchors (opt-in)
render_html / to_html accept heading_ids: to give every heading a
slugified id for anchor links. Slugs follow GitHub's scheme but keep Unicode
intact, so Japanese headings stay readable; duplicates get -1, -2 suffixes.
RedQuilt.render_html("# Hello World\n\n## はじめに", heading_ids: true)
# => "<h1 id=\"hello-world\">Hello World</h1>\n<h2 id=\"はじめに\">はじめに</h2>\n"
Tilt integration
RedQuilt ships a Tilt adapter.
NOTE: It is not loaded by default; require it explicitly and add tilt to your own bundle:
require "red_quilt/tilt"
Tilt.new("page.md").render # => HTML
Tilt.new("page.md", footnotes: true).render
Native options (allow_html:, footnotes:, …) pass straight through; Tilt's escape_html: convention is also honored.
Documentation
- API reference —
Document/NodeRef/SourceSpan, supported syntax, and usage examples - Architecture overview (日本語)
- Arena usage guide (日本語)
- CommonMark conformance notes (日本語)
CommonMark Compatibility
RedQuilt achieves 100% compliance with the CommonMark v0.31.2 specification. See the conformance notes for GFM extensions and intentional deviations.
Command-line Tool
RedQuilt ships with a redquilt CLI for converting Markdown files to HTML or inspecting the AST.
Basic usage
# Convert Markdown file to HTML
redquilt input.md > output.html
# Convert from stdin
echo "# Hello" | redquilt
# Output as AST (for debugging)
redquilt --format ast input.md
# Output as MDAST-compatible JSON (for external tools)
redquilt --format json input.md
# Standalone HTML document with title
redquilt --standalone --title "My Document" input.md
# Enable GFM extended autolinks / footnotes
redquilt --extended-autolinks --footnotes input.md
# Standalone page with the bare template (no embedded CSS)
redquilt --theme none input.md
Options
--format FORMAT Output format: html (default), ast, json
--allow-html Pass raw HTML through to the output
--disallow-raw-html With --allow-html, filter GFM's dangerous tags
--extended-autolinks Linkify bare URLs and email addresses (GFM)
--footnotes Enable GFM footnotes
--lint Collect lint diagnostics
--[no-]standalone Wrap HTML in full document (default: on)
--auto-title Use the first heading's text as <title>
--title TITLE Explicit <title> text
--lang LANG html lang attribute (default: "en")
--css URL Add a stylesheet link
--theme THEME Embedded stylesheet: default (default) or none
--diagnostics Print diagnostics to stderr
--diagnostics-only Print diagnostics only (suppress output)
-h, --help Show help
-v, --version Show version
Exit code is 0 on success, 1 if errors are detected.
Safe-by-Default HTML Rendering
Security model
RedQuilt prioritizes security by default:
# Default: All HTML is escaped, dangerous URLs blocked
RedQuilt.render_html("<script>alert('xss')</script>")
# => "<p><script>alert('xss')</script></p>"
RedQuilt.render_html("[click](javascript:alert(1))")
# => "<p><a href=\"\">click</a></p>"
Allowed URL schemes
In link/image destinations, only these schemes are permitted:
- Absolute:
http://,https://,ftp://,tel:,ssh:// - Relative:
/path,#anchor,path/to/file - Special:
mailto:(autolinks only)
All other schemes (javascript:, data:, vbscript:, etc.) are blocked by replacing the URL with an empty string.
Autolinks (<scheme:...>) follow CommonMark and allow arbitrary schemes, so they use a denylist instead: only the script-executing schemes javascript:, vbscript:, and data: are blocked.
Opting into HTML pass-through
# Allow raw HTML (use with trusted input only)
RedQuilt.render_html(user_markdown, allow_html: true)
# This passes HTML blocks and inline tags through unchanged
Development
Running tests
bundle exec rake spec
Runs 70+ CommonMark compatibility and feature tests.
Benchmark
ruby spec/bench_inline.rb
ruby spec/bench_block.rb
Profiles parse performance on various Markdown patterns.
Performance (v0.6.1, Ruby 4.0.5)
Comparison against kramdown on arm64-darwin (Apple Silicon), measured with spec/bench_vs_kramdown.rb (benchmark-ips):
| Fixture | Size | RedQuilt (i/s) | kramdown (i/s) | RedQuilt vs kramdown |
|---|---|---|---|---|
| short_paragraph | 49 B | 26,531 | 5,416 | 4.90x faster |
| long_paragraph | 1.4 KB | 981 | 926 | within error |
| nested_emphasis | 1.4 KB | 999 | 689 | 1.45x faster |
| many_links | 2.0 KB | 1,131 | 794 | 1.43x faster |
| mixed_markup | 1.8 KB | 1,028 | 729 | 1.41x faster |
| deep_nesting | 800 B | 827 | 349 | 2.37x faster |
| cmark_spec | 205 KB | 39.1 | 30.2 | 1.30x faster |
Reproduce locally:
bundle exec ruby spec/bench_vs_kramdown.rb
License
MIT