A research report skill with a fact-check before writing

Research written by one agent blends what it found with what it assumed. Here primary sources, figures, counterpoints and open questions are gathered separately, and a verifier keeps a claim only when it names a source that says it and every figure has a date.

7 steps in 4 stages · 7 subagents · a kit of 12 files

Free. Built in your browser; nothing is uploaded. No API key, no account.

How it runs

Steps in the same stage start at the same time. Each subagent gets only what its incoming edges carry, and a step in a fresh context never sees the reasoning of the steps before it. A gate decides whether the work passes, and a failed gate re-runs the work it checks.

  1. Stage 1
    • Split · Planner

      sonnet · Read

  2. Stage 24 in parallel
    • Primary Sources · Worker

      haiku · Read, WebSearch, WebFetch

    • Figures & Data · Worker

      haiku · Read, WebSearch, WebFetch

    • Counterpoints · Worker

      haiku · Read, WebSearch, WebFetch

    • Open Questions · Worker

      haiku · Read, WebSearch, WebFetch

  3. Stage 3
    • VERIFIER (Fresh Context) · Checker

      opus · Read, Grep, Glob · fresh context

      Gate: Every kept claim names a source that says it, and every figure has a date.

  4. Stage 4
    • Final answer · Writer

      sonnet · Read

Use it when

  • You need a report you can cite, not a summary.
  • The topic has numbers that go out of date.
  • You want the counterarguments, not only the case for.

Change these first

  • Ask the workers to read your own documents as well as the web.
  • Change the final answer's format to the report your readers expect.

Need a workflow built for your team? Fixed-price packages

What you get

An orchestrating SKILL.md, one Claude Code subagent per step with its own tools and model, and the same skill as a Cursor rule. Your agent runs it with its own subagents; nothing on this site calls a model.

research-report-skill-kit.zip12 files
  • .claude/skills/research-report/SKILL.mdorchestrator
  • .claude/skills/research-report/graph.skill.mdgraph source
  • .claude/agents/research-report-splitter.mdsubagent
  • .claude/agents/research-report-sources.mdsubagent
  • .claude/agents/research-report-figures.mdsubagent
  • .claude/agents/research-report-counterpoints.mdsubagent
  • .skill-graph/.gitignoresupport
  • .cursor/rules/research-report.mdcCursor rule
  • README.mdreadme
  • + 3 more subagents
.claude/skills/research-report/SKILL.md
---
name: research-report
description: "Researches a question from four angles in parallel, fact-checks every claim against its source in a fresh context, and writes a sourced report."
---

# research-report

Researches a question from four angles in parallel, fact-checks every claim against its source in a fresh context, and writes a sourced report.

This skill is a graph: each step has its own prompt and context, and only the payloads named below move between steps.

## Plan

Run the stages in order. Every model step runs in its own subagent; do not do a step's work yourself. Only command steps and approvals are yours to run. Steps in the same stage do not depend on each other: start them together, in one message with several subagent calls.

The input (`goal`) is the user's goal: their request, word for word, handed on under `### goal`. Ask for it if the user has not given one.

### Stage 1 · 1 step

- **SPLIT** (`splitter`) → subagent `research-report-splitter`
  - Hand it: the user's goal.
  - Expect: `subtask_json` (json).
  - Contract check (`subtask_json`): save its output to `.skill-graph/research-report/splitter.json`, then run `node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));const k=['sources','figures','counterpoints','open_questions'];const ok=d!==null&&typeof d==='object'&&Array.isArray(d)===false;const m=ok?k.filter((x)=>Object.hasOwn(d,x)===false):k;if(m.length>0){console.error('Missing keys: '+m.join(', '));process.exit(1)}" .skill-graph/research-report/splitter.json` with Bash. Exit code 0 passes.
  - If a contract check fails: re-run this step once with its previous answer and the error output. If it fails again, stop and show the user the output.

### Stage 2 · 4 steps in parallel

- **Primary Sources** (`sources`) → subagent `research-report-sources`
  - Hand it: only the `sources` value from the JSON of SPLIT (`splitter`).
  - Expect: `research_findings` (markdown).
- **Figures & Data** (`figures`) → subagent `research-report-figures`
  - Hand it: only the `figures` value from the JSON of SPLIT (`splitter`).
  - Expect: `research_findings` (markdown).
- **Counterpoints** (`counterpoints`) → subagent `research-report-counterpoints`
  - Hand it: only the `counterpoints` value from the JSON of SPLIT (`splitter`).
  - Expect: `research_findings` (markdown).
- **Open Questions** (`open_questions`) → subagent `research-report-open-questions`
  - Hand it: only the `open_questions` value from the JSON of SPLIT (`splitter`).
  - Expect: `research_findings` (markdown).


… 37 more lines in the kit

Or let Claude adapt it

Add Skill Graph to Claude Code as a connector, then ask. Claude loads this starter, changes it for your project, checks it and hands you the kit.

Set up the connector

Ask Claude

Use Skill Graph: get the research-report template, adapt it to this project, validate it until it has no errors, and compile it for Claude Code.

The graph file

The whole workflow is one Markdown file, graph.skill.md: the steps and edges in the frontmatter, one prompt per step below it. The guide explains every field.

graph.skill.md · 150 lines
---
name: research-report
description: Researches a question from four angles in parallel, fact-checks every claim against its source in a fresh context, and writes a sourced report.
spec: skill-graph/1
topology:
  nodes:
    - id: goal
      type: input
      label: RESEARCH QUESTION
    - id: splitter
      type: orchestrator
      label: SPLIT
      model: sonnet
      tools:
        - Read
    - id: sources
      type: worker
      label: Primary Sources
      model: haiku
      tools:
        - Read
        - WebSearch
        - WebFetch
    - id: figures
      type: worker
      label: Figures & Data
      model: haiku
      tools:
        - Read
        - WebSearch
        - WebFetch
    - id: counterpoints
      type: worker
      label: Counterpoints
      model: haiku
      tools:
        - Read
        - WebSearch
        - WebFetch
    - id: open_questions
      type: worker
      label: Open Questions
      model: haiku
      tools:
        - Read
        - WebSearch
        - WebFetch
    - id: verifier
      type: verifier
      label: VERIFIER (Fresh Context)
      isolated_context: true
      model: opus
      tools:
        - Read
        - Grep
        - Glob
      gate: Every kept claim names a source that says it, and every figure has a date.
      on_fail: retry
      max_retries: 1
    - id: merger
      type: synthesizer
      label: FINAL ANSWER
      model: sonnet
      tools:
        - Read
  edges:
    - from: goal
      to: splitter
    - from: splitter
      to:
        - sources
        - figures
        - counterpoints
        - open_questions
      contract: subtask_json
    - from:
        - sources
        - figures
        - counterpoints
        - open_questions
      to: verifier
      contract: research_findings
    - from: verifier
      to: merger
      contract: checked_findings
contracts:
  subtask_json:
    format: json
    description: One key per worker id; each value is that worker's task.
  research_findings:
    format: markdown
    description: A numbered list of claims; every claim has its source, a short quote and a confidence of high, medium or low.
  checked_findings:
    format: markdown
    description: Only the claims a cited source supports, then the rejected claims with the reason.
---

# Node Prompts & Edge Contracts

## @node: splitter
You are the research lead. Turn the question into four research tasks, one per angle, each saying what to look for and how recent it must be.

Input:
{{goal}}

Output strictly as JSON with one key per worker: `sources`, `figures`, `counterpoints`, `open_questions`. Each value is the exact task for that worker.

## @node: sources
Find ONLY primary sources: official documents, papers, datasets and first-hand accounts, with what each one says.

Your task: {{splitter.sources}}

Return findings as a numbered list. For each one give the source (title and URL), what it says in a short quote, and a confidence of high, medium or low.

## @node: figures
Collect ONLY figures: statistics, dates, prices and measurements, each with where it comes from and how recent it is.

Your task: {{splitter.figures}}

Return findings as a numbered list. For each one give the source (title and URL), what it says in a short quote, and a confidence of high, medium or low.

## @node: counterpoints
Look ONLY for disagreement: credible sources that contradict the obvious answer, and the reasons they give.

Your task: {{splitter.counterpoints}}

Return findings as a numbered list. For each one give the source (title and URL), what it says in a short quote, and a confidence of high, medium or low.

## @node: open_questions
Find ONLY what is unknown or disputed: gaps in the evidence and claims that nobody has checked.

Your task: {{splitter.open_questions}}

Return findings as a numbered list. For each one give the source (title and URL), what it says in a short quote, and a confidence of high, medium or low.

## @node: verifier
You are a fact-checker. Check each claim against the source it cites; reject claims whose source does not say it or is not named.

You only see the raw worker outputs below, not their reasoning. Drop any claim without concrete evidence, merge duplicates, and mark what you rejected and why.

Original input: {{goal}}

Worker outputs:
{{workers.output}}

## @node: merger
Write the research report in Markdown: the answer in two sentences, Key findings with their sources, Where sources disagree, Open questions, and a list of Sources.

{{verifier.output}}