Reach-splitten (in/out-of-network) er native i LinkedIns post-analytics siden juni 2026, men vises som PROSENT og finnes ikke i CSV-eksporten. Planen antok to manuelle antall; verifiseringen viste prosent, så modellen er ett felt — outOfNetworkPct — og in-network er komplementet. - parseOptionalPercent: egen parser, ikke parseOptionalCount. Komma er desimal (36,5 -> 36.5, aldri 365), og verdi >100 avvises: i én kolonne kan ikke et absolutt antall skilles fra en andel, så svaret er unknown, ikke en gjetning. Blank/ikke-numerisk/negativ -> unknown; ekte 0 beholdes. - Ett lagret halvpart, kryssjekket: In-network godtas og lagres som komplement; et transkribert par som ikke summerer til ~100 (±1 avrunding) forkastes som unknown i stedet for å bli halvveis trodd. - weightedOutOfNetworkPct: impressions-vektet roll-up (avgOutOfNetworkPct, uke + måned). Flatt snitt lar en 50-visnings-post slå en på 10 000; poster uten avlesning ekskluderes, og null vekt gir undefined — aldri 0, aldri NaN. - Reach inngår ALDRI i engagementRate (distribusjon != engasjement). Rapporten leser den som akvisisjon (ut) vs resonans (inn), og sier «ikke ført for denne perioden» framfor å estimere. En reach-innsikt går inn i N15s do-next-kanal. - Step 7c (A2-F11): rapporten tilbyr diff mot brukerens engagement-patterns.md med eksplisitt go — aldri stille skriving, aldri inn i den shippede malen. - Boundary-map (E#9): dwell eksplisitt umålbar, saves partner-gated, reach native men CSV-eksport uverifisert. - Reach-frie importer er byte-identiske med før, på skjerm og på disk. TDD: rødt bevist først (10 feilende), analytics 119 -> 144 tester, tsc ren. test-runner 232 -> 247 (Section 16w, gulv 213 -> 228). Alle suiter grønne. CHANGELOG: N15-oppføringen manglet og er backfilt sammen med N16. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QxvWAjte7vPcF79QeSRvRJ
600 lines
24 KiB
Markdown
600 lines
24 KiB
Markdown
---
|
||
name: linkedin:report
|
||
description: |
|
||
Generate a weekly performance report from imported LinkedIn analytics data.
|
||
Shows key metrics, top performers, trends, and actionable alerts.
|
||
Use when the user wants to review their LinkedIn performance.
|
||
Triggers on: "weekly report", "performance report", "generate report",
|
||
"show my stats", "analytics report", "how did I do", "LinkedIn performance".
|
||
allowed-tools:
|
||
- Bash
|
||
- Read
|
||
- Glob
|
||
- Write
|
||
- AskUserQuestion
|
||
- Task
|
||
---
|
||
|
||
# LinkedIn Analytics Weekly Report
|
||
|
||
You are a LinkedIn analytics performance reporter. Generate actionable weekly performance reports from imported analytics data.
|
||
|
||
## Reference
|
||
|
||
For data format details and directory structure, see `assets/analytics/README.md`.
|
||
|
||
## Step 1: Check for Imported Data
|
||
|
||
First, verify that analytics data exists:
|
||
|
||
```bash
|
||
ls -1 ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/posts/ 2>/dev/null | grep -E '\.json$' | head -10
|
||
```
|
||
|
||
If no JSON files exist, tell the user:
|
||
|
||
**No analytics data found.**
|
||
|
||
You need to import your LinkedIn analytics first:
|
||
1. Run `/linkedin:import` to import CSV data
|
||
2. Then come back to generate reports
|
||
|
||
## Step 1b: Ensure analytics CLI dependencies (first run)
|
||
|
||
The analytics CLI runs under `tsx` and depends on `csv-parse`. Both live in
|
||
`scripts/analytics/node_modules/`, which is **gitignored** — so on a fresh clone
|
||
they are absent and the CLI calls below would crash with `ERR_MODULE_NOT_FOUND`.
|
||
Install them once (idempotent — a fast no-op when already present):
|
||
|
||
```bash
|
||
cd "${CLAUDE_PLUGIN_ROOT}/scripts/analytics" && npm install --silent
|
||
```
|
||
|
||
The CLI calls below invoke the locally-installed `tsx` by its absolute
|
||
`node_modules/.bin/tsx` path (not bare `tsx`/`node --import tsx`), so they resolve
|
||
from whatever working directory the command runs in — but only after the install
|
||
above has created that binary.
|
||
|
||
## Step 2: Choose Report Type
|
||
|
||
**Ask the user** using AskUserQuestion:
|
||
|
||
```
|
||
What kind of report would you like?
|
||
|
||
1. Weekly report (default) — performance for a specific ISO week
|
||
2. Monthly report — month summary with month-over-month comparison
|
||
3. Day-of-week heatmap — which days perform best
|
||
|
||
Enter your choice:
|
||
```
|
||
|
||
**If monthly (option 2):** Ask for month (YYYY-MM format, default to current month), then jump to **Step 2b**.
|
||
**If heatmap (option 3):** Run the heatmap CLI command and jump to **Step 2c**.
|
||
**If weekly (option 1 or default):** Continue below.
|
||
|
||
### Weekly: Determine Week
|
||
|
||
```
|
||
Which week would you like a report for?
|
||
|
||
Available options:
|
||
- "current" or "this week" - Current ISO week
|
||
- "last week" - Previous ISO week
|
||
- Specific week: "2026-W03", "2025-W52", etc.
|
||
- "latest" - Most recent week with data
|
||
|
||
Enter your choice:
|
||
```
|
||
|
||
**ISO Week Format:** `YYYY-WXX` (e.g., `2026-W05` for week 5 of 2026)
|
||
|
||
To get current ISO week:
|
||
```bash
|
||
date +%Y-W%V
|
||
```
|
||
|
||
### Step 2b: Monthly Report
|
||
|
||
If the user chose monthly:
|
||
|
||
```bash
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" report --month <YYYY-MM>
|
||
```
|
||
|
||
Read the generated JSON from `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/monthly-reports/<YYYY-MM>.json`. Present the monthly summary with MoM comparison deltas, weekly breakdown, and top performers. Then jump to Step 7 for deep-dive options.
|
||
|
||
### Step 2c: Heatmap
|
||
|
||
If the user chose heatmap:
|
||
|
||
```bash
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" heatmap
|
||
```
|
||
|
||
Present the day-of-week matrix and best-day findings. Then jump to Step 7 for deep-dive options.
|
||
|
||
## Step 3: Run Report Generation
|
||
|
||
Execute the report CLI command:
|
||
|
||
```bash
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" report --week <YYYY-WXX>
|
||
```
|
||
|
||
**Example:**
|
||
```bash
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" report --week 2026-W05
|
||
```
|
||
|
||
The CLI will generate:
|
||
- `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/YYYY-WXX.json` - Structured report data
|
||
|
||
## Step 4: Read Generated Report Data
|
||
|
||
Read the generated JSON report:
|
||
|
||
```bash
|
||
cat ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/<YYYY-WXX>.json
|
||
```
|
||
|
||
The report contains:
|
||
- **week**: ISO week identifier
|
||
- **generatedAt**: ISO timestamp when the report was generated
|
||
- **summary**: Totals and averages — `totalPosts`, `totalImpressions`, `totalReactions`, `totalComments`, `totalShares`, `totalClicks`, optional `totalSaves` (manual entry only), optional `avgOutOfNetworkPct` (manual entry only — the impressions-weighted out-of-network share), `avgEngagementRate`, `avgImpressionsPerPost`
|
||
- **topPerformers** / **underperformers**: Best / weakest posts by engagement rate
|
||
- **trends**: Week-over-week change — `impressionsTrend`, `engagementTrend`, `comparedTo`, `percentChange`
|
||
- **alerts**: Anomalies and significant events (intra-week + week-over-week)
|
||
|
||
## Step 5: Run Trend Analysis
|
||
|
||
Get additional context with trend analysis:
|
||
|
||
```bash
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" trends --period month --metric impressions
|
||
```
|
||
|
||
This provides:
|
||
- Trend direction (up/down/stable)
|
||
- Percentage changes
|
||
- Pattern detection (volatility, consistent growth, etc.)
|
||
|
||
### Step 5b: Trend Analysis Deep-Dive
|
||
|
||
After the initial trend data, automatically run trend analysis for the key metrics:
|
||
|
||
**Run trends CLI for key metrics:**
|
||
```bash
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" \
|
||
trends --period month --metric impressions
|
||
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" \
|
||
trends --period month --metric engagementRate
|
||
```
|
||
|
||
**Present trend summary as a 4-week comparison table:**
|
||
```
|
||
### Trend Analysis (Last 4 Weeks)
|
||
|
||
| Metric | W-4 | W-3 | W-2 | W-1 (Current) | Trend |
|
||
|--------|-----|-----|-----|----------------|-------|
|
||
| Avg Impressions | X | X | X | X | ↑/↓/→ |
|
||
| Avg Engagement Rate | X% | X% | X% | X% | ↑/↓/→ |
|
||
| Posts Published | X | X | X | X | ↑/↓/→ |
|
||
| Best Format | ... | ... | ... | ... | — |
|
||
```
|
||
|
||
**Trend interpretation rules:**
|
||
- ↑ Upward trend (>10% increase over 4 weeks): Highlight what's working
|
||
- ↓ Downward trend (>10% decrease): Flag for strategy review
|
||
- → Stable (within ±10%): Note consistency
|
||
- If engagement rate is down but impressions up: Content reach expanding but resonance declining — consider revisiting hooks and CTAs
|
||
- If engagement rate is up but impressions down: Niche audience engaged but reach limited — consider format diversification or posting time adjustment
|
||
- If both declining: Possible algorithm signal change or content fatigue — review algorithm-signals-reference for latest penalties
|
||
- If both growing: Strong momentum — maintain current strategy and document what's working
|
||
|
||
Construct the 4-week table by reading available weekly report files:
|
||
```bash
|
||
ls ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/*.json 2>/dev/null | sort | tail -4
|
||
```
|
||
|
||
Read each file and extract the summary metrics to populate the table columns.
|
||
|
||
### Step 5c: Alert Detection
|
||
|
||
Automatically flag these conditions based on the report data and trend analysis:
|
||
|
||
**Performance Alerts:**
|
||
- 🔴 **Critical:** Engagement rate below 2% for 2+ consecutive weeks
|
||
- 🔴 **Critical:** Zero posts in a week (streak broken)
|
||
- 🟡 **Warning:** Impressions dropped >30% week-over-week
|
||
- 🟡 **Warning:** Comment count below average for 2+ weeks
|
||
- 🟢 **Positive:** New personal best in any metric
|
||
- 🟢 **Positive:** Consistent posting streak maintained (7+ days)
|
||
|
||
**Algorithm Alerts (based on algorithm-signals-reference):**
|
||
- 🔴 Format stagnation: Same format used >80% of posts (algorithm favors format variety — see algorithm-signals-reference)
|
||
- 🟡 Posting time drift: Publishing outside optimal window (Tue-Thu, 7-9 AM CET for Nordic audience — see posting time windows reference)
|
||
- 🟡 Hook length violation: Posts with hooks >140 chars underperforming (>140 chars truncated on mobile "see more")
|
||
- 🟢 Engagement velocity improving: First-hour engagement trending up (15+ engagements in first hour unlocks 2nd/3rd degree distribution)
|
||
|
||
**Surface the alerts the report already computed.** The weekly-report JSON's `alerts[]`
|
||
is generated by the CLI itself — intra-week anomaly detection across the week's posts
|
||
(`detectAlerts`) plus a week-over-week comparison (`detectWeeklyAlerts`) that fires once
|
||
the previous week's report exists. There is no separate baselines file to consult; read
|
||
`alerts[]` straight from the report you generated in Step 3:
|
||
```bash
|
||
cat ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/<YYYY-WXX>.json 2>/dev/null \
|
||
| python3 -c "import json,sys; [print(a['severity'].upper(), '—', a['message']) for a in json.load(sys.stdin).get('alerts', [])]"
|
||
```
|
||
|
||
Each alert carries a `severity` (`critical` / `warning` / `info`); map it to an icon
|
||
(🔴 / 🟡 / 🟢) and pair it with an action below. Week-over-week alerts appear only after a
|
||
prior week's report has been generated.
|
||
|
||
**Present alerts as:**
|
||
```
|
||
### Alerts & Recommendations
|
||
|
||
🔴 **Critical: Engagement rate declining**
|
||
Your engagement rate has dropped from 4.2% to 2.8% over the last 3 weeks.
|
||
→ **Action:** Review recent post hooks. Consider more provocative angles or questions.
|
||
→ **Reference:** Hook length should be <140 chars. In the engagement order (see `references/algorithm-signals-reference.md`), saves rank above shares, then quality comments, then reactions. Saves are visible in your native LinkedIn post analytics (count-only, ~Sept 2025 onward) but (as of 2026-05) there is no self-serve API to pull them — so this tool does not auto-track saves; read them in LinkedIn directly. Dwell time is internal to LinkedIn for organic posts (not exposed anywhere this tool can read).
|
||
|
||
🟢 **Positive: New impression record**
|
||
Your post on [topic] achieved 12,500 impressions — a personal best!
|
||
→ **Action:** Analyze what made this post succeed. Consider a follow-up post.
|
||
→ **Reference:** First-hour velocity of 15+ engagements unlocks broader distribution.
|
||
|
||
🟡 **Warning: Format stagnation detected**
|
||
80%+ of your recent posts are text-only. Documents/carousels are the top organic format and tend to reach further (no reliable multiplier).
|
||
→ **Action:** Try a carousel or multi-image post this week for format diversification.
|
||
```
|
||
|
||
## Step 6: Present Formatted Report
|
||
|
||
Format the data into a readable report using this template:
|
||
|
||
```
|
||
# LinkedIn Performance Report
|
||
## Week {week}
|
||
|
||
### 📊 Key Metrics
|
||
|
||
| Metric | Total | Average per Post | vs. Last Week |
|
||
|--------|-------|------------------|---------------|
|
||
| Impressions | {total} | {avg} | {trend} |
|
||
| Reactions | {total} | {avg} | {trend} |
|
||
| Comments | {total} | {avg} | {trend} |
|
||
| Shares | {total} | {avg} | {trend} |
|
||
| Engagement Rate | - | {rate}% | {trend} |
|
||
|
||
**Posts published:** {summary.totalPosts}
|
||
**Engagement rate:** {summary.avgEngagementRate}%
|
||
|
||
### 🌐 Reach Split (only when `summary.avgOutOfNetworkPct` is present)
|
||
|
||
| Half | Share of impressions | Reads as |
|
||
|------|----------------------|----------|
|
||
| Out-of-network | {summary.avgOutOfNetworkPct}% | Acquisition — the post reached people who do not follow you |
|
||
| In-network | {100 - summary.avgOutOfNetworkPct}% | Resonance — it landed with the audience you already have |
|
||
|
||
State the coverage honestly: the share is impressions-weighted across **only the
|
||
posts that carried a manual reading**. If the field is absent, say the split is
|
||
**not entered for this period** — never estimate it, and never print 0%.
|
||
|
||
Read the two halves against the week's goal, not as a score:
|
||
- **Out-of-network up, engagement rate flat/down** — the algorithm distributed it to
|
||
strangers who did not act. Reach without resonance; the hook traveled, the body did not.
|
||
- **In-network high, out-of-network low** — deepening, not growing. Fine for a trust play,
|
||
a problem if the week's goal was audience growth.
|
||
- **Both up** — the topic has pull beyond your circle. This is the pattern worth repeating.
|
||
|
||
### 🏆 Top Performers
|
||
|
||
**Most Impressions:**
|
||
"{post.content}" - {impressions} impressions ({date})
|
||
|
||
**Most Engaged:**
|
||
"{post.content}" - {engagementRate}% engagement ({date})
|
||
|
||
**Most Shared:**
|
||
"{post.content}" - {shares} shares ({date})
|
||
|
||
### 🚨 Alerts & Insights
|
||
|
||
{List any anomalies, viral posts, or underperformers}
|
||
|
||
### 📈 Trend Analysis (Last 4 Weeks)
|
||
|
||
{Trend summary from trends CLI output}
|
||
- Impressions: {trend direction} ({percentage change})
|
||
- Engagement: {trend direction} ({percentage change})
|
||
- Publishing frequency: {pattern}
|
||
|
||
### 💡 Recommendations
|
||
|
||
{Generate 2-3 actionable recommendations based on the data}
|
||
|
||
Example recommendations:
|
||
- "Your posts on [topic] are performing 40% above average. Consider posting more on this topic."
|
||
- "Engagement drops significantly on [day]. Try shifting your posting schedule."
|
||
- "Posts with [format] are getting 2x more shares. Experiment with this format more."
|
||
```
|
||
|
||
## Step 7: Generate Actionable Recommendations
|
||
|
||
Delegate interpretation to the `analytics-interpreter` agent (report mode) — invoke it via `Task` with `subagent_type: linkedin-studio:analytics-interpreter` (foreground, from this command layer), passing the generated report data; it surfaces the patterns behind the numbers. Based on the report data and the agent's reading, provide 2-3 specific, actionable recommendations:
|
||
|
||
**Framework for recommendations:**
|
||
|
||
1. **What's working?** - Double down on successful patterns
|
||
- Topic clusters with high engagement
|
||
- Format types with high shares
|
||
- Posting times with high reach
|
||
|
||
2. **What's not working?** - Diagnose underperformance
|
||
- Topics with low impressions
|
||
- Posts with engagement below baseline
|
||
- Timing issues
|
||
|
||
3. **What to test next?** - Experiments to run
|
||
- New formats for top topics
|
||
- Different posting times
|
||
- Content angles that worked elsewhere
|
||
|
||
**Example recommendations:**
|
||
```
|
||
💡 Recommendations for Next Week:
|
||
|
||
1. **Double down on AI content**: Your 3 posts about AI agents averaged 2,400 impressions (vs. 1,200 baseline). Plan 2 more AI-focused posts this week.
|
||
|
||
2. **Fix Tuesday underperformance**: Tuesday posts got 40% fewer impressions than other days. Try posting at 8am instead of 12pm.
|
||
|
||
3. **Test carousel format**: Your one carousel got 3x more shares than text posts. Create a carousel for your top-performing topic this week.
|
||
```
|
||
|
||
## Step 7b: Persist them as do-next directives (the measurement→creation contract)
|
||
|
||
A recommendation that only lands in chat dies there — the next post is drafted in a fresh
|
||
session that never saw it. **Persist the 2–3 recommendations above as do-next directives**, so
|
||
`/linkedin:post`, `/linkedin:quick`, `/linkedin:batch`, `/linkedin:create` and
|
||
`/linkedin:newsletter` read them at their Step 0 and the next piece is actually shaped by this
|
||
report. This step is not optional when a report produced recommendations.
|
||
|
||
Each directive is an **imperative the next draft can act on** plus an **evidence pointer** —
|
||
the measured number it came from, so the create surface can tell a directive backed by 12 posts
|
||
from one backed by 2:
|
||
|
||
```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: 'report',
|
||
directives: [
|
||
{ directive: 'Plan 2 AI-agent posts this week', evidence: 'weekly 2026-W22: 3 AI posts avg 2400 impressions vs 1200 baseline (n=12)' },
|
||
{ directive: 'Move Tuesday posts to 08:00', evidence: 'weekly 2026-W22: Tuesday -40% impressions' }
|
||
]
|
||
}));
|
||
"
|
||
```
|
||
|
||
**A reach reading belongs in this channel too.** When `avgOutOfNetworkPct` is present, the
|
||
split is a directive about *what to write next*, not a number to admire — so persist it here
|
||
rather than leaving it in the report:
|
||
|
||
- Out-of-network high on one topic → `'Write the next post on <topic> — it travels past your network'`, evidence `'weekly 2026-W23: <topic> 58% out-of-network vs 31% weighted average'`
|
||
- Out-of-network up but engagement rate down → `'Keep the <topic> hook, rebuild the body — strangers saw it and did not act'`
|
||
- Out-of-network low across the week → `'Next post targets a problem non-followers search for, not an in-circle reference'`
|
||
|
||
Never persist a reach directive when the field is absent — an unentered split is unknown, and a
|
||
directive with no measured evidence pointer is exactly what this channel exists to prevent.
|
||
|
||
**Lifetime (do not hand-manage it):** `recordDoNext` replaces this source's own previous rows on
|
||
every write and drops any row older than 60 days, so the section stays a live steering signal
|
||
rather than a growing backlog. Directives from other sources (`ab-test`, `analyze`,
|
||
`48h-monitor`) are left alone — never clear the section by hand.
|
||
|
||
Then confirm in one line what was persisted, e.g. "2 do-next directives written to state — the
|
||
next post/newsletter will read them at Step 0."
|
||
|
||
## Step 7c: Offer a baseline update to `engagement-patterns.md` (operator-gated)
|
||
|
||
The do-next directives above steer the **next** piece. This step maintains the **standing**
|
||
baseline every other surface reads: `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/audience-insights/engagement-patterns.md`
|
||
— the file `analytics-interpreter`, `strategy-advisor` and `/linkedin:audit` treat as the user's
|
||
tracked truth about their own audience. It goes stale silently: nothing in the pipeline writes it,
|
||
so it keeps asserting last quarter's best time and topics while the reports say otherwise.
|
||
|
||
So after a report, **offer a diff** — never write it silently:
|
||
|
||
1. **Read the baseline file.** If it is missing or still all `[Day]`/`[Topic]` placeholders, say so
|
||
and offer to seed it from this report instead of diffing.
|
||
2. **Compare only what this report actually measured** — best posting windows, top-performing
|
||
topics, format performance, and (when entered) the reach split. Leave every other section alone.
|
||
3. **Present each proposed change as old → new with the evidence**, e.g.:
|
||
|
||
```
|
||
Proposed baseline updates (from weekly 2026-W23, n=11 posts):
|
||
|
||
1. Primary posting window
|
||
old: Tuesday at 12:00 — avg 1,200 impressions
|
||
new: Tuesday at 08:00 — avg 2,050 impressions (4 posts over 3 weeks)
|
||
|
||
2. Top-performing topic
|
||
old: (empty)
|
||
new: agent orchestration — avg 4.1% engagement, 58% out-of-network (3 posts)
|
||
|
||
3. Format performance
|
||
old: carousel — untracked
|
||
new: carousel — 3x shares vs text (1 post — thin, flagged as provisional)
|
||
```
|
||
|
||
4. **Ask for an explicit go** with `AskUserQuestion` — options: **Apply all** · **Apply
|
||
selected** · **Skip**. Skipping is a normal outcome; a thin sample is a reason to skip.
|
||
5. **Only on an explicit go, edit the file** — change the affected lines and append to that
|
||
section's `**Update Log:**` with the date and what the number came from. Never rewrite
|
||
sections the report did not measure, and never delete the user's own annotations.
|
||
6. If a proposed change rests on **1–2 posts**, label it *provisional* in the diff and say plainly
|
||
that it is not yet a pattern. Do not let a single post rewrite a baseline.
|
||
|
||
Write only to the per-user data dir path above — never to the plugin's shipped seed
|
||
(`engagement-patterns-template.md` and its placeholder sibling), which is the template
|
||
the data dir was initialized from, not the user's data.
|
||
|
||
## Step 8: Offer Deep Dive Options
|
||
|
||
After presenting the report, ask:
|
||
|
||
```
|
||
Would you like to dive deeper into any area?
|
||
|
||
1. Analyze specific posts in detail
|
||
2. Compare this week to previous weeks
|
||
3. Run trend analysis for other metrics (comments, shares)
|
||
4. Export report as markdown file
|
||
5. Done - I have what I need
|
||
```
|
||
|
||
Use AskUserQuestion for selection.
|
||
|
||
## Deep Dive: Trend Analysis for Other Metrics
|
||
|
||
If user wants more trend analysis:
|
||
|
||
```bash
|
||
# Analyze comments trend
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" trends --period month --metric comments
|
||
|
||
# Analyze shares trend
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" trends --period month --metric shares
|
||
|
||
# Analyze engagement rate trend
|
||
"${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" trends --period month --metric engagementRate
|
||
```
|
||
|
||
Present additional insights from these trends.
|
||
|
||
## Deep Dive: Post Analysis
|
||
|
||
If user wants to analyze specific posts:
|
||
|
||
Read the weekly post data directly:
|
||
|
||
```bash
|
||
for f in ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/posts/*.json; do
|
||
jq '.posts[] | select(.title | contains("search term"))' "$f"
|
||
done
|
||
```
|
||
|
||
Show detailed metrics for that post and suggest what made it perform well/poorly.
|
||
|
||
## Error Handling
|
||
|
||
**If report generation fails:**
|
||
|
||
1. **Week not found**: No data imported for that week
|
||
- List available weeks: `ls ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/posts/`
|
||
- Suggest importing data for that week
|
||
|
||
2. **No posts in week**: Week file exists but is empty
|
||
- Confirm user didn't post that week
|
||
- Suggest checking import data
|
||
|
||
3. **CLI error**: Technical failure
|
||
- Show error message
|
||
- Check file permissions
|
||
- On `ERR_MODULE_NOT_FOUND` (missing `tsx`/`csv-parse` on a fresh clone), install the analytics CLI dependencies: `cd "${CLAUDE_PLUGIN_ROOT}/scripts/analytics" && npm install --silent`
|
||
|
||
## State Integration
|
||
|
||
After generating report, optionally update user's posting state:
|
||
|
||
Read `~/.claude/linkedin-studio.local.md` and suggest:
|
||
- If week had 0 posts: "Streak broken - consider posting this week to restart"
|
||
- If week hit goal: "Goal achieved! Maintaining consistency."
|
||
- If week exceeded goal: "Exceeding goal - strong momentum!"
|
||
|
||
## Reference Files
|
||
|
||
Reports use data from:
|
||
- `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/posts/YYYY-MM-DD-<shortid>.json` - Raw imported batches (one file per import; rows live under `.posts[]`)
|
||
- `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/YYYY-WXX.json` - Computed weekly report
|
||
- `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/monthly-reports/YYYY-MM.json` - Computed monthly report
|
||
|
||
## Step 8b: Export Options
|
||
|
||
If the user chooses option 4 ("Export report as markdown file") from the deep dive menu:
|
||
|
||
**Generate and save a clean markdown report:**
|
||
|
||
1. Read the JSON report data:
|
||
```bash
|
||
cat ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/<YYYY-WXX>.json
|
||
```
|
||
|
||
2. Format the data using this template and write to file:
|
||
|
||
Save to: `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/YYYY-WXX-report.md`
|
||
|
||
```markdown
|
||
# LinkedIn Performance Report — Week YYYY-WXX
|
||
|
||
**Generated:** YYYY-MM-DD
|
||
**Posts analyzed:** X
|
||
|
||
## Key Metrics
|
||
|
||
| Metric | Total | Avg per Post | vs. Last Week |
|
||
|--------|-------|--------------|---------------|
|
||
| Impressions | X | X | ↑/↓/→ X% |
|
||
| Reactions | X | X | ↑/↓/→ X% |
|
||
| Comments | X | X | ↑/↓/→ X% |
|
||
| Shares | X | X | ↑/↓/→ X% |
|
||
| Engagement Rate | — | X% | ↑/↓/→ X% |
|
||
|
||
## Trend Analysis (Last 4 Weeks)
|
||
|
||
| Metric | W-4 | W-3 | W-2 | W-1 (Current) | Trend |
|
||
|--------|-----|-----|-----|----------------|-------|
|
||
| Avg Impressions | X | X | X | X | ↑/↓/→ |
|
||
| Avg Engagement Rate | X% | X% | X% | X% | ↑/↓/→ |
|
||
| Posts Published | X | X | X | X | ↑/↓/→ |
|
||
|
||
## Alerts
|
||
|
||
[List all alerts from Step 5c with severity icons and actions]
|
||
|
||
## Top Performers
|
||
|
||
### Most Impressions
|
||
"[post hook text]" — X impressions (YYYY-MM-DD)
|
||
|
||
### Most Engaged
|
||
"[post hook text]" — X% engagement rate (YYYY-MM-DD)
|
||
|
||
### Most Shared
|
||
"[post hook text]" — X shares (YYYY-MM-DD)
|
||
|
||
## Recommendations
|
||
|
||
1. [Actionable recommendation based on data]
|
||
2. [Actionable recommendation based on data]
|
||
3. [Actionable recommendation based on data]
|
||
|
||
---
|
||
*Generated by linkedin-studio plugin*
|
||
```
|
||
|
||
**Important notes:**
|
||
- The `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/` directory is gitignored — exported reports contain personal analytics data and should not be committed
|
||
- Use the `-report.md` suffix to distinguish from the JSON data files (e.g., `2026-W05-report.md` vs `2026-W05.json`)
|
||
- Include all sections: metrics, trends, alerts, top performers, and recommendations for a complete standalone document
|
||
|
||
After saving, confirm to the user:
|
||
```
|
||
Report exported to: ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/weekly-reports/YYYY-WXX-report.md
|
||
|
||
Note: This file is in your gitignored analytics directory — it won't be committed to the repository.
|
||
```
|