feat(linkedin-studio): M0 — per-user external data dir (v0.5.0)

This commit is contained in:
Kjell Tore Guttormsen 2026-06-18 13:17:35 +02:00
commit 68f7701d74
5 changed files with 41 additions and 6 deletions

View file

@ -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 03): 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:<agent>`, 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"

View file

@ -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

File diff suppressed because one or more lines are too long

View file

@ -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.04.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.04.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).
---

View file

@ -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 1113 (2026-06-18)
### Environment reality vs. plan assumptions