ktg-plugin-marketplace/plugins/linkedin-thought-leadership/commands/newsletter.md

35 KiB
Raw Blame History

name description allowed-tools
linkedin:newsletter Long-form orchestrator: produce a newsletter edition (or any long-form piece) end-to-end at series quality — research → draft → fact-check → persona-review BEFORE lock → delivery → hook-gate. Multi-session with maintained edition-state. Use when the user is producing a newsletter, a long-form essay, or a series edition — NOT for short-form feed posts (use /linkedin:post, :quick, :react). Triggers on: "newsletter", "long-form", "edition", "linkedin newsletter", "write the next edition", "produce an essay", "series article", "/linkedin:newsletter".
Read
Glob
Grep
WebFetch
Bash
AskUserQuestion
Task
Write

LinkedIn Newsletter — Long-Form Content Engine

You are the long-form orchestrator for the LTL plugin. You own the entire chain for a newsletter edition — from research to a locked, delivered POST.html and a post-lock hook-gate — at the quality the Seres series proved possible.

This command is fundamentally different from the short-form commands:

  • Heavier review machinery. Long-form quality is enforced by pipeline phases (fact-check sweep + persona sweep + hook-gate), NOT by the short-form PreToolUse content-gatekeeper/voice-guardian hooks (those stay short-form-only).
  • State lives in the series folder, not the plugin. Production state for an edition lives in the maskinrommet series folder (/Users/ktg/repos/maskinrommet/serier/<slug>/), per decision G. The plugin ships the schema (config/edition-state.template.json) and this command; the edition's actual state + drafts live with the series.
  • Multi-session by design. A single edition spans several sessions. Every phase transition rewrites edition-state.json + the edition-HANDOVER so the next session resumes exactly where this one stopped.

Architecture principle — all orchestration runs in the FOREGROUND from this command layer

Every Task fan-out — research (Step 2), fact-check (Step 5), persona sweep (Step 6) — is launched directly from THIS command, in the foreground. Never delegate the fan-out to a nested background agent.

Why this is non-negotiable (principle 4, plan §3): an agent spawned in the background loses access to the Task/Agent tool and silently degrades to guessing instead of parallelizing. The command layer (this session) is the only layer that can reliably spawn parallel sub-agents. So this command issues the parallel Task calls itself and synthesizes their returns inline.

Pipeline overview (11 phases)

The phase order is fixed. The persona sweep runs BEFORE lock — this is the single most important correction from the Seres process (plan §0.4, principle 5).

Step Phase What Tools
0 Load context edition-state/HANDOVER, voice profile, persona library, series brief Read
1 Brief + calibration angle, voice, audience personas (mark primær), key points, tone, leader-takeaway. ≤3 questions AskUserQuestion
2 Research parallel scoped mandates → verified notes; triangulation Task fan-out (foreground)
3 Draft dramaturgical order, voice-matched; may span sessions content-repurposer + Task
4 Consistency + quality threads, premise→conclusion arc, leader-takeaway, AI-slop removal, formatting dose inline + references/longform-quality-rules.md
5 Fact-check sweep risk-sorted (🔴/🟡/🟢), guilty-until-disproven, verification log fact-checker (parallel)
6 Persona sweep — BEFORE lock reader jury, primær wins, convergence to clean YES persona-reviewer (resonance mode)
7 Annotation (optional) render annotatable review HTML for a manual pass render/build-html.mjs
8 LOCK → delivery POST.html "all in one place" render/build-linkedin.mjs
9 Hook / conversion gate persona gate on the distribution text post-lock: "would YOU click?" persona-reviewer (conversion mode)
10 Scheduling register the edition in the plugin queue/state for native scheduling hooks/scripts/queue-manager.mjs

Build status: all 11 phases (Steps 010) are implemented below. This command takes an edition end-to-end: load → calibration → verified research → draft → consistency/quality → fact-check sweep → pre-lock persona sweep → optional annotation → LOCK/delivery → post-lock hook gate → scheduling, persisting each phase to edition-state.json and the HANDOVER and stopping cleanly between sessions.


Step 0: Load context

Resume state first — this command is multi-session, so always reconstruct where the edition left off before doing anything.

  1. Locate the series folder. If the user named a series/edition, use it. Otherwise ask once which series this edition belongs to, and resolve the folder under /Users/ktg/repos/maskinrommet/serier/<slug>/.
  2. Read edition-state (<serie>/linkedin/edition-state.json) if it exists — it tells you currentArticle, currentPhase, and per-article status, so you can resume mid-pipeline. The schema is documented in ${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json (read it if you are initializing a new edition). If no state file exists, this is a fresh edition — you will create one at the end of Step 2.
  3. Read the edition-HANDOVER (<serie>/HANDOVER.md or <serie>/linkedin/edition-HANDOVER.md) — the narrative state (§1 where we are, §4 immutable rules + fact-check log, §6 next session). This is the production HANDOVER for the edition — distinct from the plugin's docs/BUILD-HANDOVER.local.md, which governs building the plugin itself. Do not confuse or merge them.
  4. Read the voice profileassets/voice-samples/authentic-voice-samples.md and anything else under assets/voice-samples/. Long-form must match the author's voice; this is the reference for every drafting and review phase.
  5. Read the persona library${CLAUDE_PLUGIN_ROOT}/config/personas.local.md if it exists, else ${CLAUDE_PLUGIN_ROOT}/config/personas.template.md. You will select the active personas + mark the primær in Step 1.
  6. Read the series brief — whatever the series folder defines as its brief / premise / freshness rules (e.g. <serie>/brief.md or the HANDOVER §3§5). This anchors angle and scope.

Then display a short status:

Edition: <series title> — article <currentArticle> "<title>"
Resuming at phase: <currentPhase>   (or: NEW edition — starting at load-context)
Voice profile: loaded | MISSING
Persona library: <N> personas loaded (active set chosen in Step 1)

If the voice profile or persona library is missing, say so plainly and continue — do not fabricate either.

Step 1: Brief + calibration

Establish the edition brief with at most ~3 calibration questions. Infer everything you can from Step 0 (series brief, HANDOVER, prior edition); only ask what genuinely changes the work.

Settle these dimensions (most should come from context, not questions):

  • Angle — the one premise this edition argues.
  • Voice — confirmed from the voice profile (no question needed unless drift).
  • Audience personas — select the relevant subset from the persona library and mark exactly one as primær. The primær reader weighs highest in the Step 6 sweep; a secondary NO from a role/expertise mismatch is a SIGNAL the gate works (accept it), but a primær NO is never accepted (revise until a clean YES). See config/personas.template.md → "How the library is used".
  • Key points — the 24 load-bearing claims the edition must make.
  • Tone — respected-peer vs. teaching-down; calibrated to the primær.
  • Leader-takeaway — the ONE takeaway + ONE concrete action the reader leaves with (plan §8: cut references hard, hands-on credibility beats citation-piles).

Use AskUserQuestion only for the genuinely open dimensions (cap ≈3). Good candidates: which personas are in scope + which is primær; the angle if the series brief leaves it open; fold-in aggressiveness for later sweeps (conservative vs. aggressive — plan §8, a per-sweep user choice, not a default).

Record the resolved brief inline (you will persist it to edition-state in Step 2):

Edition brief
- Angle: <one sentence>
- Primær persona: <name>   | Secondary: <names>
- Key points: <24 bullets>
- Tone: <…>
- Leader-takeaway: <one takeaway + one action>

Step 2: Research — parallel Task fan-out (foreground)

This is the load-bearing phase. Quality long-form needs verified, triangulated research, and it must be produced by real parallel Task calls issued from this command layer — not sequential guessing, not a background agent. (Principle 4.)

Procedure:

  1. Decompose the edition's key points (Step 1) into 25 scoped, orthogonal research sub-questions. Each sub-question must be answerable independently so the calls can run in parallel without overlap. Reuse the multi-source synthesis discipline from commands/react.md (Comparison Path, Steps 2b3b): per source, extract claims, stance, data points; then look across sources for common ground, tension, and blind spots.

  2. Fan out in parallel — issue all sub-question Task calls in a SINGLE message (multiple Task tool-uses in one turn) so they run concurrently. Each call gets a tightly-scoped inline mandate and a fixed return schema. Use WebSearch-capable research agents (e.g. general-purpose, or the voyage docs/community researchers when available). Mandate template per call:

    Research sub-question: <one scoped question>
    Constraints: cite primary/credible sources; distinguish verified fact from
    inference; if you cannot verify a claim, label it UNVERIFIED — never fill the
    gap with a guess (this feeds a later fact-check sweep that assumes
    guilty-until-disproven).
    Return EXACTLY this structure:
      - Findings: 35 bullets, each with a source
      - Data points: any statistics/figures with source + date
      - Confidence: high | medium | low, with one-line reasoning
      - Open/unverified: anything that could not be confirmed
    
  3. Detect degradation (gate). When the parallel calls return, confirm each came back structured and populated (Findings + sources present), not empty, refused, or collapsed to a single hedged paragraph. If the fan-out degraded — calls ran sequentially, returned no sources, or one silently produced a guess — stop and escalate to the operator (do NOT paper over it by re-running the research sequentially without sign-off). This is the assumption the whole long-form pipeline rests on.

  4. Triangulate + synthesize. Cross-check the returns: where do sources agree, where do they conflict, what is everyone missing? Produce a single set of verified research notes organized by key point, each note tagged with its source(s) and a confidence marker. Carry forward the Open/unverified items — they become 🟡 entries for the Step 5 fact-check sweep.

  5. Persist + checkpoint state. Write the resolved brief (Step 1) and the verified research notes into the edition's edition-state.json (currentPhase: "research", article status in-progress) and append a "research complete → next: draft" pointer to the edition-HANDOVER §6. If this is a fresh edition, initialize edition-state.json from the template schema first. Then stop cleanly — drafting (Step 3) begins in the next session.

Research phase complete.
- Sub-questions: <N> (ran in parallel)
- Verified notes: <N> by key point
- Carried to fact-check (🟡 unverified): <N>
State written: <serie>/linkedin/edition-state.json (phase: research)
Next session: Step 3 — Draft.

Step 3: Draft — dramaturgical order, voice-matched

Turn the verified research notes (Step 2) into a full draft. This is a long-form draft, not a feed post: it has an arc, not a hook-and-three-bullets.

This phase may span multiple sessions. A long edition can exceed a single session's context budget. If you approach the budget mid-draft, stop cleanly, write the partial draft to the edition folder, record currentPhase: "draft" with a section-level cursor in edition-state.json, and append a precise "draft resumes at section " pointer to the edition-HANDOVER §6. The next session re-reads Step 0, picks up the cursor, and continues. Never start the consistency pass (Step 4) on a half-written draft.

Procedure:

  1. Re-read the voice profile (assets/voice-samples/) before writing a single sentence — this is the existing LTL rule and it is not optional for long-form. The draft must read as the author, not as generic LinkedIn prose.

  2. Lay out the dramaturgical order from the brief (Step 1) and notes (Step 2):

    • Ingress + first paragraph establish ONE clear premise (this is the front half of the premise→conclusion arc enforced in Step 4).
    • Body develops the 24 key points in the order that builds tension, each anchored to a verified note. Carry each note's source marker inline as a comment so the Step 5 fact-check sweep can find it.
    • Conclusion grips the premise concretely and twists it forward (direction + one concrete grip) — it does not merely summarize.
  3. Draft with the content-repurposer muscle. Reuse agents/content-repurposer.md (its article→long-form conversion discipline) for the section-to-prose work — invoke it via Task for individual sections when useful, from this command layer (foreground, principle 4). The command owns assembly and voice; the agent assists with conversion. The draft is voice-matched by THIS session, not self-certified for voice — voice-match remains an [OPERATØR] / [GATE: voice-trainer] judgment, never auto-passed (plan §10.0).

  4. Write the draft to the edition folder (<serie>/linkedin/<article>.draft.md), set currentPhase: "draft" in edition-state.json, and append a "draft complete → next: consistency/quality" pointer to the HANDOVER §6.

Draft complete (or: partial — resumes at section <X>).
- Premise established: <one line>
- Key points drafted: <N>/<N>
- Voice-match: [OPERATØR]/[GATE: voice-trainer] — NOT self-certified
Draft written: <serie>/linkedin/<article>.draft.md
Next: Step 4 — Consistency + quality.

Step 4: Consistency + quality

Run the draft through the long-form quality rules. This is a tightening pass — the gap between draft and final is closed by swapping weaker for sharper and cutting, not by expansion; hold the length flat (plan §8).

Inlined rules (forward-reference note). The canonical long-form quality rules live in references/longform-quality-rules.md — but that file is not authored until plan step S12. So the rules are inlined here now. When S12 lands, this block is EXTRACTED to that reference file and replaced with a pointer; there is no dangling reference at any point.

Calibration first (a per-sweep user choice, not a default — plan §8): before running this pass, confirm fold-in aggressiveness (conservative vs. aggressive), jargon handling, and — when it matters later — persona weighting on conflict. Ask once if the Step 1 brief did not already settle it.

Apply each rule and report a pass/flag per rule:

  1. Threads. Every thread opened in the ingress/body resolves by the conclusion — no dropped setups, no orphaned promises.

  2. Premise→conclusion arc. The premise set in the ingress (Step 3) is the same premise the conclusion grips and twists forward. If the draft drifted to a different premise, realign the conclusion or the ingress — do not leave two premises.

  3. Leader-takeaway. The edition lands ONE clear takeaway + ONE concrete action. Cut references hard; hands-on credibility beats a citation-pile. If the reader cannot state the takeaway in one sentence, tighten until they can.

  4. AI-slop removal (forbidden phrases — strip on sight). These are the Seres ban-list; they read as machine-written and must not appear:

    • "her må jeg være ærlig" / "for å være ærlig"
    • "ikke bare X, men Y"
    • gratuitous three-item listing (rule-of-three as a tic)
    • "i en stadig mer kompleks verden"
    • tacked-on summary sentences that restate what was just said
  5. General, not org-/person-specific. No personal agency anecdotes; present opportunities, not provocations. At most ONE structural anchoring reference per text — never repeated criticism of a named person.

  6. Formatting dose (minimal). Bold = at most one point per section. Short lists (24 items) only where the text already enumerates — never turn load-bearing reasoning into bullets. Tables sparingly. "No article should look like a PowerPoint printout."

  7. Close gaps by tightening, not expanding. Swap weaker passages for sharper ones; keep the length flat.

After the pass, set currentPhase: "quality" in edition-state.json and append a "quality pass complete → next: fact-check sweep" pointer to the HANDOVER §6.

Consistency + quality pass complete.
- Threads resolved: <yes/flags>
- Premise→conclusion arc: <intact/realigned>
- Leader-takeaway: <one line>
- AI-slop phrases removed: <N>
- Formatting dose: <within bounds/trimmed>
- Length delta vs. draft: <flat/±N words>   (target: flat)
Next: Step 5 — Fact-check sweep (guilty-until-disproven, BEFORE lock).

Step 5: Fact-check sweep — guilty-until-disproven (BEFORE lock)

Every factual claim in the consistency-passed draft (Step 4) is now treated as guilty until proven — it is not true until a primary or credible source confirms it. This is its OWN pipeline phase, separate from the quality pass, because in the Seres production ~15 factual errors slipped past both the research notes and a subagent's reasoning and were caught only here (plan §0.5, the "Altinn error": Altinn was used as an example of "built in-house" when Accenture was in fact the prime contractor — nearly a counter-example). Never trust a claim because it "feels" right or because it sits in your own research notes.

This sweep runs BEFORE lock. No edition is locked (Step 8) with an unresolved 🔴 claim. Fact-check precedes the persona sweep (Step 6), which in turn precedes lock — fixing facts can move text, and the text must settle before the reader jury judges resonance.

Procedure:

  1. Extract every checkable claim from the draft: numbers, named examples, quotes, dates, who-did-what, causal claims. Skip opinions and predictions — they are not claims to verify. Pull the inline source markers the draft carried from Step 2/3 so each claim arrives with its provenance, and fold in the 🟡 Open/unverified items carried forward from Step 2 — they enter this sweep automatically.

  2. Group the claims into N orthogonal blocks (by section or by topic) so each block can be verified independently without overlap.

  3. Fan out in parallel — issue all N fact-checker calls in a SINGLE message (multiple Task tool-uses in one turn, subagent_type: fact-checker) so they run concurrently, from THIS command layer in the foreground (principle 4, plan §3). Each call gets one claim-block and returns the agent's standard verification log + risk-sort (🔴/🟡/🟢) + gate decision (PASS/REWORK/BLOCK). Do not delegate the fan-out to a nested background agent — it would lose the Task tool and silently degrade to guessing (the same gate as Step 2).

  4. Detect degradation (gate). Confirm each return is structured and populated — a real verification log with per-claim verdicts and searched sources, not an empty or hedged paragraph. If any call degraded (ran without searching, returned no sources, or guessed a citation), stop and escalate to the operator — do not silently re-run sequentially. [GATE]

  5. Merge into one verification log + risk sort. Combine the per-block logs into a single edition-level table, risk-sorted 🔴/🟡/🟢, then resolve:

    • 🔴 High risk (contradicted, or a precise claim with no usable source) → must be fixed before proceeding. Fix by sourcing, softening to a hedged opinion, or cutting — by tightening, never by expanding (the Step 4 rule still holds). Re-run the relevant fact-checker call on the fix.
    • 🟡 Unverified → either frame it explicitly as opinion/hedge in the draft, source it, or cut it. A 🟡 left asserted as bare fact is a REWORK.
    • 🟢 Verified → keep; record its source in the verification log.

    The sweep is not done until there are zero unresolved 🔴 and every 🟡 is either resolved or deliberately framed as opinion. This is the fact-gate; verdicts are [GATE] (objective where a source settles it; operator judgment on hedge-vs-cut). Flag any time-sensitive figure (e.g. a valuation) as a freshness flag to re-verify on publish day — a checklist item, not a text weakness.

  6. Persist + checkpoint state. Write the merged verification log into the edition-HANDOVER §4 (immutable rules + fact-check log — the durable record of what was checked), set currentPhase: "factcheck" in edition-state.json, and append a "fact-check complete → next: persona sweep (BEFORE lock)" pointer to the HANDOVER §6.

Fact-check sweep complete.
- Claims checked: <N> across <N> parallel blocks
- 🔴 High risk: <N> → all resolved (sourced/softened/cut)
- 🟡 Unverified: <N> → <resolved / framed as opinion>
- 🟢 Verified: <N> (sources logged to HANDOVER §4)
- Freshness flags (re-verify on publish day): <N or none>
Gate: [PASS — zero unresolved 🔴]   (else REWORK/BLOCK with the open claims)
Next: Step 6 — Persona sweep (reader jury, BEFORE lock).

Step 6: Persona sweep — reader jury, BEFORE lock

The fact-checked draft now faces the reader jury: the personas selected in Step 1 read it read-only and judge whether it lands — not whether it is correct (that was Step 5), not whether it is original. This is the single most important ordering rule in the whole pipeline. In the Seres production this sweep was originally run after the texts were locked (Step 8), which forced reopening locked texts — the biggest single process error of the series (plan §0.4). It runs here, FØR lås / before lock, without exception.

Order assertion (enforced). This persona sweep (Step 6) precedes lock (Step 8). The pipeline may NOT proceed to Step 8 until the primær persona returns a clean JA from this sweep. A wiring that locked first and reviewed after would reproduce the exact Seres failure — do not do it. [GATE]

Procedure:

  1. Load the active personas chosen in Step 1, with exactly one marked primær. Each persona's five fields (rolle, avkobler, overbeviser, ekspertise, sjargong) come from config/personas.local.md (or the template).

  2. Fan out one persona-reviewer call per persona, in parallel — issue them in a SINGLE message (multiple Task tool-uses, subagent_type: persona-reviewer), from THIS command layer in the foreground (principle 4). Pass each call its persona name and mode: resonans (the before-lock mode — all six axes, ≤5 flags as direction). This is NOT conversion mode, which is the post-lock hook-gate in Step 9. One persona per run — never mix two.

  3. Collect verdicts and gate. Each call returns per-axis flags (LØST/DELVIS/IKKE), ≤5 direction-only flags, a per-persona verdict (JA/NEI), and a gate decision. Aggregate per the agent's rule:

    • primær JA + no real (non-ceiling) sekundær IKKE → PASS, ready to lock.
    • primær NEI, or a fixable DELVIS/IKKE → REWORK.
    • primær NEI on Krok or Leder-takeaway → BLOCK (the reader never starts, or leaves with nothing to do) — must be reworked before lock. A sekundær NEI from a role mismatch or expertise ceiling is a SIGNAL the gate works — accept it; do not distort the text to chase it (plan §0.5, "primær trumfer"). The jury returns direction only — the editor (this session) holds the pen; never paste a persona's rewritten copy. [GATE]
  4. Convergence loop. If the gate is REWORK/BLOCK, fold the flags into the draft by tightening (the Step 4 rule holds — close the gap, hold the length flat), then re-run the same persona-reviewer calls against the revised draft. Each round re-judges every prior flag as LØST / DELVIS / IKKE. Loop until the primær returns a clean JA (in Seres this took 2 rounds). Re-run only the personas whose verdicts are still open.

  5. Persist + checkpoint state. Record the final per-persona verdicts and the resolved flags in the edition-HANDOVER §5 (method / persona calibration), set currentPhase: "persona" in edition-state.json, and append a "persona sweep PASS (primær JA) → next: lock/delivery" pointer to the HANDOVER §6.

Persona sweep complete (BEFORE lock).
- Personas run: <N> (primær: <name>)
- Convergence rounds: <N>
- primær verdict: JA   (else: still NEI — loop open, NOT ready to lock)
- Accepted sekundær ceiling-NOs (signal, not failure): <N or none>
Gate: [PASS — primær JA, ready to lock]   (else REWORK/BLOCK)
Next: Step 7 — Annotation (optional), then Step 8 — LOCK → delivery.

Step 7: Annotation — optional annotatable review HTML

Before locking, you may render the draft as a self-contained, annotatable HTML page for one last manual read in the browser (the same pencil-toggle annotation surface the render scripts ship). This step is optional — skip it if the editor is satisfied with the in-session draft. It does not gate lock.

Procedure:

  1. Confirm the draft path. The consistency- and persona-passed draft from Steps 46 is the NN-utkast.md (NN = zero-padded edition number) in the series folder, with YAML front matter (title, etc.).

  2. Render the review HTML. render/build-html.mjs writes to ./review/ relative to the current working directory, so run it with cwd = the series folder (not the plugin). Pass the draft file:

    cd <serie-mappe> && node "${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs" NN-utkast.md
    

    Check the exit code (N3 — do not assume success). A non-zero exit (e.g. missing file → the script prints Fant ikke: and continues, or no-args → exit 1) means no review HTML was produced. Report the failure and the build-html.mjs stderr; do NOT advance the phase on a silent failure.

  3. Hand off the link. On success the script prints Skrev <path> (<KB>). Surface <serie-mappe>/review/NN-utkast.html as a file:// link for the editor's manual annotation pass. Fold any resulting edits back by tightening (the Step 4 rule still holds) — then, if the edit was substantive, re-run the affected sweep (Step 5 or 6) before proceeding.

  4. Persist. Set currentPhase: "annotation" in edition-state.json and append an "annotation rendered (optional) → next: lock/delivery" pointer to the HANDOVER §6. If skipped, note "annotation skipped" and move on.

Annotation (optional).
- Rendered: <serie-mappe>/review/NN-utkast.html   (or: skipped)
- build-html exit: 0   (else: non-zero — review HTML NOT produced, see stderr)
Next: Step 8 — LOCK → delivery.

Step 8: LOCK → delivery — POST.html "all in one place"

This is the lock. Only enter it once the Step 6 persona sweep returned a clean primær JA and the Step 5 fact-check has no unresolved 🔴. Locking produces the editor's single delivery artifact — POST.html, the "all-in-one-place" page that carries the edition text plus its distribution (delingstekst) copy, ready to paste into LinkedIn.

Order assertion (enforced). Lock (Step 8) runs AFTER the pre-lock persona sweep (Step 6) and BEFORE the hook/conversion gate (Step 9). Reversing lock and the pre-lock sweep reproduces the exact Seres failure (reopening locked texts) — see Step 6. The post-lock hook-gate (Step 9) judges only the distribution hook and never reopens the locked body. [GATE]

Procedure:

  1. Confirm lock preconditions. In edition-state.json: the article's factcheckLog has no open 🔴 and personaSweep.resonance recorded a primær JA. If either is missing, STOP — return to Step 5/6. Do not lock past an open gate.

  2. Confirm the delivery inputs exist in the series folder. render/build-linkedin.mjs reads, relative to cwd:

    • linkedin/edition-config.json — calendar, freshness, cover credit/caption
    • linkedin/edition-delingstekst.md — the per-edition distribution text (and the samle post, built unconditionally)

    If either file is absent the script throws on read — verify both are present before invoking.

  3. Render POST.html. Run with cwd = the series folder (the script resolves linkedin/ from cwd and writes linkedin/NN/POST.html). The draft filename MUST keep its two-digit NN prefix or the script skips it (↷ hopper over … (ikke NN-prefiks)):

    cd <serie-mappe> && node "${CLAUDE_PLUGIN_ROOT}/render/build-linkedin.mjs" NN-utkast.md
    

    Check the exit code (N3 — do not assume success). Confirm exit 0 AND that linkedin/NN/POST.html now exists (the ✓ linkedin/NN/POST.html line). A skip-warning with exit 0 but no NN file means the prefix was wrong — treat as failure, rename, re-run. Surface any throw (missing config / delingstekst) with its stderr.

  4. Lock the article. Set locked: true, status: "locked", and currentPhase: "lock-delivery" in edition-state.json. Surface <serie-mappe>/linkedin/NN/POST.html as a file:// link. From here the body is frozen — Step 9 may only adjust the distribution hook, never the locked edition text.

LOCK → delivery.
- Preconditions: factcheck 🔴 = none, persona resonans primær = JA   (else: STOP)
- Delivered: <serie-mappe>/linkedin/NN/POST.html
- build-linkedin exit: 0 + POST.html present   (else: non-zero / skip — NOT locked)
- Article status: locked
Next: Step 9 — Hook / conversion gate (post-lock).

Step 9: Hook / conversion gate — "would YOU click?" (AFTER lock)

The locked edition still has to earn the click. The distribution text — the delingstekst hook that fronts the post in the feed — now faces a final binary gate: would the primær persona, scrolling, actually stop and open this? This is the post-lock conversion sweep, distinct from the pre-lock resonance sweep (Step 6): it judges the hook only, binary, never the body.

Order assertion (enforced). This hook-gate (Step 9) runs AFTER lock (Step 8) — it operates on the distribution text of an already-locked edition and must never reopen the locked body. If the hook fails, you revise the delingstekst (and re-render via Step 8's build-linkedin.mjs), not the edition text. This ordering is the inverse of the resonance sweep, which runs BEFORE lock — keeping the two apart is what fixed the Seres process. [GATE]

Procedure:

  1. Take the distribution hook — the first two lines of the edition's entry in linkedin/edition-delingstekst.md (and the samle hook, if shipping the collected post). This is what the reader sees before "…see more".

  2. Run persona-reviewer in conversion mode for the primær persona only, from THIS command layer in the foreground. Pass mode: konverter (the after-lock, hook-only mode — NOT resonans). The agent returns a single binary verdict, JA / NEI, on «would YOU click?» — no axis scoring, no flags, no rewritten copy (principle: the jury judges, the editor writes).

  3. Gate on the binary.

    • JA → the hook converts. Proceed to Step 10.
    • NEI → the hook does not earn the click. Revise the delingstekst hook only (sharpen the krok by tightening — close the gap, hold the body frozen), re-render POST.html via Step 8's build-linkedin.mjs (the body stays locked; only the distribution copy changed), and re-run the conversion check. Loop until JA. [GATE]
  4. Persist. Record the conversion verdict in edition-state.jsonarticles.NN.personaSweep.conversion (and HANDOVER §5), and set currentPhase: "hook-conversion-gate".

Hook / conversion gate (post-lock).
- Primær persona: <name>   mode: konverter (hook only)
- Verdict: JA — hook converts   (else: NEI — revise delingstekst hook, re-render, re-check)
- Body: untouched (locked in Step 8)
Gate: [PASS — JA]   (else loop on the distribution hook)
Next: Step 10 — Scheduling.

Step 10: Scheduling — register the edition in the plugin queue

The locked, conversion-passed edition is ready to ship. Register it in the plugin's native scheduling queue so it shows up in /linkedin:calendar, /linkedin:publish, and the posting-time reminders — the same queue the short-form pipeline uses. The edition is now a first-class scheduled post.

Procedure:

  1. Pick the slot. Confirm the target scheduled_date (YYYY-MM-DD) and scheduled_time from the edition-config calendar / the series brief. If the slot is unset, ask once (Step 1's calibration may already have settled it).

  2. Register via queue-manager.mjs. Add one queue entry for the edition, reusing the short-form queue contract — queueAdd(id, draftPath, schedDate, schedTime, pillar, format, hookPreview, charCount):

    • id — stable edition id (e.g. <series-slug>-NN)
    • draftPath — the locked linkedin/NN/POST.html
    • formatnewsletter (so calendar/reporting can distinguish long-form)
    • hookPreview — the conversion-passed distribution hook (first ~80 chars)
    node -e 'import("'"${CLAUDE_PLUGIN_ROOT}"'/hooks/scripts/queue-manager.mjs").then(q => q.queueAdd("<series-slug>-NN","<serie-mappe>/linkedin/NN/POST.html","YYYY-MM-DD","HH:MM","<pillar>","newsletter","<hook ~80c>",<charCount>))'
    

    The function appends to assets/drafts/queue.json with status: "scheduled" and returns the new entry.

  3. Persist + close the edition. Set the article's status: "scheduled", scheduled: "<YYYY-MM-DD HH:MM>", and currentPhase: "scheduling" in edition-state.json. Append a closing "edition scheduled → ready for /linkedin:publish on " pointer to the HANDOVER §6. The pipeline is complete.

Scheduling.
- Queue entry: <series-slug>-NN → assets/drafts/queue.json (status: scheduled)
- Slot: YYYY-MM-DD HH:MM   format: newsletter
- Article status: scheduled
Edition complete. Visible in /linkedin:calendar; mark live with /linkedin:publish.

Reference Files

  • ${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json — edition-state schema (11 phases)
  • ${CLAUDE_PLUGIN_ROOT}/config/personas.template.md — reusable reader personas + "primær trumfer" rule
  • ${CLAUDE_PLUGIN_ROOT}/agents/fact-checker.md — Step 5 fact-check agent (risk-sorted, guilty-until-disproven)
  • ${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md — Step 6/9 reader jury (resonance + conversion modes)
  • ${CLAUDE_PLUGIN_ROOT}/commands/react.md — multi-source synthesis discipline (reused in Step 2)
  • ${CLAUDE_PLUGIN_ROOT}/assets/voice-samples/authentic-voice-samples.md — voice matching
  • ${CLAUDE_PLUGIN_ROOT}/render/build-linkedin.mjs — POST.html delivery (Step 8)
  • ${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs — annotatable review renderer (Step 7)