Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Provides the shared STORM methodology, artifact layout, stage-gating contract, citation hygiene, and retrieval fallback. Use when executing any /storm:* skill (generate, research, outline, write, polish). Internal knowledge; never user-invocable.
.claude/skills/fradser-storm-engine/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 104% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 232% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 44% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 125% | 0% |
Internal knowledge for the STORM plugin. Encodes the methodology ported from Stanford STORM (NAACL'24 / EMNLP'24) into a Claude-native pipeline. Loaded automatically by every /storm:* skill.
The pipeline has two stages and four phases. Each phase is independently runnable and resumable — completed phases are loaded from the artifact directory, never re-run.
Stage 1 (Pre-writing) Stage 2 (Writing)
research ---------> outline ---------> write ---------> polish
(persona (draft + (per-section, (summary +
discovery, refine from cited, parallel) dedup)
simulated Q&A, research)
information table)NEVER skip stage 1. An article generated from parametric memory alone is not a STORM article — it will hallucinate citations and miss the multi-perspective grounding that defines the method. If research/ is absent, run /storm:research first.
NEVER invent citations. Every inline [n] must map to an entry in sources.json collected during research. If a section has no supporting sources, write it without citations and flag the gap in the polish phase — do not fabricate a reference.
All phases read from and write to a single per-topic directory:
<output_dir>/<slug>/
research/
personas.json # discovered personas (name + perspective + rationale)
conversations.jsonl # one record per (persona, turn): question, queries, snippets, answer
sources.json # deduplicated Information objects: {id, title, url, description, snippets}
outline.md # refined outline (markdown headings)
outline-draft.md # pre-research draft (kept for reference)
article.md # per-section draft with inline [n] citations
article-polished.md # final polished article
run-config.json # snapshot of run parametersStage-gating contract: a phase is considered complete when its primary artifact exists and is non-empty. Before running a phase, check its output artifact:
research complete iff research/sources.json exists and has ≥1 entry.outline complete iff outline.md exists and has ≥2 sections.write complete iff article.md exists and every outline section (except Introduction/Conclusion/Summary) has body text.polish complete iff article-polished.md exists.If complete and the user did not pass --force, skip the phase and read its artifact. Log what was skipped.
Derive <slug> from the topic by lowercasing, replacing non-alphanumeric runs with -, trimming leading/trailing -, and truncating to 60 chars. Two topics must not collide — append -2, -3, etc. if the dir already exists with a different run-config.json topic.
--output-dir <path> given → use <path>/<slug>/.--save given → use docs/storm/<slug>/ (relative to cwd; create if missing).$(mktemp -d)/storm-<slug>/. Write run-config.json with "temporary": true and inform the user of the absolute path so they can rescue artifacts if desired. Temporary dirs are NOT cleaned up by the plugin (let the OS handle it), so the user can still resume within the session.CRITICAL: prefer connected MCP search tools, fall back to built-in web search only when no MCP search tool is available.
exa-mcp-server__code-search, exa-mcp-server__research-paper-search, exa-mcp-server__company-search, exa-mcp-server__personal-site-search, exa-mcp-server__financial-report-search, exa-mcp-server__x-search.research-paper-search for academic topics, company-search for organizations).WebSearch + WebFetch.--docs <dir> argument; if given, ingest those files as an additional source pool alongside web results (or instead of, if --docs-only).Source shape (mirrors upstream Information): every source must be normalized to
json{"id": 1, "title": "...", "url": "...", "description": "...", "snippets": ["..."]}
Assign sequential ids as sources are added. The id is the citation key used in inline [n].
[1] / [1][2] form, placed immediately after the claim they support.## References section lists every cited source, numbered to match, with title — url (accessed YYYY-MM-DD).strip_citations(text) -> text removing all [n] and [n][m] patterns.[n] keys present in the body.<!-- TODO: no source --> so polish can flag it.Ground personas in real structure, not hallucination — mirror STORM's "scrape related Wikipedia TOCs" step:
{"name": "...", "perspective": "...", "rationale": "..."}.For each persona, run a multi-turn dialogue between a WikiWriter (asks questions) and a TopicExpert (answers, grounded in retrieval):
question_to_query), retrieves via the retrieval contract above, and answers with inline source attribution.max_turns (default 3) is reached.(question, queries, snippets, answer) tuple into conversations.jsonl and every cited source into sources.json (deduplicated by URL).outline-draft.md) — this is the LLM's prior structure.outline.md.outline.md is the one write consumes.sources.json for retrieval.[n] citations.polish.article.md preserving outline heading structure.[n] in the body resolves to a References entry and vice versa; drop orphan entries on either side.article-polished.md.run-config.json always contains:
json{ "topic": "<original topic>", "slug": "<derived>", "temporary": <bool>, "output_dir": "<absolute>", "max_perspective": 3, "max_turns": 3, "search_top_k": 3, "retrieve_top_k": 3, "retriever": "mcp" | "web" | "local", "started_at": "<ISO from caller>", "phases": {"research": "completed|skipped|pending", ...} }
Timestamps: the plugin MUST NOT call date itself in deterministic contexts — accept started_at from the invoking skill via the caller's environment. In practice the invoking /storm:* skill passes the current time; storm-engine never generates timestamps.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | fail→pass | 7,538 | 4,318 | -43% | 1 | 1 | 0% | 1,382 | 2,816 | +104% | 0 | 0 | — |
case-01 | fail→fail | 55,590 | 23,620 | -58% | 1 | 1 | 0% | 8,301 | 2,716 | -67% | 0 | 0 | — |
case-02 | fail→fail | 50,187 | 7,913 | -84% | 1 | 1 | 0% | 8,279 | 2,674 | -68% | 0 | 0 | — |
case-03 | fail→fail | 49,290 | 7,954 | -84% | 1 | 1 | 0% | 8,283 | 2,619 | -68% | 0 | 0 | — |
case-04 | fail→fail | 10,702 | 6,983 | -35% | 1 | 1 | 0% | 1,772 | 3,282 | +85% | 0 | 0 | — |
case-05 | fail→fail | 2,026 | 2,772 | +37% | 1 | 1 | 0% | 253 | 2,608 | +931% | 0 | 0 | — |
case-06 | pass→fail | 6,899 | 5,943 | -14% | 1 | 1 | 0% | 1,049 | 2,425 | +131% | 0 | 0 | — |
case-07 | fail→fail | 21,092 | 5,280 | -75% | 1 | 1 | 0% | 3,414 | 3,314 | -3% | 0 | 0 | — |
case-08 | fail→pass | 7,221 | 7,852 | +9% | 1 | 1 | 0% | 1,175 | 3,897 | +232% | 0 | 0 | — |
case-10 | fail→fail | 11,302 | 9,365 | -17% | 1 | 1 | 0% | 2,039 | 3,515 | +72% | 0 | 0 | — |
case-11 | pass→pass | 5,261 | 3,775 | -28% | 1 | 1 | 0% | 891 | 2,762 | +210% | 0 | 0 | — |
case-12 | fail→fail | 9,785 | 4,470 | -54% | 1 | 1 | 0% | 1,627 | 2,733 | +68% | 0 | 0 | — |
case-13 | fail→fail | 18,904 | 6,164 | -67% | 1 | 1 | 0% | 2,747 | 3,041 | +11% | 0 | 0 | — |
case-14 | fail→pass | 12,978 | 1,952 | -85% | 1 | 1 | 0% | 2,054 | 2,458 | +20% | 0 | 0 | — |
case-15 | pass→pass | 4,929 | 3,569 | -28% | 1 | 1 | 0% | 732 | 2,752 | +276% | 0 | 0 | — |
case-16 | fail→fail | 7,203 | 3,163 | -56% | 1 | 1 | 0% | 1,082 | 2,765 | +156% | 0 | 0 | — |
case-17 | fail→pass | 10,139 | 3,621 | -64% | 1 | 1 | 0% | 1,853 | 2,674 | +44% | 0 | 0 | — |
case-18 | pass→pass | 6,921 | 1,851 | -73% | 1 | 1 | 0% | 999 | 2,382 | +138% | 0 | 0 | — |
case-19 | fail→pass | 6,332 | 1,923 | -70% | 1 | 1 | 0% | 1,109 | 2,500 | +125% | 0 | 0 | — |
case-20 | pass→pass | 7,606 | 2,381 | -69% | 1 | 1 | 0% | 1,362 | 2,482 | +82% | 0 | 0 | — |
case-21 | pass→pass | 5,508 | 3,077 | -44% | 1 | 1 | 0% | 917 | 2,683 | +193% | 0 | 0 | — |
case-22 | fail→pass | 9,067 | 3,394 | -63% | 1 | 1 | 0% | 1,724 | 2,802 | +63% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 18 counted toward the lift figure. The other 4 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +23 percentage points is the difference between those two pass rates over the 18 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.