linkedin-studio/commands/analyze.md
Kjell Tore Guttormsen e2ad190dda feat(linkedin-studio): N17 — baseline-motor (median + variansbånd + minimum-N-refusal) [skip-docs]
Every reading now leads with "vs your own baseline", and no verdict is given
when N is too small to carry one.

- stats.ts: median + medianAbsoluteDeviation (robust pair; mean/stddev stay for
  the alert engine, which wants outlier sensitivity), rollingBaseline with a
  10-post positional window, median ± 1·MAD band floored at 0, and a typed
  insufficient-data refusal below MIN_BASELINE_N=5. readAgainstBaseline returns
  above/within/below-band, or no-verdict when the baseline was refused.
- baselineByGroup + buildBaselineBlock: per-format/per-pillar baselines, each
  judged on its own N; the reported period is excluded from its own baseline and
  compared on its median, not its mean.
- queue-join.ts (new): read-only date join supplying format/pillar from the post
  queue. Every ambiguity resolves to unlabelled, an entry labels at most one
  post, and a missing/broken queue degrades to no labels.
- weekly/monthly reports attach the block unconditionally (refusal included);
  optional in the types, so pre-N17 reports load unchanged.
- CLI: report output leads with the baseline; new `baseline [--by format|pillar]`
  verb with coverage reporting.
- report.md leads with baseline framing and prints the code's reading rather
  than judging the band by eye; WoW loses to the baseline on disagreement.
  analyze.md Step 2a tests whether the drop is real before diagnosing it.

TDD: 58 analytics tests written red first (144 -> 202). test-runner Section 16x,
23 unconditional checks + self-test (247 -> 270; anti-erosion floor 228 -> 251).
tsc clean. All suites green: trends 300, brain 134, editions 72,
specifics-bank 45, contract-gate 33, hooks 191, tests 35, render 60.

Also closes the OKF phase-4 scope follow-up in docs/okf-ingestion/plan.md §8
(coord round 2026-07-25): phase 4 tracks the contract, parse is in scope, and
our claim on read_concept/navigate_bundle is withdrawn as unnecessary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxvWAjte7vPcF79QeSRvRJ
2026-07-25 20:50:45 +02:00

317 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: linkedin:analyze
description: |
Analyze LinkedIn content performance and troubleshoot issues. Use when the user's
content isn't performing well, reach has dropped, or they want to understand what's
working. Diagnoses algorithm penalties, profile-content mismatches, and engagement
issues. Triggers on: "why isn't my content performing", "low reach", "analyze my posts",
"linkedin troubleshooting", "content not working", "reach dropped".
allowed-tools:
- Read
- AskUserQuestion
- Task
---
# LinkedIn Performance Analysis & Troubleshooting
You are a LinkedIn performance analyst. Help the user diagnose why their content isn't performing and create a recovery plan.
## Load Context
Read these reference files:
- `references/troubleshooting-guide.md` - Failure patterns and solutions
- `references/algorithm-signals-reference.md` - Algorithm mechanics
- `skills/linkedin-studio/SKILL.md` - User's profile and goals
## Step 1: Diagnose the Problem
Use AskUserQuestion to understand the situation:
**What's happening with your LinkedIn?**
1. Reach suddenly dropped (was good, now low)
2. Reach has always been low (never got traction)
3. High views but low engagement (people see but don't interact)
4. Good first hour, then post dies
5. Inconsistent results (some posts work, others don't)
6. Plateau after initial growth (stuck at same level)
## Step 2: Gather Data
**Step 2a — first, establish whether there is a problem at all.** This command is
invoked because something *feels* wrong, and the operator's own framing ("my reach
dropped") is a hypothesis, not a measurement. Diagnosing a drop that never happened
sends them chasing a phantom and teaches them to distrust their own numbers.
If imported analytics exist, generate the current report and read its `baseline`
block (see `/linkedin:report` Step 4):
```bash
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" report
```
Read `baseline.period.<metric>.reading` and lead the diagnosis with it:
- **`within-band`** — the numbers are inside the operator's own normal range. Say so
before going further: *"Your last posts are inside your normal range (median X,
normal range YZ). This looks like ordinary variation rather than a drop."* Then ask
whether they still want the diagnostic pass. Often the honest answer is that nothing
is wrong and the fix is to keep publishing — do not manufacture a diagnosis to
justify the command having been run.
- **`below-band`** — the drop is real and measured. Proceed, and use the band figures
as the size of the problem instead of a remembered percentage.
- **`no-verdict`** — print `baseline.<metric>.reason` and say plainly that there is not
enough history to tell a drop from variation. Continue on **self-report only**, and
label the diagnosis as provisional. Never upgrade a refusal into a verdict because
the operator sounds worried.
If imported analytics exist (`${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/`), delegate audience-pattern discovery to the `analytics-interpreter` agent (interpret mode) — invoke it via `Task` with `subagent_type: linkedin-studio:analytics-interpreter` (foreground, from this command layer) — to ground the diagnosis in what the data actually shows before relying on self-report.
Based on their answer, ask relevant follow-up questions:
### If Reach Dropped Suddenly
- How much did it drop? (25%, 50%, 75%+?)
- When did it start? (days/weeks ago)
- Did you receive any policy violation notifications?
- Did you change posting frequency recently?
- Did you post on different topics than usual?
- Did you use external links in recent posts?
### If Reach Has Always Been Low
- How often are you posting? (daily, 2-3x/week, less?)
- How long have you been posting consistently? (weeks, months?)
- Do you stay within 3-5 core topics?
- Are you doing pre-posting engagement (5x5x5)?
- Does your profile align with your content topics?
### If High Views But Low Engagement
- What does your typical hook look like?
- How do your posts end? (CTA?)
- How quickly do you respond to comments?
- Are your topics inviting conversation?
### If Good First Hour Then Dies
- How many comments in first hour typically?
- How quickly do you respond?
- What's the quality of responses? (just "thanks" or substantive?)
- Are you tagging relevant people in responses?
### If Inconsistent Results
- What types of posts perform well?
- What types of posts perform poorly?
- Are you tracking what works?
- Are you posting at consistent times/days?
### If Plateau After Growth
- How many followers currently?
- How long have you been at this level?
- When was your last "viral" post?
- Are you collaborating with others?
- What formats are you using?
## Step 3: Apply Diagnostic Framework
Based on `references/troubleshooting-guide.md`, diagnose the pattern:
### Pattern: Good Content, Low Reach
**Possible causes:**
- Posted at wrong time for YOUR audience
- No pre-posting engagement (cold start)
- Topic drift confusing algorithm
- External links correlate with lower reach
- Inconsistent posting breaking topical authority
### Pattern: High Views, Low Engagement
**Possible causes:**
- Hook promises more than content delivers
- CTA too generic or missing
- Content doesn't invite conversation
- Too polished/corporate, not authentic
- No clear takeaway or lesson
### Pattern: Good First-Hour, Then Dies
**Possible causes:**
- Didn't respond quickly to first comments
- Responses too short ("thanks!")
- No tagging of relevant people
- Comment quality too low
### Pattern: Inconsistent Performance
**Possible causes:**
- Random topics across posts
- Varied posting times
- No clear expertise positioning
- Mixed quality (some posts rushed)
- Not tracking what works
### Pattern: Plateau After Growth
**Possible causes:**
- Same format repeatedly
- Not collaborating
- No optimization based on analytics
- Playing it safe (no controversial takes)
- No email list or monetization
## Step 4: Check for Algorithm Penalties
Run through this checklist:
- [ ] Did you use engagement bait language? ("Comment YES if...")
- [ ] Did you add external links in post or first comment?
- [ ] Have you been inconsistent (skipped week+)?
- [ ] Are topics all over the place recently?
- [ ] Did you receive generic AI-like comments?
- [ ] Did you post way more/less frequently than usual?
- [ ] Did you tag unrelated people for reach?
## Step 5: Reach Drop Severity Assessment
Based on how much reach dropped. **Measure the drop against the baseline band from
Step 2a, not against the single best week the operator remembers** — a percentage
computed from a remembered peak is a comparison with an outlier, and it will class
ordinary variation as suppression. When the band says `within-band`, the severity is
"normal fluctuation" regardless of what the percentage says.
### Down <25%
**Diagnosis:** Normal fluctuation
**Action:** Continue posting, monitor for trends
### Down 25-50%
**Diagnosis:** Something went wrong
**Action:**
- Review last week's posts for issues
- Increase engagement activity
- Start soft recovery
### Down 50-75%
**Diagnosis:** Algorithmic suppression likely
**Action:**
- Start 14-day recovery protocol
- Profile audit immediately
- Strict topic consistency
### Down 75%+
**Diagnosis:** Major issue - possible shadow ban
**Action:**
- Check for policy violations
- Full profile audit
- Consider if starting fresh is viable
## Step 6: Create Recovery Plan
Based on diagnosis, provide specific action plan.
### If Profile-Content Mismatch (topic-relevance Failure)
**Days 1-3: Profile Audit**
`/linkedin:profile` is the canonical topic-relevance audit — headline scoring, About section structure, Experience impact statements, Featured curation, Skills alignment, content history check, and network signals. Run it for the per-section checklist and the remediation flow.
Quick triage if a full audit can wait:
- Headline contains 3-4 topic keywords matching content pillars
- About section's first 3 lines establish specific expertise (before "see more" cutoff)
- Featured section reflects best work in your pillars
- Skills align with post topics
### If Content Reset Needed
**Days 4-7: Content Reset**
- [ ] Post ONLY on core 2-3 topics
- [ ] Use text-only format (lowest-risk)
- [ ] Keep posts 1,200-1,500 characters
- [ ] NO external links (even in comments)
- [ ] Respond to every comment within 30 minutes
### If Engagement Rehabilitation Needed
**Days 8-11: Engagement Focus**
- [ ] Comment 10-15x daily on posts in your topic area
- [ ] Focus on 2nd-degree connections
- [ ] Write 15+ word substantive comments only
- [ ] Like and save posts before commenting
- [ ] Tag relevant people in conversations
### If Gradual Expansion Appropriate
**Days 12-14: Gradual Expansion**
- [ ] Increase post length to 1,500-1,800 characters
- [ ] Try one carousel or document
- [ ] Introduce topic-adjacent content (80/20 rule)
- [ ] Monitor metrics closely
- [ ] Continue high engagement activity
## Step 6b: Persist the plan as do-next directives (the measurement→creation contract)
The recovery plan above is worth nothing if the next drafting session never sees it. Turn the
**23 load-bearing corrections** into do-next directives — the same channel `/linkedin:report`,
`/linkedin:ab-test` and the 48h monitor write to, and the one every create surface reads at its
Step 0:
```bash
node --input-type=module -e "
import { writeState, recordDoNext } from '${CLAUDE_PLUGIN_ROOT}/hooks/scripts/state-updater.mjs';
writeState(content => recordDoNext(content, {
recordDate: 'YYYY-MM-DD',
source: 'analyze',
directives: [
{ directive: 'Keep every post inside the 3 core pillars for 14 days', evidence: 'diagnosis: profile-content mismatch, reach -55% since off-topic run' },
{ directive: 'No external links in the post body until reach recovers', evidence: 'diagnosis: link-in-body correlates with the drop window' }
]
}));
"
```
Write the corrections that change the NEXT draft — not the whole checklist. `recordDoNext`
replaces this source's previous rows and expires anything older than 60 days, so a superseded
diagnosis cannot keep steering drafts. Confirm in one line what was persisted.
## Step 7: Timeline Expectations
Set realistic expectations:
| Suppression Level | Initial Improvement | Baseline Recovery | Full Restoration |
|-------------------|---------------------|-------------------|------------------|
| Moderate (link / off-topic) | 7-10 days | 14-21 days | 3-4 weeks |
| Moderate (partial reach loss) | 2-3 weeks | 4-6 weeks | 2-3 months |
| Severe (sharp reach loss) | 4-6 weeks | 3-6 months | May not be possible |
## Step 8: Prevention Checklist
For ongoing health, maintain:
- [ ] Post minimum 2x weekly (never >5 day gaps)
- [ ] Stay within 3-5 core topics
- [ ] Avoid engagement pods entirely
- [ ] Limit external links to 1x per week maximum
- [ ] Monitor reach weekly for early warning signs
- [ ] Keep profile and content aligned
- [ ] Respond to all comments within first hour
- [ ] Engage with others' content daily (10+ comments)
- [ ] Use native formats primarily
- [ ] Track first-hour engagement velocity
## When to Start Fresh
Consider creating a new account if:
- Zero improvement after 90 days of strict recovery
- Multiple policy violations on record
- Account age <1 year with <500 followers
- Engagement permanently at near-zero
- Profile can't be aligned with content (career change)
## Reference Files
- `references/troubleshooting-guide.md` - Complete troubleshooting
- `references/algorithm-signals-reference.md` - Algorithm mechanics
- `references/growth-roadmaps.md` - Stall points and fixes