KEEP IT HANDS-ON functional ~ tested 2026-08-20
// sandboxed in macOS (host) Β· aarch64 Β·install log Β· why not fully functional: All deterministic surfaces were verified with positive and negative assertions (quick renderer output, HTML escaping, byte-identical determinism, MCP initialize/tools/prompts/resources, accept and reject paths for all 3 tools, PPTX ZIP container). The primary full-mode deliverable is agent-authored HTML inside a live coding harness, which cannot be exercised outside a real agent session. Β·functional log

visual-explainer

by nicobailon · https://github.com/nicobailon/visual-explainer · MIT · vv0.10.0 · updated 2026-08-20

The 9.5K-star skill that stops your agent from dumping ASCII tables in the terminal, tested down to its MCP handshake and md5 determinism.

4 / 5
quality 4/5
documentation 5/5
setup 4/5
value 5/5
ecosystem fit 4/5
// bottom line

This is one of the best engineered single-purpose skills GearScope has tested: a zero-dependency renderer, a hardened local MCP server, a 360-line changelog, and design guidance that bans its own genre's cliches. Two real defects surfaced (a silent no-op when the renderer runs from a /tmp path on macOS, and a stale 0.9.0 version inside the plugin manifest), and there is no test suite or CI to catch either. Install it if your agent ever hands you a 15-row table in the terminal.

Don't install your next skill blind. Every week: the shortlist of skills worth installing β€” and the ones to skip β€” from 100+ hands-on tests.
Claude Code marketplace
$/plugin marketplace add nicobailon/visual-explainer && /plugin install visual-explainer@visual-explainer-marketplace
npm (MCP + PPTX binaries)
$npm install -g visual-explainer
Pi package
$pi install git:github.com/nicobailon/visual-explainer

install if

  • Developers whose agents dump wide tables, diffs, or architecture sketches into the terminal. The 4-row/3-column auto-trigger plus seven review commands targets exactly this daily annoyance, and the output is a portable HTML file you can attach to a ticket.
  • Pi users. The 413-line extension registers a native tool with prepare/render/render_quick actions; this is the most first-class integration in the repo.
  • MCP-host users who want render tools without a daemon. The stdio server is local-only, needs no API key, writes nowhere but ~/.agent/diagrams/, and exposes the skill content itself as read-only resources.

What It Does

visual-explainer is an agent skill by nicobailon (9,525 stars, MIT, created 2026-02-16, pushed the morning of this review) that makes coding agents stop drawing box-art in your terminal. When you ask for a diagram, a diff review, a plan audit, a data table, or a project recap, the agent writes a complete self-contained HTML page to ~/.agent/diagrams/ and opens it in your browser. The repo ships that skill in five forms: a Claude Code marketplace plugin (7 slash commands), a Pi package with a native visual_explainer tool, a local stdio MCP server with 3 tools, a zero-dependency quick-mode JSON renderer, and a best-effort PPTX exporter, plus copy-in guidance configs for Codex, Antigravity, OpenCode, Cursor, OpenClaw, and Copilot. The target user is anyone whose agent answers "compare these 15 requirements against the plan" with a wall of pipes and dashes.

The Good

The quick-mode renderer is zero-dependency, deterministic, and hostile to injection. quick/render.mjs (209 lines, pure Node stdlib) validates a compact JSON spec and renders complete HTML. It ran on a fresh clone with no npm install, produced byte-identical output across two runs (md5 7c173c8a1648f0405fb80aa0015ff676), escaped every injected payload we fed it ( in a title came out as <script>alert(1)</script>, an card title was fully escaped), and rejected all four negative specs we crafted with errors that name the exact field: spec.sections[0].bogusKey is not supported, table rows that must match the column count, invalid tone enums, and flow edges that must reference a flow node.

The MCP server is hardened beyond what most hobby skills ship. mcp/server.mjs (405 lines) rejects filenames containing path separators or .., refuses to write if ~/.agent/diagrams/ or the target file is a symlink, validates that submitted HTML is a complete document (rejecting fragments with a named error), and injects a favicon, lang, and viewport metadata into documents missing them, all verified in our tool calls. The initialize handshake returned serverInfo visual-explainer 0.10.0, tools/list returned exactly the 3 documented tools, prompts/list returned the 7 bundled commands, and resources/list returned 10 read-only resources exposing the SKILL.md and quick schema to the host model.

The documentation discipline is top-tier for a single-maintainer project. The changelog runs 360 lines across 20+ dated releases back to v0.1.0, each crediting the issue or PR that motivated it (@romkazor in #83, @luketych in #33, @mikeyobrien in #12, and a dozen more). Version 0.10.0 is synchronized across package.json, marketplace.json, SKILL.md metadata, the npm registry, and the git tag. The SKILL.md itself is a 146-line design contract with a reference routing table (all 13 routed targets exist on disk) and an anti-slop section that bans specific hexes (#8b5cf6, #7c3aed, #a78bfa, #d946ef) and Inter-as-primary-font; we grepped the shipped templates and found zero violations of its own rules.

The Bad

The quick renderer silently no-ops when invoked through a /tmp path on macOS. render.mjs decides it is the main module by comparing import.meta.url to a non-canonicalized pathToFileURL(process.argv[1]). Because /tmp is a symlink to /private/tmp, running node /tmp/.../render.mjs spec.json out.html exits 0 and writes nothing, with no error on stdout or stderr. We reproduced this directly: an alias-path invocation given a nonexistent spec file still exited 0 (main never ran), while the canonical /private/tmp path rendered correctly. The failure mode is the problem, not the frequency: an agent that hits it gets a success exit code and no page. The README's own install snippets clone into /tmp. Notably, mcp/server.mjs and pptx/export.mjs both use realpathSync in their main-module guards and are immune; the renderer is the odd one out.

Version drift survived the release that claimed to fix version drift. The v0.10.0 changelog's headline fix is "Synchronized Claude Code marketplace and skill metadata versions after the mismatch reported by @romkazor in #83." The marketplace.json (both spots), package.json, SKILL.md, npm, and the git tag all read 0.10.0, but the inner manifest at plugins/visual-explainer/.claude-plugin/plugin.json still reads 0.9.0. It is a cosmetic gap in a repo whose brand is metadata hygiene, and our structural run failed on exactly this check.

No test suite, no CI, and a 142 MB peer-dependency surprise. There is no .github/ directory and no test files anywhere in the tree, which is why the /tmp bug and the manifest drift had nothing catching them. On the dependency side, npm install (npm 11 auto-installs peers) pulled @earendil-works/pi-coding-agent@0.84.2 into node_modules: 142 MB of the 167 MB total, installed for users who only want the MCP server or PPTX exporter and will never run Pi. A --legacy-peer-deps note in the MCP README would fix the surprise. Minor gaps on top: Hermes is not among the seven documented harness targets (the standard frontmatter means a manual copy into .hermes/skills/ works, undocumented), the repo sets no GitHub topics, and skills.sh shows only 439 installs, so demand lives almost entirely in the Claude marketplace and npm.

Smoke Test Results

Hands-on host testing on macOS 26.5.2 aarch64, Node v24.13.1, npm 11.8.0. The sandbox runner (sbx) was not authenticated, so the three scripts run on the host against fresh clones, with full logs at the paths below. Script totals: Run A 38/38, Run B 24/24, Run C 23/24 (the single failure is the version-drift finding in The Bad).

Run A. Fresh clone, no npm deps preinstalled

$ git clone --depth 1 https://github.com/nicobailon/visual-explainer
βœ… 3.0 MB clone, tag v0.10.0, HEAD dated 2026-08-19
$ node plugins/visual-explainer/quick/render.mjs spec-ok.json out-1.html
βœ… exit 0 with zero npm deps; complete doctype document with embedded CSS, flow nodes, severity-tagged risks, table
$ node plugins/visual-explainer/quick/render.mjs spec-ok.json out-2.html && md5 out-1.html out-2.html
βœ… byte-identical renders (7c173c8a1648f0405fb80aa0015ff676)
$ node quick/render.mjs spec-xss.json out-xss.html # title: <script>alert(1)</script>
βœ… escaped as &lt;script&gt;alert(1)&lt;/script&gt;; no raw injected tag anywhere in output
$ node quick/render.mjs spec-neg1.json neg1.html # unknown section key
βœ… rejected: "spec.sections[0].bogusKey is not supported"
$ node quick/render.mjs spec-neg2.json neg2.html # row shorter than columns
βœ… rejected: "must match the column count"
$ node quick/render.mjs spec-neg3.json neg3.html # tone: "sparkly"
βœ… rejected: "must be neutral, accent, positive, warning, danger, or info"
$ node quick/render.mjs spec-neg4.json neg4.html # edge points at missing node
βœ… rejected: "must reference a flow node"
$ node /tmp/.../quick/render.mjs spec-ok.json out.html # macOS /tmp alias path
βœ… bug reproduced: exit 0, no file written (non-canonical main-module guard)
$ node mcp/server.mjs
βœ… fails cleanly: Cannot find package '@modelcontextprotocol/server' (README documents npm install first)

Pass rate: 10 of 10. The zero-dependency renderer works from a bare clone and every negative case is rejected with a field-specific error. The /tmp line passes by reproducing the documented bug (see The Bad).

Full sandbox log β†’

Run B. With deps preinstalled (npm install)

$ npm install --no-package-lock
βœ… exit 0 in 6s; resolves @modelcontextprotocol/server@2.0.0, zod@4.4.3, node-html-parser@9.0.1, pptxgenjs@4.0.1 (+ peer pi-coding-agent@0.84.2)
$ python3 mcp-stdio-client.py node mcp/server.mjs --env HOME=/tmp/ve-mcp-home
βœ… initialize: serverInfo {"name": "visual-explainer", "version": "0.10.0"}; tools 3, prompts 7, resources 10
$ --call visual_explainer_prepare --args '{"topic":"auth flow"}'
βœ… isError false; returns a 5-step recommendedFlow; writes nothing
$ --call visual_explainer_render_quick --args '{"filename":"ve-smoke-auth-flow","spec":{...steps+evidence...}}'
βœ… isError false; HTML written to isolated ~/.agent/diagrams/ with correct title and step markup
$ render_quick same spec, second filename; md5 both files
βœ… byte-identical MCP renders (24eedb7d14f967bc07f820e71731981b)
$ --call visual_explainer_render_quick --args '{"filename":"neg-badkey","spec":{"sections":[{"nope":1}]}}'
βœ… isError true, names the bad key ("is not supported")
$ --call visual_explainer_render_html --args '{"filename":"../escape-attempt","html":"<!doctype html>..."}'
βœ… isError true ("filename must be a basename"); confirmed no file written outside ~/.agent/diagrams
$ --call visual_explainer_render_html --args '{"filename":"fragment","html":"<p>not a document</p>"}'
βœ… isError true ("complete HTML document" contract enforced); a valid doc passes and gains favicon + lang
$ node pptx/export.mjs deck.html deck.pptx
βœ… exit 0; 75,655-byte valid ZIP container (PK magic) from a 3-slide deck

Pass rate: 9 of 9. Every documented tool contract held under both valid and hostile input, and output is deterministic through the MCP path as well as the CLI path.

Full sandbox log β†’

Run C. Structural validation (self-consistency)

$ head -10 SKILL.md | grep -E '^(name|description|license):'
βœ… name, 256-char description, MIT license, metadata.version 0.10.0 all declared
$ compare versions: package.json, marketplace.json x2, plugin.json, SKILL.md, npm view, git tag
❌ plugin.json reads 0.9.0; the other six surfaces read 0.10.0
$ for f in commands/*.md; do check name+description frontmatter; done
βœ… 7 of 7 command templates carry full frontmatter
$ test -f each of the 13 SKILL.md reference-routing targets
βœ… all 13 exist (5 references, 4 templates, quick/README, quick/schema, base.css, pptx/export.mjs)
$ grep banned hexes and Inter-primary stacks across templates/
βœ… zero violations of the skill's own anti-slop rules
$ ls configs/ | wc -l
βœ… 7 platform config dirs (pi, opencode, openclaw, cursor, copilot, codex, antigravity)

Pass rate: 5 of 6. The one failure is the real version-drift finding reported in The Bad; the skill's content is otherwise self-consistent to an unusual degree.

Full functional log β†’

What the runs tell you

The executable surfaces do what the README claims, on a bare clone and after install, under valid and hostile input alike, and the deterministic renderer is safe to point at untrusted model output. The two defects that surfaced (the /tmp silent no-op and the stale inner plugin.json) are edge-case and cosmetic respectively, but both are the kind of drift a test suite would have caught on day one.

Setup Walkthrough

  1. Claude Code: run /plugin marketplace add nicobailon/visual-explainer, then /plugin install visual-explainer@visual-explainer-marketplace. Commands arrive namespaced as /visual-explainer:diff-review and friends. This is the lowest-friction path.
  2. MCP hosts (checkout path): git clone --depth 1, then npm install --no-package-lock inside it (6 seconds, 167 MB with the auto-installed Pi peer; add --legacy-peer-deps if you never use Pi), then point your host at node /abs/path/plugins/visual-explainer/mcp/server.mjs.
  3. Pi: pi install git:github.com/nicobailon/visual-explainer registers the native visual_explainer tool, the skill, and all 7 prompts in one step. If you used the old curl installer, remove the copied files first or Pi reports shadowing conflicts.
  4. Codex, Antigravity, OpenCode: copy plugins/visual-explainer/ into the platform's skills directory per the README snippets. On macOS, avoid keeping the working clone under /tmp if you plan to invoke quick/render.mjs directly; use a canonical path (the bug above).
  5. Try > draw a diagram of our authentication flow or /diff-review --quick main..HEAD. Output lands in ~/.agent/diagrams/ and opens in your browser.

Alternatives

  1. tt-a1i/archify - validated, self-contained HTML diagrams from a typed JSON IR with CI-checkable receipts. Prefer it when diagrams are build artifacts; prefer visual-explainer when the goal is readable explanations of reviews, plans, and recaps.
  2. anthropics/skills (frontend-design) - the design-judgment ancestor this skill credits. Lighter (no commands, renderers, or MCP), but also no quick mode, no diff/plan-review workflows, and no output tooling.
  3. pbakaus/impeccable - solves the adjacent problem: detecting and fixing AI-slop in HTML you already have. The two pair well; impeccable polishes pages visual-explainer generates.
// review provenance
reviewed by
GearScope
tested
2026-08-20 · macOS (Apple Silicon)
last verified
2026-08-20
depth
HANDS-ON
sponsorship
none, ever
// share this review
// feedback
was this review helpful?

Don't install your next skill blind.

Every week: the shortlist of skills worth installing β€” and the ones to skip β€” from 100+ hands-on tests. No spam, no affiliate links.