Visual plan
Turn ordinary text plans into a rich, interactive, self-contained HTML document — with diagrams, file maps, annotated code, collapsible sections, and open questions — instead of a flat Markdown plan rendered in the terminal.From its SKILL.md
npx -y skills add option-ai/skills --skill visual-planAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
23.0 KB, ~5.7k tokens by cl100k_base, as published. Nobody here has run it
Visual Plan (Self-Authored HTML)
This skill turns the implementation plan you would normally dump into chat as
Markdown into a single self-contained .html file the user opens in their
browser. No MCP server, no hosted service, no dependencies — just one HTML file
you write to disk and open. The goal is a scannable, navigable review surface
that's far easier to approve than a wall of terminal Markdown.
/visual-plan is the entry point. When the user already has a text plan (pasted,
in a file, or earlier in the chat), use it as source material and render it as
HTML rather than starting over.
When To Use
Build a visual plan whenever the plan is better as a reviewable artifact than a chat paragraph: multi-file, ambiguous, risky, architecture-heavy, data-heavy, or UI-heavy work — plus modest work like a single UI surface with states, a small workflow, a before/after change, or a component/API/data-shape decision that needs alignment before code.
Skip it for truly trivial, unambiguous work — typos, one-line fixes, a single well-specified function — and just make the change. Never pad a plan with filler and never ship a single-step plan.
Plan Discipline
- Research before you draft. Read the real files, actions, schema, and patterns first; name actual files, symbols, and data shapes instead of inventing them. Lead with reuse: for each step, name what it reuses (existing actions, schema, components, helpers) before what it adds. Delegate wide exploration to a sub-agent when useful.
- Decide the hard-to-reverse bets first. For non-trivial backend, data, or API work, call out decisions expensive to undo once data or callers depend on them — wire format, public ids, data-model shape, auth and ownership boundaries — and get those right in the plan. Then scope the smallest first cut that proves the approach, stating what's in and what's explicitly deferred.
- Keep examples at the right altitude. When the idea is a broad framework or operating-model change, don't collapse it into the first concrete example. Separate the core abstraction from motivating examples, and label examples as examples unless they are the whole requested scope.
- Make it stand alone. A reader who never saw the chat should understand the plan. If the user pasted an existing plan, rewrite it as a clean standalone proposal — no revision language ("unlike the previous version", "this revision changes…").
- Planning is read-only. Make no source edits while building the plan. Start editing only after the user approves the direction.
- Clarify vs. assume. Don't ask how to build it — explore and present the approach and options in the plan. Ask a clarifying question only when an ambiguity would change the design and you can't resolve it from the code; batch 2–4 high-leverage questions via the normal ask-user flow. Otherwise state the assumption explicitly and proceed, and keep anything unresolved in the plan's Open Questions section.
- The plan is the approval gate. After surfacing the HTML file, ask the user to review and approve before you write code, and name which files/areas the work touches. Presenting the plan and requesting sign-off is the approval step — don't tack on a separate "does this look good?" question.
Core Workflow
- Gather context: inspect the codebase, delegate wide exploration when useful, and ask native clarifying questions only when truly needed. If a source plan exists, use its exact text — don't invent source text.
- Write a single self-contained HTML file. Keep versions: write to
plans/<slug>/v<N>.html(start atv1; bumpNevery time you regenerate so prior versions are never overwritten). Follow the HTML Authoring Contract. Fill the header metadata from git: repo (git remote get-url origin), branch (git rev-parse --abbrev-ref HEAD), today's date, and the versionvN; list prior versions (with dates + their deployed URLs) in the version-timeline popover. - Always deploy to Cloudflare (see Deploying The Plan To Cloudflare) and
give the user the live URL — this is the default handoff, not an opt-in. Also
openthe local file on macOS as a convenience. (Skip the deploy only if the user explicitly says local-only, or the plan covers private/unreleased work and they decline a public URL.) - Ask the user to review and approve. Iterate by editing the file; for a
materially new revision, bump to the next
vN, re-deploy, and add the prior version to the timeline so every version stays reachable. - For high-stakes plans (architecture, backend, data, multi-file, risky), run a quick adversarial self-review of the written plan (not a re-research): spawn one skeptical reviewer to find weak/missing/wrong parts — unanchored steps, implicit hard-to-reverse decisions, option-menus that should commit, obvious missing decisions, padding. Apply clear-cut fixes; route genuine judgment calls back to the user in Open Questions.
HTML Authoring Contract
Produce ONE file with CSS, JS, SVG icons, and brand logos all inlined and no web
fonts (use the system font stack). The only permitted external dependency is
Mermaid, loaded from a pinned CDN for diagram rendering (see the Diagrams
bullet). Everything else stays inlined; the page must open and fully function
(theme toggle, commenting, annotations, file trees) from a file:// URL — and
the diagrams render too whenever the network is reachable (local file with
internet, or after deploying to Cloudflare). If the user asks for a strictly
offline file, vendor Mermaid by inlining its minified bundle instead of the CDN.
Required structure and behavior:
- Document head:
<!doctype html>,<meta charset>,<meta name="viewport">,<meta name="color-scheme" content="dark light">, and a descriptive<title>. - Dark-mode first, with a toggle. The page loads in dark mode by default
(don't defer to
prefers-color-schemefor the default — dark is the default). A header toggle (sun/moon Tabler icon) flips between dark and light; persist the choice tolocalStorageand apply it before first paint to avoid a flash. - Palette: foglamp-inspired neutral grayscale (dark-first). Use the CSS tokens
in
references/html-template.mdverbatim — neutral grayscale surfaces (#1c1c1cbg,#2e2e2ecard,#3d3d3dmuted) with layered shadows instead of flat borders (--card-shadow), and the clay accent used sparingly (links, "our code" highlight, the recommended-chip ring). Do NOT flood surfaces with the accent tint — that reads as washed-out "AI" styling. Selected/recommended states are a muted-gray background (--card-2) with a thin accent ring, never a solid colored fill. Semantic tints (green/amber/red) are reserved for callouts and status pills. Dark is the polished default; light mode mirrors the tokens. - Tabler icons, inlined. Use Tabler icons for all
UI affordances (theme toggle, comment/annotation, copy, collapse chevrons,
section markers). Inline each icon's SVG (Tabler is MIT-licensed
currentColorstroke SVG) — never link a CDN or icon font. Define them once as<symbol>s in a hidden<svg>sprite and reference with<use>. - Brand logos — only real ones, never substitutes. For a recognizable
product/service named in a diagram node or list, render its brand logo from
the inlined sprite. The sprite covers socials (WhatsApp, Telegram, Signal,
Discord, Slack, Instagram, Messenger, X, LinkedIn) and cloud/AI (Cloudflare,
Vercel, OpenAI, Anthropic, Gemini, Perplexity, Supabase, Google Cloud, Google,
GitHub). Two hard rules, because both were violated before:
- Never use one brand's logo for another (e.g. the Google "G" for Gemini —
use
#b-gemini). If the exact logo isn't in the sprite, add it by copying the exact Simple Icons path (fetch fromcdn.jsdelivr.net/npm/simple-iconsto be sure), or use the generic#i-cpufallback icon — never approximate. - Don't force logos onto generic concept nodes (e.g. "Cron Trigger", "KV cache", "Excel export"). Those get a neutral Tabler glyph or no icon — a brand logo there is wrong. A node with no real logo simply has no logo.
- Never use one brand's logo for another (e.g. the Google "G" for Gemini —
use
- No header bar — a stacked header. Don't render a sticky header. At the top
of the body: a metadata row (repo link · branch · date · version badge),
then the plan name (h1), then the one-line outcome full width below — no
divider line. Fill the metadata from git: repo URL, current branch, today's
date, and the version
vN. The version badge opens a timeline popover — fill its rows with each prior version (vN· date · deployed URL) so every version is reachable. A row is a link only if that version has its own deployed URL (<a href="https://…">); the current version and any version without a separate URL are plain<div>, neverhref="#"(which just jumps to top). With one deploy URL, the popover is an informational changelog, not links. - The plan is centered in the window; the TOC floats left, out of flow. The
body column is centered in the viewport (
margin: 0 auto). The table-of-contents nav is positioned absolutely/fixed to the left so it does not occupy layout space or push the plan off-center — the plan stays centered, the TOC sits in the left margin and hides on narrow screens. - Floating dock that expands (one surface, not a second window). All controls
live in a floating pill at the bottom: comment, feedback, copy-feedback,
theme, and keyboard-shortcuts. The dock sizes to its buttons (
width: fit-content) — no dead/empty width. Opening the compose box or the feedback chat expands the dock itself upward with an animation — both live inside the dock; never render a separate floating panel/window detached above it. - Collapsible sections (
<details>/<summary>, styled with a Tabler chevron) so reviewers can scan headings then expand. Keep the most important sections open by default. - Steps as discrete, numbered cards, each naming the real files/symbols it touches and what it reuses before what it adds.
- Diagrams via Mermaid — and it must be valid. Render flow, sequence, state,
ER, and dependency diagrams with Mermaid (
<pre class="mermaid">…</pre>, pinned CDN ESM build, theme-wired). Bad Mermaid syntax is the #1 failure mode, so write it carefully: quote every node label containing spaces, punctuation, parentheses, slashes, or code (A["benchy run"]notA[benchy run]); stick to common diagram types and basic edges; one statement per line; no raw</>in labels. The template renders each diagram individually and falls back to showing the source on a parse error (never Mermaid's bomb graphic), but aim to render cleanly. Keep the inlined CSS brand-logo kit (.diagram/.dnode/.dbar) for architecture/network maps where brand logos matter (it has no syntax failure mode). Never leave a relationship as plain prose when a diagram makes it legible; build nodes from elevated neutral surfaces, not flat accent-tinted boxes. - Code / diffs in styled
<pre><code>blocks with a subtle file-path label. Show added/removed lines with color, not just+/-. (A copy-code button is added to everypreautomatically.) - Callouts carry a tone — default warn, or
.ok/.info/.risk; squared, not rounded. Use real<img>for screenshots (they get a click-to-zoom lightbox; adddata-caption), not prose descriptions. - Reader QOL is built into the template — don't reinvent it. Scroll-spy TOC,
reading-progress bar, copy-code buttons, image lightbox, clickable text marks,
comment editing + relative timestamps,
prefers-reduced-motion, print/PDF stylesheet, auto-balanced card grids (.gridcolumns are computed so the last row is never an orphan — 4 cards → 2×2), the "Comment this section" selection popover (select any text or click a Mermaid node → comment pinned to it), and subtle badges (small, low-contrast — never loud filled pills) all ship in the template. Author content; the plumbing is automatic. - Feedback is versioned, not appended forever. Comments are tagged with the
plan version. When you bump to a new
vNand re-deploy, prior-version (and resolved) comments auto-tuck into an "Earlier / resolved" disclosure so the active list only shows feedback for the current version; the copied feedback payload likewise emits only the active comments (plus Decisions). Reviewers can resolve/restore individual comments. - File map / tree as a rendered tree, never plain monospace text. Use the
template's file-tree renderer: a nested
<ul class="filetree">with folder/file Tabler icons, indent guide lines, anddata-new/data-editstatus pills — so it reads like an IDE explorer, not a code block. - Open Questions as answerable chips. Near the bottom, render each open
question as selectable answer buttons (
.qa/.qopt), one option per real choice, with the recommended option markeddata-recand pre-selected by default so the user approves by exception (plus an optional write-in). The user's picks persist and round-trip to the agent under a "Decisions" section in the copied feedback. Don't use plain "Recommended default: …" prose. - Annotation / feedback feature (required on every plan). The reviewer must be
able to comment on any part of the plan, and each comment must be anchored so
the agent knows exactly what it points at. Implement per the Annotation
Contract below; the working implementation lives in
references/html-template.md— reuse it, don't reinvent it.
Annotation Contract
- Anchorable blocks. Give every meaningful block (sections, step cards,
diagrams, code blocks, table rows, open questions) a stable
data-anchor-id="kebab-id"and a human-readabledata-anchor-label. The id must be stable across edits so feedback maps back reliably — derive it from the content, not a random/incrementing counter. - One comment flow: type → optionally pin → save. There is a single
ccommand (dock "Comment" button or theckey) — no separate general-comment command. Pressing it expands the dock into a compose box (same surface as the feedback chat, not a floating window) with a target chip defaulting to "Whole plan". The reviewer types, then optionally pins a target, then saves:- Click a section to pin the comment to that block (chip shows its label).
- Select text inside the plan to pin to that exact span — the selection is captured as a quote and marked/highlighted in the doc (fine-grained, not just whole-section).
- Save without pinning → the comment applies to the whole plan (stored as
anchor-id: __general__, exported[general]). While the composer is open the body is in "assigning" state: blocks highlight on hover with anoutline+outline-offsetgap; nothing highlights while just reading. The chip's ✕ unpins back to whole-plan.
- Fine-grained text marks. Text-anchored comments store the containing block's
anchor-idplus character offsets + the quote, and are visually marked with the CSS Custom Highlight API (::highlight(vp-mark)), reconstructed on load and degrading gracefully where unsupported. Block-anchored comments get a count badge on the block. Clicking a chat entry scrolls to (and flashes) its block or span. - Feedback is a borderless chat that expands the dock. Opening feedback (
f) grows the dock upward (animated) into a compact, scrollable list of all comments — whole-plan, block, and text. Render entries as plain stacked chat messages with no border or card box around them (small accent label, optional quoted line, body, delete on hover). It never shifts or covers the document. - Copy from the dock + ⌘/Ctrl+C. A copy-feedback button sits directly on the
dock (no need to open the chat first), and
⌘/Ctrl+Ccopies all feedback when nothing is text-selected (so normal copy still works). Confirm with a small toast. - Keyboard shortcuts for everything, and visibly shown. Each dock button
carries its shortcut as an always-visible
kbdchip (not just a hover tooltip), and a?overlay lists them all. At minimum:cnew comment,ffeedback chat,ttheme,⌘/Ctrl+Ccopy feedback,?shortcuts overlay,Escclose composer/overlay/dock,⌘/Ctrl+Entersave the open comment. - Animate opening. The dock feedback chat and the composer animate in (grow/fade), not snap.
- Persistence. Store comments in
localStoragekeyed by the plan title so they survive reload. No backend, no network. - Round-trip to the agent. The dock copy button (and
⌘/Ctrl+C) serializes a compact, agent-readable block with two sections: Decisions (the chosen Open Questions answers —question → answer) and Comments (each as[anchor-id: …] (label)for block/text targets, text targets also carrying thequoteof the marked span, or[general]for whole-plan notes, plus the body). The user pastes it back; the agent applies the decisions and uses the anchor id (and quote for text) to locate each comment for targeted edits. Offer a "Download feedback" fallback saving the same payload as a.mdfile. - When the user pastes feedback back, treat the
anchor-id(and quoted span for text comments) as the source of truth for where each comment belongs, address each one with a targeted edit, and preserve every other section.
Quality bar:
- Real content over chrome. Don't add tabs, canvases, or animations that don't earn their place. Visual where visuals help; structured where structure helps.
- Avoid the over-styled "AI" look. Don't wrap every block in a rounded, accent-tinted, colored-border card. Callouts are squared (no rounding); reserve tints and rounding, keep borders restrained, and let typography and spacing carry the hierarchy.
- Self-contained and robust: opening the file twice, or from any directory, must work identically.
- Keep the prose at the quality of a serious technical plan: outcome-first and prose-first; state the objective and what "done" means, scope and non-goals, the approach with key decisions and rationale, ordered steps naming real files and symbols, risks, and a closing verification step that exercises the real workflow (an end-to-end smoke, not just typecheck) — never a step like "make it work". Every plan stands alone (no "this revision"/"as discussed" changelog language); for abstract ideas, lead with one concrete snapshot before the dense architecture. No marketing tone.
See references/html-template.md for the copy-pasteable template (the single
source of truth for structure and the built-in features).
Iterating On Feedback
When the user comments, edit the existing HTML file in place with targeted edits — preserve every existing section and only change what the feedback touches. Re-open or tell the user to refresh. When scope shifts, update the HTML (the document is the source of truth, not the chat) and keep it standalone.
Deploying The Plan To Cloudflare (default handoff)
Always deploy the finished plan to Cloudflare Workers and hand the user the live URL — it's the primary handoff, not an opt-in. Use a temporary account, which needs no Cloudflare signup, login, OAuth, or API token up front. See https://blog.cloudflare.com/temporary-accounts/.
Deploying publishes the plan to the public internet at a hard-to-guess URL. Skip
the deploy only if the user explicitly asks for local-only, or the plan covers
private/unreleased work and they decline a public URL. Each version (vN) gets
its own deploy/URL; keep the prior URLs in the plan's version-timeline popover so
every version stays reachable.
Steps:
-
Put the plan HTML in its own directory as
index.html, e.g.plans/<slug>/index.html(a Worker assets deploy serves a directory, so copy the currentvN.htmlthere asindex.html). -
Write a minimal
wrangler.jsoncnext to it that serves the directory as static assets — no Worker script needed:{ "name": "visual-plan-<slug>", "compatibility_date": "2025-01-01", "assets": { "directory": "." } } -
Always deploy to a TEMPORARY account — never the user's logged-in account.
wrangler deploy --temporaryonly provisions a throwaway account when wrangler is unauthenticated; if the user is logged in, plain--temporarywill use their real account and deploy permanently, which is wrong. Force the temporary flow by isolating wrangler's config (so it can't find the stored OAuth token) and clearing the API-token env vars. Run from the plan directory:# stable per-plan config dir → redeploys reuse the SAME temp account/URL within the 60-min window VP_CFG="${TMPDIR:-/tmp}/vp-wrangler/<slug>"; mkdir -p "$VP_CFG" env -u CLOUDFLARE_API_TOKEN -u CF_API_TOKEN -u CLOUDFLARE_ACCOUNT_ID \ XDG_CONFIG_HOME="$VP_CFG" \ npx wrangler@latest deploy --temporaryThis provisions a fresh temporary account regardless of the user's login. Output shows
Temporary account ready … Claim within: 60 minutes, a Claim URL, and the live*.workers.devURL. (Why it works: wrangler resolves its global config viaXDG_CONFIG_HOME; pointing it at an empty dir + unsetting the token env vars makes wrangler unauthenticated, which is what triggers--temporary.) Never run a barewrangler deployor--temporarywithout the isolation — that uses the user's account. -
Give the user both URLs in chat: the live plan URL to open/share, and the claim URL — and state plainly that the deploy auto-expires in 60 minutes (temporary by design; that's what the user wants) unless they click claim to keep it. Quote the 60-minute window so the expiry is explicit.
-
To push edits within the window, update
index.htmland rerun the same isolated command (sameVP_CFG) from the same directory — it reuses the cached temporary account and redeploys to the same URL.
If Wrangler errors (network, version, or a deploy failure), report what happened
and fall back to handing over the local file:// path; don't loop on retries.
Notes
- By default this skill writes plain local files — nothing leaves the machine. The single HTML file is a shareable artifact: the user can send it or check it in. When the user wants a hosted link, deploy it to Cloudflare with a temporary account (see Deploying The Plan To Cloudflare).
- If the user explicitly wants the plan checked into source control, write it
under
plans/<slug>.htmlinstead of/tmp.
What ships with it: 1 file
90.5 KB alongside SKILL.md
references/
- html-template.md90.5 KB