ContentForge — Enterprise Content Production
Transform a content requirement into a publication-ready, fact-checked, brand-compliant, SEO-optimized piece through a 10-phase autonomous agent pipeline (plus Step 0.5 title curation) with three-layer fact verification and 10 quality gates.
Context efficiency
Pipeline phase. Grep before Read for references/, humanization-patterns.json, brand voice profiles. Hand subagents artifact file paths plus a ≤10-line summary — never reload or inline full drafts (see Context & Handoff Rules). On /contentforge:resume, load run.json plus only the artifacts the next phase contractually needs.
Execution Protocol (CRITICAL — read first)
This skill orchestrates 10 phases plus Step 0.5 (Title Curation). Each numbered phase MUST be executed by invoking its dedicated subagent via the Task tool — DO NOT generate the deliverable yourself in a single inference pass. A single-pass generation skips the quality gates, fact-checking layers, humanizer 43-pattern catalog (29 core + 6 structure/framing + 8 detector-signal), and reviewer scoring that define ContentForge.
The one exception is Step 0.5: title curation is performed inline by the orchestrator (no subagent), because it requires user interaction and subagents must never wait on the user. Any subagent that needs a user decision returns a {"status": "needs_user_decision", ...} payload to the orchestrator, which owns all user interaction (including image-generation opt-in/approval).
Portable execution lane — platforms without subagent dispatch (Codex, ChatGPT, single-context clients)
If your platform has no subagent/Task dispatch, the pipeline still runs — sequentially, in this conversation, with nothing waived:
- Each phase's contract is its agent file. Before executing a phase, Read
agents/{NN}-{name}.md from the plugin directory and follow it as your instructions for that phase — INPUTS, EXECUTION STEPS, OUTPUT FORMAT, and the gate. The files are plain markdown written to be executable by whoever holds them; a subagent was always just a fresh context around the same text.
- Same artifacts, same names, same gates. Write every phase artifact to the run directory exactly as the Pipeline Contract specifies, checkpoint after each phase, and run every gate script. The auditability of a run must not depend on which platform produced it.
- What changes: ignore per-agent
maxTurns (they bound subagent sessions, not you); "return as your final output" means "write the artifact, then continue"; Progress Updates print inline. What does not change: the phase order, the loop budgets, the gate criteria, and the rule that a needs-user-decision moment stops for the user.
- Context discipline replaces context isolation. Subagents exist to give each phase a clean context. Without them, do not carry a phase's working notes forward — after checkpointing a phase, work only from the artifacts on disk, exactly as a fresh subagent would.
- Environment names: on Agent Plugins 1.0 hosts the plugin root is
${PLUGIN_ROOT} and persistent data is ${PLUGIN_DATA}; where a command below says ${CLAUDE_PLUGIN_ROOT}, use whichever of the two names your host defines. The scripts themselves accept both data-dir spellings.
Step 0 — Initialize the run (orchestrator only, before Step 0.5)
# 1. Create the checkpoint run (returns run_id). Capture run metadata so a
# cross-session resume can recover keyword, audience, word count, and tone.
RUN_RESULT=$(python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py init \
--brand <brand-slug> --topic "<topic>" --content-type <type> \
--keyword "<primary keyword>" --audience "<audience>" \
--word-count <n> --tone "<tone>")
# These flags land in run.json under meta.keyword / meta.audience /
# meta.word_count / meta.tone — use those exact key names when reading them back.
# Parse RUN_ID from the JSON result's "run_id" field.
# 2. Initialize the performance tracker for this run.
python ${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tracker.py --action init \
--brand <brand-slug> --run-id "$RUN_ID" --content-type <type> --topic "<topic>"
Rules:
pipeline-tracker.py is called by the orchestrator only — subagents never call it.
- Step 0.5 is exempt from tracker calls (no
phase-start/phase-end for 0.5). After the title is confirmed, checkpoint it directly (see contract table).
- If the user supplied their own draft (
--source-draft <path>, or they paste/dictate their own rough words), copy it verbatim to {run_dir}/source-draft.md here in Step 0 and set "source_draft": true in run.json. Do not clean it up on the way in — the mess is the signal. See "Bring your own words" below.
Required Per-Phase Workflow (Phases 1–8)
For every numbered phase:
Mark phase start (orchestrator):
python ${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tracker.py --action phase-start --brand <slug> --run-id "$RUN_ID" --phase <N>
Call Task with the phase's qualified subagent_type (e.g. contentforge:researcher). The Task prompt contains ONLY:
- the artifact file paths the phase reads (per the Pipeline Contract table),
- a ≤10-line orchestrator summary of pipeline state,
- the brand-profile path (required for phases 0.5, 3, 5, 6, 6.5, 7),
- the original-requirements block (topic, confirmed title, content type, audience, primary keyword, word-count target, tone).
Subagents Read what they need from those paths. Never inline a full draft into a Task prompt.
Verify the quality gate yourself. Gate ownership belongs to the orchestrator: check the returned artifact against the gate criteria in the Pipeline Contract table — count sources, check word count and citation density, and run python ${CLAUDE_PLUGIN_ROOT}/scripts/text-metrics.py --file <artifact-path> [--keyword "<primary keyword>"] for burstiness, Flesch-Kincaid grade, and keyword-placement checks (--file is required). A subagent's self-reported "PASS" alone is not a gate pass.
If a subagent returns nothing, or stops mid-sentence: audit the disk before you re-run it. A live run had its output-manager complete the .docx, all four delivery copies and the tracking update, then return only "Now generating the .docx with the real script." — no report, and its contracted phase-8-output.json unwritten. Re-running it blind would have regenerated finished work; declaring the phase failed would have been false. The principle above already implies the remedy — disk state is the authority, not the message — so make it the procedure: list the run directory, check which contracted artifacts exist, verify those against the gate, and ask the SAME agent for the missing piece rather than starting a new one. Only treat a phase as un-run when its artifacts are genuinely absent.
The same rule applies on resume: checkpoint-manager.py status reports orphaned_artifacts for phases whose artifact exists but was never checkpointed. Never re-run a phase listed there without looking at what is already on disk — but never checkpoint it unverified either. An unverified artifact is a claim, not a pass.
On gate PASS, checkpoint the artifact so the run is resumable:
python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py save \
--brand <slug> --run-id "$RUN_ID" --phase <N> --content-file <artifact-path> --extension <md|json|txt>
Phases 3.5 and 6 also produce a companion manifest (phase-3.5-visual-manifest.json, phase-6-structure-manifest.json) — place it at its canonical path inside the same run directory.
Mark phase end with the output word count:
python ${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tracker.py --action phase-end --brand <slug> --run-id "$RUN_ID" --phase <N> --content-words <count>
Emit the audit line (so users can see real-time progress):
[PHASE-AUDIT] phase=<N> name=<name> status=<PASS|FAIL> output_summary="<one line>" gate=<PASS|FAIL>
On gate FAIL, loop per the contract table's loop-target column. Before looping, record the loop and check limits:
python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py loop --brand <slug> --run-id "$RUN_ID" --edge phase_<N>_to_<target>
Limits: max 2 loops per edge, max 5 loops total per run. If a limit is reached: do NOT loop — mark the run for human review, finalize --status failed, and halt. When Phase 7 orders rework, the pending_rework field in run.json records the target phase and the reviewer's feedback so /contentforge:resume continues the rework instead of skipping it. Do not overwrite the saved checkpoint of an upstream phase that already passed — re-save only the looped phase when it passes.
Lifecycle steps (orchestrator-owned, v4.0)
Two small steps wire each run into the brand's living state. Both are cheap, both
are honest about missing inputs, and neither ever blocks a run:
After Gate 1 passes — merge the run's verified link inventory into the
brand profile, so the reconnaissance stops evaporating with the run:
python ${CLAUDE_PLUGIN_ROOT}/scripts/harvest-brand-pages.py \
--merge-inventory <run_dir>/phase-1-link-inventory.json --brand <slug>
Service/product and authority rows upsert (existing manual curation is never
overwritten — stamps refresh only); conversion rows only STAGE under
brand_pages.recon_candidates for the user to confirm, because a CTA is a
commercial decision. If the inventory file is missing (pre-4.0 agent, no
website), report that and continue — never fabricate rows.
Before dispatching Phase 3 — ask telemetry for drafter advisories:
python ${CLAUDE_PLUGIN_ROOT}/scripts/telemetry.py advisories --brand <slug>
When status is ok and advisories exist, append their brief_lines to the
Phase 3 Task prompt's requirements block. When insufficient_history, append
nothing — the floor is the point; a brief fed from fewer runs than the floor
is fed from anecdote. Advisories inform drafting style only: they NEVER
modify a gate, a threshold, or a verdict.
Image approval (orchestrator-owned, after Phase 3.5)
The visual-asset-annotator never waits on the user. It generates candidates (when image generation is opted in) and records each in phase-3.5-visual-manifest.json with approved_by_user: false. After Gate 3.5 passes, the orchestrator presents the generated visuals to the user for approval:
- Show each generated asset (path + description + placement) and ask approve / regenerate / drop.
- Update
approved_by_user in the manifest for approved assets.
- For rejects, re-invoke
contentforge:visual-asset-annotator with the rejection feedback (counts as a Phase 3.5 re-run, not a loop edge).
- Phase 8 embeds only assets with
approved_by_user: true — unapproved assets stay out of the .docx.
If the annotator returns {"status": "needs_user_decision", ...} (e.g., image-generation opt-in was never given), ask the user, then re-invoke with the answer.
Pipeline Contract (inputs → outputs → gate → loop target)
All artifacts live in the canonical run directory ~/.claude-marketing/{brand-slug}/runs/{run_id}/ alongside run.json (the manifest).
The machine-readable form of this table is config/pipeline-graph.json, and that file is authoritative for the pipeline's shape — nodes, reads/writes, gates, budgeted loop edges. This table narrates it for humans; tests/test_pipeline_contract_graph.py fails the build if the two (or the agent files, or checkpoint-manager.py, or run-audit.py) ever disagree. Before v4.0 this contract lived as prose in four places at once, and they drifted twice in ways no unit test could see.
| Phase |
subagent_type |
Reads (paths) |
Writes (artifact) |
Quality gate (orchestrator-verified) |
Gate-FAIL loop target |
| 0.5 |
— inline (orchestrator) |
brand profile, requirements |
phase-0.5-title.txt |
User-confirmed title (or --title bypass) — user checkpoint, not a numbered quality gate |
Regenerate title options |
| 1 |
contentforge:researcher |
phase-0.5-title.txt, requirements, brand profile |
phase-1-research.md + phase-1-link-inventory.json (the verified Internal-Link Inventory as data rows — v4.0) |
Gate 1: 12–15 sources collected; ≥10 citable; ≥5 with reliability ≥8; differentiated angle documented; Client Site Reconnaissance complete; ≥3 verified deep brand URLs when the brand has a website |
Re-run Phase 1 with broader search |
| 2 |
contentforge:fact-checker |
phase-1-research.md |
phase-2-factcheck.md |
Gate 2: ≥80% of claims verified; zero UNRESOLVED flags (flagged claims must be removed or re-sourced); ≤3 unverified tolerated; all cited URLs live |
Phase 1 (find alternative sources) |
| 3 |
contentforge:content-drafter |
phase-0.5-title.txt, phase-1-research.md, phase-2-factcheck.md, brand profile, requirements (+ telemetry advisories when the floor is met — see "Lifecycle steps" below) |
phase-3-draft.md |
Gate 3: body_word_count ±10% of target — not word_count, which includes the reference list (a live run drafted a 1,779-word body under a 1,200-word target while word_count read 2,887). What body_word_count counts, stated so nobody has to invent a convention: the prose a reader reads, plus H2/H3 headings. It excludes the H1, the bold **Key:** value metadata block, horizontal rules, HTML comments, [VISUAL-PLACEHOLDER: …] annotation lines (production instructions for Phase 3.5 that never publish), block image embeds and the italic figure-caption line directly beneath each (figure furniture — on a live run three approved charts' alt texts and captions moved the measured body from 1,274 gate-passed words to 1,501, which would have failed the final audit for having its figures described properly), and every trailing reference/appendix section. This matters: on one live draft the two defensible readings gave 1,390 (FAIL) and 1,223 (PASS) for the same file — a gate whose verdict depends on an unstated convention is not a measurement. Do not hand-count; read the field; all outline sections covered; ≥1 citation per 300 words |
Re-run Phase 3 |
| 3.5 |
contentforge:visual-asset-annotator |
phase-3-draft.md, phase-2-factcheck.md, phase-1-research.md (SERP visual patterns) |
phase-3.5-visuals.md (contains the ANNOTATED draft — the operative article from here on) + phase-3.5-visual-manifest.json |
Gate 3.5: every chart traceable to a verified statistic; manifest complete (placement, alt text, data source); human-action TODOs marked |
Re-run Phase 3.5 |
| 4 |
contentforge:scientific-validator |
phase-3-draft.md, phase-3.5-visuals.md, phase-3.5-visual-manifest.json, phase-2-factcheck.md, phase-1-research.md (the Verified Outline, required by its Step 6.1) |
phase-4-validation.md + phase-4-fixes.json (the fix ledger — required whenever the report names a correction, empty items is valid) |
Gate 4: zero hallucinations; every claim traceable to a cited source; logic consistent; fix-ledger.py validate exits 0 and every correction in the report appears in the ledger |
Phase 3 (with the specific claims to fix) |
| 5 |
contentforge:structurer-proofreader |
phase-3.5-visuals.md (the ANNOTATED draft — the operative article text, with the VISUAL anchors that must survive), phase-3-draft.md (pre-annotation reference), phase-4-validation.md, phase-4-fixes.json, brand profile |
phase-5-structured.md |
Gate 5: fix-ledger.py verify reports zero unresolved blocking items (HARD); zero grammar/spelling errors on re-scan; readability within ±0.5 grade of the content-type target (text-metrics.py); brand terminology compliance |
Re-run Phase 5 |
| 6 |
contentforge:seo-geo-optimizer |
phase-5-structured.md, phase-1-research.md (Internal-Link Inventory), phase-3.5-visual-manifest.json (feature image), brand profile, requirements (keyword) |
phase-6-seo.md + phase-6-structure-manifest.json |
Gate 6: keyword PLACEMENTS present — title, first 100 words, ≥2 H2s, conclusion, meta description (density is advisory, ~1–2%); meta title + description generated; all internal-link URLs verified live (HARD); ≥2 deep brand links when site known (scored+flag) |
Re-run Phase 6 |
| 6.5 |
contentforge:humanizer |
phase-6-seo.md, phase-6-structure-manifest.json, phase-4-fixes.json (the applied-fix protected set), brand profile, source-draft.md (when present) |
phase-6.5-humanized.md (article body only — authorship.py measures this file) + phase-6.5-report.md + phase-6.5-review-sheet.html + phase-6.5-pattern-hits.json (per-pattern fire counts for telemetry.py — v4.0) + phase-6.5-authorship.json (only when source-draft.md exists) |
Gate 6.5: grounding pass complete; 43-pattern catalog; GEO structure preserved; keywords preserved; AI-tell scan reported (advisory); burstiness advisory; with an author draft: authorship.py exits 0 — zero author sentences rewritten or dropped (NOT advisory); fix-ledger.py verify does not exit 3 — a style pass may not undo an applied accuracy correction (NOT advisory) |
Re-run Phase 6.5 with the violated constraint stated (incl. structure-manifest mismatch, authorship violations, or a regressed ledger fix) |
| 7 |
contentforge:reviewer |
ALL prior artifact paths, phase-4-fixes.json, brand profile, requirements, config/scoring-thresholds.json |
phase-7-review.json (includes publication_status + fix_ledger) + phase-7-fix-ledger.json (the verify payload, written by the script as UTF-8 so the reviewer copies bytes rather than scraping a console) + phase-7-review-pre-remediation.json (re-review mode only: the prior review, preserved before re-scoring — the old score is evidence, not garbage) |
Gate 7: reviewer decision tree per config/scoring-thresholds.json — approve ≥7.0 (industry-adjusted); all dimension minimums met; dead internal link = hard FAIL; homepage-only linking caps the sub-score and surfaces on the Completion Card; fix_ledger copied from fix-ledger.py verify, never re-derived by hand |
5.0–6.9 → loop to responsible phase (recorded as pending_rework); <5.0 → human review, halt |
| 8 |
contentforge:output-manager |
phase-6.5-humanized.md, phase-6.5-report.md, phase-7-review.json, phase-3.5-visual-manifest.json, phase-6-seo.md (SEO Scorecard for Appendix A), run.json, phase-6.5-authorship.json (when present) |
phase-8-output.json + .docx |
Gate 8: .docx generated; all four appendices present — A (SEO Scorecard), B (Quality Scorecard), C (Production Details), D (Internal Link Map) — matching appendices_present: 4 in config/scoring-thresholds.json; delivery location verified. This row previously said A/B/C while the config required 4, and this file states that the config wins where they disagree — so a Phase 8 emitting only A/B/C would have passed the documented gate and failed the configured one. Also: the body must carry no production scaffolding and must anchor every generated asset — text-metrics.py reports residual_scaffolding.clean: true and visual_markers.ids covering every manifest asset with status: generated. One run delivered three raw [VISUAL-PLACEHOLDER: …] lines to the reader and embedded none of its three valid charts, because Phase 3.5's marker replacement never landed and nothing downstream compared the two. And: fix-ledger.py verify runs here and sets publication_status. Unresolved blocking corrections do not stop the .docx being produced — they stop it being called ready: DRAFT- filename prefix, publication_blockers in phase-8-output.json, and the blocked status in the tracking row |
Re-run Phase 8; if generation still fails, save markdown + reports locally and report the failure |
That is 10 quality gates — one for each of phases 1, 2, 3, 3.5, 4, 5, 6, 6.5, 7, and 8.
Single source of truth for numbers: approval thresholds, loop bands, dimension weights, dimension minimums, and industry overrides live in config/scoring-thresholds.json. Prose in this document references those values; if they ever disagree, the config wins.
Context & Handoff Rules
- Subagents receive artifact paths, a ≤10-line orchestrator summary, the brand-profile path (phases 0.5, 3, 5, 6, 6.5, 7), and the original-requirements block. They
Read what they need.
- Never inline a full draft into a Task prompt, and never reload a full draft into the orchestrator's context when a path reference will do.
- The reviewer (Phase 7) must receive the paths of all prior artifacts, not just the Phase 6.5 output.
Final Output Requirements
After Phase 8 completes, the output-manager subagent must produce a Microsoft Word .docx file by calling:
python ${CLAUDE_PLUGIN_ROOT}/scripts/generate-docx.py \
--content <article.md> \
--output <local-path>.docx \
--reports <reports.json> \
--brand "<brand>" \
--content-type <type>
The .docx must contain: title page, full article body, sources/citations, Appendix A (SEO Scorecard), Appendix B (Quality Scorecard), Appendix C (Production Details).
Dual-copy save: the .docx is written into the run directory (~/.claude-marketing/{brand-slug}/runs/{run_id}/) AND copied to the user-visible folder ~/Documents/ContentForge/{Brand}/. Always tell the user the ~/Documents/ContentForge/ path. If the brand has Google Drive configured (tracking.backend == "google_sheets" with a tracking.google_drive.folder_id), additionally upload the .docx via drive-uploader.py.
Then audit, and only then finalize:
# 1. Re-derive every gate from the artifacts. This is not optional ceremony:
# finalize --status completed REFUSES without a fresh CLEAN verdict on disk.
python ${CLAUDE_PLUGIN_ROOT}/scripts/run-audit.py --brand <slug> --run-id "$RUN_ID"
# 2. Close the run.
python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py finalize --brand <slug> --run-id "$RUN_ID" --status completed
What the audit is. run-audit.py re-checks the finished run the way an outside auditor would: every completed phase has its artifact, no orphaned artifacts in a finalized run, the delivered body carries no production scaffolding and anchors every generated asset, the authorship record matches a fresh measurement, no fix-ledger correction was lost or undone, an APPROVED decision is backed by its own score, and no completed status hides a blocked publication. Every one of those is a failure that actually happened in a real run while every individual artifact looked healthy. The verdict lands in run-audit.json inside the run directory.
When the audit fails: fix the findings and re-run it — or, if the run is legitimately unpublishable as it stands (an open requires_human blocker, say), finalize with --status blocked, which needs no audit because it claims nothing. finalize --skip-audit exists as an escape hatch that stamps audit_skipped: true into run.json: the absence of verification becomes part of the record rather than a silence.
Why This Matters
Skipping the Task-tool orchestration means: no real fact-checking, no real humanizer (43-pattern AI removal won't fire, including detector-signal patterns 36-43), no real reviewer scoring — the pipeline becomes single-pass content generation labeled with fake phase names. The audit trail (run.json, the per-phase checkpoint artifacts, [PHASE-AUDIT] lines, real reviewer score) is the proof of execution. If those artifacts don't exist after a run, the pipeline didn't actually run.
When to Use
Use /contentforge when you need:
- Single high-quality content piece (article, blog, whitepaper, FAQ, research paper)
- Research-backed content with verified citations
- Brand-compliant content for regulated industries (Pharma, BFSI, Healthcare, Legal)
- SEO-optimized content with keyword targeting and meta tags
- Natural-sounding content with AI patterns removed (Phase 6.5 Humanizer)
For multiple pieces, use /contentforge:batch-process — a prioritized, checkpointed queue that runs the same pipeline per piece.
Express Lane (bring your own research)
When the user already has the research — pasted sources, internal notes with URLs, an existing source dossier — and asks for speed ("express", "I have my own sources", "quick article from my notes", or --express), run the EXPRESS phase set instead of the full pipeline. Verification is the product; ceremony is optional. Express is fast because the intake replaces Phase 1's deep research hunt — which dominates full-pipeline wall-clock — not because it skips craft. It keeps every verification gate AND the craft passes that make the piece read human, and drops only the phases whose value depends on surfaces outside the prose:
| Express phase |
Agent |
Contract change vs full pipeline |
| 0.5 Title |
— inline |
unchanged |
| 1-INTAKE |
contentforge:researcher |
Intake mode, not research mode: catalog ONLY the user-provided sources into the standard phase-1-research.md shape — no new source hunting. Gate 1-E: every source carries a URL (or is labeled user-provided, unverifiable), a reliability rating, and the differentiated angle is documented from the user's own framing. Tell the researcher explicitly: "intake mode — structure and rate what was provided; do not expand the source set." |
| 2 Fact-Check |
contentforge:fact-checker |
UNCHANGED — Gate 2 in full. The user's sources get the same verification as found sources; user affection for a claim is not evidence. |
| 3 Draft |
contentforge:content-drafter |
unchanged (Gate 3 in full) |
| 4 Validation |
contentforge:scientific-validator |
UNCHANGED — Gate 4 in full. The draft-vs-ledger hallucination diff is part of the verification thesis, not polish. |
| 5 Structure |
contentforge:structurer-proofreader |
Runs by default — Gate 5 in full. Proofreading and content-type structure are craft, not ceremony; a fast piece with typos is not a deliverable. Skippable only by explicit --skip-structure. |
| 6.5 Humanizer |
contentforge:humanizer |
Runs by default — Gate 6.5 in full. Nobody orders express robot prose: the 43-pattern de-AI pass and brand-personality layer ship in every lane unless the user explicitly opts out with --skip-humanizer. Reads the latest artifact (phase-5-structured.md, or phase-3-draft.md if structure was skipped); the GEO-structure-preservation and keyword-preservation checks apply only when Phase 6 ran. |
| 7 Review |
contentforge:reviewer |
Gate 7 with the express review contract (see the reviewer agent's Express runs section): skipped-phase artifacts are legitimately absent — score those dimensions from the piece itself instead of capping them; SEO dimension is N/A unless Phase 6 ran; the dead-link hard fail applies ALWAYS. |
| 8 Output |
contentforge:output-manager |
unchanged; Appendix A (SEO Scorecard) is replaced by an "Express run — SEO not performed" note |
Skipped by default, each re-addable by flag: Phase 3.5 visuals (--with-visuals) and Phase 6 SEO/GEO (--with-seo) — the two phases whose value depends on production surfaces outside the prose (asset creation, search targeting). When a flag re-adds a phase, its full gate comes with it — there is no gate-less phase in any lane. The craft passes may be dropped only by explicit request (--skip-structure / --skip-humanizer); a chosen skip is recorded in skipped_phases like any other, and the reviewer then scores those qualities from the piece itself.
Record the lane: write "mode": "express" and the skipped_phases list into run.json at run start — the reviewer and output-manager read it to apply the express contracts. A run without mode is a full run.
What express is NOT: it is not a lower quality bar — Gates 2, 4, and 7 are identical, and the piece is still proofread (Gate 5) and humanized (Gate 6.5) unless the user explicitly opted out. It produces a verified, validated, proofread, humanized, reviewed piece WITHOUT keyword optimization or visuals. Say this plainly to the user when they choose express, and offer --with-seo / --with-visuals if they hesitate.
Bring your own words (--source-draft)
The pipeline's default mode writes from research. This mode keeps the author in the piece.
Give it your own rough draft — a voice-note transcript, a wall of bullets, three angry paragraphs typed at midnight — and ContentForge builds the article around your sentences instead of over them. Quality of the input is irrelevant; authorship is the whole point.
/contentforge:contentforge "why our review estimates were wrong" --source-draft ./notes.md
What changes:
| Phase |
Behaviour with an author draft |
| 0 Init |
Your draft is copied verbatim to {run_dir}/source-draft.md; run.json records source_draft: true |
| 3 Draft |
Your sentences are carried into the draft verbatim — typos, run-ons, lowercase and all. Research and structure are added between them |
| 5, 6 |
Structure and SEO work around your sentences; they are never rewritten to fit a keyword |
| 6.5 Humanizer |
The 43-pattern catalog does not apply to your sentences. If you wrote "here's the thing", it stays. Then scripts/authorship.py verifies nothing of yours was paraphrased or lost |
| 7 Review |
A rewritten or dropped author sentence blocks approval until it is restored verbatim |
| 8 Output |
The disclosure becomes provenance-accurate: "Written by {you} with AI assistance for research, structure, and fact-checking" — but only if the record proves it |
Three honest limits, stated plainly:
- Your sentences are your voice, not verified facts. Anything factual the pipeline adds still comes from the Phase 2 ledger. If one of your claims contradicts the research, it gets flagged for you, not silently corrected — you decide.
- The authored disclosure has to be earned. It appears only when at least 25% of the finished words are yours verbatim AND none of your sentences were rewritten or dropped. It can never be turned on by asking; it is read off the record. A disclosure that overstates human authorship is the one kind a reader cannot check, so this direction is one-way by design.
- There is no target ratio and nothing here is aimed at a detector.
author_word_share exists so the disclosure can be accurate. Writing more of the piece yourself makes it more yours; it is not a score, and no number turns text "human enough".
What This Command Does
Runs your content through 10 specialized agents, each behind a quality gate:
- Research Agent — SERP analysis, source mining, competitive analysis, structured outline
- Fact Checker — URL verification, claim validation, confidence scoring
- Content Drafter — First draft with brand voice, SME calibration via industry knowledge packs
- Visual Asset Annotator — Chart generation from verified stats, visual markers, asset manifest
- Scientific Validator — Hallucination detection, domain-specific validation, logic validation
- Structurer & Proofreader — Grammar/spelling correction, readability optimization, brand compliance
- SEO/GEO Optimizer — Keyword placements, meta tag generation, internal linking markers
- Humanizer — AI pattern removal (43-pattern catalog), content-derived sentence variation (burstiness advisory), brand personality
- Reviewer — 5-dimension quality scoring (weights per
config/scoring-thresholds.json)
- Output Manager — .docx with embedded charts and internal links, dual-copy save, optional Drive upload
Quality Gates: 10 gates (phases 1–8 including 3.5 and 6.5). On failure the pipeline loops per the contract table — max 2 loops per edge, max 5 total, then human escalation.
Required Inputs
Minimum Required:
- Topic — What the content is about (e.g., "AI in Healthcare", "remote work productivity")
- Content Type — article, blog, whitepaper, faq, research_paper, video_script, case_study, newsletter
- Brand — Which brand profile to use (create with
/contentforge:cf-style-guide if new brand). See No-Brand Mode below if none exists.
Pre-Flight Validation: After gathering inputs, validate the brand profile for completeness (voice, guardrails, audience, industry pack). For regulated industries (pharma, BFSI, healthcare, legal), guardrails are required — warn if they're empty and ask whether to proceed or update the profile first.
Optional:
- Target Audience — Who this content is for (e.g., "Healthcare CIOs")
- Word Count — Target length (defaults to content type standard)
- Primary Keyword — Main SEO keyword to optimize for
- Tone — Overrides brand default (authoritative, conversational, technical, witty)
--sources=<urls or file> — User-supplied reference URLs (required in No-Web Mode; otherwise merged into Phase 1 research)
--title="Exact Title" — Non-interactive title bypass (see Title Curation)
No-Brand Mode
If the user has no brand profile and declines to create one:
- Proceed with generic defaults (neutral professional voice, no terminology enforcement).
- Phase 5 skips the brand-compliance sub-check.
- Phase 7 scores the Brand Compliance dimension as
SKIPPED and flags the run for manual review; the Quality Scorecard notes "no brand profile configured."
- Regulated-industry topics (pharma, BFSI, healthcare, legal) must NOT run in no-brand mode — require a profile with guardrails first.
No-Web Mode
If web research is unavailable (offline, no search tool, MCP down):
- Require user-supplied sources via
--sources=.
- Skip SERP analysis; build the outline from the provided sources.
- Mark every citation "user-provided, unverified" in the fact-check ledger.
- Phase 7 caps Citation Integrity at 6.0 and notes the cap in the scorecard.
- If neither web access nor user sources are available, stop and tell the user research is impossible — do not fabricate sources.
How to Use
Interactive Mode (Recommended for First-Time Users)
/contentforge
Prompts you for:
- Topic (the subject — NOT the final title)
- Content Type (select from 5 options)
- Brand (select from existing profiles)
- Target Audience
- Word Count (or use default)
- Primary Keyword
Then generates 4-5 title options (different angles: benefit-driven, how-to, data-driven, question-based, contrarian). You select, modify, or provide your own title. Pipeline starts only after title confirmation.
Quick Mode (Topic Provided)
/contentforge "AI in Healthcare" --type=article --brand=acmemed --audience="Healthcare CIOs" --keyword="AI healthcare trends"
Even in quick mode, the system generates title options and asks you to select before starting Phase 1 — unless you pass --title.
Non-Interactive Mode (evals, batch, CI)
/contentforge "AI in Healthcare" --type=article --brand=acmemed --title="How AI Is Reshaping Hospital Diagnostics"
--title skips option generation and uses the given title verbatim. The bypassed title is still checkpointed as phase-0.5-title.txt.
Use Existing Google Sheet Requirement
/contentforge --sheet-url=https://docs.google.com/spreadsheets/d/ABC123 --row=5
Reads requirement from Row 5 of the sheet.
What Happens
Step 0.5: Title Curation — MANDATORY, inline
Before the pipeline starts, the orchestrator (inline — no subagent, no tracker calls) generates 4-5 SEO-optimized title options using the topic, content type, brand voice, audience, and primary keyword. Each title takes a different angle:
- Benefit-driven — leads with reader value
- How-to / Tactical — actionable, instructional
- Data-driven / Stat-led — opens with a number or trend
- Question-based / Curiosity — provokes the reader
- Contrarian / Unexpected — challenges convention
You select, modify, or provide your own title. The confirmed title becomes the anchor for the entire pipeline — research, outline, SEO, and final output all flow from it.
Do NOT auto-select a title. The only exception is an explicit --title="..." bypass, which uses the supplied title verbatim (for non-interactive runs and evals). Either way, checkpoint the confirmed title as phase-0.5-title.txt before Phase 1.
Phases 1–8 at a glance
Gate criteria and loop targets for every phase are defined once, in the Pipeline Contract table above.
- Phase 1: Research — SERP analysis anchored on the confirmed title; mines 12–15 authoritative sources; competitor analysis; structured outline. Gate 1.
- Phase 2: Fact Checking — verifies all URLs are live, validates claims against sources, assigns confidence tiers, flags unverifiable claims for removal or re-sourcing. Gate 2.
- Phase 3: Content Drafting — first draft in brand voice with inline citations (APA format), targeting word count ±10%. Gate 3.
- Phase 3.5: Visual Assets — charts from verified stats, visual markers, asset manifest with placement, alt text, and data source. Gate 3.5.
- Phase 4: Scientific Validation — hallucination scan, claim traceability, logic validation. Gate 4; failures loop to Phase 3.
- Phase 5: Structure & Proofread — grammar/spelling, readability to the content-type target (±0.5 grade), brand terminology and style. Gate 5.
- Phase 6: SEO/GEO — keyword placements (title, first 100 words, ≥2 H2s, conclusion, meta description), meta tags, URL slug, AI-answer-engine readiness, structure manifest. Density is advisory (~1–2%), not a gate. Gate 6.
- Phase 6.5: Humanizer — human-expert grounding pass, 43-pattern AI-telltale removal (incl. detector-signal patterns 36-43), content-derived variation (burstiness advisory), brand personality, SEO-placement preservation validated against the structure manifest. Gate 6.5.
- Phase 7: Reviewer — 5-dimension weighted scoring per
config/scoring-thresholds.json; approve ≥7.0 (industry-adjusted), loop 5.0–6.9, human review <5.0. Gate 7.
- Phase 8: Output — .docx generation with appendices, dual-copy save, optional Drive upload, tracking update. Gate 8.
If a phase loops back: the system shows which phase failed, why, and what it's fixing. Loops are automatic — you don't need to do anything unless it escalates to human review.
Output Example
Every pipeline run ends with a Completion Card showing scores, stats, and delivery status. This card is mandatory — it's shown in the conversation AND added as an appendix in the .docx file.
Example Completion Card (SYNTHETIC EXAMPLE — fabricated for illustration; never reuse these numbers):
CONTENTFORGE — COMPLETION CARD
Content: "AI in Healthcare: Emerging Trends" | AcmeMed | Article | ✅ APPROVED
Quality Score: 9.2/10 (Grade A+)
Content Quality: 9.5/10 ✅
Citation Integrity: 9.0/10 ✅
Brand Compliance: 9.5/10 ✅
SEO Performance: 8.8/10 ✅
Readability: 9.0/10 ✅
Content Stats:
Words: 1,947 (target 1,500-2,000) ✅ | Citations: 14 sources ✅
Keyword placements: all critical positions ✅ | Readability: Grade 11.2 ✅
Burstiness: 0.78 (advisory) | AI Patterns: 0 remaining ✅ | Hallucinations: 0 ✅
SEO Package:
Meta Title: 58 chars ✅ | Meta Description: 152 chars ✅
Internal Links: 4 applied | Feature Image: generated (user-approved)
Pipeline: 0 loops | Guardrails: verified | Run: {run_id}
Delivery:
.docx: ✅ Generated
Local: ✅ ~/Documents/Conte
…(truncated)
1---2name: contentforge3description: Produce a publication-ready, fact-checked, brand-compliant, SEO-optimized content piece through the full 10-phase pipeline: every phase dispatched to a dedicated subagent (researcher, fact-checker, drafter, visual annotator, scientific validator, structurer, SEO/GEO optimizer, humanizer, reviewer, output manager) behind 10 orchestrator-verified quality gates — three-layer fact verification, the 43-pattern humanizer pass, and 5-dimension reviewer scoring (approve >=7.0) — ending in a .docx with scorecard appendices. Triggers on "/contentforge:contentforge", "write an article about", "create a blog post", "produce a whitepaper", "I need a fact-checked, publication-ready piece", "run the content pipeline". This is ContentForge's front door: reads the brand profile, then routes onward to /contentforge:publish, /contentforge:social-adapt, and /contentforge:translate.4---56# ContentForge — Enterprise Content Production78Transform a content requirement into a publication-ready, fact-checked, brand-compliant, SEO-optimized piece through a 10-phase autonomous agent pipeline (plus Step 0.5 title curation) with three-layer fact verification and 10 quality gates.910## Context efficiency1112Pipeline phase. **Grep before Read** for `references/`, `humanization-patterns.json`, brand voice profiles. Hand subagents artifact **file paths** plus a ≤10-line summary — never reload or inline full drafts (see Context & Handoff Rules). On `/contentforge:resume`, load `run.json` plus only the artifacts the next phase contractually needs.1314## Execution Protocol (CRITICAL — read first)1516This skill orchestrates 10 phases plus Step 0.5 (Title Curation). **Each numbered phase MUST be executed by invoking its dedicated subagent via the `Task` tool — DO NOT generate the deliverable yourself in a single inference pass.** A single-pass generation skips the quality gates, fact-checking layers, humanizer 43-pattern catalog (29 core + 6 structure/framing + 8 detector-signal), and reviewer scoring that define ContentForge.1718The one exception is Step 0.5: title curation is performed **inline by the orchestrator** (no subagent), because it requires user interaction and subagents must never wait on the user. Any subagent that needs a user decision returns a `{"status": "needs_user_decision", ...}` payload to the orchestrator, which owns all user interaction (including image-generation opt-in/approval).1920### Portable execution lane — platforms without subagent dispatch (Codex, ChatGPT, single-context clients)2122If your platform has **no subagent/Task dispatch**, the pipeline still runs — sequentially, in this conversation, with nothing waived:23241. **Each phase's contract is its agent file.** Before executing a phase, Read `agents/{NN}-{name}.md` from the plugin directory and follow it as your instructions for that phase — INPUTS, EXECUTION STEPS, OUTPUT FORMAT, and the gate. The files are plain markdown written to be executable by whoever holds them; a subagent was always just a fresh context around the same text.252. **Same artifacts, same names, same gates.** Write every phase artifact to the run directory exactly as the Pipeline Contract specifies, checkpoint after each phase, and run every gate script. The auditability of a run must not depend on which platform produced it.263. **What changes:** ignore per-agent `maxTurns` (they bound subagent sessions, not you); "return as your final output" means "write the artifact, then continue"; Progress Updates print inline. What does **not** change: the phase order, the loop budgets, the gate criteria, and the rule that a needs-user-decision moment stops for the user.274. **Context discipline replaces context isolation.** Subagents exist to give each phase a clean context. Without them, do not carry a phase's working notes forward — after checkpointing a phase, work only from the artifacts on disk, exactly as a fresh subagent would.285. **Environment names:** on Agent Plugins 1.0 hosts the plugin root is `${PLUGIN_ROOT}` and persistent data is `${PLUGIN_DATA}`; where a command below says `${CLAUDE_PLUGIN_ROOT}`, use whichever of the two names your host defines. The scripts themselves accept both data-dir spellings.2930### Step 0 — Initialize the run (orchestrator only, before Step 0.5)3132```bash33# 1. Create the checkpoint run (returns run_id). Capture run metadata so a34# cross-session resume can recover keyword, audience, word count, and tone.35RUN_RESULT=$(python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py init \36 --brand <brand-slug> --topic "<topic>" --content-type <type> \37 --keyword "<primary keyword>" --audience "<audience>" \38 --word-count <n> --tone "<tone>")39# These flags land in run.json under meta.keyword / meta.audience /40# meta.word_count / meta.tone — use those exact key names when reading them back.41# Parse RUN_ID from the JSON result's "run_id" field.4243# 2. Initialize the performance tracker for this run.44python ${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tracker.py --action init \45 --brand <brand-slug> --run-id "$RUN_ID" --content-type <type> --topic "<topic>"46```4748Rules:49- `pipeline-tracker.py` is called by the **orchestrator only** — subagents never call it.50- Step 0.5 is **exempt** from tracker calls (no `phase-start`/`phase-end` for 0.5). After the title is confirmed, checkpoint it directly (see contract table).51- **If the user supplied their own draft** (`--source-draft <path>`, or they paste/dictate their own rough words), copy it verbatim to `{run_dir}/source-draft.md` here in Step 0 and set `"source_draft": true` in `run.json`. Do not clean it up on the way in — the mess is the signal. See "Bring your own words" below.5253### Required Per-Phase Workflow (Phases 1–8)5455For every numbered phase:56571. **Mark phase start** (orchestrator):58 ```bash59 python ${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tracker.py --action phase-start --brand <slug> --run-id "$RUN_ID" --phase <N>60 ```612. **Call `Task` with the phase's qualified `subagent_type`** (e.g. `contentforge:researcher`). The Task prompt contains ONLY:62 - the artifact **file paths** the phase reads (per the Pipeline Contract table),63 - a **≤10-line orchestrator summary** of pipeline state,64 - the **brand-profile path** (required for phases 0.5, 3, 5, 6, 6.5, 7),65 - the **original-requirements block** (topic, confirmed title, content type, audience, primary keyword, word-count target, tone).6667 Subagents `Read` what they need from those paths. **Never inline a full draft into a Task prompt.**683. **Verify the quality gate yourself.** Gate ownership belongs to the **orchestrator**: check the returned artifact against the gate criteria in the Pipeline Contract table — count sources, check word count and citation density, and run `python ${CLAUDE_PLUGIN_ROOT}/scripts/text-metrics.py --file <artifact-path> [--keyword "<primary keyword>"]` for burstiness, Flesch-Kincaid grade, and keyword-placement checks (`--file` is required). A subagent's self-reported "PASS" alone is **not** a gate pass.6970 **If a subagent returns nothing, or stops mid-sentence: audit the disk before you re-run it.** A live run had its output-manager complete the .docx, all four delivery copies and the tracking update, then return only "Now generating the .docx with the real script." — no report, and its contracted `phase-8-output.json` unwritten. Re-running it blind would have regenerated finished work; declaring the phase failed would have been false. The principle above already implies the remedy — disk state is the authority, not the message — so make it the procedure: list the run directory, check which contracted artifacts exist, verify those against the gate, and ask the SAME agent for the missing piece rather than starting a new one. Only treat a phase as un-run when its artifacts are genuinely absent.7172 The same rule applies on resume: `checkpoint-manager.py status` reports `orphaned_artifacts` for phases whose artifact exists but was never checkpointed. **Never re-run a phase listed there without looking at what is already on disk** — but never checkpoint it unverified either. An unverified artifact is a claim, not a pass.734. **On gate PASS, checkpoint the artifact** so the run is resumable:74 ```bash75 python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py save \76 --brand <slug> --run-id "$RUN_ID" --phase <N> --content-file <artifact-path> --extension <md|json|txt>77 ```78 Phases 3.5 and 6 also produce a companion manifest (`phase-3.5-visual-manifest.json`, `phase-6-structure-manifest.json`) — place it at its canonical path inside the same run directory.795. **Mark phase end** with the output word count:80 ```bash81 python ${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tracker.py --action phase-end --brand <slug> --run-id "$RUN_ID" --phase <N> --content-words <count>82 ```836. **Emit the audit line** (so users can see real-time progress):84 ```85 [PHASE-AUDIT] phase=<N> name=<name> status=<PASS|FAIL> output_summary="<one line>" gate=<PASS|FAIL>86 ```877. **On gate FAIL, loop per the contract table's loop-target column.** Before looping, record the loop and check limits:88 ```bash89 python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py loop --brand <slug> --run-id "$RUN_ID" --edge phase_<N>_to_<target>90 ```91 **Limits: max 2 loops per edge, max 5 loops total per run.** If a limit is reached: do NOT loop — mark the run for human review, `finalize --status failed`, and halt. When Phase 7 orders rework, the `pending_rework` field in `run.json` records the target phase and the reviewer's feedback so `/contentforge:resume` continues the rework instead of skipping it. Do not overwrite the saved checkpoint of an upstream phase that already passed — re-save only the looped phase when it passes.9293### Lifecycle steps (orchestrator-owned, v4.0)9495Two small steps wire each run into the brand's living state. Both are cheap, both96are honest about missing inputs, and neither ever blocks a run:97981. **After Gate 1 passes** — merge the run's verified link inventory into the99 brand profile, so the reconnaissance stops evaporating with the run:100 ```bash101 python ${CLAUDE_PLUGIN_ROOT}/scripts/harvest-brand-pages.py \102 --merge-inventory <run_dir>/phase-1-link-inventory.json --brand <slug>103 ```104 Service/product and authority rows upsert (existing manual curation is never105 overwritten — stamps refresh only); conversion rows only STAGE under106 `brand_pages.recon_candidates` for the user to confirm, because a CTA is a107 commercial decision. If the inventory file is missing (pre-4.0 agent, no108 website), report that and continue — never fabricate rows.1091102. **Before dispatching Phase 3** — ask telemetry for drafter advisories:111 ```bash112 python ${CLAUDE_PLUGIN_ROOT}/scripts/telemetry.py advisories --brand <slug>113 ```114 When `status` is `ok` and advisories exist, append their `brief_line`s to the115 Phase 3 Task prompt's requirements block. When `insufficient_history`, append116 nothing — the floor is the point; a brief fed from fewer runs than the floor117 is fed from anecdote. Advisories inform drafting style only: they NEVER118 modify a gate, a threshold, or a verdict.119120### Image approval (orchestrator-owned, after Phase 3.5)121122The visual-asset-annotator never waits on the user. It generates candidates (when image generation is opted in) and records each in `phase-3.5-visual-manifest.json` with `approved_by_user: false`. After Gate 3.5 passes, the **orchestrator** presents the generated visuals to the user for approval:1231241. Show each generated asset (path + description + placement) and ask approve / regenerate / drop.1252. Update `approved_by_user` in the manifest for approved assets.1263. For rejects, re-invoke `contentforge:visual-asset-annotator` with the rejection feedback (counts as a Phase 3.5 re-run, not a loop edge).1274. Phase 8 embeds **only** assets with `approved_by_user: true` — unapproved assets stay out of the .docx.128129If the annotator returns `{"status": "needs_user_decision", ...}` (e.g., image-generation opt-in was never given), ask the user, then re-invoke with the answer.130131### Pipeline Contract (inputs → outputs → gate → loop target)132133All artifacts live in the canonical run directory `~/.claude-marketing/{brand-slug}/runs/{run_id}/` alongside `run.json` (the manifest).134135**The machine-readable form of this table is `config/pipeline-graph.json`, and that file is authoritative for the pipeline's shape** — nodes, reads/writes, gates, budgeted loop edges. This table narrates it for humans; `tests/test_pipeline_contract_graph.py` fails the build if the two (or the agent files, or `checkpoint-manager.py`, or `run-audit.py`) ever disagree. Before v4.0 this contract lived as prose in four places at once, and they drifted twice in ways no unit test could see.136137| Phase | subagent_type | Reads (paths) | Writes (artifact) | Quality gate (orchestrator-verified) | Gate-FAIL loop target |138|-------|---------------|---------------|-------------------|--------------------------------------|-----------------------|139| 0.5 | — inline (orchestrator) | brand profile, requirements | `phase-0.5-title.txt` | User-confirmed title (or `--title` bypass) — user checkpoint, not a numbered quality gate | Regenerate title options |140| 1 | `contentforge:researcher` | `phase-0.5-title.txt`, requirements, brand profile | `phase-1-research.md` + `phase-1-link-inventory.json` (the verified Internal-Link Inventory as data rows — v4.0) | **Gate 1:** 12–15 sources collected; ≥10 citable; ≥5 with reliability ≥8; differentiated angle documented; Client Site Reconnaissance complete; ≥3 verified deep brand URLs when the brand has a website | Re-run Phase 1 with broader search |141| 2 | `contentforge:fact-checker` | `phase-1-research.md` | `phase-2-factcheck.md` | **Gate 2:** ≥80% of claims verified; zero UNRESOLVED flags (flagged claims must be removed or re-sourced); ≤3 unverified tolerated; all cited URLs live | Phase 1 (find alternative sources) |142| 3 | `contentforge:content-drafter` | `phase-0.5-title.txt`, `phase-1-research.md`, `phase-2-factcheck.md`, brand profile, requirements (+ telemetry advisories when the floor is met — see "Lifecycle steps" below) | `phase-3-draft.md` | **Gate 3:** `body_word_count` ±10% of target — **not `word_count`**, which includes the reference list (a live run drafted a 1,779-word body under a 1,200-word target while `word_count` read 2,887). **What `body_word_count` counts, stated so nobody has to invent a convention:** the prose a reader reads, plus H2/H3 headings. It excludes the H1, the bold `**Key:** value` metadata block, horizontal rules, HTML comments, `[VISUAL-PLACEHOLDER: …]` annotation lines (production instructions for Phase 3.5 that never publish), block image embeds and the italic figure-caption line directly beneath each (figure furniture — on a live run three approved charts' alt texts and captions moved the measured body from 1,274 gate-passed words to 1,501, which would have failed the final audit for having its figures described properly), and every trailing reference/appendix section. This matters: on one live draft the two defensible readings gave 1,390 (FAIL) and 1,223 (PASS) for the same file — a gate whose verdict depends on an unstated convention is not a measurement. Do not hand-count; read the field; all outline sections covered; ≥1 citation per 300 words | Re-run Phase 3 |143| 3.5 | `contentforge:visual-asset-annotator` | `phase-3-draft.md`, `phase-2-factcheck.md`, `phase-1-research.md` (SERP visual patterns) | `phase-3.5-visuals.md` (contains the ANNOTATED draft — the operative article from here on) + `phase-3.5-visual-manifest.json` | **Gate 3.5:** every chart traceable to a verified statistic; manifest complete (placement, alt text, data source); human-action TODOs marked | Re-run Phase 3.5 |144| 4 | `contentforge:scientific-validator` | `phase-3-draft.md`, `phase-3.5-visuals.md`, `phase-3.5-visual-manifest.json`, `phase-2-factcheck.md`, `phase-1-research.md` (the Verified Outline, required by its Step 6.1) | `phase-4-validation.md` + `phase-4-fixes.json` (the fix ledger — **required whenever the report names a correction**, empty `items` is valid) | **Gate 4:** zero hallucinations; every claim traceable to a cited source; logic consistent; **`fix-ledger.py validate` exits 0 and every correction in the report appears in the ledger** | Phase 3 (with the specific claims to fix) |145| 5 | `contentforge:structurer-proofreader` | `phase-3.5-visuals.md` (the ANNOTATED draft — the operative article text, with the VISUAL anchors that must survive), `phase-3-draft.md` (pre-annotation reference), `phase-4-validation.md`, `phase-4-fixes.json`, brand profile | `phase-5-structured.md` | **Gate 5:** **`fix-ledger.py verify` reports zero unresolved blocking items (HARD)**; zero grammar/spelling errors on re-scan; readability within ±0.5 grade of the content-type target (`text-metrics.py`); brand terminology compliance | Re-run Phase 5 |146| 6 | `contentforge:seo-geo-optimizer` | `phase-5-structured.md`, `phase-1-research.md` (Internal-Link Inventory), `phase-3.5-visual-manifest.json` (feature image), brand profile, requirements (keyword) | `phase-6-seo.md` + `phase-6-structure-manifest.json` | **Gate 6:** keyword PLACEMENTS present — title, first 100 words, ≥2 H2s, conclusion, meta description (density is advisory, ~1–2%); meta title + description generated; all internal-link URLs verified live (HARD); ≥2 deep brand links when site known (scored+flag) | Re-run Phase 6 |147| 6.5 | `contentforge:humanizer` | `phase-6-seo.md`, `phase-6-structure-manifest.json`, `phase-4-fixes.json` (the applied-fix protected set), brand profile, `source-draft.md` (when present) | `phase-6.5-humanized.md` (**article body only** — `authorship.py` measures this file) + `phase-6.5-report.md` + `phase-6.5-review-sheet.html` + `phase-6.5-pattern-hits.json` (per-pattern fire counts for `telemetry.py` — v4.0) + `phase-6.5-authorship.json` (only when `source-draft.md` exists) | **Gate 6.5:** grounding pass complete; 43-pattern catalog; GEO structure preserved; keywords preserved; AI-tell scan reported (advisory); burstiness advisory; **with an author draft: `authorship.py` exits 0 — zero author sentences rewritten or dropped (NOT advisory)**; **`fix-ledger.py verify` does not exit 3 — a style pass may not undo an applied accuracy correction (NOT advisory)** | Re-run Phase 6.5 with the violated constraint stated (incl. structure-manifest mismatch, authorship violations, or a regressed ledger fix) |148| 7 | `contentforge:reviewer` | ALL prior artifact paths, `phase-4-fixes.json`, brand profile, requirements, `config/scoring-thresholds.json` | `phase-7-review.json` (includes `publication_status` + `fix_ledger`) + `phase-7-fix-ledger.json` (the verify payload, written by the script as UTF-8 so the reviewer copies bytes rather than scraping a console) + `phase-7-review-pre-remediation.json` (re-review mode only: the prior review, preserved before re-scoring — the old score is evidence, not garbage) | **Gate 7:** reviewer decision tree per `config/scoring-thresholds.json` — approve ≥7.0 (industry-adjusted); all dimension minimums met; dead internal link = hard FAIL; homepage-only linking caps the sub-score and surfaces on the Completion Card; **`fix_ledger` copied from `fix-ledger.py verify`, never re-derived by hand** | 5.0–6.9 → loop to responsible phase (recorded as `pending_rework`); <5.0 → human review, halt |149| 8 | `contentforge:output-manager` | `phase-6.5-humanized.md`, `phase-6.5-report.md`, `phase-7-review.json`, `phase-3.5-visual-manifest.json`, `phase-6-seo.md` (SEO Scorecard for Appendix A), `run.json`, `phase-6.5-authorship.json` (when present) | `phase-8-output.json` + `.docx` | **Gate 8:** .docx generated; **all four appendices present — A (SEO Scorecard), B (Quality Scorecard), C (Production Details), D (Internal Link Map)** — matching `appendices_present: 4` in `config/scoring-thresholds.json`; delivery location verified. This row previously said A/B/C while the config required 4, and this file states that the config wins where they disagree — so a Phase 8 emitting only A/B/C would have passed the documented gate and failed the configured one. **Also: the body must carry no production scaffolding and must anchor every generated asset — `text-metrics.py` reports `residual_scaffolding.clean: true` and `visual_markers.ids` covering every manifest asset with `status: generated`. One run delivered three raw `[VISUAL-PLACEHOLDER: …]` lines to the reader and embedded none of its three valid charts, because Phase 3.5's marker replacement never landed and nothing downstream compared the two.** **And: `fix-ledger.py verify` runs here and sets `publication_status`. Unresolved blocking corrections do not stop the .docx being produced — they stop it being called ready: `DRAFT-` filename prefix, `publication_blockers` in `phase-8-output.json`, and the blocked status in the tracking row** | Re-run Phase 8; if generation still fails, save markdown + reports locally and report the failure |150151That is **10 quality gates** — one for each of phases 1, 2, 3, 3.5, 4, 5, 6, 6.5, 7, and 8.152153**Single source of truth for numbers:** approval thresholds, loop bands, dimension weights, dimension minimums, and industry overrides live in `config/scoring-thresholds.json`. Prose in this document references those values; if they ever disagree, the config wins.154155### Context & Handoff Rules156157- Subagents receive artifact **paths**, a **≤10-line orchestrator summary**, the **brand-profile path** (phases 0.5, 3, 5, 6, 6.5, 7), and the **original-requirements block**. They `Read` what they need.158- Never inline a full draft into a Task prompt, and never reload a full draft into the orchestrator's context when a path reference will do.159- The reviewer (Phase 7) must receive the paths of **all** prior artifacts, not just the Phase 6.5 output.160161### Final Output Requirements162163After Phase 8 completes, the output-manager subagent **must produce a Microsoft Word `.docx` file** by calling:164```bash165python ${CLAUDE_PLUGIN_ROOT}/scripts/generate-docx.py \166 --content <article.md> \167 --output <local-path>.docx \168 --reports <reports.json> \169 --brand "<brand>" \170 --content-type <type>171```172173The `.docx` must contain: title page, full article body, sources/citations, **Appendix A (SEO Scorecard)**, **Appendix B (Quality Scorecard)**, **Appendix C (Production Details)**.174175**Dual-copy save:** the `.docx` is written into the run directory (`~/.claude-marketing/{brand-slug}/runs/{run_id}/`) AND copied to the user-visible folder `~/Documents/ContentForge/{Brand}/`. Always tell the user the `~/Documents/ContentForge/` path. If the brand has Google Drive configured (`tracking.backend == "google_sheets"` with a `tracking.google_drive.folder_id`), additionally upload the .docx via `drive-uploader.py`.176177Then audit, and only then finalize:178```bash179# 1. Re-derive every gate from the artifacts. This is not optional ceremony:180# finalize --status completed REFUSES without a fresh CLEAN verdict on disk.181python ${CLAUDE_PLUGIN_ROOT}/scripts/run-audit.py --brand <slug> --run-id "$RUN_ID"182183# 2. Close the run.184python ${CLAUDE_PLUGIN_ROOT}/scripts/checkpoint-manager.py finalize --brand <slug> --run-id "$RUN_ID" --status completed185```186187**What the audit is.** `run-audit.py` re-checks the finished run the way an outside auditor would: every completed phase has its artifact, no orphaned artifacts in a finalized run, the delivered body carries no production scaffolding and anchors every generated asset, the authorship record matches a fresh measurement, no fix-ledger correction was lost or undone, an APPROVED decision is backed by its own score, and no `completed` status hides a blocked publication. Every one of those is a failure that actually happened in a real run while every individual artifact looked healthy. The verdict lands in `run-audit.json` inside the run directory.188189**When the audit fails:** fix the findings and re-run it — or, if the run is legitimately unpublishable as it stands (an open `requires_human` blocker, say), finalize with `--status blocked`, which needs no audit because it claims nothing. `finalize --skip-audit` exists as an escape hatch that stamps `audit_skipped: true` into `run.json`: the absence of verification becomes part of the record rather than a silence.190191### Why This Matters192193Skipping the Task-tool orchestration means: no real fact-checking, no real humanizer (43-pattern AI removal won't fire, including detector-signal patterns 36-43), no real reviewer scoring — the pipeline becomes single-pass content generation labeled with fake phase names. The audit trail (`run.json`, the per-phase checkpoint artifacts, `[PHASE-AUDIT]` lines, real reviewer score) is the proof of execution. If those artifacts don't exist after a run, the pipeline didn't actually run.194195## When to Use196197Use `/contentforge` when you need:198- **Single high-quality content piece** (article, blog, whitepaper, FAQ, research paper)199- **Research-backed content** with verified citations200- **Brand-compliant content** for regulated industries (Pharma, BFSI, Healthcare, Legal)201- **SEO-optimized content** with keyword targeting and meta tags202- **Natural-sounding content** with AI patterns removed (Phase 6.5 Humanizer)203204**For multiple pieces**, use [`/contentforge:batch-process`](../batch-process/SKILL.md) — a prioritized, checkpointed queue that runs the same pipeline per piece.205206## Express Lane (bring your own research)207208When the user already has the research — pasted sources, internal notes with URLs, an existing source dossier — and asks for speed (**"express"**, **"I have my own sources"**, **"quick article from my notes"**, or `--express`), run the EXPRESS phase set instead of the full pipeline. Verification is the product; ceremony is optional. Express is fast because the intake replaces Phase 1's deep research hunt — which dominates full-pipeline wall-clock — not because it skips craft. It keeps every verification gate AND the craft passes that make the piece read human, and drops only the phases whose value depends on surfaces outside the prose:209210| Express phase | Agent | Contract change vs full pipeline |211|---|---|---|212| 0.5 Title | — inline | unchanged |213| 1-INTAKE | `contentforge:researcher` | **Intake mode, not research mode**: catalog ONLY the user-provided sources into the standard `phase-1-research.md` shape — no new source hunting. **Gate 1-E:** every source carries a URL (or is labeled `user-provided, unverifiable`), a reliability rating, and the differentiated angle is documented from the user's own framing. Tell the researcher explicitly: "intake mode — structure and rate what was provided; do not expand the source set." |214| 2 Fact-Check | `contentforge:fact-checker` | **UNCHANGED — Gate 2 in full.** The user's sources get the same verification as found sources; user affection for a claim is not evidence. |215| 3 Draft | `contentforge:content-drafter` | unchanged (Gate 3 in full) |216| 4 Validation | `contentforge:scientific-validator` | **UNCHANGED — Gate 4 in full.** The draft-vs-ledger hallucination diff is part of the verification thesis, not polish. |217| 5 Structure | `contentforge:structurer-proofreader` | **Runs by default — Gate 5 in full.** Proofreading and content-type structure are craft, not ceremony; a fast piece with typos is not a deliverable. Skippable only by explicit `--skip-structure`. |218| 6.5 Humanizer | `contentforge:humanizer` | **Runs by default — Gate 6.5 in full.** Nobody orders express robot prose: the 43-pattern de-AI pass and brand-personality layer ship in every lane unless the user explicitly opts out with `--skip-humanizer`. Reads the latest artifact (`phase-5-structured.md`, or `phase-3-draft.md` if structure was skipped); the GEO-structure-preservation and keyword-preservation checks apply only when Phase 6 ran. |219| 7 Review | `contentforge:reviewer` | Gate 7 with the **express review contract** (see the reviewer agent's Express runs section): skipped-phase artifacts are legitimately absent — score those dimensions from the piece itself instead of capping them; SEO dimension is N/A unless Phase 6 ran; the dead-link hard fail applies ALWAYS. |220| 8 Output | `contentforge:output-manager` | unchanged; Appendix A (SEO Scorecard) is replaced by an "Express run — SEO not performed" note |221222**Skipped by default, each re-addable by flag:** Phase 3.5 visuals (`--with-visuals`) and Phase 6 SEO/GEO (`--with-seo`) — the two phases whose value depends on production surfaces outside the prose (asset creation, search targeting). When a flag re-adds a phase, its full gate comes with it — there is no gate-less phase in any lane. The craft passes may be dropped only by explicit request (`--skip-structure` / `--skip-humanizer`); a chosen skip is recorded in `skipped_phases` like any other, and the reviewer then scores those qualities from the piece itself.223224**Record the lane**: write `"mode": "express"` and the `skipped_phases` list into `run.json` at run start — the reviewer and output-manager read it to apply the express contracts. A run without `mode` is a full run.225226**What express is NOT**: it is not a lower quality bar — Gates 2, 4, and 7 are identical, and the piece is still proofread (Gate 5) and humanized (Gate 6.5) unless the user explicitly opted out. It produces a verified, validated, proofread, humanized, reviewed piece WITHOUT keyword optimization or visuals. Say this plainly to the user when they choose express, and offer `--with-seo` / `--with-visuals` if they hesitate.227228## Bring your own words (`--source-draft`)229230The pipeline's default mode writes from research. This mode keeps the author in the piece.231232Give it your own rough draft — a voice-note transcript, a wall of bullets, three angry paragraphs typed at midnight — and ContentForge builds the article **around your sentences instead of over them**. Quality of the input is irrelevant; authorship is the whole point.233234```bash235/contentforge:contentforge "why our review estimates were wrong" --source-draft ./notes.md236```237238What changes:239240| Phase | Behaviour with an author draft |241|---|---|242| 0 Init | Your draft is copied verbatim to `{run_dir}/source-draft.md`; `run.json` records `source_draft: true` |243| 3 Draft | Your sentences are carried into the draft **verbatim** — typos, run-ons, lowercase and all. Research and structure are added *between* them |244| 5, 6 | Structure and SEO work around your sentences; they are never rewritten to fit a keyword |245| 6.5 Humanizer | **The 43-pattern catalog does not apply to your sentences.** If you wrote "here's the thing", it stays. Then `scripts/authorship.py` verifies nothing of yours was paraphrased or lost |246| 7 Review | A rewritten or dropped author sentence **blocks approval** until it is restored verbatim |247| 8 Output | The disclosure becomes provenance-accurate: *"Written by {you} with AI assistance for research, structure, and fact-checking"* — but only if the record proves it |248249Three honest limits, stated plainly:250251- **Your sentences are your voice, not verified facts.** Anything factual the pipeline *adds* still comes from the Phase 2 ledger. If one of your claims contradicts the research, it gets flagged for you, not silently corrected — you decide.252- **The authored disclosure has to be earned.** It appears only when at least 25% of the finished words are yours verbatim AND none of your sentences were rewritten or dropped. It can never be turned on by asking; it is read off the record. A disclosure that overstates human authorship is the one kind a reader cannot check, so this direction is one-way by design.253- **There is no target ratio and nothing here is aimed at a detector.** `author_word_share` exists so the disclosure can be accurate. Writing more of the piece yourself makes it more yours; it is not a score, and no number turns text "human enough".254255## What This Command Does256257Runs your content through **10 specialized agents**, each behind a quality gate:2582591. **Research Agent** — SERP analysis, source mining, competitive analysis, structured outline2602. **Fact Checker** — URL verification, claim validation, confidence scoring2613. **Content Drafter** — First draft with brand voice, SME calibration via industry knowledge packs2624. **Visual Asset Annotator** — Chart generation from verified stats, visual markers, asset manifest2635. **Scientific Validator** — Hallucination detection, domain-specific validation, logic validation2646. **Structurer & Proofreader** — Grammar/spelling correction, readability optimization, brand compliance2657. **SEO/GEO Optimizer** — Keyword placements, meta tag generation, internal linking markers2668. **Humanizer** — AI pattern removal (43-pattern catalog), content-derived sentence variation (burstiness advisory), brand personality2679. **Reviewer** — 5-dimension quality scoring (weights per `config/scoring-thresholds.json`)26810. **Output Manager** — .docx with embedded charts and internal links, dual-copy save, optional Drive upload269270**Quality Gates:** 10 gates (phases 1–8 including 3.5 and 6.5). On failure the pipeline loops per the contract table — max 2 loops per edge, max 5 total, then human escalation.271272## Required Inputs273274**Minimum Required:**275- **Topic** — What the content is about (e.g., "AI in Healthcare", "remote work productivity")276- **Content Type** — article, blog, whitepaper, faq, research_paper, video_script, case_study, newsletter277- **Brand** — Which brand profile to use (create with `/contentforge:cf-style-guide` if new brand). See No-Brand Mode below if none exists.278279**Pre-Flight Validation:** After gathering inputs, validate the brand profile for completeness (voice, guardrails, audience, industry pack). For regulated industries (pharma, BFSI, healthcare, legal), guardrails are required — warn if they're empty and ask whether to proceed or update the profile first.280281**Optional:**282- **Target Audience** — Who this content is for (e.g., "Healthcare CIOs")283- **Word Count** — Target length (defaults to content type standard)284- **Primary Keyword** — Main SEO keyword to optimize for285- **Tone** — Overrides brand default (authoritative, conversational, technical, witty)286- **`--sources=<urls or file>`** — User-supplied reference URLs (required in No-Web Mode; otherwise merged into Phase 1 research)287- **`--title="Exact Title"`** — Non-interactive title bypass (see Title Curation)288289### No-Brand Mode290291If the user has no brand profile and declines to create one:292- Proceed with generic defaults (neutral professional voice, no terminology enforcement).293- Phase 5 skips the brand-compliance sub-check.294- Phase 7 scores the **Brand Compliance dimension as `SKIPPED`** and flags the run for manual review; the Quality Scorecard notes "no brand profile configured."295- **Regulated-industry topics (pharma, BFSI, healthcare, legal) must NOT run in no-brand mode** — require a profile with guardrails first.296297### No-Web Mode298299If web research is unavailable (offline, no search tool, MCP down):300- Require user-supplied sources via `--sources=`.301- Skip SERP analysis; build the outline from the provided sources.302- Mark every citation **"user-provided, unverified"** in the fact-check ledger.303- Phase 7 **caps Citation Integrity at 6.0** and notes the cap in the scorecard.304- If neither web access nor user sources are available, stop and tell the user research is impossible — do not fabricate sources.305306## How to Use307308### Interactive Mode (Recommended for First-Time Users)309```310/contentforge311```312**Prompts you for:**3131. Topic (the subject — NOT the final title)3142. Content Type (select from 5 options)3153. Brand (select from existing profiles)3164. Target Audience3175. Word Count (or use default)3186. Primary Keyword319320**Then generates 4-5 title options** (different angles: benefit-driven, how-to, data-driven, question-based, contrarian). You select, modify, or provide your own title. Pipeline starts only after title confirmation.321322### Quick Mode (Topic Provided)323```324/contentforge "AI in Healthcare" --type=article --brand=acmemed --audience="Healthcare CIOs" --keyword="AI healthcare trends"325```326Even in quick mode, the system generates title options and asks you to select before starting Phase 1 — unless you pass `--title`.327328### Non-Interactive Mode (evals, batch, CI)329```330/contentforge "AI in Healthcare" --type=article --brand=acmemed --title="How AI Is Reshaping Hospital Diagnostics"331```332`--title` skips option generation and uses the given title verbatim. The bypassed title is still checkpointed as `phase-0.5-title.txt`.333334### Use Existing Google Sheet Requirement335```336/contentforge --sheet-url=https://docs.google.com/spreadsheets/d/ABC123 --row=5337```338Reads requirement from Row 5 of the sheet.339340## What Happens341342### Step 0.5: Title Curation — MANDATORY, inline343344**Before the pipeline starts**, the orchestrator (inline — no subagent, no tracker calls) generates **4-5 SEO-optimized title options** using the topic, content type, brand voice, audience, and primary keyword. Each title takes a different angle:345- **Benefit-driven** — leads with reader value346- **How-to / Tactical** — actionable, instructional347- **Data-driven / Stat-led** — opens with a number or trend348- **Question-based / Curiosity** — provokes the reader349- **Contrarian / Unexpected** — challenges convention350351**You select, modify, or provide your own title.** The confirmed title becomes the anchor for the entire pipeline — research, outline, SEO, and final output all flow from it.352353**Do NOT auto-select a title.** The only exception is an explicit `--title="..."` bypass, which uses the supplied title verbatim (for non-interactive runs and evals). Either way, checkpoint the confirmed title as `phase-0.5-title.txt` before Phase 1.354355### Phases 1–8 at a glance356357Gate criteria and loop targets for every phase are defined once, in the **Pipeline Contract table** above.358359- **Phase 1: Research** — SERP analysis anchored on the confirmed title; mines 12–15 authoritative sources; competitor analysis; structured outline. *Gate 1.*360- **Phase 2: Fact Checking** — verifies all URLs are live, validates claims against sources, assigns confidence tiers, flags unverifiable claims for removal or re-sourcing. *Gate 2.*361- **Phase 3: Content Drafting** — first draft in brand voice with inline citations (APA format), targeting word count ±10%. *Gate 3.*362- **Phase 3.5: Visual Assets** — charts from verified stats, visual markers, asset manifest with placement, alt text, and data source. *Gate 3.5.*363- **Phase 4: Scientific Validation** — hallucination scan, claim traceability, logic validation. *Gate 4; failures loop to Phase 3.*364- **Phase 5: Structure & Proofread** — grammar/spelling, readability to the content-type target (±0.5 grade), brand terminology and style. *Gate 5.*365- **Phase 6: SEO/GEO** — keyword placements (title, first 100 words, ≥2 H2s, conclusion, meta description), meta tags, URL slug, AI-answer-engine readiness, structure manifest. Density is advisory (~1–2%), not a gate. *Gate 6.*366- **Phase 6.5: Humanizer** — human-expert grounding pass, 43-pattern AI-telltale removal (incl. detector-signal patterns 36-43), content-derived variation (burstiness advisory), brand personality, SEO-placement preservation validated against the structure manifest. *Gate 6.5.*367- **Phase 7: Reviewer** — 5-dimension weighted scoring per `config/scoring-thresholds.json`; approve ≥7.0 (industry-adjusted), loop 5.0–6.9, human review <5.0. *Gate 7.*368- **Phase 8: Output** — .docx generation with appendices, dual-copy save, optional Drive upload, tracking update. *Gate 8.*369370**If a phase loops back:** the system shows which phase failed, why, and what it's fixing. Loops are automatic — you don't need to do anything unless it escalates to human review.371372## Output Example373374Every pipeline run ends with a **Completion Card** showing scores, stats, and delivery status. This card is mandatory — it's shown in the conversation AND added as an appendix in the .docx file.375376**Example Completion Card** (SYNTHETIC EXAMPLE — fabricated for illustration; never reuse these numbers):377```378CONTENTFORGE — COMPLETION CARD379380Content: "AI in Healthcare: Emerging Trends" | AcmeMed | Article | ✅ APPROVED381382Quality Score: 9.2/10 (Grade A+)383 Content Quality: 9.5/10 ✅384 Citation Integrity: 9.0/10 ✅385 Brand Compliance: 9.5/10 ✅386 SEO Performance: 8.8/10 ✅387 Readability: 9.0/10 ✅388389Content Stats:390 Words: 1,947 (target 1,500-2,000) ✅ | Citations: 14 sources ✅391 Keyword placements: all critical positions ✅ | Readability: Grade 11.2 ✅392 Burstiness: 0.78 (advisory) | AI Patterns: 0 remaining ✅ | Hallucinations: 0 ✅393394SEO Package:395 Meta Title: 58 chars ✅ | Meta Description: 152 chars ✅396 Internal Links: 4 applied | Feature Image: generated (user-approved)397398Pipeline: 0 loops | Guardrails: verified | Run: {run_id}399400Delivery:401 .docx: ✅ Generated402 Local: ✅ ~/Documents/Conte403404…(truncated)