r-markdown-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -548,28 +548,68 @@ body[data-rmd-theme] {
548
548
 
549
549
  .rmd-timeline-horizontal ol {
550
550
  display: flex;
551
+ flex-wrap: nowrap;
551
552
  overflow-x: auto;
552
- gap: 20px;
553
- padding-bottom: 10px;
553
+ overflow-y: hidden;
554
+ gap: 24px;
555
+ padding-bottom: 12px;
556
+ /* Treat the ol as a horizontal scroll viewport with explicit snap so
557
+ each @item lines up nicely when the user scrolls. */
558
+ scroll-snap-type: x proximity;
559
+ scrollbar-width: thin;
554
560
  }
555
561
 
556
562
  .rmd-timeline-horizontal .rmd-timeline-item {
557
- flex: 0 0 auto;
558
- min-width: 200px;
563
+ /* Cap each item to a predictable width so a single overflowing item
564
+ can't squeeze siblings out of the visible viewport. Long prose
565
+ wraps inside the box; the user scrolls horizontally to see the
566
+ next item. */
567
+ flex: 0 0 240px;
568
+ width: 240px;
569
+ max-width: 240px;
559
570
  position: relative;
560
571
  padding-top: 28px;
572
+ scroll-snap-align: start;
573
+ /* Prevent runaway content (long URLs, code, CJK without spaces) from
574
+ widening the flex item beyond its declared basis. */
575
+ min-width: 0;
576
+ overflow-wrap: anywhere;
577
+ word-break: break-word;
578
+ }
579
+
580
+ .rmd-timeline-horizontal .rmd-timeline-content {
581
+ /* Belt-and-suspenders: cap inner content too, in case authors nest
582
+ wide blocks (chart, table) inside a timeline item. */
583
+ max-width: 100%;
584
+ overflow-wrap: anywhere;
585
+ }
586
+
587
+ .rmd-timeline-horizontal .rmd-timeline-content pre,
588
+ .rmd-timeline-horizontal .rmd-timeline-content img,
589
+ .rmd-timeline-horizontal .rmd-timeline-content table {
590
+ max-width: 100%;
561
591
  }
562
592
 
563
- .rmd-timeline-horizontal ol::before {
593
+ /* The connector line is drawn per-item (::after) so that it scrolls with
594
+ the items inside the overflow:auto container. The previous ol::before
595
+ approach anchored the line to the visible viewport, which made the
596
+ line stay put while items scrolled past — broken for any timeline
597
+ wider than the viewport. */
598
+ .rmd-timeline-horizontal .rmd-timeline-item::after {
564
599
  position: absolute;
565
600
  top: 5px;
566
- left: 0;
567
- right: 0;
601
+ left: 6px;
602
+ /* Extend across the 24px gap to meet the next item's dot. */
603
+ right: calc(-24px + 6px);
568
604
  height: 2px;
569
605
  background: var(--rmd-color-line);
570
606
  content: "";
571
607
  }
572
608
 
609
+ .rmd-timeline-horizontal .rmd-timeline-item:last-child::after {
610
+ display: none;
611
+ }
612
+
573
613
  .rmd-timeline-horizontal .rmd-timeline-item::before {
574
614
  position: absolute;
575
615
  top: 0;
@@ -548,28 +548,68 @@ body[data-rmd-theme] {
548
548
 
549
549
  .rmd-timeline-horizontal ol {
550
550
  display: flex;
551
+ flex-wrap: nowrap;
551
552
  overflow-x: auto;
552
- gap: 20px;
553
- padding-bottom: 10px;
553
+ overflow-y: hidden;
554
+ gap: 24px;
555
+ padding-bottom: 12px;
556
+ /* Treat the ol as a horizontal scroll viewport with explicit snap so
557
+ each @item lines up nicely when the user scrolls. */
558
+ scroll-snap-type: x proximity;
559
+ scrollbar-width: thin;
554
560
  }
555
561
 
556
562
  .rmd-timeline-horizontal .rmd-timeline-item {
557
- flex: 0 0 auto;
558
- min-width: 200px;
563
+ /* Cap each item to a predictable width so a single overflowing item
564
+ can't squeeze siblings out of the visible viewport. Long prose
565
+ wraps inside the box; the user scrolls horizontally to see the
566
+ next item. */
567
+ flex: 0 0 240px;
568
+ width: 240px;
569
+ max-width: 240px;
559
570
  position: relative;
560
571
  padding-top: 28px;
572
+ scroll-snap-align: start;
573
+ /* Prevent runaway content (long URLs, code, CJK without spaces) from
574
+ widening the flex item beyond its declared basis. */
575
+ min-width: 0;
576
+ overflow-wrap: anywhere;
577
+ word-break: break-word;
561
578
  }
562
579
 
563
- .rmd-timeline-horizontal ol::before {
580
+ .rmd-timeline-horizontal .rmd-timeline-content {
581
+ /* Belt-and-suspenders: cap inner content too, in case authors nest
582
+ wide blocks (chart, table) inside a timeline item. */
583
+ max-width: 100%;
584
+ overflow-wrap: anywhere;
585
+ }
586
+
587
+ .rmd-timeline-horizontal .rmd-timeline-content pre,
588
+ .rmd-timeline-horizontal .rmd-timeline-content img,
589
+ .rmd-timeline-horizontal .rmd-timeline-content table {
590
+ max-width: 100%;
591
+ }
592
+
593
+ /* The connector line is drawn per-item (::after) so that it scrolls with
594
+ the items inside the overflow:auto container. The previous ol::before
595
+ approach anchored the line to the visible viewport, which made the
596
+ line stay put while items scrolled past — broken for any timeline
597
+ wider than the viewport. */
598
+ .rmd-timeline-horizontal .rmd-timeline-item::after {
564
599
  position: absolute;
565
600
  top: 5px;
566
- left: 0;
567
- right: 0;
601
+ left: 6px;
602
+ /* Extend across the 24px gap to meet the next item's dot. */
603
+ right: calc(-24px + 6px);
568
604
  height: 2px;
569
605
  background: var(--rmd-color-line);
570
606
  content: "";
571
607
  }
572
608
 
609
+ .rmd-timeline-horizontal .rmd-timeline-item:last-child::after {
610
+ display: none;
611
+ }
612
+
573
613
  .rmd-timeline-horizontal .rmd-timeline-item::before {
574
614
  position: absolute;
575
615
  top: 0;
@@ -548,28 +548,68 @@ body[data-rmd-theme] {
548
548
 
549
549
  .rmd-timeline-horizontal ol {
550
550
  display: flex;
551
+ flex-wrap: nowrap;
551
552
  overflow-x: auto;
552
- gap: 20px;
553
- padding-bottom: 10px;
553
+ overflow-y: hidden;
554
+ gap: 24px;
555
+ padding-bottom: 12px;
556
+ /* Treat the ol as a horizontal scroll viewport with explicit snap so
557
+ each @item lines up nicely when the user scrolls. */
558
+ scroll-snap-type: x proximity;
559
+ scrollbar-width: thin;
554
560
  }
555
561
 
556
562
  .rmd-timeline-horizontal .rmd-timeline-item {
557
- flex: 0 0 auto;
558
- min-width: 200px;
563
+ /* Cap each item to a predictable width so a single overflowing item
564
+ can't squeeze siblings out of the visible viewport. Long prose
565
+ wraps inside the box; the user scrolls horizontally to see the
566
+ next item. */
567
+ flex: 0 0 240px;
568
+ width: 240px;
569
+ max-width: 240px;
559
570
  position: relative;
560
571
  padding-top: 28px;
572
+ scroll-snap-align: start;
573
+ /* Prevent runaway content (long URLs, code, CJK without spaces) from
574
+ widening the flex item beyond its declared basis. */
575
+ min-width: 0;
576
+ overflow-wrap: anywhere;
577
+ word-break: break-word;
561
578
  }
562
579
 
563
- .rmd-timeline-horizontal ol::before {
580
+ .rmd-timeline-horizontal .rmd-timeline-content {
581
+ /* Belt-and-suspenders: cap inner content too, in case authors nest
582
+ wide blocks (chart, table) inside a timeline item. */
583
+ max-width: 100%;
584
+ overflow-wrap: anywhere;
585
+ }
586
+
587
+ .rmd-timeline-horizontal .rmd-timeline-content pre,
588
+ .rmd-timeline-horizontal .rmd-timeline-content img,
589
+ .rmd-timeline-horizontal .rmd-timeline-content table {
590
+ max-width: 100%;
591
+ }
592
+
593
+ /* The connector line is drawn per-item (::after) so that it scrolls with
594
+ the items inside the overflow:auto container. The previous ol::before
595
+ approach anchored the line to the visible viewport, which made the
596
+ line stay put while items scrolled past — broken for any timeline
597
+ wider than the viewport. */
598
+ .rmd-timeline-horizontal .rmd-timeline-item::after {
564
599
  position: absolute;
565
600
  top: 5px;
566
- left: 0;
567
- right: 0;
601
+ left: 6px;
602
+ /* Extend across the 24px gap to meet the next item's dot. */
603
+ right: calc(-24px + 6px);
568
604
  height: 2px;
569
605
  background: var(--rmd-color-line);
570
606
  content: "";
571
607
  }
572
608
 
609
+ .rmd-timeline-horizontal .rmd-timeline-item:last-child::after {
610
+ display: none;
611
+ }
612
+
573
613
  .rmd-timeline-horizontal .rmd-timeline-item::before {
574
614
  position: absolute;
575
615
  top: 0;
@@ -548,28 +548,68 @@ body[data-rmd-theme] {
548
548
 
549
549
  .rmd-timeline-horizontal ol {
550
550
  display: flex;
551
+ flex-wrap: nowrap;
551
552
  overflow-x: auto;
552
- gap: 20px;
553
- padding-bottom: 10px;
553
+ overflow-y: hidden;
554
+ gap: 24px;
555
+ padding-bottom: 12px;
556
+ /* Treat the ol as a horizontal scroll viewport with explicit snap so
557
+ each @item lines up nicely when the user scrolls. */
558
+ scroll-snap-type: x proximity;
559
+ scrollbar-width: thin;
554
560
  }
555
561
 
556
562
  .rmd-timeline-horizontal .rmd-timeline-item {
557
- flex: 0 0 auto;
558
- min-width: 200px;
563
+ /* Cap each item to a predictable width so a single overflowing item
564
+ can't squeeze siblings out of the visible viewport. Long prose
565
+ wraps inside the box; the user scrolls horizontally to see the
566
+ next item. */
567
+ flex: 0 0 240px;
568
+ width: 240px;
569
+ max-width: 240px;
559
570
  position: relative;
560
571
  padding-top: 28px;
572
+ scroll-snap-align: start;
573
+ /* Prevent runaway content (long URLs, code, CJK without spaces) from
574
+ widening the flex item beyond its declared basis. */
575
+ min-width: 0;
576
+ overflow-wrap: anywhere;
577
+ word-break: break-word;
561
578
  }
562
579
 
563
- .rmd-timeline-horizontal ol::before {
580
+ .rmd-timeline-horizontal .rmd-timeline-content {
581
+ /* Belt-and-suspenders: cap inner content too, in case authors nest
582
+ wide blocks (chart, table) inside a timeline item. */
583
+ max-width: 100%;
584
+ overflow-wrap: anywhere;
585
+ }
586
+
587
+ .rmd-timeline-horizontal .rmd-timeline-content pre,
588
+ .rmd-timeline-horizontal .rmd-timeline-content img,
589
+ .rmd-timeline-horizontal .rmd-timeline-content table {
590
+ max-width: 100%;
591
+ }
592
+
593
+ /* The connector line is drawn per-item (::after) so that it scrolls with
594
+ the items inside the overflow:auto container. The previous ol::before
595
+ approach anchored the line to the visible viewport, which made the
596
+ line stay put while items scrolled past — broken for any timeline
597
+ wider than the viewport. */
598
+ .rmd-timeline-horizontal .rmd-timeline-item::after {
564
599
  position: absolute;
565
600
  top: 5px;
566
- left: 0;
567
- right: 0;
601
+ left: 6px;
602
+ /* Extend across the 24px gap to meet the next item's dot. */
603
+ right: calc(-24px + 6px);
568
604
  height: 2px;
569
605
  background: var(--rmd-color-line);
570
606
  content: "";
571
607
  }
572
608
 
609
+ .rmd-timeline-horizontal .rmd-timeline-item:last-child::after {
610
+ display: none;
611
+ }
612
+
573
613
  .rmd-timeline-horizontal .rmd-timeline-item::before {
574
614
  position: absolute;
575
615
  top: 0;
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "r-markdown-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "rmd": "dist/cli.js"
7
7
  },
8
8
  "files": [
9
9
  "dist",
10
+ "skills",
10
11
  "README.md"
11
12
  ],
12
13
  "workspaces": [
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: rich-markdown
3
+ description: Generate Rich Markdown (.rmd) source and self-contained interactive HTML artifacts. Use when the user asks for rmd, Rich Markdown, rich interactive Markdown, token-efficient rich docs, shareable AI documents, charts, sliders, copy/export blocks, flow diagrams, timelines, kanban boards, collapsible details, carousels, embeds, math blocks, comparison reports, PR explainers, tunable prototypes, project status reports, or any rich document that should remain readable as Markdown but render as a polished interactive HTML page.
4
+ ---
5
+
6
+ # Rich Markdown
7
+
8
+ Use this skill when the user wants a rich, readable, interactive document
9
+ instead of plain Markdown or hand-written HTML. The local renderer
10
+ (`packages/cli`) turns `.rmd` source into a self-contained HTML artifact that
11
+ renders in Claude's chat / desktop sandbox, in any browser, or as an offline file.
12
+
13
+ ## Why .rmd over plain Markdown or HTML
14
+
15
+ - Source stays close to Markdown — diff-friendly, AI-friendly, low-token.
16
+ - The renderer adds charts, layouts, sliders, exports, flows, timelines, etc.
17
+ without forcing you to write SVG/CSS/JS.
18
+ - One source file, one self-contained HTML. No external assets needed for
19
+ Claude-rendered artifacts.
20
+
21
+ ## Output Choice (decide before writing)
22
+
23
+ | User intent | What to produce |
24
+ |---|---|
25
+ | Wants source only | `.rmd` file, no HTML build |
26
+ | Wants something to view / share / archive | `.rmd` + `--mode self-contained` HTML |
27
+ | Wants smallest artifact + has network | `.rmd` + `--mode cdn` HTML |
28
+ | Wants inspectable assets they can host themselves | `.rmd` + `--mode split` directory |
29
+ | Wants to demo locally during the session | `rmd open` preview server |
30
+
31
+ When unsure, default to source `.rmd` plus a `self-contained` HTML build.
32
+
33
+ ## Workflow
34
+
35
+ 1. Decide the smallest useful block set from `references/blocks.md`. Use
36
+ plain Markdown for narrative; use `:::` blocks only when they add density,
37
+ structure, or interaction.
38
+
39
+ 2. Write the `.rmd` file. Always include a YAML frontmatter with at least
40
+ `title`. Suggested location: `examples/<short-name>.rmd`.
41
+
42
+ 3. Validate the source with the Bash tool:
43
+
44
+ ```bash
45
+ npm run rmd -- validate path/to/doc.rmd
46
+ ```
47
+
48
+ If validation fails, fix the source. Do not return a file that fails
49
+ validation.
50
+
51
+ 4. Build the artifact:
52
+
53
+ ```bash
54
+ # Default: single self-contained HTML
55
+ npm run rmd -- build path/to/doc.rmd --mode self-contained --out path/to/doc.html
56
+
57
+ # CDN-loaded variant (small artifact, requires network at view time)
58
+ npm run rmd -- build path/to/doc.rmd --mode cdn --version 0.1.0 --out path/to/doc.html
59
+
60
+ # Split directory (HTML + JS + CSS as separate files)
61
+ npm run rmd -- build path/to/doc.rmd --mode split --out path/to/dist/index.html
62
+ ```
63
+
64
+ 5. (Optional) Local preview during the session:
65
+
66
+ ```bash
67
+ npm run rmd -- open path/to/doc.rmd --port 0 --host 127.0.0.1 --no-open true
68
+ ```
69
+
70
+ The CLI prints the bound URL. Use `--no-open true` so the agent does not
71
+ try to launch a desktop browser.
72
+
73
+ 6. Return the generated HTML file path to the user. If self-contained, the
74
+ file alone is the deliverable.
75
+
76
+ ## Rules (these are hard constraints)
77
+
78
+ - **No styling in source.** Never write colors, pixel sizes, fonts, or layout
79
+ CSS into `.rmd`. Use semantic attributes like `emphasis=primary` and let
80
+ the theme decide visuals. (Themes can change; source must not.)
81
+
82
+ - **Diff-clean edits.** One semantic change should touch only nearby lines.
83
+ Don't reorder unrelated attributes or rewrite a whole file for a small fix.
84
+
85
+ - **Validate before shipping.** Validation failures are not warnings. Fix
86
+ the source before returning the artifact.
87
+
88
+ - **Plain Markdown for fragile content.** Use plain Markdown — code blocks,
89
+ tables, blockquotes — for anything you're unsure how to express in `.rmd`.
90
+ Don't invent block names.
91
+
92
+ - **Self-contained for sandboxes.** If the user will view the artifact inside
93
+ Claude's sandbox, in email, or anywhere external assets can't be fetched,
94
+ use `--mode self-contained`. `split` mode will not load in those contexts.
95
+
96
+ ## Block Selection Cheatsheet
97
+
98
+ Map the user's intent to the smallest block set that delivers value:
99
+
100
+ | Intent | Blocks |
101
+ |---|---|
102
+ | Compare options / approaches | `grid` + `chart` + `callout` |
103
+ | PR / code review explainer | `diff` + `tabs` + `callout` |
104
+ | Tunable prototype (params + copy back to chat) | `slider` + `export` |
105
+ | Release / workflow | `flow` + `callout` + `timeline` |
106
+ | Project status report | `chart` + `timeline` + `kanban` |
107
+ | Research brief | `chart` + `grid` + `details` |
108
+ | Showcase / gallery | `carousel` + `grid layout=masonry` |
109
+ | Long doc with collapsible appendix | `details` + `tabs` |
110
+ | Math / formal explanation | `math` + `callout` |
111
+
112
+ The 14 supported blocks (v0.2): `chart`, `grid`, `callout`, `slider`,
113
+ `export`, `flow`, `diff`, `tabs`, `timeline`, `kanban`, `details`, `carousel`,
114
+ `embed`, `math`. Full reference: `references/blocks.md`.
115
+
116
+ ## Default Recipe
117
+
118
+ For Claude-visible rich output:
119
+
120
+ 1. Write `examples/<short-name>.rmd` with appropriate blocks.
121
+ 2. `npm run rmd -- validate examples/<short-name>.rmd`
122
+ 3. `npm run rmd -- build examples/<short-name>.rmd --mode self-contained --out examples/<short-name>.html`
123
+ 4. Return `examples/<short-name>.html` as the deliverable.
124
+
125
+ See `examples/` in this skill for two ready-to-study patterns:
126
+ - `examples/decision-report.rmd` — comparison + chart + callout
127
+ - `examples/tunable-config.rmd` — slider + export + flow
128
+
129
+ ## References
130
+
131
+ - `references/blocks.md` — all 14 block types with attributes and examples
132
+ - `references/artifacts.md` — build modes, validation, frontmatter tips
@@ -0,0 +1,64 @@
1
+ ---
2
+ title: "Storage Tier Decision Report"
3
+ theme: default
4
+ share: team
5
+ description: "Comparison of hot/warm/cold storage strategies for the analytics pipeline."
6
+ ---
7
+
8
+ # Storage Tier Decision Report
9
+
10
+ We need to pick a storage strategy for the analytics pipeline that handles
11
+ ~3 TB/day. Three candidates evaluated against latency, cost, and operational
12
+ complexity.
13
+
14
+ ## Candidates
15
+
16
+ :::grid 3
17
+ ### Hot only
18
+ All data on NVMe SSD.
19
+ **Pros**: lowest read latency (≈2 ms).
20
+ **Cons**: $$$ per TB; capacity ceiling reached in ~6 months.
21
+ ---
22
+ ### Tiered (hot + cold)
23
+ Recent 7 days on SSD, older on object storage.
24
+ **Pros**: 70% cost reduction, latency unchanged for typical queries.
25
+ **Cons**: needs lifecycle automation; cold-restore latency 30-60 s.
26
+ ---
27
+ ### Cold only
28
+ Everything on object storage with index cache.
29
+ **Pros**: cheapest; effectively unlimited.
30
+ **Cons**: P95 read latency 1.5 s, breaks the SLA for live dashboards.
31
+ :::
32
+
33
+ ## Cost vs Latency
34
+
35
+ :::chart bar title="Monthly cost (k$) vs P95 read latency (ms)" y="cost(k$)" y2="P95(ms)" legend=top
36
+ HotOnly 48 2
37
+ Tiered 14 2
38
+ ColdOnly 3 1500
39
+ :::
40
+
41
+ ## Recommendation
42
+
43
+ :::callout tip title="Pick Tiered"
44
+ Tiered storage hits the SLA, costs roughly a third of hot-only, and the
45
+ lifecycle automation is a one-time investment we already use for backups.
46
+ :::
47
+
48
+ ## Rollout Plan
49
+
50
+ :::flow direction=lr
51
+ Spec -> Review -> Migrate cold path -> Enable lifecycle -> Monitor
52
+ Migrate cold path -> Issue -> Pause and audit
53
+ :::
54
+
55
+ ## Risk Register
56
+
57
+ :::details title="Operational risks and mitigations"
58
+ 1. **Cold restore stalls during peak query**: cap concurrent restore jobs;
59
+ surface a "restoring" badge in the UI so users don't retry.
60
+ 2. **Lifecycle policy misfires and deletes hot data**: dry-run mode for first
61
+ 7 days; alert on >1% delta vs expected size.
62
+ 3. **Object storage region outage**: keep last 24h of cold data mirrored to a
63
+ second region; documented failover runbook.
64
+ :::
@@ -0,0 +1,53 @@
1
+ ---
2
+ title: "Rate Limiter Config — Tune & Copy"
3
+ theme: default
4
+ share: private
5
+ description: "Adjust the token-bucket parameters and copy the resulting YAML."
6
+ ---
7
+
8
+ # Rate Limiter Config — Tune & Copy
9
+
10
+ Drag the sliders to tune the token-bucket rate limiter. The export button
11
+ below copies the matching YAML config straight to your clipboard.
12
+
13
+ ## Parameters
14
+
15
+ :::slider name=capacity label="Bucket capacity" min=10 max=2000 step=10 default=200 unit=req
16
+ :::
17
+
18
+ :::slider name=refill_rate label="Refill rate" min=1 max=500 step=1 default=50 unit=req/s
19
+ :::
20
+
21
+ :::slider name=burst_window label="Burst window" min=1 max=120 step=1 default=10 unit=s
22
+ :::
23
+
24
+ ## Generated YAML
25
+
26
+ :::export label="Copy YAML config" format=text
27
+ rate_limiter:
28
+ type: token_bucket
29
+ capacity: {{capacity | int}}
30
+ refill_rate: {{refill_rate | int}}
31
+ burst_window_seconds: {{burst_window | int}}
32
+ :::
33
+
34
+ ## How requests flow
35
+
36
+ :::flow direction=lr
37
+ Request -> Bucket has token? -> Allow
38
+ Bucket has token? -> Refill check -> Allow
39
+ Bucket has token? -> Refill check -> Reject 429
40
+ :::
41
+
42
+ ## Tradeoffs
43
+
44
+ :::callout warning title="Watch the burst window"
45
+ A wide burst window smooths short spikes but lets sustained overload through
46
+ longer. If your downstream is fragile, prefer narrow windows even at the cost
47
+ of more 429s.
48
+ :::
49
+
50
+ :::callout tip title="Sane starting point"
51
+ For most APIs, capacity ≈ 4× refill rate, burst window ≈ 10 s. Adjust from
52
+ there based on observed P99 incident shape.
53
+ :::
@@ -0,0 +1,118 @@
1
+ # Rich Markdown Artifacts
2
+
3
+ ## Source First
4
+
5
+ Always write `.rmd` source first. It is the canonical artifact and must remain
6
+ readable in plain Markdown tools. The HTML build is a derived view that can
7
+ be regenerated any time.
8
+
9
+ ## Three Build Modes
10
+
11
+ The CLI supports three output modes via `--mode`. Pick based on where the
12
+ artifact will be viewed.
13
+
14
+ ### self-contained (default)
15
+
16
+ ```bash
17
+ npm run rmd -- build path/to/doc.rmd --mode self-contained --out path/to/doc.html
18
+ ```
19
+
20
+ Single HTML file with the renderer, theme CSS, runtime, and `.rmd` source all
21
+ inlined. Zero external dependencies. Best for:
22
+
23
+ - Claude desktop / chat sandbox (the artifact has to be self-contained)
24
+ - Email attachments
25
+ - Offline / archival
26
+ - S3 / static-host one-click sharing
27
+ - Any place where the consumer cannot install or fetch the renderer
28
+
29
+ Tradeoff: file size is larger (~50–150 KB) because the renderer is inlined.
30
+
31
+ ### cdn
32
+
33
+ ```bash
34
+ npm run rmd -- build path/to/doc.rmd --mode cdn --version 0.1.0 --out path/to/doc.html
35
+ ```
36
+
37
+ Small HTML shell containing only the `.rmd` source plus a script tag pointing
38
+ at a pinned CDN version of the renderer. Best for:
39
+
40
+ - Blog posts, Notion, web pages where the renderer can be fetched from CDN
41
+ - When the artifact itself must be small (token economy)
42
+
43
+ Requires `--version` to be a complete semver (e.g. `0.1.0`); `latest` is rejected
44
+ because sandboxed viewers must not depend on a moving CDN target.
45
+
46
+ ### split
47
+
48
+ ```bash
49
+ npm run rmd -- build path/to/doc.rmd --mode split --out path/to/dist/index.html
50
+ ```
51
+
52
+ Writes the HTML alongside `rmd.min.js` and `themes/<theme>.css` as separate
53
+ files in the same directory. Best for:
54
+
55
+ - Local development / hot reload
56
+ - Custom hosting where you want to serve the renderer from your own origin
57
+ - Inspecting the generated assets
58
+
59
+ Cannot be opened in sandboxed environments (Claude artifact, email) because
60
+ the relative asset paths will 404.
61
+
62
+ ## Validation
63
+
64
+ Always validate before building or returning to the user:
65
+
66
+ ```bash
67
+ npm run rmd -- validate path/to/doc.rmd
68
+ ```
69
+
70
+ Validation prints `ok` on success or a list of `path: message` lines on failure.
71
+ If validation fails, fix the source and re-run. Do not ship a file that fails
72
+ validation — the renderer may degrade silently to plain code blocks.
73
+
74
+ ## Recommended Default
75
+
76
+ For most Claude-driven requests:
77
+
78
+ ```bash
79
+ npm run rmd -- validate examples/my-doc.rmd
80
+ npm run rmd -- build examples/my-doc.rmd --mode self-contained --out examples/my-doc.html
81
+ ```
82
+
83
+ Return the path `examples/my-doc.html`.
84
+
85
+ ## Local Preview During the Session
86
+
87
+ When the user wants to interact with the artifact while you iterate:
88
+
89
+ ```bash
90
+ npm run rmd -- open path/to/doc.rmd --port 0 --host 127.0.0.1 --no-open true
91
+ ```
92
+
93
+ The CLI prints the bound URL. Use `--no-open true` so the agent does not try
94
+ to launch a desktop browser.
95
+
96
+ ## Frontmatter Tips
97
+
98
+ Every `.rmd` should start with a frontmatter block. Useful fields:
99
+
100
+ ```yaml
101
+ ---
102
+ title: Quarterly Roadmap # Required for sharing & metadata
103
+ theme: default # Theme id; only `default` ships today
104
+ share: private # private / team / public
105
+ description: Short summary... # Used by share cards / OG
106
+ lang: zh-CN # BCP 47 — affects type/font defaults
107
+ ---
108
+ ```
109
+
110
+ Unknown fields are kept but ignored. Custom fields should use the `x-` prefix
111
+ to mark them as non-core (e.g. `x-team: backend`).
112
+
113
+ ## Iteration Loop
114
+
115
+ When the user asks for revisions, re-run validate and build only — do not
116
+ rewrite unrelated parts of the source. The skill optimizes for clean diffs;
117
+ preserve the user's existing block structure unless they explicitly ask
118
+ otherwise.