refactor(linkedin)!: rename plugin linkedin-thought-leadership → linkedin-studio (v3.0.0)

BREAKING CHANGE: the marketplace slug, the agent namespace
(linkedin-studio:<agent>), and the runtime state-file path
(~/.claude/linkedin-studio.local.md) all change. Reinstall required;
existing state migrated in place (post metrics, streak, history preserved).
The /linkedin:* commands are unchanged — the command namespace is set
per-command in frontmatter and was always independent of the plugin slug.
Functionality is byte-identical to v2.4.0; this release is pure identity.

- dir + manifests: plugins/linkedin-studio + plugin.json + root marketplace.json
- agent namespace updated in commands/newsletter.md (only functional invoker)
- state path updated in 4 hook scripts + topic-rotation prompt + state template
- catch-all skill dir renamed skills/linkedin-studio (5 functional skills unchanged)
- docs + version bump to 3.0.0 across README badge, CHANGELOG, root README/CLAUDE.md
- historical records (CHANGELOG past entries, docs/ build artifacts,
  config-audit v5.0.0 snapshots) intentionally retain the old slug

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-29 11:32:02 +02:00
commit b6bb61246b
196 changed files with 164 additions and 138 deletions

View file

@ -0,0 +1,21 @@
LINKEDIN CONTENT QUALITY GATE: If the file being written/edited is LinkedIn content (a post draft, article, or content file — NOT config files, state files, scripts, or documentation), verify these requirements before proceeding:
**Hook Check:**
- The first line (hook) MUST be 110-140 characters. Count precisely.
- If over 140: the hook gets cut off on mobile. Shorten it.
- If under 110: wasting prime real estate. Expand it.
**Link Check:**
- NO external links (http/https URLs) in the post body. LinkedIn suppresses reach by 40-50% for posts with links.
- If a link is needed, instruct the user to put it in the FIRST COMMENT after posting.
**Tone Check:**
- Scan for corporate buzzwords: 'leverage', 'synergy', 'paradigm shift', 'thought leader', 'disruptive', 'value proposition', 'ecosystem', 'holistic approach', 'actionable insights', 'best practices'.
- If 2+ are found, flag: 'This reads corporate. LinkedIn rewards authentic, conversational tone. Replace buzzwords with plain language.'
**Length Check:**
- Standard posts: 1,200-1,800 characters optimal.
- Quick posts: 150-500 characters.
- If outside range, flag with specific character count.
**Skip this check** if the file is a config file, state file (.local.md), script, hook, JSON, or documentation file. Only apply to LinkedIn content.

View file

@ -0,0 +1,32 @@
LINKEDIN POST-CREATION AUTOMATION: If a LinkedIn content file was just written (post draft, article, or content — NOT config, state, scripts, or docs), perform these post-processing steps:
**1. Generate Alternative Hooks**
Create 3 alternative hooks for the content just written. Present them as:
```
Alternative hooks:
1. [hook 1] (X chars)
2. [hook 2] (X chars)
3. [hook 3] (X chars)
```
**2. Suggest Optimal Posting Time**
Based on the day of the week, suggest the next optimal posting window:
- Tuesday-Thursday: 8-9 AM or 12-1 PM CET (best)
- Monday/Friday: 9-10 AM CET (good)
- Weekend: 10-11 AM CET (lower reach but less competition)
**3. 5x5x5 Engagement Reminder**
Remind: 'Before posting, spend 15-20 minutes on 5x5x5 pre-engagement: find 5 people with overlapping audiences, comment thoughtfully on their recent posts.'
**4. Content Logging**
Note: State tracking is handled deterministically by `state-updater.mjs` via the Stop hook. Do not manually edit the state file YAML frontmatter.
**5. Voice Sample Suggestion**
After generating alternative hooks and posting time, add a brief note:
"Tip: Your post hook could become a voice sample. When the session ends, the Stop hook will ask if you'd like to save it to your voice profile."
This creates awareness of the voice extraction feature without interrupting the post-creation flow.
**Skip this** if the file written is a config file, state file (.local.md), script, hook, JSON, plan file, or documentation.

View file

@ -0,0 +1,85 @@
Before ending this LinkedIn content session, do two things:
**1. Update State File**
If a post was created or finalized in this session, use the state-updater script:
```bash
node --input-type=module -e "
import { writeState, updatePostTracking } from '${CLAUDE_PLUGIN_ROOT}/hooks/scripts/state-updater.mjs';
writeState(content => updatePostTracking(content, {
postDate: 'YYYY-MM-DD',
postTopic: 'topic_area',
hookText: 'First 60 chars of hook...',
charCount: NNNN,
format: 'post'
}));
"
```
Replace the placeholder values with actual post data from this session.
If the user mentioned or updated their follower count during this session:
```bash
node --input-type=module -e "
import { writeState, updateFollowerCount } from '${CLAUDE_PLUGIN_ROOT}/hooks/scripts/state-updater.mjs';
writeState(content => updateFollowerCount(content, {
count: NNNN,
month: 'YYYY-MM'
}));
"
```
- Clear `next_planned_topic` if it was used, or set it to the next suggested topic
- If analytics data was imported in this session, set `last_import_date` to today (YYYY-MM-DD) and `last_import_week` to current ISO week (YYYY-WXX)
**2. Pre-Publish Reminders** (only if a post was created)
- **Quality Check**: Has content been reviewed against quality scorecard? Hook 110-140 chars, 1,200-1,800 chars total, authentic tone, no external links.
- **5x5x5 Engagement**: Before posting, complete 15-20 min pre-posting engagement — 5 people with overlapping audiences, find their recent posts, write 5 thoughtful comments (15+ words each).
- **First-Hour Plan**: Respond within 5 minutes to first comments. Add value in responses. Target 15+ engagements in first hour.
- **Posting Time**: Post when target audience is most active.
**3. Queue Status Check**
If posts were added to the queue during this session (`assets/drafts/queue.json` was modified):
- Confirm how many posts were queued and their scheduled dates
- Remind: "View your full schedule with /linkedin:calendar"
If a scheduled post was published during this session:
- Verify it was marked as published in queue.json (status = "published")
- If not, remind: "Run /linkedin:calendar to mark the post as published and update queue status"
Provide reminders naturally based on what was done in the session. If no LinkedIn content was created, skip the reminders and just ensure state is consistent.
**4. Voice Sample Collection** (if a post was created)
If a LinkedIn post was created or finalized in this session, save the full post text as a voice sample:
- Read the full post text from the draft that was just created
- Check if `assets/voice-samples/authentic-voice-samples.md` exists
- Append the full post to the `## Collected Post Samples` section:
```
### [YYYY-MM-DD] — [post type] ([char count] chars)
[Full post text exactly as written]
```
- **Ask the user for confirmation** before writing: "I'll save this post as a voice sample for drift detection. OK?"
- This builds the voice sample library that enables automatic drift scoring (needs 5+ samples for reliable scoring)
- The more samples collected, the more accurate the voice-trainer's drift detection becomes
**5. Content History Log** (if a post was created)
If a LinkedIn post was created or finalized, append an entry to the content history log:
- If `assets/analytics/content-history.md` does not exist, initialize it from `config/content-history.template.md`
- Append a new row to the "## Content Log" table:
```
| YYYY-MM-DD | "Hook text..." | topic_area | format | word_count | char_count | source |
```
Where:
- `date`: Today's date
- `hook`: First 60 characters of the hook line
- `topic`: Matching expertise_area value (for pillar tracking)
- `format`: post/quick/react/video/pipeline
- `word_count`: Word count of the full post
- `char_count`: Character count of the full post
- `source`: original/url/curated (where the idea came from)
- This is append-only — never edit or delete existing entries
- This log enables `/linkedin:report` and `analytics-interpreter` to track content production over time without requiring LinkedIn CSV imports

View file

@ -0,0 +1,37 @@
LINKEDIN TOPIC ROTATION GATE: If the file being written/edited is LinkedIn content (a post draft, article, or content file — NOT config files, state files, scripts, documentation, JSON, or plan files), check topic diversity before proceeding.
**Step 1: Read State**
Read `~/.claude/linkedin-studio.local.md` and extract:
- `last_post_topic` — the pillar of the most recent post
- `expertise_areas` — the user's 5 content pillars
- `## Recent Posts` section — post history with topic_area tags
**Step 2: Identify Current Pillar**
Determine which expertise_area the current post best matches. Use semantic matching — the post doesn't need to use the exact pillar name, but its core topic should clearly map to one of the 5 expertise_areas.
**Step 3: Run Checks**
If fewer than 3 posts exist in the last 14 days, skip all checks (insufficient data for meaningful rotation analysis).
**Check 1 — Back-to-back repetition:**
If the current post's pillar matches `last_post_topic`, flag:
> "TOPIC ROTATION WARNING: This post covers the same pillar ([pillar]) as your last post. Consider switching to an underrepresented pillar for better audience diversity and algorithmic reach."
**Check 2 — 14-day balance:**
Count posts per pillar from the `## Recent Posts` section (last 14 days only). If any single pillar accounts for more than 50% of posts in that window, flag:
> "PILLAR BALANCE WARNING: [pillar] has [X] of [Y] posts ([Z]%) in the last 14 days. LinkedIn's algorithm rewards topic consistency across your niche, but over-concentration on one pillar signals narrowing expertise."
**Check 3 — Off-topic:**
If the current post does not match ANY of the 5 expertise_areas, flag:
> "OFF-TOPIC WARNING: This post doesn't align with any of your 5 expertise areas. Off-pillar posts weaken your 360Brew topical authority signal. Consider reframing to connect with [closest pillar]."
**Step 4: Suggest Alternatives**
If any check flagged, suggest 2-3 underrepresented pillars with context:
> "Underrepresented pillars to consider:
> - [Pillar A] — last posted [X] days ago ([N] posts in 14 days)
> - [Pillar B] — last posted [Y] days ago ([M] posts in 14 days)
> - [Pillar C] — last posted [Z] days ago ([P] posts in 14 days)"
**This is a WARN-ONLY hook.** Do not block content creation. Present the warning and let the user decide whether to adjust.
**Skip this check** if the file is a config file, state file (.local.md), script, hook, JSON, plan file, documentation, or any non-content file. Only apply to LinkedIn post drafts and articles.

View file

@ -0,0 +1,56 @@
VOICE GUARDIAN — DRIFT SCORING & AI AUTHENTICITY CHECK: If the file being written/edited is LinkedIn content (post draft, article, or content file — NOT config, state, scripts, docs), perform both AI detection and voice drift scoring:
## 1. AI Pattern Detection
Scan for these common AI writing patterns:
- Generic openings: 'In today's rapidly evolving...', 'As we navigate...', 'In the ever-changing landscape...'
- Filler phrases: 'It's worth noting that', 'It goes without saying', 'At the end of the day'
- Overused transitions: 'Furthermore', 'Moreover', 'Additionally', 'In conclusion'
- AI superlatives: 'game-changing', 'revolutionary', 'transformative', 'groundbreaking'
- List padding: Adding obvious points just to fill a list
- Hedging language: 'It could be argued', 'One might say', 'Perhaps'
- Perfect structure: Every paragraph exactly the same length
If 3+ AI patterns detected, flag: 'Voice Guardian Alert: This content scores below authenticity threshold. AI patterns found: [list specific patterns]. Suggested fixes: [specific rewrites using natural language].'
## 2. Six-Dimension Voice Drift Scoring
Read the voice profile and collected post samples from `${CLAUDE_PLUGIN_ROOT}/assets/voice-samples/authentic-voice-samples.md`.
Score the draft against these 6 dimensions (0 = perfect match, 1 = minor drift per dimension):
| Dimension | What to Compare |
|-----------|----------------|
| **Sentence structure** | Average length, complexity, use of fragments vs. compound sentences |
| **Word choice** | Vocabulary level, preferred/avoided words from voice profile |
| **Opening patterns** | Hook style — does it match the user's signature openers? |
| **Storytelling** | Anecdote usage, narrative arc, concrete vs. abstract |
| **Tone markers** | Humor, directness, formality level, empathy signals |
| **Formatting** | Paragraph length, whitespace, emoji usage, punctuation habits |
**Sum the 6 scores (0-6 total) and output a verdict:**
| Score | Verdict | Action |
|-------|---------|--------|
| 0-1 | AUTHENTIC | No changes needed |
| 2-3 | CAUTION | Flag specific dimensions that drifted, suggest fixes |
| 4-5 | ALERT | Significant drift — list all deviating dimensions with rewrites |
| 6 | REWRITE | Content doesn't sound like the user — recommend starting over |
**Confidence gate:** If `## Collected Post Samples` has fewer than 5 posts, perform ONLY the AI Pattern Detection (section 1). Skip the Six-Dimension Voice Drift Scoring entirely — there is insufficient data for meaningful drift analysis. Do NOT output "LOW CONFIDENCE" messages. Instead, silently skip drift scoring and only flag if 3+ AI patterns are detected.
**Output format (always include at end of system message):**
```
Voice Drift: [VERDICT] ([score]/6) [confidence: HIGH/LOW]
[If CAUTION+: list dimensions that scored 1 with brief fix suggestion]
```
## 3. Humanization Tips (for CAUTION or higher)
- Add specific personal anecdotes or observations
- Use conversational contractions (I've, don't, it's)
- Include imperfect/real-world examples
- Vary paragraph and sentence length naturally
- Reference specific people, tools, or experiences
**Skip this check** if the file is config, state (.local.md), script, hook, JSON, or documentation.