feat(linkedin-thought-leadership): v1.0.0 — initial open-source import

Build LinkedIn thought leadership with algorithmic understanding,
strategic consistency, and AI-assisted content creation. Updated for
the January 2026 360Brew algorithm change.

16 agents, 25 commands, 6 skills, 9 hooks, 24 reference docs.

Personal data sanitized: voice samples generalized to template,
high-engagement posts cleared, region-specific references replaced
with placeholders.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-07 22:09:03 +02:00
commit 39f8b275a6
143 changed files with 32662 additions and 0 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: The post topic and hook should be logged to the state file when the session ends (handled by Stop hook).
**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,73 @@
Before ending this LinkedIn content session, do two things:
**1. Update State File**
If a post was created or finalized in this session, update `~/.claude/linkedin-thought-leadership.local.md`:
- Set `last_post_date` to today (YYYY-MM-DD format)
- Set `last_post_topic` to the main topic (use the matching `expertise_areas` value when possible for consistent pillar tracking)
- If `first_post_date` is null and a post was created, set `first_post_date` to today (YYYY-MM-DD). This is set ONCE and never changed after that.
- Check if ISO week has changed — if so, reset `posts_this_week` to 0 and update `current_week`
- Increment `posts_this_week`
- Update streak: increment `current_streak` if posting on consecutive days (gap <= 1 day), reset to 1 if gap > 2 days
- Update `longest_streak` if current exceeds it
- Add entry to '## Recent Posts' section: [YYYY-MM-DD] "Hook text..." (char count) - topic_area (use expertise_area name for consistent pillar tracking)
- 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)
- If the user mentioned or updated their follower count during this session:
- Update `follower_count` to the new value
- If the month changed since last monthly_growth entry, append: {month: "YYYY-MM", count: X, delta: X}
- Recalculate `growth_rate_needed`: (follower_target - follower_count) / months_remaining
- Recalculate `projected_10k_date` from average of last 3 monthly deltas
- Add entry to '## Milestone Log': [YYYY-MM] count (+delta)
**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:publish to update the 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 Extraction** (if a post was created)
If a LinkedIn post was created or finalized in this session, consider extracting the hook line as a voice sample:
- Read the hook line from the post that was just created
- Check if `assets/voice-samples/authentic-voice-samples.md` exists
- If it does, suggest appending a new entry to the "## Update Log" section at the bottom:
```
- [YYYY-MM-DD]: "[Hook text]" — [post type] (extracted from session post)
```
- **Ask the user for approval before writing.** Say: "Would you like me to save this hook as a voice sample for future reference?"
- Only write if the user approves
- This passively grows the voice profile over time, improving personalization score
**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-thought-leadership.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,26 @@
VOICE GUARDIAN — AI AUTHENTICITY CHECK: If the file being written/edited is LinkedIn content (post draft, article, or content file — NOT config, state, scripts, docs), check for AI-sounding patterns:
**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
**Authenticity Score:**
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].'
**Voice Matching:**
If voice samples exist at `${CLAUDE_PLUGIN_ROOT}/assets/voice-samples/`, compare the writing style against the user's authentic voice patterns. Flag deviations.
**Humanization Tips:**
- 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.