ktg-plugin-marketplace/plugins/linkedin-studio/CLAUDE.md
Kjell Tore Guttormsen 55c94ee964 feat(linkedin-studio): S16 — optional manual saves in analytics + close deferred onboarding Write MAJOR
Lifts the original v4.0.0 Non-Goal: an optional, manually-entered `saves`
metric through the analytics layer, built location-agnostic (option c) so
UI-brief §9b/M0 relocates the data dir in one place later.

- types: PostMetrics.saves? + Weekly/Monthly summary.totalSaves? (optional);
  new RankableMetric type for the always-numeric index-access whitelist
- parser: dedicated parseOptionalCount() — blank/non-numeric/negative -> undefined
  ("unknown != 0"), genuine 0 kept; saves NOT folded into engagementRate
- reports: totalSaves set only when >=1 post carries saves (backward-compat)
- cli: saves surfaced in import summary + weekly/monthly totals + per-post
- S16-pre: onboarding.md allowed-tools gains Write (closes S15-deferred MAJOR)
- docs (three-doc rule): plugin README boundary + analytics README + root README
  + plugin CLAUDE.md + CHANGELOG; dwell stays explicitly unmeasurable

Independent /trekreview: brief-conformance 0 findings; code-correctness 2 MAJOR
(own lockstep misses) FIXED in-session (parseOptionalCount + edge tests). Gate:
tsc clean, analytics 116/116, lint 74/0/0, hooks 98/98. Within-v4.1.0 refinement
(no surface/count/version change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 22:23:12 +02:00

18 KiB
Raw Blame History

LinkedIn Studio Plugin (v4.1.0)

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 03): 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.

Architecture

  • State file: ~/.claude/linkedin-studio.local.md (YAML frontmatter, auto-initialized from config/state-file.template.md)
  • State updater: hooks/scripts/state-updater.mjs — deterministic state mutations (post tracking, streak, content history pruning). Pure functions, tested, no AI involvement
  • Clipboard helper: hooks/scripts/clipboard-helper.mjs — cross-platform clipboard integration (macOS pbcopy, Linux xclip/xsel, WSL clip.exe). All content commands auto-copy to clipboard
  • iCal generator: hooks/scripts/ical-generator.mjs — RFC 5545 calendar file generation for batch scheduling. Standalone CLI + importable module
  • Post queue: assets/drafts/queue.json (managed by hooks/scripts/queue-manager.mjs)
  • Analytics CLI: scripts/analytics/ (TypeScript, requires tsx and npm install)
  • Analytics data: assets/analytics/ (gitignored)
  • Analytics metrics (S16): the parsed CSV columns plus an optional, manually-entered saves count. Saves are count-only in native LinkedIn post analytics (~Sept 2025), absent from the CSV export, and have no self-serve API — so the ingest path is the user adding a Saves column with the number they read off LinkedIn. parseOptionalCount() parses it when present: blank / non-numeric / negative → undefined (unknown, never 0), a genuine 0 is kept, and saves is not folded into engagementRate (kept comparable to older imports). Surfaced per-post + as totalSaves in the weekly/monthly reports; never auto-tracked.
  • Unmeasured by design: dwell time stays explicitly unmeasurable — internal to LinkedIn for organic posts, no exportable count, no API; no dwell field or surface exists. The S16 analytics extension routes all I/O through the existing getAnalyticsRoot() seam, so the planned per-user data-dir migration (UI-brief §9b/M0) relocates the root in one place without reworking the schema.

Hooks

9 hooks across 7 events. All Node.js (.mjs). PreToolUse/PostToolUse hooks use parameterized content-gatekeeper.mjs with isLinkedInContent() check.

Event Purpose
SessionStart Load state, REMEMBER.md, milestone tracker
PreToolUse (Write|Edit) Content quality gate, voice guardian, topic rotation gate
Stop State update, pre-publish reminders, content history
UserPromptSubmit LinkedIn context enrichment (three-tier matching)
PostToolUse (Write) Post-creation automation (5x5x5, posting time)
PreCompact Preserve LinkedIn context during compaction
Notification Posting reminders (rate-limited 30min)

Session markers: /tmp/linkedin-hooks/session-active (Stop hook gating, 12h staleness). Shared modules: linkedin-content-filter.mjs, queue-manager.mjs, personalization-score.mjs, state-updater.mjs, clipboard-helper.mjs.

State updates: Post tracking, streak management, and content history are handled deterministically by state-updater.mjs (called from Stop hook and commands). Content history entries older than 90 days are auto-pruned at session start.

Hook editing: Edit hooks/hooks.template.json + hooks/prompts/*.md, then run python3 hooks/scripts/compile-hooks.py. Do not edit hooks.json directly. Prompts are loaded at runtime by gatekeeper scripts; the compile step is only needed when adding type: prompt hooks.

Commands (29)

All content commands (post, quick, react, pipeline, first-post, video, multiplatform, carousel, newsletter) auto-copy output to clipboard via clipboard-helper.mjs. Interactive steps are minimized — angle, format, and post type are inferred from context, with max 2 questions per post. v2.0.0 net change: 5 commands removed (templates, publish, authority, collab, speaking — absorbed into quick, calendar, strategy, outreach respectively) + 2 commands added (newsletter, outreach) = 27 → 24. v3.1.0 adds 2 longform companions (headless-review, pivot) = 24 → 26. Remediation Step 16 adds firsthour (wiring orphan agent #11 engagement-coach) = 26 → 27. v4.1.0 (S14) adds the two journey front-doors (create, measure) = 27 → 29. The surface is organized into five journeys (Start · Create · Engage · Measure · Grow); create/measure are new guided front-doors, onboarding/strategy are elevated as the Start/Grow front-doors, and the 27 atomic commands remain the execution tier (14a found zero redundancy → no merges/cuts).

Command Purpose
/linkedin Router — status line + five-journey command menu
/linkedin:create (v4.1) Create front-door — guided "what to make?" → routes to the creation command that owns the format (post/quick/react/carousel/video/multiplatform/batch/newsletter); delegates only
/linkedin:measure (v4.1) Measure front-door — guided "how am I doing?" → routes to the analytics command (import/report/analyze/audit/ab-test); delegates only
/linkedin:onboarding Multi-step onboarding wizard (profile → setup → first-post); Start-journey front-door (v4.1)
/linkedin:first-post First-post accelerator (10 min)
/linkedin:setup Guided personalization setup
/linkedin:react URL-to-post pipeline
/linkedin:post Full post creation (10-15 min)
/linkedin:quick 5-minute quick post (3-line formula) + 8 post-type templates
/linkedin:pipeline Full end-to-end content pipeline
/linkedin:newsletter Long-form orchestrator: newsletter edition / essay / series article — multi-session 16-phase pipeline with skeleton + spine-prose gates BEFORE prose (v2.1), editorial-review craft gate BEFORE the persona sweep (Step 5.5, v2.4), fact-check + persona-sweep BEFORE lock, headless adversarial review BEFORE lock (Step 6.5, v3.1), and visual-assets gate BEFORE lock (Step 7.5, v2.3)
/linkedin:headless-review (v3.1) Cold adversarial review package — run the 3 headless archetypes (content-reviewer, language-reviewer, fact-reviewer) + persona-reviewer (resonance/conversion) on a FROZEN draft with no drafting-session context; consolidated, operator-gated report. Step 6.5's standalone surface (run in a fresh session for maximum isolation)
/linkedin:pivot (v3.1) Re-open a long-form edition after a late substantive change so cleared gates (fact-check → editorial → persona → headless) re-run before lock; logs pivots[], resets currentPhase, un-locks if needed (pivot heuristic: >20 % word-count change or >2 new sections)
/linkedin:batch Create a full week of content
/linkedin:calendar View/manage post scheduling queue + publish action (mark scheduled posts as published)
/linkedin:firsthour Post-publish first-hour / reply-loop sprint — delegates to engagement-coach for a timestamped target list + draft comments + timeline, persists the plan to state (recordFirstHourPlan), hands off to post-feedback-monitor
/linkedin:carousel Structured multi-slide carousel generator
/linkedin:video Video script generator (30s-2min)
/linkedin:multiplatform Adapt content for other platforms (short-form/cross-format; long-form → /linkedin:newsletter)
/linkedin:analyze Content/performance analysis
/linkedin:audit Periodic content strategy audit
/linkedin:import Import CSV export → structured JSON (delegates analysis to /linkedin:report)
/linkedin:report Generate weekly performance report
/linkedin:ab-test Design and manage A/B content tests
/linkedin:strategy Growth strategy + authority building (phase guidance, trajectory, signature content compounding)
/linkedin:competitive Competitive analysis of niche
/linkedin:monetize Monetization strategy and funnels (unlocks at ~1K followers)
/linkedin:outreach Outreach orchestrator — collaborations + speaking opportunities (unlocks at ~1K followers)
/linkedin:profile profile/topic-relevance optimization

Agents (19)

Agent Model Color Responsibility
content-optimizer Sonnet Blue Optimize existing posts
strategy-advisor Sonnet Green Growth recommendations
analytics-interpreter Sonnet Yellow Audience pattern analysis + weekly/monthly performance reports (interpret/report modes)
engagement-coach Sonnet Magenta 5x5x5 + first-hour tactics + CEA commenting + target selection
content-planner Sonnet Cyan Content audit + weekly/monthly plans
network-builder Sonnet Teal Strategic networking + outreach
content-repurposer Sonnet Purple Format conversion + evergreen refresh
trend-spotter Sonnet White Trending topics + opportunity scores
voice-trainer Sonnet Pink Voice profile building + drift detection
differentiation-checker Sonnet Gray Originality scoring + commodity detection
post-feedback-monitor Opus Lime Post-publish 48h monitoring
video-scripter Sonnet Violet Video script creation with pacing
fact-checker Opus Brown Factual-claim verification against primary sources, post-cutoff web-search mandate (longform)
editorial-reviewer Opus Orange Editor's craft gate (v2.4, Step 5.5, before persona sweep): prosa-håndverk + narrativ-arkitektur, ≤10 flags BLOCK/REWORK/NICE as direction, operator-gated via SendUserFile; mirrors Maskinrommet §C2 (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-reviewer Opus Maroon (v3.1, Step 6.5 — cold/headless) Argument-integrity review on a frozen draft: C1 logical holes · C2 unsupported assumptions · C3 argument contradiction · C4 missing concretization · C5 unanswered objection. ≤8 flags BLOCK/REWORK/NICE as direction; refuses drafting-session framing as context pollution (longform)
language-reviewer Opus Navy (v3.1, Step 6.5 — cold/headless) Norwegian-language review on a frozen draft: L1 verbatim repetition · L2 anglicisms · L3 stiff bureaucratic register · L4 language-level self-contradiction · L5 clang/rhythm. ≤10 flags BLOCK/REWORK/NICE; deliberate cold re-take of editorial's prose axis (longform)
fact-reviewer Opus Gold (v3.1, Step 6.5 — cold/headless) Cold re-verification on the frozen/pivoted version (web search): F1 verifiable claims · F2 quote precision · F3 number attribution · F4 source quality. 🔴/🟡/🟢 + pivot-risk subsection; deliberate redundancy with fact-checker to catch a pivot premise that arrived after Step 5 (longform)

Rule: Always read assets/voice-samples/ before generating content.

Invocation form: Commands invoke plugin agents by their namespaced type — subagent_type: linkedin-studio:<name> — never the bare <name> (a bare type does not resolve and the Task call fails).

Reload requirement: Adding a NEW agent file under agents/ registers it only after a Claude Code session reload — the plugin agent set is built at session start, so a freshly-added agent (e.g. fact-checker, persona-reviewer when first added) is not invokable until the session reloads. After adding an agent, reload before invoking it.

Content Quality Rules

  1. Hook: 110-140 characters (mobile cutoff)
  2. Post length: 1,200-1,800 chars (standard), 150-500 chars (quick)
  3. No external links in post body (correlate with lower reach; see references/algorithm-signals-reference.md)
  4. No corporate buzzwords: leverage, synergy, paradigm shift, thought leader, disruptive, value proposition, ecosystem, holistic approach
  5. Topic must align with user's 5 core expertise areas (topic-relevance signal)
  6. Topic rotation: no back-to-back same pillar, no pillar >50% in 14 days (warn-only)
  7. Progressive onboarding: personalization score hidden until 3+ posts; voice guardian suppressed until 5+ voice samples