Write an article with an editor check before the draft
Drafting first and fixing later produces articles with the wrong angle and unsourced facts. This graph settles the angle, outline, facts and reader in parallel, then an editor in a fresh context checks that every fact has a source and the plan fits the brief before anything is written.
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.
- Stage 1
Split · Planner
sonnet · Read
- Stage 24 in parallel
Angle & Headline · Worker
haiku · Read, WebSearch, WebFetch
Outline · Worker
haiku · Read, WebSearch, WebFetch
Facts & Quotes · Worker
haiku · Read, WebSearch, WebFetch
Reader · Worker
haiku · Read, WebSearch, WebFetch
- Stage 3
VERIFIER (Fresh Context) · Checker
opus · Read, Grep, Glob · fresh context
Gate: Every fact kept has a source, and the angle and outline match the brief's audience and length.
- Stage 4
Final answer · Writer
sonnet · Read
Use it when
- You write posts, articles or newsletters with Claude.
- Drafts come back generic or off-brief.
- Facts in drafts need sources.
Change these first
- Put your style guide in the writer's prompt.
- Add the audience and length to the brief the planner reads.
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.
- .claude/skills/write-an-article/SKILL.mdorchestrator
- .claude/skills/write-an-article/graph.skill.mdgraph source
- .claude/agents/write-an-article-splitter.mdsubagent
- .claude/agents/write-an-article-angle.mdsubagent
- .claude/agents/write-an-article-outline.mdsubagent
- .claude/agents/write-an-article-facts.mdsubagent
- .skill-graph/.gitignoresupport
- .cursor/rules/write-an-article.mdcCursor rule
- README.mdreadme
- + 3 more subagents
---
name: write-an-article
description: "Plans an article, post or newsletter from four angles in parallel, has an editor check the notes in a fresh context, and writes the draft."
---
# write-an-article
Plans an article, post or newsletter from four angles in parallel, has an editor check the notes in a fresh context, and writes the draft.
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 `write-an-article-splitter`
- Hand it: the user's goal.
- Expect: `subtask_json` (json).
- Contract check (`subtask_json`): save its output to `.skill-graph/write-an-article/splitter.json`, then run `node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));const k=['angle','outline','facts','reader'];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/write-an-article/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
- **Angle & Headline** (`angle`) → subagent `write-an-article-angle`
- Hand it: only the `angle` value from the JSON of SPLIT (`splitter`).
- Expect: `content_notes` (markdown).
- **Outline** (`outline`) → subagent `write-an-article-outline`
- Hand it: only the `outline` value from the JSON of SPLIT (`splitter`).
- Expect: `content_notes` (markdown).
- **Facts & Quotes** (`facts`) → subagent `write-an-article-facts`
- Hand it: only the `facts` value from the JSON of SPLIT (`splitter`).
- Expect: `content_notes` (markdown).
- **Reader** (`reader`) → subagent `write-an-article-reader`
- Hand it: only the `reader` value from the JSON of SPLIT (`splitter`).
- Expect: `content_notes` (markdown).
… 37 more lines in the kitOr 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 connectorAsk Claude
Use Skill Graph: get the write-an-article 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: write-an-article
description: Plans an article, post or newsletter from four angles in parallel, has an editor check the notes in a fresh context, and writes the draft.
spec: skill-graph/1
topology:
nodes:
- id: goal
type: input
label: BRIEF (topic, audience, length, voice)
- id: splitter
type: orchestrator
label: SPLIT
model: sonnet
tools:
- Read
- id: angle
type: worker
label: Angle & Headline
model: haiku
tools:
- Read
- WebSearch
- WebFetch
- id: outline
type: worker
label: Outline
model: haiku
tools:
- Read
- WebSearch
- WebFetch
- id: facts
type: worker
label: Facts & Quotes
model: haiku
tools:
- Read
- WebSearch
- WebFetch
- id: reader
type: worker
label: Reader
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 fact kept has a source, and the angle and outline match the brief's audience and length.
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:
- angle
- outline
- facts
- reader
contract: subtask_json
- from:
- angle
- outline
- facts
- reader
to: verifier
contract: content_notes
- from: verifier
to: merger
contract: approved_notes
contracts:
subtask_json:
format: json
description: One key per worker id; each value is that worker's task.
content_notes:
format: markdown
description: A numbered list of notes, each marked with its source or as opinion.
approved_notes:
format: markdown
description: The notes that passed the edit, then the cut ones with the reason.
---
# Node Prompts & Edge Contracts
## @node: splitter
You are the managing editor. Read the brief and give each writer the part of the piece they prepare, with the audience and length in mind.
Input:
{{goal}}
Output strictly as JSON with one key per worker: `angle`, `outline`, `facts`, `reader`. Each value is the exact task for that worker.
## @node: angle
Work ONLY on the angle: three possible headlines with a hook for each, and which one fits the audience best and why.
Your task: {{splitter.angle}}
Return your notes as a numbered list. Mark each note with the source it rests on, or with "opinion" when it rests on none.
## @node: outline
Write ONLY the outline: the sections in order, the point of each one, and where examples go.
Your task: {{splitter.outline}}
Return your notes as a numbered list. Mark each note with the source it rests on, or with "opinion" when it rests on none.
## @node: facts
Gather ONLY the facts the piece needs: claims, figures and quotes, each with its source.
Your task: {{splitter.facts}}
Return your notes as a numbered list. Mark each note with the source it rests on, or with "opinion" when it rests on none.
## @node: reader
Think ONLY about the reader: what they already know, the questions they will ask, and the jargon to avoid.
Your task: {{splitter.reader}}
Return your notes as a numbered list. Mark each note with the source it rests on, or with "opinion" when it rests on none.
## @node: verifier
You are the editor. Check each note for accuracy and for fit with the brief.
You only see the raw worker outputs below, not their reasoning. Cut every factual note without a source and every note off the brief, merge duplicates, and list what you cut and why.
Original input: {{goal}}
Worker outputs:
{{workers.output}}
## @node: merger
Write the piece from the approved notes: the headline, a hook paragraph, the sections of the outline, and a closing line. Use only facts from the notes, in the voice and length the brief asks for.
{{verifier.output}}
More starter graphs
- PR reviewSecurity, performance, architecture and test coverage reviewers
- Bug triageStack trace, logs, recent commits and a minimal repro
- RFC discoveryFeasibility, prior art, interface design and failure modes
- Ship a changeEdit until tests pass, review the diff in parallel, approve once before the PR
- Review each fileOne fresh-context review per changed file, however many there are, then merge and gate
- Parallel auditResearch, compare, check and find gaps, then verify in a fresh context
- Research reportSources, figures, counterpoints and open questions, fact-checked in a fresh context
- Analyze a datasetProfile, clean, analyze and sanity-check a table in parallel, then re-check every figure
- Design an appUsers, features, screens and data model in parallel, then a product review before the spec