When you pull a full Distro story into a Claude Cowork or Claude Desktop session, the Distro Reader hands back the article's body as raw Markdown: links as [text](url), thematic breaks as * * *, and any embedded diagrams as ```mermaid fences. Readable, but not the story. You get a wall of markup instead of the piece the way it looks on the site, and the Mermaid diagrams sit there as inert code.

distro-story-viewer closes that gap. The moment distro_story_read returns a body, the skill asks the Distro backend for the canonical reading page and opens it in the side panel, framed in the faithful DeAI News / DistroVerse reading shell (warm near-black canvas, Orbitron headline, Inter body, green links, byline and read-time meta), with every embedded Mermaid diagram rendered as a live figure and the featured image inlined. It's the read-side companion to the Distro Publisher skills: they file stories, this one lets you read them the way they were meant to look.

This is v2, and it is a rewrite. Version 1 built the page locally, with a vendored Markdown engine, a bundled mermaid.min.js and hand-measured CSS. That renderer is gone on purpose. It was the fifth independent copy of the article shell, and every copy re-created the same styling bugs. The shell now lives server-side in the Distro backend, is covered by the backend test suite, and gets style fixes without a skill update. The skill's whole job is delivery: call distro_story_render_hud with selfContained: true, then SendUserFile with display: "render". Two files, no local rendering, no vendored assets. If you are running v1, replace it.

A note on the name: an interim version of this listing called the skill claude-story-viewer. Skill identifiers can't carry the Claude name, so the canonical identifier is, and stays, distro-story-viewer. If you installed the interim build, delete that folder and install the one below.

What you'll need

You need the Distro Reader (or Distro Publisher) MCP connected so the agent can fetch story bodies with distro_story_read and pages with distro_story_render_hud, plus a client that supports side-panel rendering, which means Claude Cowork or Claude Desktop. Nothing else. v2 ships no scripts and no vendored runtime, because the server inlines the Mermaid runtime and the images into the page it returns. Premium stories still require the Distro Reader's x402 payment flow to unlock the body; once unlocked, pass the same accessToken to the render call.

What it does

  • Auto-fires on a full read. As soon as distro_story_read returns a non-empty body, it renders. No need to say "render," "view," or "side panel." A full fetch is itself the cue.
  • Server-rendered, always current. Fetches the canonical reading page from distro_story_render_hud rather than rebuilding it, so the render matches the site and inherits backend style fixes automatically.
  • Live Mermaid diagrams, with the author's colors. The shell pins Mermaid's label text to the diagram author's own classDef ink, so bright node fills stay legible instead of rendering as dark-on-dark.
  • Featured images inlined. The server fetches and embeds them, so no browser detour and no expired signed-S3 misses.
  • Premium-aware citation. For a paid story it cites headline, publication, author and date as plain text, with no hyperlink, because an x402 access token does not authenticate you on the website and the link would send a paying reader back to a paywall.
  • Render every time, persist on request. Always shows in the side panel, and only saves to the artifact gallery if you ask, so the gallery stays uncluttered.
  • No local fallback, by design. If the render call fails, the skill hands you the markdown in chat and says so, rather than quietly rebuilding a drifted copy of the shell.

Install the skill

Ask the agent:

"Please fetch the distro-story-viewer skill from Distro Skills and give me a .skill file I can install."

It will pull this story, extract the SKILL.md from the fenced block below, and package it as distro-story-viewer.skill. The file will appear in your chat with a Save skill button. Click it to install directly. That registers the skill with your app so it shows up in your skills list and triggers on matching requests.

Requires the Distro Reader or Distro Publisher MCP connected so the agent can pull the story. While Distro Skills is private, this works for account holders with access. Public read access is coming.

Claude Code users: you have a direct path. Ask for the unzipped folder to be dropped into ~/.claude/skills/distro-story-viewer/, then restart the session. No packaging step needed.

No Distro MCP connected? Copy the SKILL.md contents from the fenced block below into a file called SKILL.md inside a folder called distro-story-viewer, zip it (folder as zip root), and upload through Settings → Capabilities → Skills → Upload skill.

Upgrading from v1? The SKILL.md below is the whole skill. Delete the old scripts/ and assets/ folders that shipped with v1; nothing references them anymore, and leaving the vendored Mermaid runtime in place only invites a future session to rebuild the local renderer.

The skill source

This is the canonical SKILL.md:

---
name: distro-story-viewer
description: >-
  Render a fetched Distro story in the side panel. Use this AUTOMATICALLY
  whenever a full article body is pulled from Distro via the Distro Reader (the
  distro_story_read tool) — for any of Brad / Bradley Keoun's publications (Distro
  Newslode, DeAI News, Hardcore Tech, Liqquidity's Newslode, DistroVerse) or any
  Distro / DeAI News URL or slug. As soon as distro_story_read returns a body
  (free, or premium once paid), fetch the canonical reading page with
  distro_story_render_hud (selfContained: true) and show it in the side panel —
  the server renders the faithful article style with live Mermaid diagrams and
  images inlined. Trigger on plain reads like "get me that story", "pull the full
  article", "read this Distro story" — the user need NOT say "render", "view", or
  "side panel". Do NOT use when the user asks for the text, markdown, or a summary
  (answer from the distro_story_read body), for feed/search listings or previews
  (no body), for publishing or editing stories (Distro Publisher tools), or
  non-Distro web pages.
---

# Distro Story Viewer (v2 - server-rendered)

## What this does and why

The Distro backend now renders the canonical reading page itself:
`distro_story_render_hud` returns a complete, self-contained HTML document in
the site-faithful article style — warm near-black canvas, Orbitron headline,
Inter body, green links, live Mermaid diagrams with the diagram author's
`classDef` colors intact, and the story's featured image inlined. This skill's
job is only **delivery**: request that page and open it in the Cowork side
panel via `SendUserFile` with `display: "render"`.

Earlier versions of this skill rendered the page locally (vendored Markdown
engine, bundled mermaid.min.js, hand-measured CSS). That renderer is
deliberately **gone**: it was the fifth independent copy of the article shell,
and every copy re-created the same styling bugs. One shell now lives
server-side, is covered by the backend test suite, and style fixes reach this
skill with no skill update. Do not rebuild any local rendering fallback.

Two deliberate design choices Brad made, unchanged from v1:

- **Faithful article style, no site nav** — now guaranteed by the server, not
  approximated here.
- **Render every time, persist on request.** Always show it in the side panel.
  Only save it to the artifact gallery if Brad asks — keep the gallery
  uncluttered.

## When to fire

Fire **automatically** the moment `distro_story_read` returns a body. You have
a body when the result contains a non-empty `body` (or `content`) field. You do
**not** have a body — so don't render — when:

- The result is a paywall challenge (`paywall.required` / HTTP 402) that hasn't
  been paid yet. Handle payment first (that's the Distro Reader's x402 flow);
  once the paid retry returns the body — and its `X-Distro-Access-Token` — then
  render.
- You only ran `distro_feed_latest` or `distro_search` (those return listings
  and previews, never the body).

**Text-only carve-out:** if the user asked for the text, the markdown, a quote,
or a summary, skip the render entirely — the `distro_story_read` body is the
deliverable. Rendering is for *reading*, not for every mention of a story.

If several stories are fetched at once, render each one (or ask which, if
that's clearly what Brad wants). Rendering is cheap and non-destructive.

## Workflow

1. **Fetch the page.** Call `distro_story_render_hud` with the same identifier
   you read the story by (one of `storyId`, `slug`
   `"<publication-slug>/<story-slug>"`, or `url`), plus:

   - `selfContained: true` — always, for the side panel. The sandbox blocks all
     network, and this makes the server inline the Mermaid runtime and every
     image as data URIs. Expect ~3.3 MB when the story has diagrams; that is
     normal and well within `SendUserFile` limits.
   - `accessToken: <X-Distro-Access-Token>` — for premium stories, the same
     token the paid `distro_story_read` used or returned. Without a valid
     token the tool returns the paywall instructions instead of HTML.

   Take the HTML from `structuredContent.html` (identical to
   `content[0].text`) and write it to a file, e.g. `story.html`.

2. **Show it in the side panel.**

   ```
   SendUserFile(files=["story.html"], display="render", status="normal",
                caption="<title> — Distro reading page.")
   ```

   `display: "render"` is what opens it in the side panel. Keep the caption to
   one line — Brad can read the story itself.

   **Don't cite the canonical web URL for a premium story.** The x402 access
   token does not authenticate the reader on the website, so linking the
   article in chat (`Sources:` line included) sends a paying reader to a
   paywall they already paid through. Cite premium stories as plain text —
   headline, publication, author, date, no hyperlink. Free stories cite
   normally, with the link. (The rendered page itself already applies this
   rule server-side: free pages carry a "View on Distro" link, paid pages
   don't.)

3. **Offer to persist (one line, don't auto-save).** After sending, offer in a
   single sentence to save it to the artifact gallery, e.g. *"Want this saved
   to your artifact gallery so you can pull it up later?"* For a premium story
   this offer **replaces** the web link rather than accompanying it — the
   durable ways back to a paid article are the artifact gallery and the
   purchase itself, since x402 ownership is permanent and a re-read costs
   nothing (pass the saved `accessToken` to `distro_story_read` or
   `distro_story_render_hud`, or re-request and the wallet is not charged
   again). Say that, not "here's the link." Only if he says yes:
   `SendUserFile` returns a `file_uuid`; pass it to
   `mcp__remote-devices__create_artifact` with a kebab-case id derived from
   the slug (e.g. `journobot-diagrams`) and a one-line description. If no
   desktop is connected, that tool is absent — just note the page is delivered
   and can be saved once the desktop app is open.

## Notes and edge cases

- **If the render call fails** (tool error, MCP unreachable, unexpected
  paywall), say so plainly and give Brad the story as markdown in chat from
  the `distro_story_read` body. Do **not** attempt to build the page locally —
  a hand-rolled fallback is exactly the drifted shell this version removed.
- **Books:** `distro_book_render_hud` works the same way (`selfContained: true`,
  whole-book `accessToken` for owned books) and renders the cover, table of
  contents, and chapters in the same shell.
- **Featured images are the server's job now.** They arrive inlined in the
  page. Never fetch one with the browser, and never pass one in by hand.
- **Diagram label colors are the server's job now.** The shell pins Mermaid's
  label `<p>`s to the diagram author's `classDef` ink; if labels ever look
  wrong, that's a backend bug to report (the shell lives in
  `packages/backend/src/mcp/render/storyShell.js`), not something to patch
  here.
- **Full HTML blocks render as authored** — Distro stories may embed raw HTML
  and the server passes it through into the page. These are Brad's own trusted
  stories; that passthrough is intended.

When to use / when not to use

Use it when:

  • distro_story_read returns a full story body, whether a free story or a premium one whose paywall was paid.
  • You want to read a Distro / DeAI News / Hardcore Tech / Liqquidity's Newslode story the way it looks on the site.
  • A story has embedded Mermaid diagrams you want rendered rather than shown as code.
  • You want a whole book rendered, cover and table of contents included, via distro_book_render_hud.

Don't use it when:

  • The user asked for the text, the markdown, a quote or a summary. The distro_story_read body is the deliverable, and rendering is for reading.
  • You only ran distro_feed_latest or distro_search. Those return listings and previews, never a body.
  • The story is behind an unpaid paywall (HTTP 402). Handle payment first, then render.
  • You're publishing or editing a story (that's the Distro Publisher tools), or the page is non-Distro web content.

Feedback

This is v2 of distro-story-viewer, the server-rendered rewrite. Edge cases or suggestions → reply or ping Bradley Keoun.