From 68f7701d748483694dff91f2295c44f7cf56896e Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Thu, 18 Jun 2026 13:17:35 +0200 Subject: [PATCH] =?UTF-8?q?feat(linkedin-studio):=20M0=20=E2=80=94=20per-u?= =?UTF-8?q?ser=20external=20data=20dir=20(v0.5.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude-plugin/plugin.json | 2 +- CHANGELOG.md | 17 +++++++++++++++++ CLAUDE.md | 4 ++-- README.md | 6 +++--- docs/m0/log.md | 18 ++++++++++++++++++ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index a0c306d..c24afac 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "linkedin-studio", - "version": "0.4.0", + "version": "0.5.0", "description": "LinkedIn Studio — full-spectrum LinkedIn content engine: feed posts, carousels, video scripts, and long-form newsletter editions, with the 2026 relevance-ranking model baked in. v4.0.0 is an audit-remediation release (Voyage Phase 0–3): every user-facing claim is made honest or removed, all 11 previously-orphaned agents are wired (→ 19 agents), a `/linkedin:firsthour` post-publish command is added (→ 27 commands), the algorithm-signal claims are reconciled to one sourced statement (no unpublishable model name or date), short-form de-AI and video quality gates are added, and the structure lint is rebuilt to guard the real layout plus version/count/stat consistency. Breaking: the newly-wired agents register only on reinstall/reload, and this consolidates the v3.0.0 identity break (slug, agent namespace `linkedin-studio:`, state-file path `~/.claude/linkedin-studio.local.md`). v3.1.0 added the cold adversarial review package (`/linkedin:headless-review` + Step 6.5 + `/linkedin:pivot` + per-artifact personas); the `/linkedin:*` commands are unchanged. v4.1.0 adds a journey layer: two guided front-doors (`/linkedin:create`, `/linkedin:measure`) plus a router re-tiered into five journeys (Start · Create · Engage · Measure · Grow), with the 27 existing commands kept as the execution tier (→ 29 commands; additive, reload registers the two new commands).", "author": { "name": "Kjell Tore Guttormsen" diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a156f9..7acdc32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ 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). +## [0.5.0] - 2026-06-18 + +### Added — M0: per-user external data dir (architecture workstream) + +**User data now lives outside the plugin.** The first of the four `v1.0.0` workstreams (architecture) is complete: every class of user data — voice profile, analytics, drafts, plans, A/B tests, audience insights, frameworks, case studies, network/repurposing trackers, user profile — now resolves under `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/` instead of the plugin tree. **Non-breaking** (minor bump): an automatic, idempotent, atomic migration runs once on session-start (copy → fsync → byte-verify → rename; external is canonical, never clobbered), and the deprecated `ANALYTICS_ROOT` / `STATE_FILE` / `PLUGIN_ROOT` aliases are still honored for one minor version. + +- **Resolver seam per runtime (twins).** `hooks/scripts/data-root.mjs` (`getDataRoot()`, zero-dep `.mjs`) and `scripts/analytics/.../storage.ts` (`getDataRoot()`, TS via `tsx`) resolve the same default + override semantics, guarded by a twin-consistency test — the runtime split (zero-dep hooks vs `tsx` analytics) forbids one shared module. +- **Migration tool.** `hooks/scripts/migrate-data.mjs` is the single source of truth for external destinations (`MOVE_FILES` + `COPY_FILES`); `personalization-score.mjs` mirrors it. Idempotent re-runs report `already-migrated`. +- **D2 — scaffold/instance split.** Every COPY-class data file (`examples/high-engagement-posts`, `audience-insights/{demographics,engagement-patterns}`, `templates/my-post-templates`) ships a read-only `*-template.md` seed in-plugin; the canonical instance lives external with in-plugin scaffold fallback. +- **D3 — path convention.** `references/data-path-convention.md` defines the inline `${LINKEDIN_STUDIO_DATA:-…}/` token (generalizing the proven `${LTL_SERIES_ROOT:-…}` newsletter pattern); ~168 prose references across commands, agents, skills, hook prompts, and references repointed to it. Style-A `${CLAUDE_PLUGIN_ROOT}` is preserved for shipped read-only assets (templates, checklists, references, the analytics CLI). +- **Privacy.** Closed a real voice-sample leak in the in-plugin `examples` scaffold (scrubbed to a generic seed; git-history scrub tracked as a pre-publish follow-up). + +### Changed + +- Version declarations bumped to `0.5.0` across `.claude-plugin/plugin.json`, `README.md` (badge), and `CLAUDE.md` (header). +- **Structure lint** (`scripts/test-runner.sh`) extended 74 → 81 checks: `EXPECT_REFS` 25→26 (+ exactly-+1 delta), a no-bare-in-plugin-data-path guard (R1), a no-`ANALYTICS_ROOT`-pin guard (M3 — caught 5 surviving pins in the analytics agent + skill), an SC2 working-tree dry-run, and an assertion-count anti-erosion floor — each with a non-vacuity self-test. No functionality regressed: hooks 128/0, analytics 119/0 + tsc clean, structure 81/0. + ## [0.4.0] - 2026-05-31 ### Re-baselined diff --git a/CLAUDE.md b/CLAUDE.md index ad5cda9..da53d03 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ -# LinkedIn Studio Plugin (v0.4.0) +# LinkedIn Studio Plugin (v0.5.0) -> **Version re-baseline (2026-05-31).** Previously numbered 1.0.0–4.1.0; those were pre-release iterations. The honest maturity is **v0.4.0** — user data still lives inside the plugin tree (`.gitignore`-defended), no command has yet passed the hardening quality-gate, command testing is incomplete, and there is no GUI. The path to **v1.0.0** is four workstreams: **architecture** (move user data out of the plugin into a per-user data dir — the M0 migration), **hardening** (every command through the quality-gate), **command testing**, and a **GUI**. The development narrative below is preserved as history. +> **Version re-baseline (2026-05-31) · M0 landed (2026-06-18, v0.5.0).** Previously numbered 1.0.0–4.1.0; those were pre-release iterations. The honest maturity is **v0.5.0** — **the architecture workstream (M0) is complete: user data now lives in a per-user data dir (`${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/`) resolved through one seam per runtime, with automatic idempotent migration on session-start** (see `references/data-path-convention.md`). No command has yet passed the hardening quality-gate, command testing is incomplete, and there is no GUI. The remaining path to **v1.0.0** is three workstreams: **hardening** (every command through the quality-gate), **command testing**, and a **GUI**. The development narrative below is preserved as history. Full-spectrum LinkedIn content engine — short-form feed posts, carousels, video scripts, and long-form newsletter editions — with the 2026 relevance-ranking model baked in. **v4.0.0** is an **audit-remediation release (Voyage Phase 0–3)**: a critical self-review found overclaiming (tracking/analytics/review-independence the plugin couldn't deliver), dormant capability (11 agents never invoked by any command), and structural rot (a dead lint, a self-contradicting algorithm claim, an unpublishable model brand/date in user copy). The fix wires **all 11 orphaned agents** (no deletions → 19 agents), adds **`/linkedin:firsthour`** (→ 27 commands) + a short-form de-AI gate + a video quality gate, promotes `post-feedback-monitor` to Opus, makes the newsletter-distribution / profile-SEO / outreach surfaces honest, **reconciles the algorithm signals to one sourced statement** (no model name or date; `references/algorithm-signals-reference.md` is the single source of truth), fixes the analytics fresh-clone crash, closes the voice-profile leak (placeholder + sentinel + gitignore), and rebuilds the structure lint with version/count/stat/model-consistency + render-chain-propagation + `$`-safety guards (each agent's frontmatter model must match every surface declaration; no honesty pattern a command was cleaned of survives in the reference it renders from — S12; no untrusted value reaches a `String.replace` replacement string in `state-updater.mjs`, proven behaviorally + coverage-complete + self-testing — S13). Breaking — reinstall/reload required for the newly-wired agents; consolidates the v3.0.0 identity break (slug, agent namespace, state-file path). 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 hardened the longform gates with the lessons from the second production run (Seres-serien): blocking persona hard-fails, a post-cutoff fact-check mandate, a `voice-scrubber` agent, render+annotate operator gates, and STATE.md-reconciled edition state. v2.3.0 made **visual assets an explicit pipeline phase** — Step 7.5 (visual-assets) between annotation (Step 7) and lock (Step 8): cover (+ optional inline figures) or a carousel deck, generated (default `mcp-image`, external `cover-raw.png` accepted) and operator-gated BEFORE lock so `render/build-linkedin.mjs` picks up `cover.png` at lock without a post-lock re-render. **v2.4.0** makes an **editor's craft gate an explicit pipeline phase** — new **Step 5.5 (editorial-review)** between fact-check (Step 5) and the persona sweep (Step 6): a new **`editorial-reviewer` agent** (Opus) judges **craft** (prosa-håndverk + narrativ-arkitektur), not reader-response, returning ≤10 flags (BLOCK/REWORK/NICE) as direction, **operator-gated via `SendUserFile` BEFORE the persona sweep** so the personas measure resonance instead of stumbling on craft noise. Motivated by Del 4: every persona reported PASS, yet the editor found 8 fresh points on first reading, ~6/8 of them craft/architecture blind spots no agent measured. Mirrors the Maskinrommet writing-contract §C2. Pipeline 14 → 15 phases; agents 15 → 16; additive `editorialReview` state. Doc/orchestration-only for the wiring (the new agent + its fasit fixture + lint test are the only new files); commands unchanged (24). **v3.1.0 (Endring 9)** adds an **adversarial review package** run COLD on a frozen draft — new **Step 6.5 (headless-review)** between the persona sweep (Step 6) and lock, plus a standalone **`/linkedin:headless-review`** command (run in a fresh session for maximum isolation): three new headless archetypes — **`content-reviewer`** (argument integrity), **`language-reviewer`** (Norwegian language), **`fact-reviewer`** (cold re-verification incl. claims a late pivot bolted on) — plus `persona-reviewer` in resonance + conversion modes, all with NO drafting-session context (the independence layer the in-session gates structurally cannot be). v3.1.0 also adds **`/linkedin:pivot`** (re-opens cleared gates after a late change + a >20 %/>2-section pivot-detection gate at lock) and **per-artifact personas** (`articles.NN.personas` — one or more readers configurable per edition, resolved edition-state → series file → plugin library → interactive). Pipeline 15 → 16 phases; agents 16 → 19; commands 24 → 26; additive `personas` / `pivots` / `headlessReview` state. Motivated by Del 4: the in-session editor + persona sweep shared the drafting session's framing-bias, so the version that shipped was never independently re-reviewed. **v4.1.0** adds a **journey layer** over the (unchanged) command surface: two guided front-doors — **`/linkedin:create`** (routes to the right creation command) and **`/linkedin:measure`** (routes to the right analytics command) — plus a router re-tiered into five journeys (Start · Create · Engage · Measure · Grow), with `onboarding`/`strategy` elevated as the Start/Grow front-doors and the 27 atomic commands kept as the execution tier (→ 29 commands). Additive: 14a's cold command-rationalization found **zero redundancy** (no merges/cuts; `docs/remediation/command-rationalization.md` + `journey-layer-design.md`), so the journey layer organizes rather than removes; reload registers the two new commands. diff --git a/README.md b/README.md index 61a8163..892ac2d 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ *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-0.4.0-blue) +![Version](https://img.shields.io/badge/version-0.5.0-blue) ![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple) ![Commands](https://img.shields.io/badge/commands-29-green) ![Agents](https://img.shields.io/badge/agents-19-orange) ![Hooks](https://img.shields.io/badge/hooks-9-red) -![Reference Docs](https://img.shields.io/badge/reference_docs-25-teal) +![Reference Docs](https://img.shields.io/badge/reference_docs-26-teal) ![License](https://img.shields.io/badge/license-MIT-lightgrey) Most experts know they *should* post on LinkedIn — and quietly don't. The blank editor wins. LinkedIn Studio turns that chore into a system: structured workflows that take you from idea to published, in your own voice, calibrated to how LinkedIn's **topic-relevance** ranking model (2026) actually distributes content. Two engines under one surface — a **feed engine** for short-form posts, carousels, and video scripts, and a **long-form engine** that runs newsletter editions and essays through a serious editorial pipeline before they ever lock. @@ -22,7 +22,7 @@ This is not a shortcut. Hand the wheel to the AI and you land where everyone who > New here? Run `/linkedin:onboarding` — it walks you through profile optimization, personalization, and your first published post in one guided flow (~10 minutes). > [!NOTE] -> **Pre-1.0 (v0.4.0).** The earlier 1.0.0–4.1.0 numbering reflected ambition, not maturity. Honest about where it stands today: user data still lives inside the plugin, no command has been through a hardening gate, command testing is incomplete, and there is no GUI yet. See [CHANGELOG.md](CHANGELOG.md). +> **Pre-1.0 (v0.5.0).** The earlier 1.0.0–4.1.0 numbering reflected ambition, not maturity. Honest about where it stands today: the **architecture workstream (M0) is done** — user data now lives in a per-user data dir *outside* the plugin, with automatic migration — but no command has been through a hardening gate, command testing is incomplete, and there is no GUI yet. See [CHANGELOG.md](CHANGELOG.md). --- diff --git a/docs/m0/log.md b/docs/m0/log.md index 9316e2b..51dcf0f 100644 --- a/docs/m0/log.md +++ b/docs/m0/log.md @@ -89,6 +89,24 @@ after the default flipped external (the exact M3 failure). Dropped all 5 (surgic only the `ANALYTICS_ROOT=… ` prefix, kept the `node --import tsx` form — no CLI-style change), matching how Step 11 left the commands. Lint now **81/0**. +### Step 18 — release 0.4.0 → 0.5.0 (minor, non-breaking) + +Bumped `.claude-plugin/plugin.json` + the three lint-grepped literals (README +`version-0.5.0-blue` badge, CLAUDE.md `(v0.5.0)` header, CHANGELOG `## [0.5.0]`). +Also synced the README `reference_docs-25→26` badge (not lint-checked, but stale after +the convention doc) and refreshed the now-false "user data still lives inside the plugin" +prose in README + CLAUDE.md to "M0 done — data external." Version-consistency lint green; +the only remaining `0.4.0` refs are CHANGELOG history + the `docs/m0/` planning docs that +describe the `0.4.0 → 0.5.0` transition itself (correct, not stale declarations). + +**Plan deviation — root marketplace docs NOT touched (scope).** Plan Step 18 listed +`/Users/ktg/.claude/plugins/marketplaces/ktg-plugin-marketplace/{README,CLAUDE}.md` as +"root docs." Skipped: that path is the **installed** marketplace artifact, **outside this +polyrepo**, and STATE.md scope is "KUN denne pluginnen" (+ global "don't write in other +repos"). The binding gate (the lint) checks only this plugin's four declarations, all +green. **Follow-up (separate catalog repo task):** reflect linkedin-studio v0.5.0 in the +marketplace catalog README if/when desired — operator's call, not this plugin's M0. + ## Session 3 — Steps 11–13 (2026-06-18) ### Environment reality vs. plan assumptions