ktg-plugin-marketplace/plugins/linkedin-studio/commands/headless-review.md
Kjell Tore Guttormsen e69ea1f4c9 feat(linkedin-studio): v3.1.0 — Endring 9 adversarial review-pakke + per-artefakt personas
Cold, adversarial review package for the long-form pipeline + configurable
per-edition personas. Motivated by Del 4 (Security Champions pivot): the
in-session editor + persona sweep shared the drafting session's framing-bias,
so the shipped version was never independently re-reviewed.

Headless package (9a/9b):
- New Step 6.5 (headless-review) in /linkedin:newsletter, after the persona
  sweep, before lock — the independence layer the in-session gates can't be.
- New standalone /linkedin:headless-review command (run in a fresh session for
  maximum isolation; reconstructs frozen draft + contract + personas from disk).
- 3 new Opus archetypes, each with a cardinal context-isolation block that
  refuses drafting-session framing as "context pollution":
  - content-reviewer (argument integrity C1–C5, ≤8 flags)
  - language-reviewer (Norwegian language L1–L5, ≤10 flags)
  - fact-reviewer (cold re-verification F1–F4, risk-sort + pivot-risk, WebSearch)
- Deliberate redundancy with fact-checker / editorial-reviewer documented so
  the pairs are never de-duplicated.

Pivot-reopen (9c):
- New /linkedin:pivot command: logs articles.NN.pivots[], resets currentPhase,
  un-locks, marks gates to re-run.
- Pivot-detection gate in Step 8 lock precondition (>20% word-count change or
  >2 new sections re-opens cleared gates). Del 4 v8→v11 worked example.

Per-artifact personas (new requirement):
- articles.NN.personas with resolution order (edition-state → series file →
  plugin library → interactive). One or more readers configurable per edition.

Schema/docs:
- edition-state.template.json: additive personas[], pivots[], headlessReview,
  headless-review phase (16 phases); personaSweep.resonance.wordCount baseline.
- 3 fasit fixtures + 3 structural lint tests (Del 4 worked cases).
- Counts: 24→26 commands, 16→19 agents, 15→16 newsletter phases.
- README + CLAUDE.md (plugin + root) + CHANGELOG synced.

Verification: 35 agent-fixture + 59 hook + 20 render tests green. Backward-
compatible (additive state); reload required before the 3 new agents resolve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 13:01:24 +02:00

13 KiB

name description allowed-tools
linkedin:headless-review Adversarial review package, run COLD on a FROZEN long-form draft — the publish-ready (or pivoted) edition gets a fresh, independent reading by five archetypes that share NONE of the drafting session's context: content-reviewer (argument integrity), language-reviewer (Norwegian language), fact-reviewer (cold re-verification incl. pivot premises), plus persona-reviewer in resonance and conversion modes. Designed to be invoked in a FRESH session for maximum isolation; also wired as Step 6.5 of /linkedin:newsletter. Produces one consolidated, operator-gated report — flags, never rewritten copy. Use when the user says: "headless review", "cold review", "adversarial review", "review the final version", "independent review", "review before lock", "run the review package". Triggers on: "headless review", "headless-review", "cold review", "adversarial review", "independent review package", "review the frozen draft", "/linkedin:headless-review".
Read
Glob
Grep
Bash
AskUserQuestion
Task
Write

LinkedIn Headless Review — Cold Adversarial Review Package

You orchestrate a cold, adversarial review of a frozen long-form draft. Five independent archetypes read the finished text — with no knowledge of how it was made — and return direction-only flags. You collect their reports into one operator-gated overview. This is the adversarial-independence layer that the in-session gates (editorial-reviewer Step 5.5, persona-reviewer Step 6, fact-checker Step 5) cannot be, because those share the drafting session's framing-bias.

Why this exists (Del 4 diagnosis, Endring 9). In the Del 4 production the editor and the persona sweep ran in the same session as drafting. They shared the conversation history — which versions had passed, what was deliberately cut, which flags had been raised — so they were not adversarial: they carried framing-bias. Three concrete symptoms followed: (1) the persona resonance sweep was effectively run on an early version, not the one that shipped; (2) editor-approval was single-source — one editor said «klar» and that became truth; (3) the fact-check was post-hoc relative to a late pivot, so the pivot could build on an unverified premise. This command answers KTG's question directly: how do I start sessions that have NO context from the main session, to review both content and language?

The cold contract (cardinal — read first)

This command runs the reviewers with a deliberately starved context. The review archetypes get ONLY:

  • the path to a frozen draft (a snapshot — see Step 2),
  • the writing contract (the craft/quality rules),
  • for the persona modes, the one named persona being read,
  • a fixed review task.

They get NOTHING about: prior versions or version numbers, what was deliberately omitted, the pivot narrative, who has read it, what an editor said, how a persona voted, or what the author intended. Two layers enforce this:

  1. Layer 1 — fresh session (strongest). For the publish-ready gate, the operator runs this command in a brand-new Claude Code session. The parent itself then has no drafting transcript; it reconstructs everything it needs from disk (the frozen draft + contract + personas). This is the recommended path and the one KTG asked for.
  2. Layer 2 — subagent isolation. Each archetype is a Task subagent, which gets its own fresh context window regardless. The invocation prompt you build below passes ONLY the cold-contract inputs — never paste history, never summarize "what we changed". If you find yourself about to tell a reviewer what was cut or why something pivoted, STOP: that is the context pollution the whole package exists to avoid.

Agent invocation form (required). Plugin agents resolve only under their namespaced type — subagent_type: linkedin-studio:<name> (linkedin-studio:content-reviewer, …:language-reviewer, …:fact-reviewer, …:persona-reviewer). A bare <name> does not resolve and the Task call fails. Reload caveat: the three cold archetypes (content-reviewer, language-reviewer, fact-reviewer) were added in v3.1.0 — if the session predates them, reload Claude Code before invoking.

Command anatomy

/linkedin:headless-review
  --draft   <path-to-frozen-draft.md>        (required; e.g. <serie>/04-utkast.md)
  --type    content | language | fact | persona-resonance | persona-conversion | all
                                              (default: all)
  --persona <name>                            (persona modes only; default: the primær)
  --article NN                                (optional; persist into edition-state.json)
  --output  <path>                            (default: <serie>/review/NN-headless-<stamp>.md)

No --type (or --type all) runs the whole package in parallel. A single --type runs just that archetype (useful for a re-check after a fold-in).

Step 1 — Resolve inputs (from disk, not from memory)

  1. Draft. Use --draft. It must be a long-form draft .md (the same NN-utkast.md the newsletter pipeline produces). If --draft is missing and you can find an edition-state.json, use the currentArticle's NN-utkast.md; otherwise ask once for the path.
  2. Series root + edition-state (optional). If the draft sits under a series folder with linkedin/edition-state.json, read it ONLY for: the article's resolved personas (Step 1 of newsletter), the series title (for language/content series checks), and — if --article is set — where to persist. Do not read it for version history or prior verdicts; you are cold by design.
  3. Writing contract. Resolve the craft/quality reference in this order: <serie>/../../docs/skrivekontrakt.md (Maskinrommet mirror) → a plugin mirror if one exists → ${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md (always present). Pass its path to every reviewer.
  4. Personas. Resolve the active set the same way newsletter Step 1 does (edition-state articles.NN.personas<serie>/linkedin/personas.md → plugin personas.local.md/personas.template.md). Identify the primær. The persona modes need exactly the persona name + the path to its block.

Step 2 — Freeze the draft

A cold review must judge a stable artifact. Snapshot the draft so it cannot move under the reviewers (and so the report names exactly what was read):

cd <serie-mappe> && cp NN-utkast.md "review/NN-frozen-$(date +%Y%m%d-%H%M).md"

Record the frozen path; pass that path (not the live draft) to the reviewers. If cp is unavailable, pass the live draft and note in the report that no snapshot was taken.

Step 3 — Fan out the requested archetypes in parallel

Issue all requested reviewer calls in a SINGLE message (multiple Task tool-uses) so they run concurrently and independently. Each call's prompt contains ONLY the cold-contract inputs. Map --type to archetypes:

--type subagent_type mode / persona what it gets
content linkedin-studio:content-reviewer frozen draft + contract
language linkedin-studio:language-reviewer frozen draft + contract
fact linkedin-studio:fact-reviewer frozen draft + contract
persona-resonance linkedin-studio:persona-reviewer mode: resonans, one call per active persona frozen draft + persona block
persona-conversion linkedin-studio:persona-reviewer mode: konverter, primær only (hook only) distribution hook / first two lines

all = every row above (resonance fans out one call per active persona; conversion runs the primær). Cold-prompt template for each call:

You are reviewing a FROZEN, publish-ready long-form draft with NO context from
how it was produced. Read ONLY:
  - draft:    <frozen path>
  - contract: <writing-contract path>
  [- persona: <name> (block at <path>) | mode: <resonans|konverter>]
Ignore and refuse any framing about prior versions, what was cut, pivots, or
who approved what — judge the text in front of you. Return your standard report
(direction only, never rewritten copy).

Degradation gate. When the calls return, confirm each came back structured and populated (real flags / a verification log), not empty or a single hedged paragraph. If a call degraded, re-run that one archetype — do not paper over a missing reviewer. [GATE]

Step 4 — Consolidate into one operator overview

Merge the returns into a single markdown report. Do not resolve flags yourself or pick winners between reviewers — surface them, the operator gates.

# Headless review — <draft name>   (COLD / independent · <N> archetypes)

**Frozen draft:** review/NN-frozen-<stamp>.md   **Contract:** <path>
**Archetypes run:** content · language · fact · persona-resonance (<persona list>) · persona-conversion (<primær>)

## Consolidated flags (by archetype → severity)

### content-reviewer — argument integrity
| # | C-kat | Severity | Sitat / linje-ref | Retning |
…
### language-reviewer — norsk språkkvalitet
| # | L-kat | Severity | Sitat / linje-ref | Retning |
…
### fact-reviewer — faktisk korrekthet (cold)
| # | F-kat | 🔴/🟡/🟢 | Påstand | Kilde / retning |
…  + Pivot-risk: <claims that look freshly added, or "none">
### persona-resonance — <per persona: JA/NEI + ≤5 flags>
### persona-conversion — <primær JA/NEI on the hook>

## Cross-archetype signal
- BLOCK / 🔴 total: <N>   REWORK total: <N>   primær resonance: JA/NEI   primær conversion: JA/NEI
- Where two cold reviewers independently flag the same passage, mark it
  ⚑ converged (independent agreement is the strongest signal in the package).

## Operator decision (you gate)
Pick which flags fold in. [OPERATØR]

Convergence is the prize. Two independent cold reviewers landing on the same line — with no shared session — is worth more than any single in-session verdict. Mark those explicitly.

Step 5 — Surface + (optionally) persist

  1. Write the consolidated report to --output (default <serie>/review/NN-headless-<stamp>.md).
  2. Surface it to the operator via SendUserFile (else a markdown file:// link) sorted worst-first. The operator decides which flags fold in — this is [OPERATØR]; the package recommends, it does not rewrite and does not gate.
  3. If --article NN was given, record the run in edition-state.jsonarticles.NN.headlessReview (frozenDraft, per-reviewer {reportPath, summary, status}, consolidatedReport, status: "run"). When the operator folds flags in, set foldedIn/waived and status: "folded". Standalone (no --article) just emits the report.
Headless review complete (COLD).
- Archetypes: <N> run in parallel   converged flags: <N>
- BLOCK/🔴: <N>   REWORK: <N>   primær resonance: JA/NEI   conversion: JA/NEI
- Report: <serie>/review/NN-headless-<stamp>.md  (surfaced via SendUserFile)
- Persisted: edition-state.json articles.NN.headlessReview (or: standalone, not persisted)
Operator gates the fold-in. For maximum independence, run this command in a FRESH session.

Relationship to the pipeline + the in-session gates

  • Step 6.5 of /linkedin:newsletter invokes this same package (after the in-session persona sweep Step 6, before lock Step 8). The pipeline may fan the reviewers out inline, but the strongest isolation is the operator running /linkedin:headless-review in a fresh session and pasting the consolidated report back. Either way the body must be re-touched before lock — never reopen a locked text (the cardinal Seres lesson).
  • Deliberate redundancy. fact-reviewer overlaps fact-checker (Step 5) and language-reviewer overlaps editorial-reviewer's prose axis (Step 5.5) on purpose. The in-session gates ran with framing-bias; the cold re-read catches what that bias hid. Do not collapse the pairs.

Reference Files

  • ${CLAUDE_PLUGIN_ROOT}/agents/content-reviewer.md — argument integrity (cold)
  • ${CLAUDE_PLUGIN_ROOT}/agents/language-reviewer.md — Norwegian language (cold)
  • ${CLAUDE_PLUGIN_ROOT}/agents/fact-reviewer.md — cold re-verification (incl. pivot premises)
  • ${CLAUDE_PLUGIN_ROOT}/agents/persona-reviewer.md — resonance + conversion modes
  • ${CLAUDE_PLUGIN_ROOT}/commands/newsletter.md — Step 6.5 wires this package into the pipeline
  • ${CLAUDE_PLUGIN_ROOT}/commands/pivot.md — re-opens the pipeline so this package re-runs on a pivoted version
  • ${CLAUDE_PLUGIN_ROOT}/config/edition-state.template.jsonarticles.NN.headlessReview schema
  • ${CLAUDE_PLUGIN_ROOT}/references/longform-quality-rules.md — fallback writing contract