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.
- package/dist/cli.js +102 -25
- package/dist/rmd.min.js +76 -36
- package/dist/themes/default.css +47 -7
- package/dist/themes/notion-like.css +47 -7
- package/dist/themes/paper.css +47 -7
- package/dist/themes/tech-dark.css +47 -7
- package/package.json +2 -1
- package/skills/claude/SKILL.md +132 -0
- package/skills/claude/examples/decision-report.rmd +64 -0
- package/skills/claude/examples/tunable-config.rmd +53 -0
- package/skills/claude/references/artifacts.md +118 -0
- package/skills/claude/references/blocks.md +334 -0
- package/skills/codex/SKILL.md +92 -0
- package/skills/codex/agents/openai.yaml +8 -0
- package/skills/codex/references/artifacts.md +107 -0
- package/skills/codex/references/blocks.md +321 -0
package/dist/themes/default.css
CHANGED
|
@@ -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
|
-
|
|
553
|
-
|
|
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
|
-
|
|
558
|
-
|
|
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
|
-
|
|
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:
|
|
567
|
-
|
|
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
|
-
|
|
553
|
-
|
|
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
|
-
|
|
558
|
-
|
|
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
|
|
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:
|
|
567
|
-
|
|
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/dist/themes/paper.css
CHANGED
|
@@ -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
|
-
|
|
553
|
-
|
|
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
|
-
|
|
558
|
-
|
|
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
|
|
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:
|
|
567
|
-
|
|
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
|
-
|
|
553
|
-
|
|
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
|
-
|
|
558
|
-
|
|
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
|
|
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:
|
|
567
|
-
|
|
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
|
@@ -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.
|