STEP 01 · STRATEGY + OUTLINE01
Submit your topic.
Pass your topic as user_message. The Strategy stage turns it into a position, researches what already ranks, and scopes the supporting claims. The Outline stage normalises the plan into H2/H3 sections ready for Research. You watch both run via SSE.
# Trigger the pipeline. JWT from /api/auth/sign-in carries workspace_id.
$ curl -X POST http://localhost:7878/api/article-jobs \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"brand_voice_id": "33333333-...-...",
"user_message": "How AI coding agents change SDLC",
"audience_level": "intermediate",
"audience_type": "technical",
"tone_preset": "professional",
"article_word_count_preset": "RANGE_2500_3500"
}'
→ 201 Created
{ "id": "a9c3b1e4-..." }
SSE emits:generating_seedsfetching_keywordsclustering_keywordsfetching_serpfetching_competitor_contentparsing_competitor_contentanalyzing_competitorsanalyzing_gapsplanning_articlebuilding_content_briefgenerating_outlinevalidating_outline
TIPReuse the same position across the cluster. Pillar article and sub-articles keep one angle. Depth differs between them.
STEP 02 · RESEARCH02
Watch the research populate.
Research stage extracts topics from the outline, runs SERP queries per topic, and captures facts. The result is a 4-table tree in Postgres (topics → queries → SERP results → facts). You follow along via SSE; the stage takes 40 to 90 seconds for typical articles.
# Subscribe to the SSE stream for live per-step updates.
$ curl -N -H "Authorization: Bearer $JWT" \
http://localhost:7878/api/article-jobs/a9c3b1e4-.../status
→ data: { step: "extracting_topics", status: "processing" }
data: { step: "researching_topics", status: "processing" }
data: { step: "consolidating_research", status: "processing" }
...
SSE emits:extracting_topicsresearching_topicsconsolidating_research
TIPExpect 8 or more tier-A sources for a YMYL topic. Below that, verify-time claim failures climb sharply.
STEP 03 · GENERATE03
Generate with your voice.
The Generate stage loads outline + plan + research from Postgres and drafts the article section by section. Your brand_voice_id fingerprint is applied at draft time through Brand Voice; Brand Guard filters forbidden phrasing inline. The result is article_md + FAQ + JSON-LD.
# SSE continues to stream. These step names appear during Generate.
data: { step: "preparing_generation", status: "processing" }
data: { step: "generating_sections", status: "processing" }
data: { step: "generating_faq", status: "processing" }
data: { step: "assembling_article", status: "processing" }
SSE emits:preparing_generationgenerating_sectionsgenerating_faqassembling_article
TIPVoice-score under 0.80 means the draft does not sound like you yet. Re-fingerprint on 15 to 30 of your most recent articles and re-run.
STEP 04 · VERIFY04
Verify every factual claim.
The Verify stage walks the draft sentence by sentence. For every factual assertion, Perplexity sonar-pro checks the cited source and scores the match. Unverified claims are flagged and rewritten before the stage closes. Typical run: 40 to 60 claims checked, 2 to 6 flagged on a strong source base.
data: { step: "extracting_claims", status: "processing" }
data: { step: "verifying_claims", status: "processing" }
data: { step: "fixing_claims", status: "processing" }
# article_verification_results row written:
# claims_extracted: 58
# claims_verified: 54
# fixes_applied: 4
SSE emits:extracting_claimsverifying_claimsfixing_claims
TIPFix flagged claims by rewriting the draft. The cited source is ground truth; the draft bends to match.
STEP 05 · OPTIMIZE + QUALITY05
Ship through the quality gate.
Optimize normalises formatting, runs SEO and GEO audits, scores the article on combined_score. Quality (the finalize orchestrator) runs an 8-phase pure-function audit: burstiness CV above 0.55, opener diversity above 58 percent, AI pattern ratio under 40 percent, HIGH-severity tells fewer than 10. Fail any one and the job terminates with status FAIL.
data: { step: "normalizing_article", status: "processing" }
data: { step: "running_seo_audit", status: "processing" }
data: { step: "running_geo_audit", status: "processing" }
data: { step: "running_quality_audit", status: "processing" }
data: { step: "running_quality_audit", status: "completed" }
# article_quality_results row:
# quality_score: 0.87
# status: PASS
# needs_humanization: false
SSE emits:normalizing_articlerunning_seo_auditrunning_geo_auditrunning_quality_audit
TIPOn FAIL, the Editor engine fixes patterns without full rewrites. It targets the tells, not the voice.