ktg-plugin-marketplace/plugins/linkedin-studio/CHANGELOG.md
Kjell Tore Guttormsen 64a3b0b84d chore(linkedin-studio): re-baseline 4.1.0 → 0.4.0 (honest pre-1.0 maturity)
Reset version declarations to v0.4.0 across plugin.json, README badge + version-history, CLAUDE.md header, and the root marketplace README entry. The 1.0.0–4.1.0 numbering reflected ambition, not maturity: user data still lives inside the plugin tree (.gitignore-defended), no command has passed the hardening quality-gate, command testing is incomplete, and there is no GUI. A deliberate marketplace downgrade (existing installs will not auto-pull a lower number). Path to v1.0.0 = architecture (M0 per-user data-dir migration) + hardening + command testing + GUI. No functionality changed — only version declarations; all prior changelog/history preserved. Lint green (Passed 74 / Failed 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 19:13:35 +02:00

46 KiB
Raw Permalink Blame History

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.4.0] - 2026-05-31

Re-baselined

Honest version reset: 4.1.0 → 0.4.0. The project was previously numbered 1.0.04.1.0, but those were pre-release iterations. The honest maturity is v0.4.0: user data still lives inside the plugin tree (defended only by .gitignore), no command has yet passed the hardening quality-gate, command testing is incomplete, and there is no GUI. This is a deliberate marketplace downgrade — existing installs will not auto-pull a lower number. The path to v1.0.0 is four workstreams: architecture (move all user data out of the plugin into a per-user data dir — the M0 migration), hardening (every command through the quality-gate), command testing (each command run against real/isolated ground truth), and a GUI.

Changed

  • Version declarations reset to 0.4.0 across .claude-plugin/plugin.json, README.md (badge + version-history), CLAUDE.md (header), and the root marketplace README.md entry. No functionality changed — no code, command, agent, hook, or state-shape change. All prior changelog entries below are preserved as the development history.

[4.1.0] - 2026-05-30

Summary

Journey layer over the command surface (Voyage S14). Step 14a's cold, independent command-rationalization (docs/remediation/command-rationalization.md) audited all 27 commands under the same subsumption discipline as the agent-overlap study and found zero redundancy — the surface was over-grown in count, not in duplication (the two prior consolidations already removed the genuine overlaps). So instead of cutting, this release organizes: the 27 atomic commands are kept as the execution tier, and a journey layer is added on top. Additive and minor — no command removed, renamed, or behavior-changed; the two new commands register on reload. Design contract: docs/remediation/journey-layer-design.md.

Added

  • /linkedin:create — Create front-door. One guided "what do you want to make?" entry that routes to the command owning the format (post/quick/react/carousel/video/multiplatform/batch/newsletter). Delegates only — no drafting logic of its own.
  • /linkedin:measure — Measure front-door. One guided "how am I doing?" entry that routes to the right analytics command (import/report/analyze/audit/ab-test). Delegates only. Commands 27 → 29.

Changed

  • Router re-tiered into five journeys (commands/linkedin.md) — Start · Create · Engage · Measure · Grow, each headed by a front-door (onboarding/strategy elevated as the Start/Grow front-doors; create/measure new; Engage is a calendar + firsthour relay), with the atomic commands nested as the execution tier. Absorbs the planned router-tiering UX step.
  • Honesty nits from 14a fixed — the router now lists /linkedin:firsthour (was agent-only under Post-Publish); calendar's publish-action first-hour block cross-links to /linkedin:firsthour for the full worked sprint plan.
  • EXPECT_COMMANDS in scripts/test-runner.sh 27 → 29; CLAUDE.md / README rosters + counts updated in lockstep.

Fixed

  • 14a deliverable correction — the cold review's first pass omitted multiplatform (covered 26/27) and raised a competitive 1K-gating inconsistency that did not survive verification (CLAUDE.md :64, README :222, the router, and the command body all leave competitive ungated). Both corrected in command-rationalization.md; net finding unchanged (keep 27, 0 merge, 0 cut).

Compatibility

  • Minor / additive. No command removed, renamed, or behavior-changed; the 27 existing commands, all 19 agents, and all state shapes are unchanged. The two new commands (create, measure) register when the plugin command set is rebuilt at session start — reload required to see them.

Added — within 4.1.0 (refinement sessions, no surface/count/version change)

  • Manual per-post saves in analytics (Voyage S16). Lifts the original v4.0.0 Non-Goal: PostMetrics gains an optional saves field, ingested when the user adds a Saves column to the CSV with the count read off native LinkedIn post analytics (count-only, ~Sept 2025; absent from the export, no self-serve API). The parser (scripts/analytics/src/parsers/csv-parser.ts) reads it when present; weekly/monthly summaries gain an optional totalSaves; the CLI (import/report) surfaces saves per-post and as a total. Backward-compatible — a missing column or blank cell leaves saves unknown (never coerced to 0), saves is not folded into engagementRate (which stays comparable to older imports), and saves-free data round-trips byte-identical. Dwell stays explicitly unmeasurable — no dwell field or surface was added. This refines the v4.0.0 "the plugin cannot read those signals" wording: the plugin still cannot auto-track saves, but it now ingests a manually-entered count. Built location-agnostically through the existing getAnalyticsRoot() seam so the planned data-dir migration (UI brief §9b/M0) relocates it in one place. New RankableMetric type fixes the trend/alert index access that the optional field would otherwise widen to number | undefined.
  • Onboarding tool-grant fix (S16-pre). commands/onboarding.md Phase 2 saves voice/user-profile files but its frontmatter omitted Write; added Write to allowed-tools (matching first-post.md). Closes a pre-existing tool-contract gap surfaced by the S15 review.

[4.0.0] - 2026-05-30

Summary

Audit-remediation release (Voyage Phase 03). A critical self-review (docs/critical-review-2026-05-29.local.md) found the plugin had drifted in three ways: (1) overclaiming — surfaces promised tracking, analytics, and review independence the plugin could not actually deliver; (2) dormant capability — eleven agents shipped in agents/ were never invoked by any command; (3) structural rot — the structure lint validated a layout the plugin had outgrown, an algorithm-signal claim contradicted itself across files, and an unpublishable model brand/date was baked into user-facing copy. This release is the systematic fix: every claim is made honest or removed, every orphan agent is wired, and the lint is rebuilt to guard the real layout plus version/count/stat consistency. Major version marks the scope of the remediation (every user-facing claim re-examined) and the reinstall/reload required for the newly-wired agents to register; it consolidates — but does not repeat — the v3.0.0 identity break (slug, agent namespace, state-file path). No content-pipeline behavior is removed; the short-form and long-form engines are unchanged except where a gate was added.

Added

  • /linkedin:firsthour — post-publish first-hour / reply-loop sprint command wiring the previously-orphaned engagement-coach agent: a timestamped target list, draft comments, and a timeline, persisted to state (recordFirstHourPlan), handing off to post-feedback-monitor. Commands 26 → 27.
  • All 11 orphaned agents wired (case-by-case: 9 in the wiring pass, 2 via the new gates/command) — the agent set is now fully reachable from a command, with no deletions. Agents stay 19.
  • Short-form de-AI gate — the short-form content commands run differentiation-checker + the voice-guardian before output, the short-form mirror of the long-form de-AI discipline.
  • Video quality gate/linkedin:video enforces captions + aspect-ratio guidance (4:5 / 1:1 + captions) and drops the hard 9:16 mandate.
  • Version-consistency grep in the structure lint (scripts/test-runner.sh) — the plugin.json version must match the README badge, the plugin CLAUDE.md header, and the CHANGELOG top entry; the plugin.json description is now also covered by the algorithm-stat-consistency scan.

Changed

  • Structure lint rebuilt (scripts/test-runner.sh) — dynamic registration counts derived from ls (agents/commands/refs/skills), frontmatter shape, hook-drift (compile-hooks.py --check), and an algorithm-stat-consistency grep that forbids the unpublishable model brand/date and competing magnitudes from returning. Replaces a dead validator that asserted an outgrown layout.
  • Algorithm signals reconciled to one sourced statementreferences/algorithm-signals-reference.md is the single source of truth (per-claim Source + Confidence); every citer cites rather than restates. The 2026 relevance-ranking model is referenced without a name or a date (the unpublishable brand/date removed everywhere, including the root README and the marketplace manifest).
  • post-feedback-monitor promoted to Opus (Opus-default for human-facing reasoning).
  • Newsletter distribution, profile-SEO, and outreach surfaces made honest — they describe what the plugin produces (drafts, recommendations, queues) versus what the operator does manually, with no implied automation.
  • Long-form review language is configurable; render output de-branded; series path parameterized (no hard-coded author or series).
  • Counts reconciled to the ls-derived source of truth: 27 commands · 19 agents · 6 skills · 9 hooks · 25 reference docs · 16 newsletter phases. README badges + intro, root README, and the marketplace catalog brought into sync.
  • Long-form review-pass overlap measured (docs/remediation/overlap-measurement.md) across the seven long-form review gates against in-repo fixtures: every gate has ≥ 1 unique catch and the real overlaps are justified → no gate trimmed (the review stack stays seven).

Fixed

  • Analytics CLI fresh-clone crashreport.md / import.md surface the npm install at point-of-use, and getAnalyticsRoot() is anchored on the .claude-plugin/plugin.json marker instead of a build-layout-relative depth (latent correctness bug).
  • No false metric claims — saves/dwell wording is honest (the plugin cannot read those signals), and the A/B significance claim is downgraded to directional.

Security / Privacy

  • Voice-profile leak closed — the tracked authentic-voice-samples.md is now a PII-free placeholder carrying a <!-- VOICE_PLACEHOLDER --> sentinel; the author's real profile moved to a gitignored .local.md; personalization-score.mjs scores the placeholder 0 voice points via the sentinel (both voice writers replace-not-append). The author name is scrubbed from plugin.json (the LICENSE MIT copyright holder is the intentional exception). Per a documented decision, git history is not rewritten — the historical voice file is attributed open-source authorship, not a leaked secret.

Compatibility

  • Breaking — reinstall / reload required. The eleven newly-wired agents register only when the plugin agent set is rebuilt at session start; the v3.0.0 slug / agent-namespace (linkedin-studio:<agent>) / state-path (~/.claude/linkedin-studio.local.md) break is consolidated here. Existing editions and analytics data are unaffected (state shapes are additive; posts/streak/history preserved). The /linkedin:* command namespace is unchanged.

[3.1.0] - 2026-05-29

Summary

An adversarial review package becomes part of the long-form pipeline (Endring 9). The Del 4 production run (Maskinrommet, 2026-05-29 — the Security Champions pivot, v8 → v11) shipped a high-quality article, but its quality assurance leaned on one good editor + KTG's availability to read it several times — it did not scale. The root cause: the editor and the persona sweep ran in the same session as drafting, sharing the conversation history (which versions passed, what was deliberately cut, which flags had been raised). They were therefore not adversarial — they carried framing-bias. Three concrete symptoms: (1) the persona resonance sweep effectively judged an early version, not the one that shipped; (2) editor-approval was single-source; (3) the fact-check was post-hoc relative to the late pivot, so the pivot could build on an unverified premise. v3.1.0 answers KTG's explicit question — how do I start sessions with no context from the main session, to review both content and language? — and makes per-artifact personas a first-class input.

Added

  • /linkedin:headless-review command — runs the cold adversarial review package on a FROZEN draft. Designed to be invoked in a fresh session for maximum isolation (the parent then has no drafting transcript); reconstructs everything from disk (frozen draft + writing contract + personas). Flags --draft, --type {content|language|fact|persona-resonance|persona-conversion|all}, --persona, --article, --output.
  • Three new headless review archetypes (all Opus, each with an explicit cardinal context-isolation block that refuses drafting-session framing as "context pollution"):
    • content-reviewer (color maroon, Read+Grep) — argument integrity: C1 logical holes · C2 unsupported assumptions · C3 argument-level contradiction · C4 missing concretization · C5 unanswered «what about X?». ≤8 flags BLOCK/REWORK/NICE.
    • language-reviewer (navy, Read+Grep) — Norwegian language: L1 verbatim repetition · L2 anglicisms · L3 stiff bureaucratic register · L4 language-level self-contradiction · L5 clang/rhythm. ≤10 flags. Deliberate cold re-take of editorial-reviewer's prose axis.
    • fact-reviewer (gold, Read+WebSearch) — cold re-verification on the frozen/pivoted version: F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality. Carries over fact-checker's 5-dimension scoring + 🔴/🟡/🟢 sort + contradiction sweep + post-cutoff mandate, adds a pivot-risk subsection. Deliberate redundancy with fact-checker to catch a pivot premise that arrived after Step 5.
  • Step 6.5 (headless-review) in /linkedin:newsletter — fans the package out in parallel after the in-session persona sweep (Step 6), on a frozen draft snapshot, BEFORE lock; consolidated report surfaced via SendUserFile; converged flags (two independent cold reviewers agreeing) marked as the strongest signal. Pipeline 15 → 16 phases.
  • /linkedin:pivot command + pivot-detection gate — a pivot re-opens the pipeline so the cleared gates (fact-check 5 → editorial 5.5 → persona 6 → headless 6.5) re-run on the changed version before lock. Heuristic: a draft that drifted > 20 % in word count OR gained > 2 sections since Step 6 cleared triggers the gate (enforced as a Step 8 lock precondition). Worked example: the Del 4 v8→v11 run (+42 %, 2 new sections) would have fired the gate and forced the re-sweep.
  • Per-artifact personasarticles.NN.personas in edition-state.json: one or more readers configurable per edition, resolved in Step 1 in order (edition-state → <serie>/linkedin/personas.md per-series file → plugin personas.local.md/template → interactive definition). Feeds both the Step 6 sweep and the Step 6.5 package. config/personas.template.md documents the resolution order.
  • Three fasit fixtures + three structural lint tests for the new agents (Del 4 / Security Champions worked cases), mirroring the editorial-reviewer fixture discipline. All 35 agent-fixture assertions green.

Changed

  • config/edition-state.template.json — additive: per-article personas[], pivots[], headlessReview object; new headless-review phase string (16 phases total); personaSweep.resonance.wordCount recorded at Step 6 as the pivot-detection baseline.
  • commands/newsletter.md — Step 0/1 persona resolution reworked to per-artifact; new Step 6.5; Step 8 lock preconditions add the headless gate + pivot-detection gate; pipeline + resumption tables updated (persona-sweep-prelock → resume at Step 6.5; new headless-review → Step 7).
  • Counts: 24 → 26 commands; 16 → 19 agents; 15 → 16 newsletter phases.

Compatibility

Backward-compatible: every state-shape change is additive (existing editions resume by currentPhase; persona-sweep-prelock now resumes at Step 6.5 — an intended deterministic improvement). Reload required before the three new agents resolve (the plugin agent set is built at session start). No new runtime code beyond the agents/commands/fixtures; the render pipeline, hooks, and short-form surface are untouched.

[3.0.0] - 2026-05-29

Summary

Plugin renamed linkedin-thought-leadershiplinkedin-studio ("LinkedIn Thought Leadership" → LinkedIn Studio). The old display title read as pompous; the new name is plain and matches how the plugin already describes itself ("LinkedIn content engine"). This is a breaking change — the marketplace slug, the agent namespace (linkedin-studio:<agent>), and the runtime state-file path all change — so it bumps to a major version. Functionality is byte-for-byte identical to v2.4.0; this release is pure identity.

Changed (breaking)

  • Slug / directory / manifests: plugins/linkedin-thought-leadership/plugins/linkedin-studio/; plugin.json and root marketplace.json name/source updated. Reinstall required.
  • Agent namespace: commands invoke plugin agents as linkedin-studio:<name> (was linkedin-thought-leadership:<name>). Functional change in commands/newsletter.md; docs updated to match.
  • Runtime state path: ~/.claude/linkedin-thought-leadership.local.md~/.claude/linkedin-studio.local.md. Hardcoded in hooks/scripts/{state-updater,session-start,posting-reminder,user-prompt-context}.mjs, hooks/prompts/topic-rotation-gate.md, and config/state-file.template.md. Existing state migrated in place (post metrics, streak, content history preserved).
  • Catch-all skill skills/linkedin-thought-leadership/skills/linkedin-studio/ (frontmatter name: linkedin-studio); the five functional skills (linkedin-analytics, -content-creation, -networking, -strategy, -voice) are unchanged.

Not changed (explicit non-deltas)

  • Command namespace /linkedin:* — set per-command in frontmatter (name: linkedin:post), already independent of the plugin slug. Every command (/linkedin:post, /linkedin:newsletter, …) is invoked exactly as before. 24 commands, 16 agents — counts unchanged.
  • All hooks, scripts, renderers, agent contracts, content — bit-for-bit identical to v2.4.0.
  • History preserved: config-audit v5.0.0 test snapshots and the docs/ build artifacts retain the old slug as point-in-time records and were intentionally not rewritten.

[2.4.0] - 2026-05-29

Summary

An editor's craft gate becomes an explicit pipeline phase in /linkedin:newsletter. The Del 4 production run (Maskinrommet, 2026-05-28) exposed a gap: the persona resonance sweep returned 15 flags across three personas and every persona reported PASS / ready-to-publish — yet the editor (KTG) found eight fresh editorial points on first reading, and only ~25 % overlapped anything the personas had touched. The other six — a missing theory anchor (SDT), a broken series-title link, a stranded small-business addressee, verbatim repetitions, em-dash over-density, an internal contradiction — were craft and narrative-architecture blind spots no agent measured. persona-reviewer measures reader response (does it land?); it does not measure prose craft or narrative architecture (is it well-made?). Two different roles; only one existed. A persona PASS was mis-reporting "ready for the editor's reading", costing an extra editorial round per article. v2.4.0 adds Step 5.5 — Editorial review, between fact-check (Step 5) and the persona sweep (Step 6), and a new editorial-reviewer agent (Opus) that mirrors the Maskinrommet writing-contract §C2. Pipeline 14 → 15 phases; 15 → 16 agents. Backward-compatible: the only state-shape change is additive (editorialReview), and existing editions resume by currentPhase (factcheck-sweep now resumes at Step 5.5 instead of Step 6 — an intended deterministic improvement). Doc/orchestration-only for the pipeline wiring; the new agent + its fasit fixture + structural lint test are the only new files.

Added

  • agents/editorial-reviewer.md (new, Opus, orange) — an editor, not a reader. Judges two axes: prosa-håndverk (P1 em-dash density · P2 verbatim repetition · P3 postulated numbers without source/hedge · P4 internal contradiction · P5 versal-tic — mostly grep-able) and narrativ-arkitektur (A1 concrete instantiation · A2 theory-anchored hypotheses · A3 series-title symmetry · A4 equally-usable action per addressee · A5 un-overloaded conclusion — evaluative). Returns ≤10 flags as direction (never rewritten copy — the jury judges, the writer writes), each with a quote/line-ref and a severity: BLOCK / REWORK / NICE. Tools Read + Grep. The checklist is the operationalized mirror of the Maskinrommet skrivekontrakt §C2 (bidirectional mirror rule: §C2 is the source of truth). New agent — requires a session reload before it is invokable.
  • Step 5.5 — Editorial review in commands/newsletter.md, between Step 5 (fact-check) and Step 6 (persona sweep). Runs a single foreground editorial-reviewer Task call, writes the report to <serie>/NN-editorial-review.md, surfaces it to the operator via SendUserFile (the Endring-5 / Step-7.5 operator-gate pattern), folds approved flags in by tightening (rule 6) → v(n+1), and optionally re-runs the agent on the cleaned version. Why before the persona sweep: the personas measure response — if the prose is locally messy the persona flags become noise; clean the craft first so Step 6 measures what it was built to measure.
  • editorial-review phase string + articles.NN.editorialReview schema + _doc.editorialReview note in config/edition-state.template.json _doc.phases (14 → 15 phases). Additive; editorialReview: null until Step 5.5 runs. The craft companion to factcheckLog (truth) and personaSweep (response).
  • agents/fixtures/editorial-reviewer-cases.md (new) — fasit fixture: the Del 4 v5 gold standard. KTG's eight editorial points mapped to the two axes + severities (3 BLOCK / 5 REWORK), with the persona-overlap column showing 6/8 were editorial-only blind spots. The calibration target for acceptance-criterion #8 (a live run needs a session reload + Maskinrommet read access; until then the fixture is the gold-standard of record).
  • agents/__tests__/editorial-reviewer-fixture.test.mjs (new) — structural lint mirroring the persona-reviewer / fact-checker fixture tests: asserts both axes, all ten checks (P1P5 + A1A5), the three severities, the eight Del 4 cases, the §C2 tie, the direction-not-copy boundary, and the blind-spot rationale. 7 tests, green.

Changed

  • /linkedin:newsletter pipeline overview — 14 → 15 phases; the overview table, build-status note, and reference-file list reflect Step 5.5.
  • Resumption table in commands/newsletter.mdcurrentPhase: "factcheck-sweep" now resumes at Step 5.5 (was Step 6); new editorial-review row resumes at Step 6. (Spec said currentPhase: "fact-check"; the canonical key in this plugin is factcheck-sweep — wired to the real key.)
  • Step 5 hand-off + ordering note — fact-check now hands off to Step 5.5; the BEFORE-lock note names editorial review (5.5) and the persona sweep (6) as the two gates the fact-check precedes.
  • Step 6 intro — now reads on the "editorially-cleaned, fact-checked draft"; the persona sweep judges response, not craft (that was 5.5).
  • README, CLAUDE.md, root README, root CLAUDE.md, plugin.json version + descriptions.

Not changed (explicit non-deltas)

  • persona-reviewer contract — bit-for-bit unchanged. Editorial review is supplementary: one agent measures craft (5.5), one measures response (6). The role boundary is sharp — editorial-reviewer never flags "this won't resonate", persona-reviewer never flags em-dash density.
  • Steps 05, 6 body, 7, 7.5, 810 — contract unchanged apart from the Step 5→5.5→6 wiring and the Step 6 intro line.
  • Renderers, hooks, scripts, command count (24) — all unchanged. No new .mjs runtime code (the only new code is the fixture lint test).

[2.3.0] - 2026-05-28

Summary

Visual assets become an explicit pipeline phase in /linkedin:newsletter. Until now images (cover + inline figures) were produced ad-hoc outside the 13-phase pipeline and referenced manually from edition-config.json + linkedin/NN/cover.png — even though a cover is mandatory (KTG cover-directive 27.05: «TLDR on top + at least one figure per article») and must coordinate with the text. v2.3.0 adds Step 7.5 — Visual assets, between annotation (Step 7) and lock (Step 8), so the cover is generated, operator-gated, and approved before lock — render/build-linkedin.mjs picks up linkedin/NN/cover.png at lock, so generating images after lock would force a re-render and break the lock. Pipeline 13 → 14 phases. Doc/orchestration-only — no new code; mcp-image is the default generation route but the interface stays pluggable (external cover-raw.png accepted), and the carousel branch reuses the existing render/build-carousel.mjs. Backward-compatible: the only state-shape change is additive (visualAssets), and existing editions resume by currentPhase (annotation now resumes at Step 7.5 instead of Step 8 — an intended deterministic improvement).

Added

  • Step 7.5 — Visual assets in commands/newsletter.md (between Step 7 annotation and Step 8 lock). Decides image needs from the article type (method-heavy → 12 inline figures, diagnosis-heavy → cover only), writes a per-image brief, generates via two routes (default mcp__mcp-image__generate_imagecover-v<N>-kandidat.png; external → cover-raw.png), runs the operator-gate (candidates surfaced via SendUserFile, approval copied to the fixed cover.png name — the same render+annotate pattern as Steps 2.5/3a), and records credit + caption. Explicit carousel branch (format: "carousel"): render the deck via render/build-carousel.mjs instead of cover+inline.
  • visual-assets phase string + articles.NN.visualAssets schema in config/edition-state.template.json _doc.phases (13 → 14 phases) — { format, cover: { brief, route, candidates[], approved, status }, figures: [ { id, brief, placement, status } ], carousel }. Additive; default format: "standard".
  • config/image-credit-caption.template.md (new) — cover motif + credit + caption table, modelled on the established Seres-serien image-credit-caption.md. Honest-about-AI credit per the verification duty; documents the cover/figure naming convention.
  • Naming convention documented in commands/newsletter.md Step 7.5 — cover.png (approved, fixed) / cover-v<N>-kandidat.png (attempts) / cover-raw.png (external pre-edit source) / fig<N>.png (inline). Consistent with existing series use.

Changed

  • /linkedin:newsletter pipeline overview — 13 → 14 phases; the overview table, build-status note, and reference-file list reflect Step 7.5.
  • Resumption table in commands/newsletter.mdcurrentPhase: "annotation" now resumes at Step 7.5 (was Step 8); new visual-assets row resumes at Step 8. persona-sweep-prelock flows Step 7 → Step 7.5.
  • Step 8 lock preconditions now require the gated visualAssets (approved cover.png for standard format, or approved carousel.pdf for carousel format) alongside the existing fact-check (no open 🔴) and primær-JA gates.
  • README, CLAUDE.md, root README, root CLAUDE.md, plugin.json version + descriptions.

Not changed (explicit non-deltas)

  • Steps 07, 8 body, 9, 10 in /linkedin:newsletter — contract unchanged apart from the Step 7→7.5→8 wiring and the additive Step 8 precondition.
  • Renderersrender/build-linkedin.mjs, build-html.mjs, build-carousel.mjs untouched (Step 7.5 calls them; no code change). build-linkedin.mjs still reads cover.png by fixed name and does not embed fig<N>.png (figures are referenced in the draft and uploaded manually) — Step 7.5 documents this actual behavior rather than overstating it.
  • Hooks, scripts, command count (24), agent count (15) — all unchanged.

[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.mjsfile:// 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 <serie>/STATE.md (auto-injected by the session-start hook); every phase writes narrative status to <serie>/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; <serie>/STATE.md + edition-state.json carry its content per the global continuity rule.

[2.1.0] - 2026-05-28

Summary

Skeleton gate before prose in /linkedin:newsletter. Two new pipeline phases (Step 2.5 — Skeleton + section pitch; Step 3a — Spine prose) split the old Step 3 into pre-prose / spine-prose / full-prose stages, each with an operator-gate. Adds a third persona-reviewer mode (skjelett) that judges the five-line skeleton + section pitches BEFORE prose is written. Empirically motivated by the Seres-serien Del 3 + Del 4 production: spine errors caught post-prose cost ~1 day; the same error caught at the skeleton stage costs 515 minutes. Backward-compatible: existing editions stop at currentPhase: "research" and now resume at Step 2.5 instead of Step 3 — an intended deterministic improvement, never a contract break.

Added

  • Step 2.5 — Skeleton + section pitch in commands/newsletter.md. Writes <serie>/NN-skjelett.md with the five-line spine (premiss / problem / anbefaling / gevinst / vei videre) + one-line section pitches. Operator-gate (JA / REVIDER / NEI) AND parallel persona-skjelett-sweep must both return JA before the pipeline advances. Encodes the Maskinrommet writing-contract §A discipline into the pipeline itself.
  • Step 3a — Spine prose in commands/newsletter.md. One paragraph per section against the gated skeleton, ~2030 % of final edition length. Operator-gate on whether the axis lands now that there is prose on it. Cheap second checkpoint before full expansion.
  • Step 3b — Full prose expansion in commands/newsletter.md. Splits the old Step 3 (Draft) into spine prose (3a) and full prose expansion (3b). 3b owns the existing draft-cursor logic for multi-session expansion; 3a is short enough to restart on interruption.
  • persona-reviewer skjelett-mode (third mode alongside resonans and konverter). Five spine axes (Premiss / Problem / Anbefaling / Gevinst / Vei videre) scored HOLDER / TVILER / MANGLER, ≤3 direction-only flags, per-pitch section-pay-in check, gate ladder PASS / REWORK / BLOCK. Caller passes mode: skjelett.
  • skeleton-pitch + spine-prose phase strings in config/edition-state.template.json _doc.phases — 11 → 13 phases. Resumption table in commands/newsletter.md extended with deterministic rows for both new phases.
  • Rule 8 — Skjelett før prosa in references/longform-quality-rules.md. Documents the skeleton-before-prose pre-condition that all other rules implicitly rely on, with the same five-slot format the pipeline enforces.

Changed

  • /linkedin:newsletter pipeline overview — 11 → 13 phases; pipeline tables in commands/newsletter.md and CLAUDE.md reflect the new ordering (0, 1, 2, 2.5, 3a, 3b, 410).
  • Resumption table in commands/newsletter.mdcurrentPhase: "research" now resumes at Step 2.5 (was Step 3). Two new rows added for skeleton-pitch (→ Step 3a) and spine-prose (→ Step 3b). Draft-cursor note clarifies that the cursor applies only to Step 3b.
  • agents/persona-reviewer.md description, principles, and anti-patterns — extended to cover the third mode (skjelett). Existing resonans + konverter modes unchanged in contract.
  • CLAUDE.md header + persona-reviewer row + newsletter command row — reflect v2.1.0 surface.

Not changed (explicit non-deltas)

  • Step 1, Step 2, Steps 410 in /linkedin:newsletter — bit-for-bit unchanged in contract.
  • Renderersrender/build-html.mjs and render/build-linkedin.mjs untouched; both still consume NN-utkast.md (3a writes the spine state, 3b overwrites with the full state, but only currentPhase: "draft" triggers rendering).
  • Hooks, scripts, command count (24), agent count (14) — all unchanged.

[2.0.0] - 2026-05-28

Summary

Full-spectrum LinkedIn content engine — short-form feed posts AND long-form newsletter editions in one cohesive surface, with net-fewer commands and net-stronger pipeline. Built across 21 Voyage sessions (S1..S20+S1a) with 1 step = 1 session discipline. Locked decisions AH in docs/voyage-build-brief.md §3.

Added

  • /linkedin:newsletter — long-form orchestrator command. Multi-session pipeline: load → calibrate → research fan-out → draft → consistency/quality → fact-check sweep → persona sweep → annotate → lock → delivery → hook-gate → schedule. Maintained edition-state.json across sessions. Supports newsletter editions, essays, and series articles
  • /linkedin:outreach — outreach orchestrator (absorbed /linkedin:collab and /linkedin:speaking). Covers collaborations, partner pitches, and CFPs/speaking opportunities in one surface
  • agents/fact-checker.md (Opus, brown) — verifies every factual claim in long-form drafts against primary sources. Outputs 🟢/🔴/🟡 verdicts per claim. Runs BEFORE lock
  • agents/persona-reviewer.md (Opus, olive) — evaluates reader-persona resonance + hook-conversion gate. Two modes: per-persona deep review, multi-persona scoreboard. Runs BEFORE lock
  • render/ pipeline migrated in-pluginbuild-html.mjs, build-pdf.mjs, build-linkedin.mjs, build-carousel.mjs. Self-hosted fonts (Newsreader, Inter, JetBrains Mono) under OFL-1.1 with render/OFL.txt. WeasyPrint degradation: missing binary → skip-signal, not throw
  • config/personas.template.md — reader persona library. Knowledge level, time-pressure, resonance criteria per persona. Consumed by persona-reviewer
  • config/edition-state.template.json — schema for long-form edition state across sessions
  • references/longform-quality-rules.md — quality bar specific to long-form (different from short-form rules)
  • Router gating/linkedin:monetize and /linkedin:outreach surface "unlocks at ~1K followers" guidance and point sub-1K users at /linkedin:strategy first
  • docs/agents-capability-matrix.md — single source of truth for which agent owns which capability. Pipeline diagram + intent table + model tier table

Changed

  • Agent merges (16 → 14):
    • performance-reporteranalytics-interpreter (interpret + report modes, same data sources, mode-selector by trigger phrase)
    • comment-strategistengagement-coach (5x5x5 + first-hour + CEA method + target scoring + daily routine + comment quality scorecard; upgraded haiku → sonnet since the agent now handles deeper work)
    • content-tracker → absorbed by state-updater.mjs + analytics-interpreter
    • personalization-scorer → absorbed by personalization-score.mjs (deterministic, no AI)
  • Command merges (27 → 24):
    • /linkedin:templates → mode in /linkedin:quick (8 post-type templates)
    • /linkedin:publish → action in /linkedin:calendar (mark scheduled posts as published)
    • /linkedin:authority → absorbed into /linkedin:strategy (canon for authority building, trajectory dedup)
    • /linkedin:collab + /linkedin:speaking/linkedin:outreach
  • /linkedin:import Step 6 analysis — delegated to /linkedin:report (both consume the same trends CLI; no more duplicated analysis pipeline)
  • commands/linkedin.md router — newsletter row added, removed-command rows pruned, gating-rule paragraph for monetize/outreach
  • All 6 skill catalogs reconciled — linkedin-content-creation, linkedin-analytics, linkedin-strategy, linkedin-networking, linkedin-thought-leadership, linkedin-voice all reflect the v2.0.0 command/agent set

Removed

  • commands/templates.md (absorbed into commands/quick.md)
  • commands/publish.md (absorbed into commands/calendar.md)
  • commands/authority.md (absorbed into commands/strategy.md)
  • commands/collab.md (absorbed into commands/outreach.md)
  • commands/speaking.md (absorbed into commands/outreach.md)
  • agents/content-tracker.md
  • agents/personalization-scorer.md
  • agents/performance-reporter.md
  • agents/comment-strategist.md

Fixed

  • references/glossary.md "Authority Score" entry — corrected stale ref to commands/authority.md (removed) → commands/strategy.md (canon)
  • scripts/test-runner.sh EXPECTED_AGENTS list — reconciled to 14 agents

Migration notes

  • Plugin remains fully backward-compatible from a user-perspective: removed commands now route to their absorbing command via commands/linkedin.md
  • v1.x users who had commands/templates.md etc. in muscle memory will be auto-redirected by the router

[1.2.0] - 2026-04-11

Summary

Friction reduction release. Fewer interactive steps, auto-clipboard, deterministic state management, and progressive onboarding.

Added

  • clipboard-helper.mjs — cross-platform clipboard utility (macOS pbcopy, Linux xclip/xsel, WSL clip.exe). All 8 content commands auto-copy output to clipboard
  • state-updater.mjs — deterministic state mutations: updatePostTracking, pruneContentHistory, updateFollowerCount. Pure functions with 19 tests. No AI involvement in state updates
  • ical-generator.mjs — RFC 5545 calendar file generation for batch scheduling. VALARM reminders, VTIMEZONE support, line folding, special character escaping. 16 tests
  • MCP image carousel pipeline/linkedin:carousel generates professional slide images via mcp-image (1080x1350, 3:4 ratio) with text overlays. Mermaid Chart and text-based fallbacks
  • Progressive onboarding — personalization score hidden until 3+ posts; voice guardian suppressed until 5+ voice samples; reasonable defaults in state template
  • iCal integration in batch/linkedin:batch generates .ics file importable into macOS Calendar, Google Calendar, and Outlook
  • Auto-prune content history — session-start dynamically imports pruneContentHistory to remove entries older than 90 days

Changed

  • Reduced interactive steps — angle, format, and post type inferred from context. Max 2 questions per post (down from 4-6) in post, quick, react, pipeline
  • State management — Stop hook and 8 commands now reference state-updater.mjs for deterministic writes instead of AI-driven YAML editing
  • State file template — default expertise area changed from domain-specific to "general" for better new-user experience

[1.1.0] - 2026-04-08

Summary

Q2 2026 feature release. 9 improvements across onboarding, content quality, and analytics pipeline.

Added

  • /linkedin:onboarding — multi-step onboarding wizard: profile → setup → first-post as one guided flow
  • /linkedin:carousel — structured multi-slide carousel generator with 5 templates and design specs
  • Voice drift scoring — 6-dimension rubric (sentence structure, word choice, openings, storytelling, tone, formatting) with AUTHENTIC/CAUTION/ALERT/REWRITE verdicts in voice-guardian hook
  • Industry angle variants — 48 concrete variants (6 industries × 8 angles) in thought-leadership-angles reference
  • Multi-URL comparison/linkedin:react now supports 2-3 URL synthesis with contrarian and pattern analysis angles
  • Day-of-week heatmapheatmap CLI command and HeatmapReport type in analytics pipeline
  • Month-over-month reportsreport --month YYYY-MM CLI command with MoM deltas, weekly breakdown, top performers
  • Automated week-rollover — session-start hook now writes posts_this_week: 0 and updates current_week on ISO week change
  • Collected Post Samples — Stop hook passively accumulates published posts in voice-samples file for drift scoring

Changed

  • README Quick Start — replaced 4-step manual flow with single /linkedin:onboarding entry point
  • /linkedin:report — Step 2 now offers report type choice (weekly/monthly/heatmap)
  • /linkedin:post — Step 2 shows industry-specific angles when user-profile has industry set; Step 3 redirects to carousel when appropriate
  • /linkedin router — added onboarding and carousel to menus and direct routing
  • Command count — 25 → 27 (onboarding, carousel)

[1.0.0] - 2026-04-07

Summary

Public release for open-source marketplace. All runtime bugs fixed, documentation aligned, agent model tiering implemented.

Fixed

  • Agent model assignments — all 16 agents corrected from opus to proper tiering (12 Sonnet, 4 Haiku)
  • Queue manager references — 10 stale queue-manager.sh references replaced with queue-manager.mjs Node.js invocations
  • Quick-import references — 2 stale quick-import.sh references updated to .mjs
  • Personalization score import bug — standalone execution block now guarded to prevent stdout contamination on import
  • Regex anchor — invalid \Z JavaScript regex replaced with $ in user-prompt-context.mjs
  • Agent color mismatches — 8 agent frontmatter colors unified with CLAUDE.md documentation
  • Version inconsistency — unified from 3 conflicting versions (0.6.0/1.7.0/2.0.1) to 1.0.0

Added

  • plugin.json — added license, repository, keywords fields for marketplace compliance
  • README — attribution note, "What This Plugin Does Not Cover" section, Node.js 18+ prerequisite, hooks badge
  • CONTRIBUTING.md — replaced GitHub PR template with solo-project boilerplate
  • Quality scorecard — added "Voice Authenticity" criterion (total now /81)
  • Commands/linkedin:react and /linkedin:first-post added to README command tables
  • agents/README.md — updated from 14 to 16 agents, added personalization-scorer and post-feedback-monitor
  • SKILL.md — added 5 missing commands to router command table

Changed

  • CLAUDE.md — compacted from 237 to 90 lines, removed duplicated content
  • All hooks — 100% Node.js (.mjs), no bash dependencies (cross-platform: macOS/Linux/Windows)
  • Error handling — added JSON.parse guards in queue-manager.mjs and analytics storage.ts

Removed

  • Skill version fields — removed non-standard version: from all 6 SKILL.md frontmatter
  • Development artifacts — removed internal evaluation note from collab.md
  • Orphaned files — deleted outdated docs/commands-reference.md
  • BACKLOG.md and DEVELOPMENT-LOG.md — gitignored (internal development files)

[0.6.0] - 2026-02-07

Note

First formal version. Previously unversioned.

What exists today

  • 20 commands covering full content lifecycle
  • 15 specialized agents
  • 8 hooks for workflow automation
  • Analytics system with CSV import
  • Profile/topic-relevance optimization
  • Content matrix system (40+ post ideas from single topic)
  • Personalization engine
  • 20 reference documents for LinkedIn best practices
  • Full content pipeline from ideation to post-publish monitoring