| name | rich-content |
| description | Skill for producing high-fidelity, interactive blog posts, research reports, and intelligent reports on the Dataspheres AI platform. Drives ARI and ari-dai-skills to use the full tool suite — web search, image generation, YouTube embeds, code blocks, Mermaid diagrams, datasets, live data cards, citations, and SEO metadata — to produce publication-ready interactive pages. |
| argument-hint | blog post <topic> in <datasphere-uri> | research report <topic> | intelligent report <topic> | [--public] |
Rich Content Skill — Interactive Pages
You are producing a high-fidelity, interactive page on the Dataspheres AI platform. This skill orchestrates the full tool suite to create content that is visually rich, data-driven, SEO-friendly, and far beyond a plain article.
Default voice and visuals (read first)
- Prose voice → use the
house-style skill by default. All page bodies are written in the measured, human, white-paper-without-being-a-white-paper register defined there. Strip the AI tells it lists (rhetorical triplets, "not X but Y", fragment-drama, clickbait headings, marketing closers, hype words). This is the default unless the user asks for a different register.
- Custom diagrams / stat rows → use the
data-viz skill. Never embed a raw inline <svg> in page content (TipTap strips it). Use the sanitizer-safe <img> data-URI components (statCards, flowStrip, flowStack, toFigure). See the "Simple SVG / Inline Charts" section below.
Temporal Accuracy — Non-Negotiable Rules
These rules apply to every piece of content, no exceptions.
1. Always know today's date
Check the environment for the current date before writing a single word. Every date reference, year label, and "current" claim must reflect that date. Never write "2025" if the year is 2026. Never write "recently" without anchoring it to a specific month and year.
2. Web search is mandatory — not optional
Every statistic, market figure, company claim, and trend assertion MUST be verified via web_search before it appears in the body. Do not synthesise data from training knowledge — models have a knowledge cutoff and that cutoff is in the past. Run the search, get the result, cite the source.
3. YouTube videos must be recent OR explicitly contextualised
- Preferred: search for videos published in the last 12 months. Scan
web_search results for YouTube URLs. Use those video IDs.
- If embedding an older foundational video (e.g., a 2022 seminal talk): you MUST add a bracketed note in the caption:
[Published 2022 — cited here because it remains the definitive technical reference for X; the core mechanism has not changed]. Never embed an old video silently as if it is current.
- Never use a video ID from memory or training data. Only embed videos whose URLs appeared in a
web_search result during this session.
4. Cite sources with recency signals
When referencing a report, study, or article, always name it with its publication date in the text:
- Good:
According to Goldman Sachs' AI Infrastructure Outlook (March 2026)...
- Bad:
According to analysts...
If the best available source is older than 18 months:
- Acknowledge it explicitly:
This figure comes from Gartner's 2024 report — the most recent available. Updated 2026 data is not yet published, but the trend direction has accelerated since then based on [recent search result].
- Do NOT silently present stale data as current fact.
5. Data in datasets must reflect current year
When generating rows for datasets, the prompt must instruct the AI to use the current year's figures. If data is estimated or projected, say so in the dataset description. Label columns with the year (e.g., revenue_2026_usd_billions not revenue_usd_billions).
Content Types
Choose the type from the user's request or infer from the topic:
| Type | Best For | Signature Elements |
|---|
| Blog Post | Opinions, tutorials, how-tos, announcements | Hero image, strong narrative, 1–2 embeds, citations |
| Research Report | Data-heavy analysis, findings, comparisons | Dataset + data cards, Mermaid diagrams, tables, citation appendix |
| Intelligent Report | AI-synthesised multi-source intelligence | Web search citations, multiple data cards, YouTube embeds, dataset, callout boxes |
Step-by-Step Workflow
Every rich content piece follows this exact order. Do not skip steps.
Step 1 — Research & Gather (mandatory before writing anything)
Check today's date first. Every piece of content is anchored to the current date — not the model's training cutoff.
Run web_search with targeted queries covering:
- The core topic + current year (e.g.
"AI infrastructure investment 2026")
- Latest statistics or data points (
"2026 report" OR "Q1 2026" OR "latest figures")
- Expert quotes or contrasting perspectives from the last 6 months
- For Intelligent Reports: add
site:youtube.com <topic> to find recent relevant videos
Minimum queries: Blog Post = 2–3 · Research Report = 4–5 · Intelligent Report = 5–6
Save every result. Track which URL each fact comes from. Every statistic in the body must trace back to a search result from this session — not from training memory.
YouTube sourcing: Only use a video ID that appeared in a search result URL from this session. If no recent video is found, do not embed one. If you embed an older foundational video found via search, add the age acknowledgement in the caption (see Temporal Accuracy rules above).
If web search finds no data newer than 18 months old: surface this to the user before writing. Do not silently present stale data as current.
Step 2 — Generate Hero Image
Call generate_media_image with a vivid, art-directed prompt. Guidelines:
- Blog Post: editorial photography style, real scene, specific lighting
- Research Report: abstract data visualization, clean infographic aesthetic, no text
- Intelligent Report: cinematic, wide-aspect composite, futuristic or domain-specific
aspectRatio: "16:9" ← always for hero
sampleCount: 1
Capture the returned mediaUrl — this becomes the <figure> hero at the top of the page.
Step 3 — Build Datasets (Research & Intelligent Reports only)
If the topic has quantitative data (rankings, comparisons, time-series, survey results):
- Call
create_dataset with a clear schema matching the data
- Call
generate_dataset_rows with count: 10–20 and a rich prompt describing the data to synthesise from the web search results
- Capture the
datasetId for Step 4
Step 4 — Build Data Cards (Research & Intelligent Reports only)
For each dataset created, call create_data_card with a plain-English prompt describing EXACTLY what the chart should show. One card per insight:
"Show a horizontal bar chart of the top 10 companies by market share, sorted descending"
"Show a line chart of monthly active users over 12 months with a trend annotation"
"Show a donut chart of budget allocation across 5 categories"
Capture each dataCardId.
Step 5 — Create Mermaid Diagrams (when applicable)
Use diagramming for:
- Process flows →
flowchart
- Timelines / sequences →
gantt or sequence
- Relationships / data models →
er
- Simple pie / bar charts WITHOUT a dataset →
pie or xychart-beta
- System architecture →
flowchart with subgraphs
Step 6 — Find YouTube Videos (Intelligent Reports)
From Step 1 search results, extract YouTube URLs (youtube.com/watch?v=VIDEO_ID). If none found, run an explicit web_search for site:youtube.com <topic> and extract from results.
Capture: VIDEO_ID (the v= parameter value).
Step 7 — Compose the Page HTML
Assemble the full TipTap HTML. See HTML Reference below.
Step 8 — Publish
Call create_page (blog/research) or create_landing_page (public-facing):
title: "<compelling SEO title — 50–60 chars>"
content: "<full TipTap HTML>"
metaDescription: "<150–160 char summary — includes primary keyword>"
folderName: "<semantic folder — call list_folders first>"
status: "PUBLISHED"
isPubliclyVisible: true ← for public content
Step 9 — Post to Feed (optional)
If the datasphere has an active community, call create_post with a 2–3 sentence teaser linking to the page.
HTML Reference — Every Element
Hero Section
Always the first element in the page body. Use the generated image URL from Step 2.
<figure style="margin:0 0 2rem 0">
<img src="MEDIA_URL" alt="DESCRIPTIVE_ALT_TEXT" style="width:100%;border-radius:12px;display:block" />
<figcaption style="text-align:center;font-size:0.85rem;color:#888;margin-top:0.5rem">CAPTION — source or brief description</figcaption>
</figure>
Lead Paragraph
Immediately after hero. Hook sentence + 2–3 sentences establishing scope.
<p><strong>HOOK SENTENCE that states the core finding or premise.</strong> Follow-up context sentence. Third sentence that scopes what the reader will learn.</p>
Heading Hierarchy
Page titles come from the title field — never put an <h1> inside content. Use only <h2> and <h3>.
<h2>Section Title</h2>
<p>Section body...</p>
<h3>Subsection</h3>
<p>Subsection body...</p>
Callout / Key Insight Box
Use <blockquote> for key insights, pull quotes, and data callouts.
<blockquote><p><strong>Key Insight:</strong> One punchy sentence that stands alone. Keep under 25 words.</p></blockquote>
Callout Box (styled)
For "What to know", "Warning", "Tip" boxes — use a styled div inside a blockquote:
<blockquote><p>💡 <strong>What This Means:</strong> Plain-English implication of the data or finding above. Write for a non-technical reader.</p></blockquote>
Tables
Always include a <caption> for SEO and accessibility.
<table>
<caption>TABLE DESCRIPTION — what it shows and source</caption>
<thead>
<tr><th>Column A</th><th>Column B</th><th>Column C</th></tr>
</thead>
<tbody>
<tr><td>Value</td><td>Value</td><td>Value</td></tr>
</tbody>
</table>
Bullet / Numbered Lists
<ul>
<li><p><strong>Term or label</strong> — explanation or value</p></li>
<li><p><strong>Term or label</strong> — explanation or value</p></li>
</ul>
<ol>
<li><p>First step or ranked item — detail</p></li>
<li><p>Second step or ranked item — detail</p></li>
</ol>
Interactive Task Checklists (checkboxes)
For checkable to-do lists — in pages, task descriptions, and comments — use the TipTap task list. These render as real, clickable checkboxes (not bullets).
<ul class="tiptap-task-list" data-type="taskList">
<li class="tiptap-task-item" data-checked="false" data-type="taskItem"><label><input type="checkbox"><span></span></label><div><p>Item to do</p></div></li>
<li class="tiptap-task-item" data-checked="true" data-type="taskItem"><label><input type="checkbox"><span></span></label><div><p>Item already done</p></div></li>
</ul>
⚠️ data-type="taskList" on the <ul> and data-type="taskItem" on EVERY <li> are mandatory. TipTap's parser keys off data-type, not the class. A <li class="tiptap-task-item"> without data-type="taskItem" renders as a plain bullet — the checkbox never appears and the item isn't interactive. This is the single most common mistake when generating checklists programmatically.
Rules for a checklist that renders correctly:
<ul> carries class="tiptap-task-list" data-type="taskList".
- Each
<li> carries class="tiptap-task-item" data-type="taskItem" and data-checked="false" (unchecked) or data-checked="true" (checked).
- Inner structure is exactly
<label><input type="checkbox"><span></span></label><div><p>…</p></div> — the text lives in the <div><p>, not directly in the <li>.
- Do not substitute
☐/☐ glyphs inside a plain <ul><li> — they store as raw text and never become checkboxes.
(The SDD lifecycle uses a minimal variant — <ul data-type="taskList"><li data-type="taskItem" data-checked="false"><p>text</p></li></ul> — which TipTap also parses, because data-type is present. When in doubt, use the full form above; it's what the editor itself serializes.)
Code Blocks
Inline code: <code>functionName()</code> inside a <p>.
Block code (with syntax highlighting):
<pre><code class="language-javascript">// JavaScript example
const result = await fetch('/api/v2/search', {
method: 'POST',
body: JSON.stringify({ q: 'query', types: ['page'] }),
});
const data = await result.json();
</code></pre>
Supported language classes: language-javascript, language-typescript, language-python, language-bash, language-sql, language-json, language-html, language-css, language-rust, language-go.
Inline Image (within body)
For supplementary images, not the hero:
<figure style="margin:1.5rem 0">
<img src="MEDIA_URL" alt="ALT TEXT" style="width:100%;border-radius:8px;display:block" />
<figcaption style="text-align:center;font-size:0.85rem;color:#888;margin-top:0.5rem">Caption text</figcaption>
</figure>
YouTube / Video Embed
Replace VIDEO_ID with the 11-character YouTube ID from Step 6.
<figure data-embed-figure="true" data-node-id="embed-VIDEO_ID" data-alignment="center" data-size="full" class="embed-figure">
<div class="embed-content" data-embed-html="%3Ciframe%20width%3D%22100%25%22%20height%3D%22400%22%20src%3D%22https%3A%2F%2Fwww.youtube-nocookie.com%2Fembed%2FVIDEO_ID%22%20frameborder%3D%220%22%20allow%3D%22accelerometer%3B%20autoplay%3B%20clipboard-write%3B%20encrypted-media%3B%20gyroscope%3B%20picture-in-picture%22%20allowfullscreen%3D%22true%22%3E%3C%2Fiframe%3E">
<iframe width="100%" height="400" src="https://www.youtube-nocookie.com/embed/VIDEO_ID" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true"></iframe>
</div>
<figcaption class="embed-caption">VIDEO TITLE — brief context for why this video is relevant</figcaption>
</figure>
Note: data-embed-html must be the URL-encoded version of the iframe HTML. The raw iframe inside embed-content is for fallback rendering. Use youtube-nocookie.com for privacy-respecting embeds.
For Twitter/X, Vimeo, CodePen: same pattern, replace the iframe src with the appropriate embed URL from the platform.
Mermaid Diagram
Use the diagramming tool to generate the Mermaid source, then embed it:
<div data-type="mermaid" data-code="ENCODED_MERMAID_CODE" class="mermaid-wrapper"><pre class="mermaid">MERMAID_CODE_RAW</pre></div>
data-code: HTML-entity-encode the mermaid code (escape > → >, < → <, " → ", & → &)
- Inner
<pre class="mermaid">: raw unencoded mermaid code
Simple data charts via Mermaid (no dataset needed):
Pie chart:
pie title Market Share 2025
"Company A" : 42
"Company B" : 31
"Company C" : 27
Bar chart:
xychart-beta
title "Monthly Revenue ($M)"
x-axis [Jan, Feb, Mar, Apr, May, Jun]
y-axis "Revenue" 0 --> 50
bar [12, 18, 24, 31, 38, 45]
line [12, 18, 24, 31, 38, 45]
Live Data Card (from Dataset)
Requires dataCardId from Step 4. Get datasphereId from the create_dataset result.
<div data-type="dataCard" data-datacard-id="DATACARD_ID" data-dataset-id="DATASET_ID" data-datasphere-id="DATASPHERE_ID">[Data Card: CARD_NAME]</div>
Add a heading above it explaining what the chart shows:
<h3>Revenue Growth by Quarter</h3>
<p>The chart below shows quarterly revenue across the five largest segments, based on synthesised industry data.</p>
<div data-type="dataCard" data-datacard-id="DATACARD_ID" data-dataset-id="DATASET_ID" data-datasphere-id="DATASPHERE_ID">[Data Card: Revenue by Quarter]</div>
Horizontal Rule (Section Break)
Use sparingly — only between major sections in long-form content:
<hr />
Doc Footer
Always the last element on publication-quality pages:
<div data-type="doc-footer"></div>
Full Page Skeleton — Blog Post
<figure style="margin:0 0 2rem 0">
<img src="HERO_IMAGE_URL" alt="DESCRIPTIVE ALT" style="width:100%;border-radius:12px;display:block" />
<figcaption style="text-align:center;font-size:0.85rem;color:#888;margin-top:0.5rem">CAPTION</figcaption>
</figure>
<p><strong>HOOK SENTENCE.</strong> Context sentence. Scope sentence.</p>
<h2>First Section Title</h2>
<p>Body paragraph...</p>
<blockquote><p><strong>Key Insight:</strong> Pull quote or data callout.</p></blockquote>
<p>Continuation...</p>
<h2>Second Section Title</h2>
<p>Body paragraph...</p>
<ul>
<li><p><strong>Point one</strong> — detail</p></li>
<li><p><strong>Point two</strong> — detail</p></li>
</ul>
<h3>Watch: Related Video</h3>
<figure data-embed-figure="true" data-node-id="embed-VIDEO_ID" data-alignment="center" data-size="full" class="embed-figure">
<div class="embed-content" data-embed-html="ENCODED_IFRAME_HTML">
<iframe width="100%" height="400" src="https://www.youtube-nocookie.com/embed/VIDEO_ID" frameborder="0" allowfullscreen="true"></iframe>
</div>
<figcaption class="embed-caption">VIDEO TITLE</figcaption>
</figure>
<h2>Conclusion</h2>
<p>Summary of findings and call to action.</p>
<div data-type="doc-footer"></div>
Full Page Skeleton — Research Report
<figure style="margin:0 0 2rem 0">
<img src="HERO_IMAGE_URL" alt="ALT TEXT" style="width:100%;border-radius:12px;display:block" />
<figcaption style="text-align:center;font-size:0.85rem;color:#888;margin-top:0.5rem">Research commissioned by [Datasphere Name] · [Year]</figcaption>
</figure>
<h2>Executive Summary</h2>
<p><strong>KEY FINDING in one sentence.</strong> Supporting context. Scope of the report.</p>
<ul>
<li><p><strong>Finding 1</strong> — brief</p></li>
<li><p><strong>Finding 2</strong> — brief</p></li>
<li><p><strong>Finding 3</strong> — brief</p></li>
</ul>
<h2>Data Analysis</h2>
<p>Explanatory paragraph for the chart below.</p>
<div data-type="dataCard" data-datacard-id="DC_ID_1" data-dataset-id="DS_ID" data-datasphere-id="DSP_ID">[Data Card: Primary Chart]</div>
<h3>Breakdown by Segment</h3>
<p>Context for second chart.</p>
<div data-type="dataCard" data-datacard-id="DC_ID_2" data-dataset-id="DS_ID" data-datasphere-id="DSP_ID">[Data Card: Segment Breakdown]</div>
<h2>Process / Architecture</h2>
<p>Explanatory text before the diagram.</p>
<div data-type="mermaid" data-code="ENCODED" class="mermaid-wrapper"><pre class="mermaid">MERMAID_RAW</pre></div>
<h2>Comparison</h2>
<table>
<caption>Comparison of KEY DIMENSION across ENTITIES — Source: [web search source]</caption>
<thead><tr><th>Entity</th><th>Metric A</th><th>Metric B</th><th>Notes</th></tr></thead>
<tbody>
<tr><td>Row 1</td><td>Value</td><td>Value</td><td>Note</td></tr>
</tbody>
</table>
<h2>Conclusions & Recommendations</h2>
<p>Summary paragraph.</p>
<ol>
<li><p><strong>Recommendation 1</strong> — rationale</p></li>
<li><p><strong>Recommendation 2</strong> — rationale</p></li>
</ol>
<div data-type="doc-footer"></div>
Full Page Skeleton — Intelligent Report
<figure style="margin:0 0 2rem 0">
<img src="HERO_IMAGE_URL" alt="ALT TEXT" style="width:100%;border-radius:12px;display:block" />
<figcaption style="text-align:center;font-size:0.85rem;color:#888;margin-top:0.5rem">Intelligence Report · Updated [Date]</figcaption>
</figure>
<h2>Situation Overview</h2>
<p><strong>HEADLINE FINDING.</strong> Paragraph establishing why this topic matters right now.</p>
<blockquote><p><strong>Signal:</strong> Key data point or quote from web search results.</p></blockquote>
<h2>Key Metrics</h2>
<p>What the data shows and how it was compiled.</p>
<div data-type="dataCard" data-datacard-id="DC_ID_1" data-dataset-id="DS_ID" data-datasphere-id="DSP_ID">[Data Card: Key Metrics Overview]</div>
<h2>In Their Own Words</h2>
<p>Brief context for why this video is included.</p>
<figure data-embed-figure="true" data-node-id="embed-VIDEO_ID" data-alignment="center" data-size="full" class="embed-figure">
<div class="embed-content" data-embed-html="ENCODED_IFRAME">
<iframe width="100%" height="400" src="https://www.youtube-nocookie.com/embed/VIDEO_ID" frameborder="0" allowfullscreen="true"></iframe>
</div>
<figcaption class="embed-caption">VIDEO TITLE — context</figcaption>
</figure>
<h2>Trend Analysis</h2>
<div data-type="mermaid" data-code="ENCODED" class="mermaid-wrapper"><pre class="mermaid">MERMAID_RAW</pre></div>
<h2>Implications & Outlook</h2>
<p>Forward-looking analysis.</p>
<ul>
<li><p><strong>Short-term (0–6 months)</strong> — prediction</p></li>
<li><p><strong>Medium-term (6–18 months)</strong> — prediction</p></li>
<li><p><strong>Long-term (18+ months)</strong> — prediction</p></li>
</ul>
<h2>Supporting Data</h2>
<div data-type="dataCard" data-datacard-id="DC_ID_2" data-dataset-id="DS_ID" data-datasphere-id="DSP_ID">[Data Card: Supporting Breakdown]</div>
<div data-type="doc-footer"></div>
SEO Guidelines
Apply to every piece of content regardless of type.
Title (passed to create_page)
- 50–60 characters
- Lead with primary keyword
- Use power words: "Complete Guide", "Analysis", "Report", "[Year]", "How", "Why"
- Never keyword-stuff — write for humans first
Meta Description (metaDescription field)
- 150–160 characters exactly
- Include primary keyword in first 20 words
- End with a subtle call to action: "Learn more.", "Read the full report.", "Explore the data."
Heading Structure
<h2> — major sections (aim for 3–6 per page)
<h3> — subsections within a major section
- Never skip levels — no
<h3> without a parent <h2>
- Each
<h2> should naturally contain the topic keyword or a close variant
Image Alt Text
- Describe what's actually in the image (don't keyword-stuff)
- Include the topic naturally: "bar chart showing AI adoption rates by industry 2025"
- Never leave alt text empty
Internal Linking
- When mentioning other pages/dataspheres in the body, link them:
<a href="/pages/URI/SLUG">anchor text</a>
- Use descriptive anchor text — never "click here"
Content Length Targets
- Blog Post: 800–1,500 words equivalent
- Research Report: 1,500–3,000 words + data
- Intelligent Report: 2,000–4,000 words + data + video
YouTube Embed — URL Encoding Reference
When encoding the iframe HTML for data-embed-html, percent-encode these characters:
| Character | Encoded |
|---|
< | %3C |
> | %3E |
" | %22 |
(space) | %20 |
= | %3D |
/ | %2F |
: | %3A |
Full encoded iframe for video ID dQw4w9WgXcQ:
%3Ciframe%20width%3D%22100%25%22%20height%3D%22400%22%20src%3D%22https%3A%2F%2Fwww.youtube-nocookie.com%2Fembed%2FdQw4w9WgXcQ%22%20frameborder%3D%220%22%20allow%3D%22accelerometer%3B%20autoplay%3B%20clipboard-write%3B%20encrypted-media%3B%20gyroscope%3B%20picture-in-picture%22%20allowfullscreen%3D%22true%22%3E%3C%2Fiframe%3E
Simple SVG / Inline Charts (No Dataset)
Pick by intent:
| Need | Use |
|---|
| Live chart backed by real data | Datasets + data cards (see Step 4) |
| Process/flow or quick pie/bar generated from data | Mermaid via the diagramming tool |
| Custom static diagram, stat row, or on-brand schematic | data-viz skill (sanitizer-safe SVG components) |
⚠️ Never embed a raw inline <svg> in page content. <svg> is not in TipTap's node schema — it survives the first save then gets stripped to run-on text on the next re-serialization. It must be an <img> data-URI, and that data-URI is parsed as strict XML (named entities like · and width="100%" on the root both break it). The data-viz skill's svg-components.mjs handles all of this. Do not hand-roll it.
For a custom diagram or stat row, use the components from the data-viz skill — they return paste-ready <figure><img> markup:
import { statCards, flowStrip, flowStack, toFigure }
from './.claude/skills/data-viz/svg-components.mjs';
content += statCards([
{ value: '24%', lines: ['of developers merged AI code', 'without reviewing it'], source: 'Stack Overflow, 2025' },
]);
content += flowStrip([{ label: 'Research', badge: 'ORIGIN GATE', tone: 'gold' }, { label: 'Done', tone: 'green' }]);
For manual editing, run node .claude/skills/data-viz/encode.mjs … (see the data-viz skill's templates.md). Always render-validate (naturalWidth > 0) before publishing.
Mermaid is still the right tool for data-driven flow/pie/bar charts via the diagramming tool; datasets + data cards remain the tool for interactive live charts.
Quality Checklist
Before calling create_page, verify every item:
Temporal accuracy (check these first)
Voice & visuals
Content structure
Tool Chain Summary
web_search (2–5 queries)
↓
generate_media_image (hero image)
↓
create_dataset + generate_dataset_rows ← Research / Intelligent only
↓
create_data_card (one per insight) ← Research / Intelligent only
↓
diagramming (Mermaid) ← when process/flow needed
↓
[extract YouTube IDs from search results] ← Intelligent only
↓
create_page / create_landing_page
↓
create_post (feed teaser) ← optional
The output is a publication-quality, SEO-optimised, interactive page that a human editor would be proud to publish.