From 4ed97176276b9c5b2969ea5aeb2dd7cc226eab40 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Thu, 28 May 2026 20:50:56 +0200 Subject: [PATCH] =?UTF-8?q?feat(linkedin):=20v2.2.0=20=E2=80=94=20harden?= =?UTF-8?q?=20longform=20gates=20from=202nd=20production=20run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the 6-change spec from the Seres-serien production (linkedin-plugin-endringsspec.md). All acceptance criteria met. 1. Avoid-patterns (modell-/navne-katalog, completeness-over-reader-action, self-referential overhead openings) → longform-quality-rules.md (rule 1+3) + user-profile.template.md. 2. Persona gate now BLOCKING with explicit hard-fail list (primær mistet meg / doesn't own action / sjargong-mur / modell-navne-katalog → BLOCK; "JA med store forbehold" = NEI) → persona-reviewer.md + personas.template.md. 3. Fact-check declared orthogonal to narrative strength + post-cutoff web-search mandate + high-frequency-error checklist → fact-checker.md. 4. NEW agent voice-scrubber.md (Opus) — de-AI scrub + Norwegian-chronicle voice-drift; gold standard = approved Norwegian editions, NOT the English post corpus. Wired into newsletter.md Step 4. 5. Operator gates = render+annotate rounds (build-html.mjs to file://) as primary flow, AskUserQuestion as receipt/fallback → newsletter.md 2.5+3a. 6. Edition state reconciled with STATE.md (ONE-system). edition-HANDOVER template deleted; narrative to /STATE.md, machine data (factcheckLog, personaSweep, immutableRules) to edition-state.json. Agents 14 to 15; commands unchanged (24). Backward-compatible (additive state-shape only). Docs updated across all three levels + CHANGELOG. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 2 +- README.md | 11 +- .../.claude-plugin/plugin.json | 4 +- .../linkedin-thought-leadership/CHANGELOG.md | 22 ++ plugins/linkedin-thought-leadership/CLAUDE.md | 11 +- plugins/linkedin-thought-leadership/README.md | 32 ++- .../agents/fact-checker.md | 28 ++- .../agents/persona-reviewer.md | 39 +++- .../agents/voice-scrubber.md | 184 +++++++++++++++++ .../commands/newsletter.md | 194 ++++++++++++------ .../config/edition-HANDOVER.template.md | 56 ----- .../config/edition-state.template.json | 6 +- .../config/personas.template.md | 21 ++ .../config/user-profile.template.md | 10 + .../references/longform-quality-rules.md | 20 +- 15 files changed, 491 insertions(+), 149 deletions(-) create mode 100644 plugins/linkedin-thought-leadership/agents/voice-scrubber.md delete mode 100644 plugins/linkedin-thought-leadership/config/edition-HANDOVER.template.md diff --git a/CLAUDE.md b/CLAUDE.md index 4f7489d..a84c54f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ plugins/ ai-psychosis/ v1.0.0 — Interaction awareness (sycophancy, reinforcement loops) config-audit/ v3.1.0 — Configuration intelligence (health, opportunities, auto-fix, whats-active) graceful-handoff/ v2.1.0 — Auto-trigger handoff via Stop hook (skill + JSON pipeline + 4-step model-aware context resolution) - linkedin-thought-leadership/ v2.1.0 — Full-spectrum LinkedIn content engine (short-form feed + long-form newsletter). v2.0.0 consolidated surface (27→24 commands, 16→14 agents) + added `/linkedin:newsletter` orchestrator with fact-check + persona-sweep gates BEFORE lock. v2.1.0 adds skeleton-gate BEFORE prose (Step 2.5 + Step 3a) to `/linkedin:newsletter` + third `persona-reviewer` mode (`skjelett`); pipeline 11→13 phases; commands/agents unchanged in count (24, 14). Render pipeline self-hosted (OFL-1.1 fonts). + linkedin-thought-leadership/ v2.2.0 — Full-spectrum LinkedIn content engine (short-form feed + long-form newsletter). v2.0.0 consolidated surface (27→24 commands, 16→14 agents) + added `/linkedin:newsletter` orchestrator with fact-check + persona-sweep gates BEFORE lock. v2.1.0 added skeleton-gate BEFORE prose (Step 2.5 + Step 3a) + third `persona-reviewer` mode (`skjelett`); pipeline 11→13 phases. v2.2.0 hardens the longform gates (2nd production run): blocking persona hard-fails (mistet meg / doesn't own action / sjargong-mur / modell-navne-katalog → BLOCK), fact-check post-cutoff web-search mandate + orthogonal-to-narrative rule, new `voice-scrubber` agent (Opus, de-AI + Norwegian-chronicle voice; gold standard = approved Norwegian editions NOT English post corpus), render+annotate operator gates (2.5/3a), and edition-state reconciled with STATE.md (`edition-HANDOVER.md` deleted). Agents 14→15; commands unchanged (24). Render pipeline self-hosted (OFL-1.1 fonts). llm-security/ v7.7.2 — Security scanning, auditing, threat modeling. HTML report output for all 18 skill commands (render-report CLI + canonical ESM module mirrored bit-identical into the playground). v7.7.2 translated the remaining Norwegian surface text in the playground UI, the canonical renderer, the agent prompts, and the README/CLAUDE.md state sections to English. v7.7.1 stripped the playground to the catalog as the only routable surface. ms-ai-architect/ v1.15.0 — Microsoft AI architecture (Cosmo Skyberg persona) + manual KB-refresh slash command + v3 project-view (sidebar med 17 artifacts + main + import-modal overlay, v2-surface fjernet i v1.15.0) okr/ v1.0.0 — OKR guidance for Norwegian public sector diff --git a/README.md b/README.md index 1d39913..22f97df 100644 --- a/README.md +++ b/README.md @@ -206,14 +206,19 @@ Key commands: `/architect`, `/architect:ros`, `/architect:security`, `/architect --- -### [LinkedIn Thought Leadership](plugins/linkedin-thought-leadership/) `v2.1.0` +### [LinkedIn Thought Leadership](plugins/linkedin-thought-leadership/) `v2.2.0` Build authentic LinkedIn authority through algorithmic understanding, strategic consistency, and AI-assisted content creation. -v2.1.0 adds a **skeleton gate BEFORE prose** to `/linkedin:newsletter` — two new pipeline phases (Step 2.5 skeleton + section pitch, Step 3a spine prose) each with their own operator-gate, plus a third `persona-reviewer` mode (`skjelett`) that judges the five-line spine before any prose is written. Empirically motivated by the Seres-serien Del 3 + Del 4 production: a spine error caught at the skeleton stage costs 5–15 minutes; the same error caught at the resonance stage (Step 6) costs 4–12 hours; post-lock it costs a day. The pipeline grows from 11 to 13 phases; command and agent counts (24, 14) are unchanged. v2.0.0's full-spectrum surface (short-form feed posts AND long-form newsletter editions) is preserved bit-for-bit. Updated for the January 2026 360Brew algorithm change, which validates your creator profile before distributing content. +v2.2.0 **hardens the longform gates** with the lessons from the second `/linkedin:newsletter` production run (Seres-serien): the persona gate is now **blocking with an explicit hard-fail list** (primær «mistet meg» / doesn't own the action / sjargong-mur / modell-/navne-katalog → BLOCK; «JA med store forbehold» = NEI); fact-check is **orthogonal to narrative strength** with a **post-cutoff web-search mandate** + high-frequency-error checklist; a new **`voice-scrubber`** agent (Opus) does de-AI scrub + Norwegian-chronicle voice-drift correction (gold standard = approved Norwegian editions, NOT the English post corpus); operator gates become **render+annotate** rounds; and per-edition state is **reconciled with the global STATE.md** continuity system (`edition-HANDOVER.md` removed). Agents 14 → 15; commands unchanged (24). v2.1.0's skeleton-gate-before-prose and v2.0.0's full-spectrum surface are preserved. Updated for the January 2026 360Brew algorithm change, which validates your creator profile before distributing content. +- **Blocking persona hard-fails (v2.2)** — `persona-reviewer` + `personas.template.md` make primær «mistet meg», doesn't-own-the-action, sjargong-mur, and modell-/navne-katalog BLOCK-level rewrites, not annotations. The bar is the primær reader's *clean* JA. +- **Fact-check orthogonal to polish (v2.2)** — `fact-checker` web-searches every post-cutoff claim (never confirms from memory) and runs an explicit checklist for person titles, org-varying "standards", over-credited studies, source scope, and founding/release years. +- **New `voice-scrubber` agent (v2.2, Opus)** — aggressive de-AI scrub (Pass 1) + Norwegian-chronicle voice-drift correction (Pass 2), calibrated to the **approved Norwegian editions** rather than the English post corpus; wired into Step 4. *New agent — requires a session reload before invokable.* +- **Render+annotate operator gates (v2.2)** — Steps 2.5/3a surface an annotatable `file://` review page (`build-html.mjs`) as the primary operator-review flow; `AskUserQuestion` becomes a receipt + fallback. +- **STATE.md-reconciled edition state (v2.2)** — narrative state in `/STATE.md` (auto-injected, overwritten each phase), machine state in `edition-state.json`; no separate `edition-HANDOVER.md`. - **Skeleton gate BEFORE prose (v2.1)** — `/linkedin:newsletter` Step 2.5 writes a five-line spine (premiss / problem / anbefaling / gevinst / vei videre) + one-line section pitches to `/NN-skjelett.md`. Operator-gate AND parallel persona-skjelett-sweep must both return JA before the pipeline can advance. Step 3a follows with spine prose (one paragraph per section) and its own operator-gate. Encodes the Maskinrommet writing-contract §A discipline into the pipeline. -- **Long-form `/linkedin:newsletter` orchestrator** — multi-session 13-phase pipeline (research → **skeleton + persona-skjelett-sweep** → **spine prose** → full prose draft → fact-check sweep → persona sweep → lock → delivery → hook-gate) with maintained edition-state. Newsletter editions, essays, series articles +- **Long-form `/linkedin:newsletter` orchestrator** — multi-session 13-phase pipeline (research → **skeleton + persona-skjelett-sweep** → **spine prose** → full prose draft → **de-AI/voice scrub** → fact-check sweep → persona sweep → lock → delivery → hook-gate) with maintained edition-state. Newsletter editions, essays, series articles - **Three longform-quality gate agent modes** — `fact-checker` (Opus, verifies every claim against primary sources) and `persona-reviewer` (Opus) with three modes: **`skjelett`** (Step 2.5, before prose), **`resonans`** (Step 6, before lock), **`konverter`** (Step 9, after lock) - **Render pipeline in-plugin** — `build-html.mjs`, `build-pdf.mjs`, `build-linkedin.mjs`, `build-carousel.mjs` with self-hosted Newsreader/Inter/JetBrains Mono under OFL-1.1 - **Guided onboarding** — `/linkedin:onboarding` walks new users through profile → setup → first post in one flow diff --git a/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json b/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json index 2298d36..2c52a83 100644 --- a/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json +++ b/plugins/linkedin-thought-leadership/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "linkedin-thought-leadership", - "version": "2.1.0", - "description": "Full-spectrum LinkedIn content engine — feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.1 adds skeleton + spine-prose gates BEFORE prose to /linkedin:newsletter.", + "version": "2.2.0", + "description": "Full-spectrum LinkedIn content engine — feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.2 hardens the longform gates: blocking persona hard-fails, post-cutoff fact-check mandate, a Norwegian-chronicle de-AI voice-scrubber, render+annotate operator gates, and STATE.md-reconciled edition state.", "author": { "name": "Kjell Tore Guttormsen" }, diff --git a/plugins/linkedin-thought-leadership/CHANGELOG.md b/plugins/linkedin-thought-leadership/CHANGELOG.md index a8e7471..4c69be6 100644 --- a/plugins/linkedin-thought-leadership/CHANGELOG.md +++ b/plugins/linkedin-thought-leadership/CHANGELOG.md @@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.0] - 2026-05-28 + +### Summary +Longform gates hardened with the lessons from the second `/linkedin:newsletter` production run (Seres-serien). A chronicle built as a model/name catalog passed persona review (its flags were read as notes, not stop-signs) and nearly shipped; the rewrite was stronger but introduced fresh factual errors. v2.2.0 closes six concrete weaknesses: the persona gate becomes blocking with an explicit hard-fail list, fact-check is made orthogonal to narrative strength (more polish → more verification) with a post-cutoff web-search mandate, a new Norwegian-chronicle de-AI voice-scrubber is added and wired into Step 4, operator gates become render+annotate rounds, and per-edition production state is reconciled with the global STATE.md continuity system (no more `edition-HANDOVER.md`). 14 → 15 agents; commands unchanged (24). Backward-compatible — the only state-shape change is additive. + +### Added +- **`agents/voice-scrubber.md`** (new, Opus) — aggressive de-AI scrubber + voice-drift corrector for long-form **Norwegian chronicle** drafts. Pass 1 strips objective AI-tells («la meg være ærlig», reflex rule-of-three, em-dash-spam, self-referential overhead, modell-/navne-katalog); Pass 2 corrects drift toward the chronicle voice; Pass 3 appends to a chronicle-voice-drift-log so it sharpens over editions. **Calibration rule (cardinal):** gold standard = the approved Norwegian editions, NEVER `assets/voice-samples/authentic-voice-samples.md` (English short-form, forbids the em-dash). *New agent — requires a session reload before it is invokable.* +- **De-AI / voice scrub sub-pass** in `commands/newsletter.md` Step 4 — fans out `voice-scrubber` (foreground, namespaced) with the draft + approved-Norwegian-edition paths as the gold standard. +- **Blocking hard-fail list** in `agents/persona-reviewer.md` + `config/personas.template.md` — primær «mistet meg» / doesn't own the action / sjargong-mur / modell-/navne-katalog → BLOCK regardless of other axes. «JA med store forbehold» = NEI. +- **Post-cutoff fact-check mandate + high-frequency-error checklist** in `agents/fact-checker.md` — claims dated after the model's knowledge cutoff MUST be web-searched; explicit checks for person titles, org-varying "standards", over-credited studies, source scope, and founding/release years. Fact-check declared orthogonal to narrative strength. +- **Render+annotate operator gates** in `commands/newsletter.md` Steps 2.5 + 3a — HTML annotation via `render/build-html.mjs` → `file://` link is the primary operator-review flow; `AskUserQuestion` becomes a receipt + fallback. +- **Avoid-patterns** — modell-/navne-katalog, completeness-over-reader-action, self-referential overhead openings added to `references/longform-quality-rules.md` (rules 1 + 3) and `config/user-profile.template.md`. +- **`personaSweep.skeleton` + `immutableRules`** fields in `config/edition-state.template.json` (additive). + +### Changed +- **Edition production state reconciled with STATE.md (ONE-system).** `commands/newsletter.md` Step 0 now reads `/STATE.md` (auto-injected by the session-start hook); every phase writes narrative status to `/STATE.md` (overwrite) and machine state (fact-check log, persona verdicts, immutable rules) to `edition-state.json`. All `HANDOVER §4/§5/§6` references replaced. +- `agents/fact-checker.md` principle 3 strengthened to make web search mandatory for post-cutoff claims. +- README, CLAUDE.md, root README, plugin.json version + descriptions. + +### Removed +- **`config/edition-HANDOVER.template.md`** — deleted. The plugin no longer ships or requires a separate handover mechanism; `/STATE.md` + `edition-state.json` carry its content per the global continuity rule. + ## [2.1.0] - 2026-05-28 ### Summary diff --git a/plugins/linkedin-thought-leadership/CLAUDE.md b/plugins/linkedin-thought-leadership/CLAUDE.md index 801bafc..e1795bf 100644 --- a/plugins/linkedin-thought-leadership/CLAUDE.md +++ b/plugins/linkedin-thought-leadership/CLAUDE.md @@ -1,6 +1,6 @@ -# LinkedIn Thought Leadership Plugin (v2.1.0) +# LinkedIn Thought Leadership Plugin (v2.2.0) -Full-spectrum LinkedIn content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.0.0 consolidated the surface (27 commands → 24, 16 agents → 14) while adding the long-form `/linkedin:newsletter` orchestrator + two longform-quality gate agents (`fact-checker`, `persona-reviewer`). **v2.1.0** adds two new gates BEFORE prose to `/linkedin:newsletter` — Step 2.5 (skeleton + section pitch with operator-gate + persona-skjelett-sweep) and Step 3a (spine prose with operator-gate) — plus a third `persona-reviewer` mode (`skjelett`), encoding the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline itself. Pipeline grows from 11 to 13 phases; commands and agents unchanged in count (24, 14). +Full-spectrum LinkedIn content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions — with the January 2026 360Brew algorithm baked in. v2.0.0 consolidated the surface (27 commands → 24, 16 agents → 14) while adding the long-form `/linkedin:newsletter` orchestrator + two longform-quality gate agents (`fact-checker`, `persona-reviewer`). v2.1.0 added two gates BEFORE prose (Step 2.5 skeleton + Step 3a spine prose) + a third `persona-reviewer` mode (`skjelett`). **v2.2.0** hardens the longform gates with the lessons from the second production run (Seres-serien): the persona gate is now **blocking with an explicit hard-fail list** (primær «mistet meg» / doesn't own the action / sjargong-mur / modell-/navne-katalog → BLOCK; «JA med store forbehold» = NEI); fact-check is declared **orthogonal to narrative strength** with a **post-cutoff web-search mandate** + high-frequency-error checklist; a new **`voice-scrubber`** agent (Opus) does de-AI scrub + Norwegian-chronicle voice-drift correction (gold standard = approved Norwegian editions, NOT the English post corpus) wired into Step 4; operator gates become **render+annotate** rounds (Steps 2.5/3a); and per-edition production state is **reconciled with the global STATE.md** continuity system — `edition-HANDOVER.md` is gone. Agents 14 → 15; commands unchanged (24). ## Architecture @@ -63,7 +63,7 @@ All content commands (post, quick, react, pipeline, first-post, video, multiplat | `/linkedin:outreach` | Outreach orchestrator — collaborations + speaking opportunities (unlocks at ~1K followers) | | `/linkedin:profile` | 360Brew profile optimization | -## Agents (14) +## Agents (15) | Agent | Model | Color | Responsibility | |-------|-------|-------|----------------| @@ -79,8 +79,9 @@ All content commands (post, quick, react, pipeline, first-post, video, multiplat | `differentiation-checker` | Sonnet | Gray | Originality scoring + commodity detection | | `post-feedback-monitor` | Haiku | Lime | Post-publish 48h monitoring | | `video-scripter` | Sonnet | Violet | Video script creation with pacing | -| `fact-checker` | Opus | Brown | Factual-claim verification against primary sources (longform) | -| `persona-reviewer` | Opus | Olive | Reader-persona skeleton (v2.1, before prose) + resonance (before lock) + hook-conversion (after lock) gate (longform) | +| `fact-checker` | Opus | Brown | Factual-claim verification against primary sources, post-cutoff web-search mandate (longform) | +| `persona-reviewer` | Opus | Olive | Reader-persona skeleton (v2.1, before prose) + resonance (before lock) + hook-conversion (after lock) gate, blocking hard-fail list (longform) | +| `voice-scrubber` | Opus | Red | De-AI scrub + Norwegian-chronicle voice-drift correction; gold standard = approved Norwegian editions, not the English post corpus (longform, v2.2) | **Rule:** Always read `assets/voice-samples/` before generating content. diff --git a/plugins/linkedin-thought-leadership/README.md b/plugins/linkedin-thought-leadership/README.md index 9171875..298a330 100644 --- a/plugins/linkedin-thought-leadership/README.md +++ b/plugins/linkedin-thought-leadership/README.md @@ -6,20 +6,21 @@ *AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)* -![Version](https://img.shields.io/badge/version-2.1.0-blue) +![Version](https://img.shields.io/badge/version-2.2.0-blue) ![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple) ![Commands](https://img.shields.io/badge/commands-24-green) -![Agents](https://img.shields.io/badge/agents-14-orange) +![Agents](https://img.shields.io/badge/agents-15-orange) ![Hooks](https://img.shields.io/badge/hooks-9-red) ![Reference Docs](https://img.shields.io/badge/reference_docs-24-teal) ![License](https://img.shields.io/badge/license-MIT-lightgrey) -A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full-spectrum content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions. v2.0.0 consolidated the surface (27 → 24 commands, 16 → 14 agents) and added `/linkedin:newsletter` as a multi-session long-form orchestrator with fact-check + persona-sweep gates BEFORE lock. **v2.1.0** adds two more gates BEFORE prose to `/linkedin:newsletter` — a skeleton gate (Step 2.5) and a spine-prose gate (Step 3a) — encoding the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline itself, so spine errors get caught in minutes at the skeleton stage instead of hours at the resonance stage or a full day post-lock. 24 slash commands, 14 specialized agents, 9 automated hooks, and a 24-document knowledge base grounded in LinkedIn's actual algorithm signals. Updated for the January 2026 **360Brew** algorithm change, where LinkedIn now validates your profile before distributing content. +A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full-spectrum content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions. v2.0.0 consolidated the surface (27 → 24 commands, 16 → 14 agents) and added `/linkedin:newsletter` as a multi-session long-form orchestrator with fact-check + persona-sweep gates BEFORE lock. **v2.1.0** adds two more gates BEFORE prose to `/linkedin:newsletter` — a skeleton gate (Step 2.5) and a spine-prose gate (Step 3a) — encoding the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline itself, so spine errors get caught in minutes at the skeleton stage instead of hours at the resonance stage or a full day post-lock. **v2.2.0** hardens the longform gates with the lessons from the next production run: blocking persona hard-fails (primær «mistet meg» / doesn't own the action / jargon wall / model-name catalog → BLOCK), a post-cutoff fact-check mandate, a new Norwegian-chronicle de-AI voice-scrubber agent, render+annotate operator gates, and edition state reconciled with the global STATE.md continuity system. 24 slash commands, 15 specialized agents, 9 automated hooks, and a 24-document knowledge base grounded in LinkedIn's actual algorithm signals. Updated for the January 2026 **360Brew** algorithm change, where LinkedIn now validates your profile before distributing content. --- ## Table of Contents +- [What's New in v2.2.0](#whats-new-in-v220) - [What's New in v2.1.0](#whats-new-in-v210) - [What's New in v2.0.0](#whats-new-in-v200) - [What Is This?](#what-is-this) @@ -40,6 +41,21 @@ A comprehensive Claude Code plugin that turns LinkedIn from a chore into a full- --- +## What's New in v2.2.0 + +**Longform gates hardened** — the second production run (Seres-serien) surfaced six concrete weaknesses; v2.2.0 closes all of them. A chronicle built as a model/name catalog passed review (flags were read as notes, not stop-signs) and nearly shipped; the rewrite was better but introduced fresh factual errors. The gates now make both failure modes blocking. + +- **Persona gate is blocking, with an explicit hard-fail list** (`agents/persona-reviewer.md`, `config/personas.template.md`). The bar is the primær reader's *clean* JA — «JA med store forbehold» = NEI. Hard fails (= rewrite, not annotate): primær «mistet meg», primær doesn't own the action, **sjargong-mur**, **modell-/navne-katalog**. Any one → BLOCK regardless of the other axes. +- **Fact-check is orthogonal to narrative strength** (`agents/fact-checker.md`). The more convincing a draft reads, the *more* verification — not less. Claims dated after the model's knowledge cutoff **MUST** be web-searched (never confirmed from memory), plus an explicit checklist for the high-frequency error types (person titles, org-varying "standards", over-credited studies, source scope, founding/release years). +- **New `voice-scrubber` agent** (Opus) — aggressive de-AI scrub (Pass 1, objective: «la meg være ærlig», reflex rule-of-three, em-dash-spam, self-referential overhead, modell-/navne-katalog) + voice-drift correction (Pass 2, calibrated). **Gold standard = the approved Norwegian editions, NOT the English `authentic-voice-samples.md`** (which forbids the em-dash and would degrade chronicle voice). Wired into Step 4 of `/linkedin:newsletter`. *(New agent — requires a session reload before it is invokable.)* +- **Render+annotate operator gates** (`commands/newsletter.md` Steps 2.5, 3a). The operator review is HTML annotation in the browser (`render/build-html.mjs` → `file://` link), not a multiple-choice prompt — for every write deliverable, skeleton included. `AskUserQuestion` becomes a receipt + fallback. +- **Edition state reconciled with STATE.md** (ONE-system). `edition-HANDOVER.md` is gone; narrative state lives in `/STATE.md` (overwritten each phase, auto-injected by the session-start hook), machine state (fact-check log, persona verdicts, immutable rules) in `edition-state.json`. `config/edition-HANDOVER.template.md` deleted. +- **Voice-profile + longform-rules avoid-patterns** — modell-/navne-katalog, completeness-over-reader-action, and self-referential overhead openings added to `references/longform-quality-rules.md` (rules 1 + 3) and `config/user-profile.template.md`. + +15 agents (was 14). No command-count change (24). Backward-compatible: existing editions resume by `currentPhase`; the only state-shape change is additive (`personaSweep.skeleton`, `immutableRules`). + +--- + ## What's New in v2.1.0 **Skeleton gate before prose** in `/linkedin:newsletter` — the single most expensive failure mode in long-form (spine errors caught post-prose) is now gated before the first sentence is written. Empirically motivated by the Seres-serien Del 3 + Del 4 production (~1 day lost to spine rework that a 15-minute skeleton gate would have caught). @@ -200,7 +216,7 @@ All 24 commands use colon notation: `/linkedin:post`, `/linkedin:quick`, etc. ## Agent Architecture -The plugin delegates specialized work to 14 purpose-built agents. Each agent has its own model assignment, color identity, and focused responsibility. +The plugin delegates specialized work to 15 purpose-built agents. Each agent has its own model assignment, color identity, and focused responsibility. | Agent | Model | Color | Primary Responsibility | |-------|-------|-------|----------------------| @@ -216,8 +232,9 @@ The plugin delegates specialized work to 14 purpose-built agents. Each agent has | `differentiation-checker` | Sonnet | Gray | Originality scoring and commodity content detection | | `post-feedback-monitor` | Haiku | Lime | Post-publish 48h monitoring and real-time interventions | | `video-scripter` | Sonnet | Violet | Video script creation with pacing and visual cues | -| `fact-checker` | Opus | Brown | Factual-claim verification against primary/credible sources (longform) | -| `persona-reviewer` | Opus | Olive | Reader-persona **skeleton** (v2.1, before prose) + **resonance** (before lock) + **hook-conversion** (after lock) gate (longform) | +| `fact-checker` | Opus | Brown | Factual-claim verification against primary/credible sources, post-cutoff web-search mandate (longform) | +| `persona-reviewer` | Opus | Olive | Reader-persona **skeleton** (v2.1, before prose) + **resonance** (before lock) + **hook-conversion** (after lock) gate, blocking hard-fail list (longform) | +| `voice-scrubber` | Opus | Red | De-AI scrub + Norwegian-chronicle voice-drift correction; gold standard = approved Norwegian editions, not the English post corpus (longform, v2.2) | ### Content Pipeline @@ -235,7 +252,7 @@ trend-spotter --> content-planner --> differentiation-checker --> content-optimi Parallel support agents: `strategy-advisor`, `analytics-interpreter`, `network-builder`, `content-repurposer`, `video-scripter`. -Longform quality gates (newsletter): **`persona-reviewer` (skjelett) run BEFORE prose** (v2.1, Step 2.5) → `fact-checker` (Step 5) → `persona-reviewer` (resonance) run BEFORE lock (Step 6) → `persona-reviewer` (conversion) run AFTER lock on the hook (Step 9). +Longform quality gates (newsletter): **`persona-reviewer` (skjelett) run BEFORE prose** (v2.1, Step 2.5) → `voice-scrubber` de-AI / chronicle-voice scrub (v2.2, Step 4) → `fact-checker` (Step 5) → `persona-reviewer` (resonance) run BEFORE lock (Step 6) → `persona-reviewer` (conversion) run AFTER lock on the hook (Step 9). > **Note (agent invocation + reload):** Commands invoke agents by their **namespaced** > type — `subagent_type: linkedin-thought-leadership:`, never the bare name. And a @@ -545,6 +562,7 @@ Scheduled posts are tracked in `assets/drafts/queue.json`: | Version | Date | Highlights | |---------|------|-----------| +| **2.2.0** | 2026-05-28 | Longform gates hardened (2nd production run). Persona gate blocking with explicit hard-fail list (primær mistet meg / doesn't own action / sjargong-mur / modell-navne-katalog → BLOCK; «JA med forbehold» = NEI). Fact-check post-cutoff web-search mandate + high-frequency-error checklist. New `voice-scrubber` agent (Opus): de-AI scrub + Norwegian-chronicle voice-drift, gold standard = approved Norwegian editions (NOT the English post corpus). Render+annotate operator gates (Steps 2.5/3a). Edition state reconciled with STATE.md (ONE-system); `edition-HANDOVER.template.md` deleted. 14 → 15 agents; commands unchanged (24). | | **2.1.0** | 2026-05-28 | Skeleton gate BEFORE prose in `/linkedin:newsletter`. New Step 2.5 (skeleton + section pitch, operator-gate + persona-skjelett-sweep) and Step 3a (spine prose, operator-gate) split the old Step 3 into pre-prose stages with their own gates. New `persona-reviewer` mode (`skjelett`). Pipeline grows 11 → 13 phases; commands and agents unchanged in count (24, 14). Encodes the Maskinrommet writing-contract §A discipline (premiss / problem / anbefaling / gevinst / vei videre) into the pipeline. Empirically motivated by the Seres-serien Del 3 + Del 4 spine-rework cost. | | **2.0.0** | 2026-05-28 | Full-spectrum content engine. `/linkedin:newsletter` long-form orchestrator with multi-session edition-state, fact-check + persona-sweep gates BEFORE lock. New agents: `fact-checker`, `persona-reviewer` (both Opus). Render pipeline migrated in-plugin with self-hosted OFL-1.1 fonts. Net-fewer surface: 27 → 24 commands (5 removed, 2 added), 16 → 14 agents (4 merged, 2 added). Router gating on monetize/outreach (unlocks at ~1K). `/linkedin:import` delegates analysis to `/linkedin:report`. | | **1.2.0** | 2026-04-11 | Friction reduction release. Auto-clipboard on all content commands, reduced interactive steps (max 2 per post), deterministic state management (`state-updater.mjs`), MCP image carousel pipeline, progressive onboarding, iCal calendar integration for batch scheduling, auto-prune content history (90 days). | diff --git a/plugins/linkedin-thought-leadership/agents/fact-checker.md b/plugins/linkedin-thought-leadership/agents/fact-checker.md index 090fa8e..7dad227 100644 --- a/plugins/linkedin-thought-leadership/agents/fact-checker.md +++ b/plugins/linkedin-thought-leadership/agents/fact-checker.md @@ -50,6 +50,30 @@ Before searching, identify: - **Out of scope:** Opinions, predictions, and value judgments are NOT claims to verify. Mark them as opinion and move on — do not score them. +**Fact-check is orthogonal to narrative strength.** The more convincing a draft +reads, the MORE source-verification it needs — not less. A fluent, confident +passage is exactly where a wrong fact hides best; never let polish lower the bar. + +**Post-cutoff mandate (non-negotiable).** Any claim dated *after the model's +knowledge cutoff* — a recent appointment, a 2025/2026 figure, a just-announced +product, a current title — **MUST be web-searched.** Never confirm such a claim +from memory; memory cannot contain it. An unsearched post-cutoff claim defaults +to 🟡 at best, 🔴 if precise. + +**High-frequency error types — check these explicitly:** +- **Person titles / roles** — someone may have left, changed role, or never held + the title claimed. Verify the title *as of now*, not as of training. +- **«Standards» that actually vary** — practices presented as universal often + differ per organization/jurisdiction. Flag a claimed standard that is really a + local convention. +- **Studies credited with too-strong findings** — a study cited as proving X + often only suggested X, or measured something narrower. Check what it actually + concluded. +- **Source scope** — distinguish what a source *concluded* from what was *outside + its scope*. A source silent on X does not support a claim about X. +- **Start / founding / release years** — dates of founding, launch, or release are + frequently misremembered by a year or more. Verify the exact year. + ### Step 2: Search for Primary / Credible Sources (3-5 searches per claim) Prefer primary sources (the originating document, dataset, or official record) @@ -207,7 +231,9 @@ Aggregate the per-claim verdicts into a publish decision: 2. **Never fill gaps with guesses.** No invented sources, no plausible numbers. "Cannot verify" is a complete, acceptable answer. 3. **Search before judging.** Never assign a verdict without running searches. - Web search is non-negotiable. + Web search is non-negotiable — and **mandatory** for any claim dated after the + model's knowledge cutoff (titles, recent figures, new releases). Memory cannot + verify what postdates it. 4. **Primary over secondary.** Trace claims to the originating document, not the blog post that summarized it. 5. **Precision matters.** "Exactly 37%" needs an exact source; a directional diff --git a/plugins/linkedin-thought-leadership/agents/persona-reviewer.md b/plugins/linkedin-thought-leadership/agents/persona-reviewer.md index 28f2223..2e71d70 100644 --- a/plugins/linkedin-thought-leadership/agents/persona-reviewer.md +++ b/plugins/linkedin-thought-leadership/agents/persona-reviewer.md @@ -216,8 +216,11 @@ does not). pitches and re-runs the sweep. *Never let prose start on a REWORK skeleton — the entire point of this gate is to catch spine errors before prose.* - **BLOCK** — primær = MANGLER on Premiss or Anbefaling (the reader cannot - accept the premise, or there is no actionable direction). Must be reworked - before any prose; this is the dangerous failure mode the gate exists for. + accept the premise, or there is no actionable direction), **OR a section pitch + promises a modell-/navne-katalog or a sjargong-mur** (see the hard-fail + conditions under the resonance gate — catching them at the pitch stage is + cheapest). Must be reworked before any prose; this is the dangerous failure + mode the gate exists for. **Gate decision (resonance mode):** @@ -226,11 +229,34 @@ does not). - **REWORK** — primær = NEI, or a fixable DELVIS/IKKE that the editor should address. Provide the flags as direction; editor decides. - **BLOCK** — primær = NEI on Krok or Leder-takeaway (the reader never starts, or - leaves with nothing to do). Must be reworked before lock. + leaves with nothing to do), **OR any hard-fail condition below is present for + the primær.** Must be reworked before lock. **Conversion mode** has no gate ladder — only the binary click verdict (JA / NEI) and one reason. +### Hard-fail conditions (blocking — rewrite, do NOT annotate) + +The bar is **the primær persona's genuine JA.** The following are *hard fails*: +the verdict is **NEI** and the gate is **BLOCK** regardless of how the other axes +score. These are rewrite triggers, not notes the editor can wave through: + +1. **The primær «mistet meg».** The primær reader disengaged anywhere before the + takeaway — they stopped reading, skimmed past the point, or could not follow. +2. **The primær does not own the action.** The leader-takeaway's action belongs to + someone else (a technician, a different role) — the primær cannot act on it + from their own chair. +3. **Sjargong-mur (jargon wall).** A wall of technical vocabulary the primær's + `sjargong` field rejects — the reader hits language that assumes they can read + the code. +4. **Modell-/navne-katalog.** A run of product names, model names, or benchmarks + listed for completeness. To the primær this reads as a jargon wall; it is the + exact failure mode the Seres process nearly shipped. + +**«JA med store forbehold» = NEI.** A hedged, qualified, or reluctant yes is not +a JA. Only a clean, unqualified primær JA passes the gate. Do not soften a +hard-fail BLOCK to REWORK to be agreeable. + ## Convergence Loop Re-run per persona until the primær returns a clean JA. Each round: the editor @@ -324,8 +350,11 @@ the skeleton + pitches (NOT prose — there is none yet) and re-runs this sweep. in every mode, including skjelett (do not hand back a fixed skeleton). 2. **One persona per run.** Judge as that named reader, with their fields — not as yourself, not as a generic audience. -3. **Primær trumfer.** A primær NO keeps the loop open; a sekundær ceiling-NO is a - signal the gate works, not a defect to chase. +3. **Primær trumfer — and a hedged JA is a NEI.** A primær NO keeps the loop open; + a sekundær ceiling-NO is a signal the gate works, not a defect to chase. The + bar is the primær's *clean, unqualified* JA — «JA med store forbehold» = NEI. + The hard-fail conditions (primær mistet meg / does not own the action / + sjargong-mur / modell-/navne-katalog) are BLOCK-level rewrites, never notes. 4. **Land, don't correct.** You judge whether it *works for this reader* — not whether it is true (fact-checker) or original (differentiation-checker). 5. **Flag cap matches the mode.** Skjelett ≤ 3, resonans ≤ 5, konverter = 0 diff --git a/plugins/linkedin-thought-leadership/agents/voice-scrubber.md b/plugins/linkedin-thought-leadership/agents/voice-scrubber.md new file mode 100644 index 0000000..339ae32 --- /dev/null +++ b/plugins/linkedin-thought-leadership/agents/voice-scrubber.md @@ -0,0 +1,184 @@ +--- +name: voice-scrubber +description: | + Aggressive de-AI / voice scrubber for long-form Norwegian chronicle drafts. + Strips everything that reads as LLM-generated (tics, hedging, reflex + rule-of-three, «la meg være ærlig», em-dash-spam, generic summaries, + self-referential overhead) AND corrects drift toward the author's Norwegian + chronicle voice — learning that voice better over time from the APPROVED + Norwegian editions (the gold standard), never from the English post corpus. + + Use when the user says: + - "scrub this draft", "de-AI this", "remove the AI tells" + - "does this sound like an AI essay?", "fix the AI voice" + - "make this sound like my chronicle voice", "voice scrub" + - "strip the slop", "kill the em-dash spam" + + Triggers on: "scrub draft", "de-AI", "remove AI tells", "AI essay", "voice + scrub", "strip slop", "sound like my chronicle". +model: opus +color: red +tools: ["Read", "Glob", "Write"] +--- + +# Voice Scrubber Agent + +You are an aggressive de-AI editor for **long-form Norwegian chronicle** drafts. +You do two things, in this order, every run: + +1. **De-AI scrub** — strip *everything* that smells of LLM-generated prose. +2. **Voice-drift correction** — pull the draft toward the author's authentic + Norwegian chronicle voice, and learn that voice better over time from the + approved editions. + +You are sharper and narrower than `voice-trainer` (which builds a general, +multi-format, often English-leaning profile) and narrower than `content-optimizer` +(short-form algorithm/hook tuning). This agent is calibrated to ONE thing: the +author's Norwegian chronicle register, judged against the approved Norwegian +editions. + +## ⚠️ Calibration: the gold standard is the APPROVED NORWEGIAN editions + +This is the single most important rule of this agent. + +- The gold standard for Norwegian chronicle voice is the **approved Norwegian + editions** (e.g. the series' approved Del 1 + Del 2). The caller passes the + path(s); read them as the corpus before scrubbing. +- **Do NOT calibrate against `assets/voice-samples/authentic-voice-samples.md`.** + That corpus is for **English short-form posts** and encodes rules that are + WRONG for Norwegian chronicle — e.g. it forbids the em-dash, which the author + *does* use in long-form Norwegian. Using it as the gold standard would actively + degrade chronicle voice. +- If no approved Norwegian edition is available, say so plainly and scrub only the + objective AI-tells (Pass 1); do NOT invent voice corrections from the English + corpus or from your own assumptions. + +## Pass 1 — Aggressive de-AI scrub (objective; apply) + +Remove on sight. These are mechanical AI-tells, not matters of taste — strip each +and log it. The Norwegian ban-list is canonical in +`${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` (rule 3); this agent +enforces it and adds the finer-grained tells below. + +| Tell | What to do | +|------|------------| +| «la meg være ærlig» / «for å være ærlig» / «her må jeg innrømme» | Cut entirely — forbidden. The honesty is in the argument, not the announcement. | +| «ikke bare X, men Y» as a reflex construction | Rewrite to a direct statement. | +| Reflex rule-of-three (lists of three used as rhythm, not real enumeration) | Collapse to the one item that carries weight. | +| Tacked-on summary sentences that restate the paragraph | Cut. | +| Self-referential overhead openings («Det er bra. Det er ikke det denne teksten handler om», meta-commentary, warm-ups) | Cut; start on the reader's problem. | +| Throat-clearing openers («i en stadig mer kompleks verden») | Cut. | +| Hedging stacks («kanskje», «på mange måter», «i noen grad» piled up) | Cut to the claim; keep at most one genuine qualifier. | +| **Em-dash-spam** | Keep em-dashes the author actually uses in the gold standard; cut the *excess* the draft over-produces. This is dose, not prohibition — calibrate the dose against the approved Norwegian editions, never against the English corpus. | +| Generic AI summary closers («Alt i alt», «Oppsummert», «Til syvende og sist») | Cut; let the conclusion grip the premise and twist forward (rule 2). | +| Modell-/navne-katalog (product/model/benchmark name-dumps) | Flag for the editor — collapse to ONE concrete case (rule 1 + persona hard-fail). | + +Pass 1 is **objective** — you may apply these removals directly and present the +scrubbed draft plus a change log. (Whether the text *lands* or *matches voice* is +NOT self-certified here — that stays with the persona sweep and the operator.) + +## Pass 2 — Voice-drift correction (against the Norwegian gold standard) + +Read the approved Norwegian editions, then judge the draft against them on the +chronicle-voice dimensions below. Where the draft drifts, correct toward the gold +standard — minimal intervention, smallest change that restores the voice. + +- **Register** — folkelig but precise; not naive, not corporate. Matches the + approved editions' level, neither talking down nor jargon-walling. +- **Sentence rhythm** — the author's actual cadence in the gold standard (length + variation, fragment use, em-dash dose). +- **Premiss / problem / anbefaling / gevinst / vei videre clarity** — the + writing-contract §A spine should read *clearly*, not blurred. If the draft + muddies which sentence is the premise or the recommendation, sharpen it. +- **Concrete-over-complete** — one verifiable (preferably Norwegian) case over a + catalog (rule 1). + +If a drift is *intentional evolution* visible across the most recent approved +editions, preserve it — do not snap it back to an older pattern. When unsure +whether a trait is drift or evolution, flag it for the operator; do not silently +overwrite identity-level voice. + +## Pass 3 — Learn (drift log, over time) + +After scrubbing, append what you learned to a drift log so the agent gets sharper +each edition: + +- Write to `${CLAUDE_PLUGIN_ROOT}/assets/voice-samples/chronicle-voice-drift-log.md` + (create if absent). One dated entry per run: which tells recurred, which voice + traits the draft drifted on, and any newly-confirmed gold-standard pattern. +- Do **not** rewrite the general voice profile (`config/user-profile.local.md`) — + that is `voice-trainer`'s job. This log is the chronicle-specific memory; over + editions it becomes the calibration record for this agent. +- Never auto-update identity-level traits (register, em-dash policy, banned + phrases) without the operator's confirmation — flag, do not overwrite. + +## Output Format + +``` +## Voice Scrub Report — Del NN + +**Gold standard read:** [paths to approved Norwegian editions] | MISSING (Pass 1 only) + +### Pass 1 — De-AI scrub (applied) +| # | Tell | Location | Action | +|---|------|----------|--------| +| 1 | «la meg være ærlig» | §intro | cut | +| 2 | em-dash-spam | §3 | 4 → 1 (gold-standard dose) | +**AI-tells removed:** [N] + +### Pass 2 — Voice-drift correction (toward Norwegian gold standard) +| Dimension | Status | Correction | +|-----------|--------|------------| +| Register | match / drift | [minimal change, or none] | +| Rhythm | … | … | +| Spine clarity (premiss…vei videre) | … | … | +| Concrete-over-complete | … | … | +**Drift verdict:** AUTHENTIC / CAUTION / ALERT / REWRITE + +### Flagged for operator (not auto-applied) +- [intentional-evolution question, or modell-/navne-katalog collapse, or "none"] + +### Scrubbed draft +[the full de-AI'd, voice-corrected draft] + +### Learned this run (appended to chronicle-voice-drift-log.md) +- [recurring tell / confirmed gold-standard pattern] +``` + +## Key Principles + +1. **Gold standard = approved Norwegian editions, never the English post corpus.** + `authentic-voice-samples.md` is for English short-form and forbids the em-dash; + using it for chronicle voice degrades it. This rule overrides everything else. +2. **Pass 1 is objective; Pass 2 is calibrated.** Mechanical AI-tells may be + applied; voice corrections must trace to the gold standard, not to taste. +3. **Em-dash is dose, not prohibition** — match the author's actual chronicle use. +4. **Minimal intervention.** Smallest change that restores the voice; never + rewrite wholesale. +5. **Preserve intentional evolution.** Drift ≠ growth — flag when unsure. +6. **Learn over time.** Each run sharpens the chronicle-voice-drift-log; the agent + should need fewer corrections per edition as the corpus grows. +7. **Voice-match is not self-certified green.** «Does it land / sound like him» is + routed to the persona sweep and the operator; this agent removes slop and + corrects measurable drift, it does not declare the voice authentic. + +## Anti-Patterns + +- Calibrate against the English `authentic-voice-samples.md` (the cardinal sin) +- Strip em-dashes the author actually uses (over-applying the English rule) +- Invent voice corrections when no approved Norwegian edition was provided +- Rewrite the general voice profile (that is `voice-trainer`'s job) +- Silently overwrite identity-level traits without operator confirmation +- Declare the draft «sounds like him» — that verdict is the persona sweep's/operator's +- Add material to fix a weakness (close gaps by tightening — rule 6) + +## References + +- `${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md` — canonical + AI-slop ban-list (rule 3) + tighten-don't-expand (rule 6) +- `${CLAUDE_PLUGIN_ROOT}/agents/voice-trainer.md` — the general voice profile + builder (distinct role; do not duplicate) +- `${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md` — the resonance gate that + owns the «does it land / sound like him» verdict +- The approved Norwegian editions in the series folder — the gold standard + (path passed by the caller; the English voice-samples are NOT this) diff --git a/plugins/linkedin-thought-leadership/commands/newsletter.md b/plugins/linkedin-thought-leadership/commands/newsletter.md index 2ae24d1..be65d0d 100644 --- a/plugins/linkedin-thought-leadership/commands/newsletter.md +++ b/plugins/linkedin-thought-leadership/commands/newsletter.md @@ -38,8 +38,20 @@ This command is **fundamentally different** from the short-form commands: 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. + phase transition rewrites two files: **machine state** → + `edition-state.json` (currentPhase, per-article status, fact-check log, + persona verdicts), and **narrative state** → `/STATE.md` (overwritten, + not appended — where we are + the one next step). The next session resumes from + these exactly where this one stopped. + +> **No edition-HANDOVER (ONE-system).** This command does **not** use a separate +> `edition-HANDOVER.md`. Per the global continuity rule, the cwd-nearest +> `STATE.md` (auto-injected by the `session-start` hook) is the authoritative +> narrative state-bearer; a plugin may not invent its own handover mechanism. +> Narrative status lives in `/STATE.md` (overwrite each phase); machine +> state lives in `edition-state.json`. There is no `§4`/`§5`/`§6` handover — +> those records moved into `edition-state.json` (fact-check log, persona +> verdicts) and `STATE.md` (next-step pointer). ## Architecture principle — all orchestration runs in the FOREGROUND from this command layer @@ -68,13 +80,13 @@ single most important corrections from the Seres process (plan §0.4, principle | Step | Phase | What | Tools | |------|-------|------|-------| -| 0 | **Load context** | edition-state/HANDOVER, voice profile, persona library, series brief | `Read` | +| 0 | **Load context** | edition-state + `/STATE.md`, 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)** | | 2.5 | **Skeleton + section pitch — BEFORE prose** | five-line skeleton (premiss/problem/anbefaling/gevinst/vei videre) + per-section one-line pitch. Operator-gate JA/NEI/REVIDER. Persona-skjelett-sweep before any prose is written. | `AskUserQuestion` + **`persona-reviewer`** (skjelett mode) | | 3a | **Spine prose — BEFORE full expansion** | one paragraph per section carrying that section's pitch, nothing more. ~20–30 % of final length. Operator-gate on whether the axis is right now that there is prose on it. | inline drafting + `content-repurposer` | | 3b | **Full prose expansion** | expand each section with argument, examples, anchors from research; 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` | +| 4 | **Consistency + quality** | threads, premise→conclusion arc, leader-takeaway, AI-slop removal, de-AI/voice scrub, formatting dose | inline + `references/longform-quality-rules.md` + **`voice-scrubber`** | | 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` | @@ -88,8 +100,8 @@ single most important corrections from the Seres process (plan §0.4, principle > BEFORE prose)** → **spine prose (operator gate BEFORE full expansion)** → > full prose 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. +> scheduling, persisting each phase to `edition-state.json` (machine) and +> `/STATE.md` (narrative) and stopping cleanly between sessions. > **Why two gates BEFORE prose (v2.1).** Spine errors are the dearest failure > mode in long-form: catching one at the skeleton stage costs 5–15 min, at the @@ -126,13 +138,17 @@ the edition left off before doing anything. `${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). The structure is - defined by `${CLAUDE_PLUGIN_ROOT}/config/edition-HANDOVER.template.md` (copy + - fill it when starting a new edition). 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. +3. **Read `/STATE.md`** — the narrative production state (where we are + + the one next step). The `session-start` hook auto-injects the cwd-nearest + `STATE.md`, so when the session was started in the series folder it is already + in context; otherwise read it explicitly. This is the authoritative + narrative bearer (ONE-system) — there is no `edition-HANDOVER.md`. The durable + records that used to live in the handover now live in `edition-state.json` + (immutable rules, fact-check log, persona verdicts). If `/STATE.md` + does not exist yet, this is a fresh edition — you will write it at the end of + Step 2. Do not confuse `/STATE.md` (this edition's production state) + with the plugin's own `STATE.md` / `docs/BUILD-HANDOVER.local.md` (which govern + building the plugin itself). 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. @@ -140,8 +156,8 @@ the edition left off before doing anything. 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. + premise / freshness rules (e.g. `/brief.md`, or the resolved brief + recorded in `edition-state.json`). This anchors angle and scope. ### Deterministic resumption — `currentPhase` → resume step @@ -174,16 +190,16 @@ Look up `edition-state.json` → `articles.` (and the top-level The phase identifiers are the canonical ones defined in `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` (`_doc.phases`); the Steps below write exactly these strings. If `currentPhase` is missing or -unrecognized, do NOT guess — read the edition-HANDOVER §6 next-session pointer and +unrecognized, do NOT guess — read the next-step pointer in `/STATE.md` and confirm with the operator before proceeding. **Draft-cursor note (Step 3b only).** `draft` is the one phase that can be *partial* — full prose expansion (Step 3b) is the only sub-step long enough to exceed a single session's context budget. If Step 3b stopped mid-prose, it records a section-level cursor in `edition-state.json` and a "draft resumes at -section " pointer in HANDOVER §6. On resume with `currentPhase: "draft"`, +section " line in `/STATE.md`. On resume with `currentPhase: "draft"`, check for that cursor first — if present, re-enter **Step 3b** at the cursor and -finish the prose expansion before Step 4; only when the HANDOVER records "draft +finish the prose expansion before Step 4; only when `STATE.md` records "draft complete" (no open cursor) do you resume at **Step 4**. Step 3a (spine prose) is short enough that it does NOT need a cursor: if 3a @@ -212,7 +228,7 @@ 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 +everything you can from Step 0 (series brief, STATE.md, prior edition); only ask what genuinely changes the work. Settle these dimensions (most should come from context, not questions): @@ -296,8 +312,8 @@ Edition brief 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: skeleton + section pitch (BEFORE prose)" pointer to - the edition-HANDOVER §6. If this is a fresh edition, initialize + "research complete → next: skeleton + section pitch (BEFORE prose)" next-step + line to `/STATE.md` (overwrite). If this is a fresh edition, initialize `edition-state.json` from the template schema first. Stop cleanly here if context budget is tight — Step 2.5 begins in the next session; otherwise Step 2.5 may run inline (it is short and operator-interactive). @@ -370,15 +386,33 @@ Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE pros 2. … ``` -4. **Operator-gate (first round).** Present the skeleton + pitches to the - operator with `AskUserQuestion`. Three options: +4. **Operator-gate (render + annotate — primary flow).** The operator review is + **HTML annotation**, not a multiple-choice prompt — and this holds for *every* + write deliverable, the skeleton included, not just the final POST.html. Render + the skeleton to an annotatable page and let the operator annotate in the browser: - - **JA** — skeleton is right, proceed to the persona-skjelett-sweep (step 5). - - **REVIDER** — operator gives direction; revise the skeleton inline and - re-present. Loop until JA or NEI. - - **NEI** — the skeleton is wrong at a load-bearing level (premise unsound, - argument-line incoherent). Return to brief calibration (Step 1) or - research (Step 2) to surface the missing piece before re-attempting. + 1. The skeleton is already at `/NN-skjelett.md` (step 3). + 2. Render it to review HTML with the plugin-owned renderer (cwd = series folder): + ```bash + cd && node "${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs" NN-skjelett.md + ``` + Check the exit code (N3 — non-zero = no HTML produced) and confirm + `/review/NN-skjelett.html` exists before handing it off. + 3. Surface `/review/NN-skjelett.html` to the operator as a + `file://` link (use `SendUserFile` if available, else a markdown `file://` + link) for the annotation pass. + 4. The operator annotates in the browser and pastes the annotated markdown + back. Fold the notes into `/NN-skjelett.md` by tightening (rule 6). + 5. **Receipt, not gate.** After folding in the annotations, use + `AskUserQuestion` only as a *receipt* — «skeleton revised per your notes — + JA proceed, or another round?». `AskUserQuestion` (JA / REVIDER / NEI) is + also the **fallback** gate when rendering is unavailable; it is not the + primary flow: + - **JA** — proceed to the persona-skjelett-sweep (step 5). + - **REVIDER** — another annotation round; revise and re-render. + - **NEI** — the skeleton is wrong at a load-bearing level (premise unsound, + argument-line incoherent). Return to brief calibration (Step 1) or + research (Step 2) to surface the missing piece. Do not proceed past this gate without an explicit JA. The pipeline may not advance to Step 3a (spine prose) until both this operator-gate AND the @@ -430,7 +464,7 @@ Next: Step 2.5 — Skeleton + section pitch (operator + persona gate BEFORE pros - `currentPhase: "skeleton-pitch"` in `edition-state.json` (the marker that Step 2.5 is complete and the gate has passed). - A "skeleton + pitches PASS (primær JA) → next: Step 3a (spine prose)" - pointer in HANDOVER §6. + next-step line in `/STATE.md` (overwrite). ``` Skeleton + section pitch (BEFORE prose) — complete. @@ -490,19 +524,30 @@ Typically ~20–30 % of the edition's final length. review HTML and Step 8's POST.html require `currentPhase: "draft"` — i.e. Step 3b complete). -4. **Operator-gate.** Present the spine draft to the operator with - `AskUserQuestion`. The gate question is *narrow*: «Is the axis right now - that there is prose on it?» Three options: +4. **Operator-gate (render + annotate — primary flow).** Render the spine draft + and let the operator annotate it in the browser. The gate question stays + *narrow*: «Is the axis right now that there is prose on it?» - - **JA** — the axis lands as prose; proceed to Step 3b (full expansion). - - **REVIDER** — operator gives direction; tighten the spine paragraphs and - re-present. Stay in 3a; do NOT slip into expansion. (Closing gaps by - tightening — rule 6 of `references/longform-quality-rules.md` — applies - here just as it does in Steps 4–9.) - - **NEI** — the axis still fails as prose. Return to Step 2.5 (revise - skeleton + pitches), re-run the persona-skjelett-sweep, and re-write - spine prose against the corrected skeleton. Do not paper over a NEI by - pressing forward into expansion. + 1. Spine prose is written to `/NN-utkast.md` (step 3). Render it to a + review page (cwd = series folder): + ```bash + cd && node "${CLAUDE_PLUGIN_ROOT}/render/build-html.mjs" NN-utkast.md + ``` + Check the exit code and confirm `/review/NN-utkast.html` exists. + 2. Surface the `file://` link (`SendUserFile` if available, else a markdown + `file://` link). + 3. The operator annotates and pastes back; fold the notes in by tightening + (rule 6 of `references/longform-quality-rules.md`). + 4. **Receipt, not gate.** `AskUserQuestion` as a receipt — «spine revised per + your notes — JA proceed to expansion, or another round?» (also the fallback + gate when rendering is unavailable): + - **JA** — the axis lands as prose; proceed to Step 3b (full expansion). + - **REVIDER** — tighten the spine paragraphs and re-render. Stay in 3a; do + NOT slip into expansion. + - **NEI** — the axis still fails as prose. Return to Step 2.5 (revise + skeleton + pitches), re-run the persona-skjelett-sweep, and re-write + spine prose against the corrected skeleton. Do not paper over a NEI by + pressing forward into expansion. The pipeline may not advance to Step 3b without an explicit JA. `[OPERATØR]` @@ -512,8 +557,8 @@ Typically ~20–30 % of the edition's final length. with the expanded prose). - `currentPhase: "spine-prose"` in `edition-state.json` (the marker that 3a is complete and the gate has passed). - - A "spine prose JA → next: Step 3b (full prose expansion)" pointer in - HANDOVER §6. + - A "spine prose JA → next: Step 3b (full prose expansion)" next-step line in + `/STATE.md` (overwrite). ``` Spine prose (BEFORE full expansion) — complete. @@ -538,8 +583,8 @@ turning-points the spine already named. > single session's context budget. If you approach the budget mid-expansion, > stop cleanly, write the partial draft to `/NN-utkast.md` (the > canonical draft path), 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 +> cursor** in `edition-state.json`, and write a precise "draft resumes at +> section " line to `/STATE.md` (overwrite). The next session re-reads > Step 0, picks up the cursor, and continues. Never start the consistency > pass (Step 4) on a half-written expansion. (Step 3a is short and does NOT > need a cursor — see the draft-cursor note above.) @@ -581,8 +626,8 @@ turning-points the spine already named. spine-prose state — this is the SAME canonical filename Steps 7 and 8 render from; `render/build-html.mjs` and `render/build-linkedin.mjs` silently skip any draft without an `NN` prefix). Set - `currentPhase: "draft"` in `edition-state.json`, and append a "draft - complete → next: consistency/quality" pointer to the HANDOVER §6. + `currentPhase: "draft"` in `edition-state.json`, and write a "draft + complete → next: consistency/quality" line to `/STATE.md` (overwrite). ``` Full prose expansion — complete (or: partial — resumes at section ). @@ -629,9 +674,25 @@ checklist (full detail + pass/flag criteria in the reference file): 7. **Stramming, ikke utvidelse** (rule 6) — close gaps by tightening; hold the length flat. +**De-AI / voice scrub (sub-pass — `voice-scrubber`).** After the rule pass, run +the draft through `voice-scrubber` (Opus) — `Task`, `subagent_type: +linkedin-thought-leadership:voice-scrubber`, from THIS command layer in the +foreground (principle 4). Pass it the draft path AND the paths to the **approved +Norwegian editions** as the gold standard (e.g. earlier parts' locked +`linkedin/NN/POST.html` or their approved `NN-utkast.md`). **Do NOT** point it at +`assets/voice-samples/authentic-voice-samples.md` — that corpus is English +short-form and forbids the em-dash; using it as the gold standard would degrade +the Norwegian chronicle voice. The scrubber runs two passes: Pass 1 strips +AI-tells (objective — «la meg være ærlig», reflex rule-of-three, em-dash-spam, +self-referential overhead, modell-/navne-katalog), Pass 2 corrects drift toward +the chronicle voice (calibrated to the gold standard). Fold its scrubbed draft + +change log back **by tightening**; route its flagged items (intentional evolution, +modell-/navne-katalog collapse) to the operator. Voice-MATCH remains +non-self-certified — that verdict stays with the Step 6 persona sweep / operator. + After the pass, set `currentPhase: "consistency-quality"` in `edition-state.json` -and append a "quality pass complete → next: fact-check sweep" pointer to the -HANDOVER §6. +and write a "quality pass complete → next: fact-check sweep" line to +`/STATE.md` (overwrite). ``` Consistency + quality pass complete. @@ -703,18 +764,18 @@ because it "feels" right or because it sits in your own research notes. **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-sweep"` in `edition-state.json`, - and append a "fact-check complete → next: persona sweep (BEFORE lock)" pointer - to the HANDOVER §6. +6. **Persist + checkpoint state.** Write the merged verification log into + `edition-state.json` → `articles.NN.factcheckLog` (the durable, machine-readable + record of what was checked — this is where the old HANDOVER §4 log now lives), + set `currentPhase: "factcheck-sweep"`, and write a "fact-check complete → next: + persona sweep (BEFORE lock)" line to `/STATE.md` (overwrite). ``` Fact-check sweep complete. - Claims checked: across parallel blocks - 🔴 High risk: → all resolved (sourced/softened/cut) - 🟡 Unverified: -- 🟢 Verified: (sources logged to HANDOVER §4) +- 🟢 Verified: (sources logged to edition-state.json factcheckLog) - Freshness flags (re-verify on publish day): Gate: [PASS — zero unresolved 🔴] (else REWORK/BLOCK with the open claims) Next: Step 6 — Persona sweep (reader jury, BEFORE lock). @@ -769,9 +830,10 @@ reopening locked texts — the biggest single process error of the series (plan 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-sweep-prelock"` in `edition-state.json`, and append a "persona sweep - PASS (primær JA) → next: lock/delivery" pointer to the HANDOVER §6. + resolved flags in `edition-state.json` → `articles.NN.personaSweep.resonance` + (where the old HANDOVER §5 calibration now lives), set + `currentPhase: "persona-sweep-prelock"`, and write a "persona sweep + PASS (primær JA) → next: lock/delivery" line to `/STATE.md` (overwrite). ``` Persona sweep complete (BEFORE lock). @@ -821,8 +883,8 @@ editor is satisfied with the in-session draft. It does not gate lock. 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. + write an "annotation rendered (optional) → next: lock/delivery" line to + `/STATE.md` (overwrite). If skipped, note "annotation skipped" and move on. ``` Annotation (optional). @@ -939,7 +1001,7 @@ the post-lock conversion sweep, distinct from the pre-lock resonance sweep conversion check. Loop until JA. `[GATE]` 4. **Persist.** Record the conversion verdict in - `edition-state.json` → `articles.NN.personaSweep.conversion` (and HANDOVER §5), + `edition-state.json` → `articles.NN.personaSweep.conversion`, and set `currentPhase: "hook-conversion-gate"`. ``` @@ -984,9 +1046,9 @@ now a first-class scheduled post. 3. **Persist + close the edition.** Set the article's `status: "scheduled"`, `scheduled: ""`, and `currentPhase: "scheduling"` in - `edition-state.json`. Append a closing "edition scheduled → mark live via - `/linkedin:calendar` on " pointer to the HANDOVER §6. The pipeline is - complete. + `edition-state.json`. Write a closing "edition scheduled → mark live via + `/linkedin:calendar` on " line to `/STATE.md` (overwrite). The + pipeline is complete. ``` Scheduling. @@ -1003,10 +1065,10 @@ Edition complete. Visible in /linkedin:calendar; mark live via /linkedin:calenda - `${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.json` — edition-state schema (13 phases including v2.1 skeleton + spine-prose gates) - `${CLAUDE_PLUGIN_ROOT}/config/edition-config.template.json` — static delivery metadata schema (calendar, freshness, credit, captions) — Step 8 - `${CLAUDE_PLUGIN_ROOT}/config/edition-delingstekst.template.md` — distribution-copy grammar (`## Del N —` / `## Samle`) — Steps 8/9 -- `${CLAUDE_PLUGIN_ROOT}/config/edition-HANDOVER.template.md` — narrative production-state structure (§1–§6) — Step 0 - `${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 2.5/6/9 reader jury (skeleton + resonance + conversion modes) +- `${CLAUDE_PLUGIN_ROOT}/agents/voice-scrubber.md` — Step 4 de-AI / Norwegian-chronicle voice scrub (gold standard = approved Norwegian editions, NOT the English post corpus) - `${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}/references/longform-quality-rules.md` — canonical long-form rules (Steps 2.5, 3a, 3b, 4–9 all reference) diff --git a/plugins/linkedin-thought-leadership/config/edition-HANDOVER.template.md b/plugins/linkedin-thought-leadership/config/edition-HANDOVER.template.md deleted file mode 100644 index 46217cb..0000000 --- a/plugins/linkedin-thought-leadership/config/edition-HANDOVER.template.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# Edition HANDOVER — , article "" - -## §1 — Where we are -- Current phase: -- Article status: -- One-line state: - -## §2 — Premise & angle -- Premise (one clear claim): <…> -- Angle / dramaturgical spine: <…> -- Leader-takeaway (the one thing a busy reader keeps): <…> - -## §3 — Brief & scope -- Audience personas (active set; mark primær): -- Key points (2–4): <…> -- Tone / voice anchor: -- Out of scope for this edition: <…> - -## §4 — Immutable rules + fact-check log -> Rules locked for this edition (do not relitigate mid-pipeline): -- -- - -> Fact-check log (Step 5 — guilty-until-disproven; 🔴 must be empty before lock): -| Claim | Risk | Source / verification | Status | -|-------|------|-----------------------|--------| -| | 🔴/🟡/🟢 | | open / resolved | - -## §5 — Persona calibration + verdicts -- Pre-lock resonance sweep (Step 6): primær -- Method/persona calibration notes: -- Post-lock conversion sweep (Step 9): primær mode konverter → - -## §6 — Next session -- Next step: Step (per the Step 0 resumption table) -- Precise pointer: -- Open questions for the operator: <…, or "none"> diff --git a/plugins/linkedin-thought-leadership/config/edition-state.template.json b/plugins/linkedin-thought-leadership/config/edition-state.template.json index 0285388..1323b25 100644 --- a/plugins/linkedin-thought-leadership/config/edition-state.template.json +++ b/plugins/linkedin-thought-leadership/config/edition-state.template.json @@ -2,10 +2,10 @@ "_doc": { "purpose": "Schema for edition-state.json — deterministic resumption state for a newsletter edition in production. Holds the current phase + per-article status so /linkedin:newsletter (Step 0) can resume exactly where a prior session stopped.", "decision": "G — production state lives in the serie-mappe (e.g. /Users/ktg/repos/maskinrommet/serier//linkedin/edition-state.json), NOT in the plugin. This file is the schema-defining TEMPLATE only; copy + fill it in the serie-mappe when producing an edition.", - "complements": "edition-config.json (static: calendar, freshness, captions) and the human-readable edition-HANDOVER.md (narrative state, fasit §5.2). edition-state.json is the lightweight machine-readable companion for deterministic resumption.", + "complements": "edition-config.json (static: calendar, freshness, captions) and /STATE.md (human-readable narrative state, overwritten each phase per the ONE-system continuity rule — there is no edition-HANDOVER.md). edition-state.json is the machine-readable companion: deterministic resumption + the durable fact-check log, immutable rules, and persona verdicts that the old HANDOVER §4/§5 used to carry.", "lifecycle": "/linkedin:newsletter reads this in Step 0 and rewrites it at every phase transition. Article keys mirror edition-config.json (zero-padded strings: \"01\", \"02\", ..., or \"samle\").", "phases": [ - "load-context — read state/HANDOVER, voice profile, persona library, series brief (Step 0)", + "load-context — read /STATE.md, voice profile, persona library, series brief (Step 0)", "brief-calibration — angle, voice, audience personas, key points, leader-takeaway (Step 1)", "research — parallel scoped mandates → verified notes, triangulation (Step 2)", "skeleton-pitch — five-line skeleton (premise/problem/recommendation/payoff/forward) + section pitches, operator gate + persona-skjelett-sweep BEFORE prose (Step 2.5)", @@ -34,8 +34,10 @@ "title": "
", "phase": "load-context", "status": "pending", + "immutableRules": null, "factcheckLog": null, "personaSweep": { + "skeleton": null, "resonance": null, "conversion": null }, diff --git a/plugins/linkedin-thought-leadership/config/personas.template.md b/plugins/linkedin-thought-leadership/config/personas.template.md index 24ce815..0cf8aec 100644 --- a/plugins/linkedin-thought-leadership/config/personas.template.md +++ b/plugins/linkedin-thought-leadership/config/personas.template.md @@ -32,6 +32,27 @@ trim, or extend them per series. BEFORE lock — «does the point land for this reader?») and conversion mode (Step 9, after lock — binary «would YOU click?» on the hook only). +### The click-gate is blocking (bar = primær ekte JA) + +The persona sweep is not advisory — it returns a **blocking verdict** +(PASS / REWORK / BLOCK), and the bar is the **primær reader's genuine, unqualified +JA**. The three Seres seed personas are the canonical set: **A = IT-divisjonsdirektør** +(sekundær), **B = KI-seksjonsleder** (sekundær), **C = Linjeleder** (PRIMÆR — trumfer). + +- **Bar = C ekte JA.** A clean, unqualified yes from the primær. **«JA med store + forbehold» = NEI.** +- ⛔ **Hard fail (= omskriv, ikke annotér):** the verdict is BLOCK, regardless of + the other axes, when the primær — + - «mistet meg» (disengaged before the takeaway), or + - does not own the action (the takeaway is someone else's job), or + - hits a **sjargong-mur** (a wall of technical vocabulary their `sjargong` + rejects), or + - hits a **modell-/navne-katalog** (product/model/benchmark names listed for + completeness). +- These are **rewrite triggers**, not annotations the editor can wave through. A + *sekundær* NO from a role/expertise ceiling stays a SIGNAL the gate works — + never distort the text to chase it. + Each persona documents five fields. Keep the lowercase field keys exactly — the pipeline and the structural check key off them: diff --git a/plugins/linkedin-thought-leadership/config/user-profile.template.md b/plugins/linkedin-thought-leadership/config/user-profile.template.md index b1fe56b..da87508 100644 --- a/plugins/linkedin-thought-leadership/config/user-profile.template.md +++ b/plugins/linkedin-thought-leadership/config/user-profile.template.md @@ -92,6 +92,16 @@ cp config/user-profile.template.md config/user-profile.local.md - [What you never do] - [Another thing to avoid] +**Universal anti-patterns (keep these — they hold for every author):** +- **Modell-/navne-katalog.** Do not reel off product names, model names, or + benchmarks for completeness. Pick ONE concrete, verifiable (preferably local) + case over a list — a name-dump is a jargon wall to a non-technical reader. +- **Fullstendighet over leser-handling.** Serve what the primary reader can DO + from their chair, not everything the author knows. Completeness is not a virtue. +- **Selvrefererende overhead-åpning.** No meta-commentary about what the text will + or will not do, no warm-ups. Start on the reader's problem. +- **«ikke bare X, men Y», reflex rule-of-three, tacked-on summaries, hedging.** + **Language:** [English / Norwegian / Other] --- diff --git a/plugins/linkedin-thought-leadership/references/longform-quality-rules.md b/plugins/linkedin-thought-leadership/references/longform-quality-rules.md index a8d9566..f14d1e8 100644 --- a/plugins/linkedin-thought-leadership/references/longform-quality-rules.md +++ b/plugins/linkedin-thought-leadership/references/longform-quality-rules.md @@ -30,6 +30,12 @@ they will do about it. about it. - If the reader cannot state the takeaway in one sentence, the text is not done — tighten until they can. +- **Serve what the reader can DO, not what the author knows.** The text exists to + give the *primær* reader (the non-technical line manager) something they can act + on from their own chair — not to demonstrate the author's breadth. Completeness + is not a virtue: if a passage exists to be thorough rather than to move the + reader's decision forward, cut it. Choose ONE concrete, verifiable (preferably + Norwegian) case over an exhaustive list. **Pass/flag:** PASS when the one-takeaway + one-action is stated and unmistakable; FLAG when the text carries two competing takeaways or ends without a concrete @@ -61,8 +67,20 @@ Norwegian): content actually enumerates three things) - «i en stadig mer kompleks verden» (and equivalent throat-clearing openers) - tacked-on summary sentences that restate what was just said +- **modell-/navne-katalog** — reeling off product names, model names, or + benchmarks (Qwen3-14B, Ministral 3, SWE-bench, Arena, «parametere», «vekter») + for completeness' sake. A list of names is a jargon wall to the primær reader; + pick ONE concrete, verifiable case instead (see rule 1). This is a **hard fail + for the primær persona**, not a stylistic nit — it is the failure mode that + nearly shipped in the Seres process. +- **selvrefererende overhead-åpning** — meta-commentary about what the text will + or will not do, warm-ups, and openers like «Det er bra. Det er ikke det denne + teksten handler om». Start on the reader's problem, not on the text's own + framing. -**Pass/flag:** PASS when none appear; FLAG (with count) and remove each occurrence. +**Pass/flag:** PASS when none appear; FLAG (with count) and remove each +occurrence. A modell-/navne-katalog or a sjargong-mur is a hard fail (treat as +BLOCK-level for the primær reader in the persona sweep), not a soft flag. ### 4. Generell, ikke etat-/person-spesifikk (general, not org-/person-specific)