anfloy.AcademyBook a call

Marketing · 01 · The content engineLesson 3 of 4

The drafting system

75 min working time · Weeks 5-6

By the end of this lesson you can
  • Run the full pipeline: brief -> outline -> draft -> edit
  • Encode your editorial standards as the editor skill

One mega-prompt vs four agents

The deliverable here is one real piece from your actual calendar: drafted by a four-agent pipeline, verified claim by claim, sitting in approved/ because you read it and moved it there yourself. To get there, first understand why the obvious approach fails. The naive way to draft with AI is one giant prompt: here's the topic, the voice guide, the research, now write. It works until it doesn't. Research bleeds into style. The model paraphrases its own paraphrases until a real quote becomes a fake one. And when the output is mediocre, you can't tell which part of the giant prompt failed.

The 2026-standard pattern is a pipeline of subagents, each with its own context window and a narrow job: a researcher gathers, a writer drafts, an editor enforces style, a fact-checker audits. Separate contexts mean no contamination - the writer never sees raw web pages, the fact-checker never gets charmed by the draft's voice because it only compares claims to sources.

Proof this scales: RSL/A, a two-person agency, runs a six-stage pipeline like this and took blog production from a full day to 2-3 hours, tripling output with the same headcount. Their final stage is always a human review in the CMS before anything publishes - keep that in mind for module 2.

The four-subagent pipeline

You built the researcher and fact-checker in the last lesson. Now add the writer and editor, and orchestrate all four with a single skill: write-post.

  1. Create .claude/agents/writer.md: it reads exactly two inputs - the brief and brand/voice.md - and produces an outline first, then the draft. It may not search the web; if it needs a fact that's not in the brief, it inserts a TODO instead of inventing one.
  2. Create .claude/agents/editor.md: it reads the draft plus voice.md and banned-words.md, and rewrites for voice compliance. It may not add facts or change claims - style only.
  3. Create the write-post skill that runs the relay: researcher fills the brief -> writer outlines, you approve the outline -> writer drafts to content/drafts/ -> editor passes -> fact-checker audits against the brief -> report lands next to the draft.
  4. Run it on the brief from last lesson. Read the outline before the draft - redirecting an outline costs minutes; redirecting a finished draft costs the afternoon.
  5. You review last. The pipeline ends at content/drafts/ with a clean fact-check report. Moving the file to content/approved/ is your job, by hand, every time.
.claude/skills/write-post/SKILL.md (frontmatter)
---
name: write-post
description: Run the full drafting pipeline for one brief. Orchestrates
  researcher -> writer -> editor -> fact-checker as separate subagents.
  Input: a brief file in content/briefs/. Output: a draft in
  content/drafts/ plus a fact-check report. Never writes to approved/.
argument-hint: <brief-file>
disable-model-invocation: true
---

Notice what just happened on the ladder. The voice file was a chat you ran once and encoded as a skill. write-post is the top rung: a skill that orchestrates a whole agent pipeline. Nobody on your team will ever re-prompt 'write me a blog post' again - they run /write-post on a brief, because the same kind of asset twice means a skill, not a retyped prompt.

Which model runs which job

Each subagent file takes a model: line, so the pipeline can route work by what it's worth. The rule for writing: the model that decides what a reader sees gets the best judgment you have; the model that sorts and labels gets the cheapest one that's accurate. Prices below are Anthropic's API list prices per million tokens (input/output) as of September 2026; on a subscription the same choice draws down your usage limits at different speeds.

  • Voice drafting and critique: Opus 5.5 (opus, $4/$20). It's the Claude Code default, and voice is judgment. Fable 5.1 (fable, $10/$50) is for long multi-step research runs, not for a 200-word post.
  • Volume variants: Sonnet 5 (sonnet, $2/$10). Five angles on one idea, twenty derivatives from a transcript, a batch of subject lines. You pick the survivors anyway, so fast and good beats slow and best.
  • Tagging and metadata: Haiku 4.5 (haiku, $1/$5). Pillar tags, channel labels, moment classification, alt-text drafts, pulling the date and topic out of a posted post. Haiku 4.5 has a retirement floor of October 15, 2026 on Anthropic's models page, so check its successor before you pin it anywhere permanent.
  • Never let the writer grade itself. The critics (editor and fact-checker) run as separate subagents with their own context, reading only the draft, the brief, and the rules. A model reviewing its own fluent sentences approves them. A second context, with the mechanical rules in code (next section), doesn't. Subagents are plain files: ask Claude to write them or edit .claude/agents/ directly.
.claude/agents/writer.md and editor.md (frontmatter)
---
name: writer
description: Outlines, then drafts, from one brief + brand/voice.md.
  No web access. Missing fact = TODO, never an invented one.
tools: Read, Write
model: opus
---

---
name: editor
description: Critiques a draft it did not write. Runs
  scripts/lint_draft.py first, then judges voice against voice.md
  and banned-words.md, then fixes style. Never adds or changes a
  claim. Reports what it changed and why.
tools: Read, Edit, Bash
model: opus
---

Outside Claude Code, in your own scripts that tag hundreds of posts or classify a scraped feed, you'll also see cheap open models offered through OpenRouter (DeepSeek, GLM-5.3, MiniMax). They're a fair option only for bulk, schema-checked labeling with no tools and nothing a reader sees, and only after you compare against the cheapest Claude option (Haiku 4.5 with a cached prompt, or the Batch API at 50% off), not the default one. Check where the provider stores data before you send it anything about customers. Claude Code itself does not support pointing at non-Claude models, so none of this touches your drafting pipeline. Whatever you run, log the provider and model on every usage row, or your cost report will price calls at the wrong rate.

The editor skill: standards as code

Your editorial standards split into two kinds, and they need different enforcement. Judgment standards - rhythm, structure, whether the hook lands - live in the editor agent's instructions and the voice file. Mechanical standards - banned words, em dashes, character limits - belong in a script, because a script enforces them every single time and a prompt only mostly does.

  • The humanize pass (judgment): kill throat-clearing intros, vary sentence rhythm, cut every line that adds nothing, replace abstractions with specifics from the brief. Encode it as its own skill - .claude/skills/humanize/SKILL.md - so the editor agent runs it inside the pipeline and anyone on the team can run /humanize on any text, anytime. Nobody re-prompts 'make this sound less AI'. Humanizers are a library staple: install one from skillsmp.com if it fits, then adapt it to voice.md and banned-words.md rather than starting blank.
  • The lint pass (mechanical): scan for banned-words.md entries, em dashes, sentence-length violations, missing required sections. Output: pass, or a list of exact line numbers.
  • The voice check: every rewrite pair in voice.md is effectively a test case. Spot-check the draft against three random pairs.
scripts/lint_draft.py (the idea, not the whole file)
import re, sys

BANNED = [w.strip().lower() for w in open("brand/banned-words.md")
          if w.strip() and not w.startswith("#")]
DASHES = {"\u2014": "em dash", "\u2013": "en dash"}
PATTERNS = {  # constructions a word list can't catch
    r"\bit'?s not (just )?\w+[^.]*, it'?s\b": "not-X-it's-Y reveal",
    r"^(most|every) (teams?|founders?|people|marketers?)\b": "strawman opener",
}

def lint(path: str) -> list[str]:
    issues = []
    for n, line in enumerate(open(path), 1):
        low = line.lower()
        issues += [f"L{n}: {name}" for ch, name in DASHES.items() if ch in line]
        issues += [f"L{n}: banned '{w}'" for w in BANNED
                   if re.search(rf"\b{re.escape(w)}\b", low)]
        issues += [f"L{n}: {name}" for rx, name in PATTERNS.items()
                   if re.search(rx, low.strip())]
    return issues

if __name__ == "__main__":
    found = lint(sys.argv[1])
    print("\n".join(found) or "PASS")
    sys.exit(1 if found else 0)   # nonzero = the pipeline stops

Two details in there matter more than they look. Whole-word matching, because substring checks misfire: in our own lead pipeline a substring match on 'bdr' once rejected a founder whose headline just happened to contain those letters. And a nonzero exit code, because a linter that prints problems but exits 0 lets the pipeline carry on as if it passed. Prove the check can fail before you trust it: paste an em dash and a banned phrase into a test draft and confirm it stops. Then wire it as a PostToolUse hook on writes to content/drafts/, so it runs on every draft whether or not anyone remembers to call it.

The human gate is a folder

Every automation in this course respects one boundary: content/drafts/ is the machine's territory, content/approved/ is human territory. Agents write to drafts/, read from approved/, and never move a file across the line. A person does that, with their own hands, after reading the piece.

When a piece is published, move it from approved/ to published/ and add the URL plus a performance note. That archive is fuel: it feeds next quarter's voice re-extraction, the newsletter assembly in module 2, and the 'what compounds' analysis in module 3.

Run it end to end

Time to ship one piece through the whole machine: brief in, reviewed draft out, every claim verified, every standard enforced.

  1. Pick a topic that's actually on your calendar - not a toy. Run seo-brief or write the brief by hand.
  2. Run /write-post on the brief. Approve or fix the outline when it pauses.
  3. Read the editor's output against the lint report and the fact-check report. Fix what's flagged.
  4. Do your human read. Anything you change by hand, consider as a new rewrite pair for voice.md.
  5. Move it to content/approved/. Note the total wall-clock time - you will compare it to your old process and to your module-2 numbers.

Expect the first run to be rough and the third to be smooth. The pipeline improves because every fix lands in a file - the voice guide, the agent instructions, the lint script - instead of evaporating after one conversation.

Do this now

Sources and further reading

We set it up with you

Want us to set it up with you, end to end?

Three one-on-one sessions. We train you on your real stack and build your first agents together, until you can run it yourself. You keep everything.