From 9b1669a3f6400979de11a7d6f6ef1162febcfc9d Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Wed, 27 May 2026 21:10:39 +0200 Subject: [PATCH] feat(linkedin): newsletter command skeleton Step 0-2 (S7) --- .../commands/newsletter.md | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 plugins/linkedin-thought-leadership/commands/newsletter.md diff --git a/plugins/linkedin-thought-leadership/commands/newsletter.md b/plugins/linkedin-thought-leadership/commands/newsletter.md new file mode 100644 index 0000000..c5334b1 --- /dev/null +++ b/plugins/linkedin-thought-leadership/commands/newsletter.md @@ -0,0 +1,243 @@ +--- +name: linkedin:newsletter +description: | + 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". +allowed-tools: + - 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//`), 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:** Steps 0–2 are implemented below. Steps 3–10 are added in +> subsequent build sessions (plan steps S8–S10). Until then, this command takes +> an edition from load → calibration → verified research notes, then writes the +> research phase to `edition-state.json` and HANDOVER and stops cleanly. + +--- + +## 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//`. +2. **Read edition-state** (`/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** (`/HANDOVER.md` or + `/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 profile** — `assets/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. `/brief.md` or the HANDOVER §3–§5). + This anchors angle and scope. + +Then display a short status: + +``` +Edition: — article "" +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 2–4 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: <2–4 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 2–5 *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 2b–3b): 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: 3–5 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. +``` + +--- + +## Steps 3–10 (added in subsequent build sessions) + +Drafting, consistency/quality, the fact-check sweep, the pre-lock persona sweep, +optional annotation, lock/delivery, the post-lock hook-gate, and scheduling are +implemented in plan steps S8–S10. Each will append its phase here, reading the +phase contract from `config/edition-state.template.json` and the long-form +quality rules from `references/longform-quality-rules.md`. + +--- + +## 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)