Implementing your own reader
Skip the
@rho/mdlibrary and implement a Rho reader directly from the Rho format spec. Suitable for: non-JS ecosystems (Python / Go / Rust / Swift) / wanting fully license-free (avoiding PolyForm) / deep integration with an existing reader (Obsidian plugin / Vim plugin / etc.).
Why implement your own
| You want to… | Self-implement? |
|---|---|
| Plug into Obsidian / Bear / Typora and similar existing readers | ✅ Self-implement (as plugin) |
| Use it in Python / Go / Rust ecosystems | ✅ Self-implement (@rho/md is a JS package) |
| Fully avoid PolyForm Noncommercial license | ✅ Self-implement (spec is CC BY 4.0; your impl chooses license) |
| Integrate into a web project | ❌ Just use @rho/md (unless special requirements) |
| Hand-coded markdown tool for learning | ✅ Self-implement (learning purpose) |
Legal / License
- The spec is CC BY 4.0 — you can implement freely; no need to contact scos-lab
- Your implementation's license is yours to choose — MIT / Apache / commercial / closed-source freely
- Only requirement: preserve attribution in your reader's docs / about page: "Implements Rho format spec by scos-lab"
You cannot use "Rho" / "Rho format" as a trademark in marketing — but you can say "compatible with Rho" / "supports Rho format documents."
Core components needed
In rough order of importance:
1. Markdown parser (any standard CommonMark / GFM implementation)
No need to write from scratch — use an existing markdown parser:
- Python: markdown / mistune / markdown-it-py
- Go: blackfriday / goldmark
- Rust: pulldown-cmark / comrak
- Swift: swift-markdown / Down
- C: cmark / md4c
Needs to support:
- Standard CommonMark
- GFM tables / strikethrough / task lists
- Fenced code blocks (with lang label)
- Blockquotes
- Ideally directive containers (
:::xxx); if not, parse them yourself
2. Rho DSL parser (you write this)
Per spec:
> [!TYPE]blockquote → callout```layout grid cols=N+:::card→ layout```tabs+:::tab→ tabs```stepper+:::step→ stepper```modal+ content → modal```timeline+:::event→ timeline```annotate+ body +---+ annotation table → annotate```stl→ STL syntax highlighting```interact+ sliders/templates/computed/timer → interact
Each DSL outputs marker class HTML (see Remark plugins).
3. Inner processor (nesting support)
Container DSLs (layout / tabs / stepper / modal / timeline / callout) need their content run through the full pipeline again — see Inner processor.
Simplest implementation: recursively call the same parser function on inner content.
4. CSS (write your own or borrow Rho's)
You can:
- Write CSS from scratch (refer to CSS class hooks)
- Borrow
@rho/md's default CSS (CC BY 4.0 spec doesn't include CSS impl license — CSS is PolyForm Noncommercial. Verify license independently before borrowing) - Or design your own visual entirely
5. Hydration (if web/client reader)
Turn static HTML into interactive components:
- Tabs / Stepper / Modal — DOM event listeners
- Interact controls — form elements + reactive update
- Vega-Lite chart — integrate vega-embed library (callable from any language)
- SVG scenes — built-in mini DSL evaluator (or borrow an existing expression parser)
- Timer —
setInterval/ equivalent scheduling
Non-web readers (e.g., Obsidian plugin) — implement equivalent functionality in Obsidian's view system.
6. Mini DSL evaluator (interact expressions)
Rho's mini DSL: + - * / % ** == != < > <= >= && || ! ?: pow sqrt abs min max sin cos tan log exp pi e ...
Implementation options:
- Hand-write parser + tree-walking interpreter (~300 lines)
- Use existing expression libraries:
- JS: custom (don't use
eval!) - Python:
simpleeval - Go:
expr - Rust:
evalexpr
- JS: custom (don't use
⚠️ Critical: the mini DSL must be pure-function + safe — no IO / network / state mutation / eval. This is Rho's safety stance.
7. SVG sanitizer (when using svg template)
Strip dangerous elements / attributes:
<script>,<foreignObject>on*event attributeshrefcontainingjavascript:- External URL
<image href="external://...">
Implementation:
- JS: DOMParser + allowlist filter
- Python:
nh3/bleach - Rust:
ammonia
Recommended implementation steps
Step 1: standard markdown working (0.5 day)
- Pick a markdown parser
- Get it producing normal HTML
Step 2: add Callout support (0.5 day)
- parse > [!TYPE] blockquote
- emit marker class HTML
Step 3: add Layout grid + cards (1 day)
- parse ```layout fenced + :::card directive
- CSS Grid layout
Step 4: add other static DSLs (1 day)
- Annotate / Timeline / STL syntax highlight
Step 5: add interactive structural DSLs (2 days)
- Tabs / Stepper / Modal
- Their hydration
Step 6: add interact basics (2 days)
- sliders / inputs / template stl
- mini DSL evaluator
Step 7: add computed + namespace sharing (1 day)
- Derived values + topological sort
- Cross-block state sharing
Step 8: add advanced interact (3 days)
- Vega-Lite chart integration
- Timer auto-play
- SVG scenes + sanitizer
Step 9: add inner processor (nesting support) (1 day)
- Recursive parse
Step 10: plain-text fallback testing (0.5 day)
- Verify source is readable in cat / GitHub
Total: ~13 days person-effort.
@rho/md compatibility testing
If you want to claim "compatible with @rho/md" — run this conformance test pack:
- Take a standard document rendered with
@rho/md(refer to SPEC_v0.0_RENDER_TEST.md) - Render the same document with your reader
- Compare output HTML (class names, data attributes should match)
- Compare interactive behavior (slider drag, output text matches)
A complete conformance test pack is planned for spec v1.0 release.
Known / planned implementations
| Reader | Status | License |
|---|---|---|
@rho/md (official JS reference impl) |
✅ v0.1 released | PolyForm Noncommercial |
| markview desktop app (Tauri 2 + React) | 🔨 v1.0 binary in preparation | PolyForm Noncommercial |
| cloud.rho.md (SaaS) | 🔨 MVP in development | Closed-source SaaS |
| Obsidian plugin | 🔮 community contribution welcome | Choose your own |
| Bear plugin | 🔮 community contribution welcome | Choose your own |
Python python-rho |
🔮 (community wanted) | Choose your own |
Rust rho-rs |
🔮 (community wanted) | Choose your own |
| Vim plugin | 🔮 (community wanted) | Choose your own |
Community implementations: PRs / issues welcome at scos-lab/markview (repo to be renamed) for compatibility issues.
See also
- Rho format spec v0.6 — Full specification
- Remark plugins — How
@rho/mddoes it (reference) - Hydration utilities — Runtime hydration patterns
- Inner processor — Nesting mechanism
- License & Commercial — License details