Monthly board prep
Skill mohitkhandelwal242/ai-pm-operator/.claude/skills/monthly-board-prep
AI operating system for product managers — 19 Claude Code skills that connect to Jira, Confluence, GA4 & the app stores. 7-day free trial.
npx -y skills add mohitkhandelwal242/ai-pm-operator --skill monthly-board-prepAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Monthly Analysis — leadership-deck format month-over-month (MoM) comparison driven by business.json. Pulls two consecutive months of your product's metrics, computes deltas, and renders a leadership-style markdown deck with sections derived from your revenue_model and key_metrics, then optionally auto-publishes to Confluence. Use when asked for 'monthly analysis', 'month over month', 'MoM report', 'leadership monthly', 'board prep', or '/monthly-analysis'.
SKILL.md
12.3 KB, as published. Nobody here has run it
Monthly Analysis — MoM Leadership Report
Generate a leadership-deck monthly analysis. Compares two consecutive months (or any user-specified pair) across the metrics defined in business.json, computes month-over-month deltas, and renders an executive markdown deck. Optionally auto-publishes to Confluence.
The report is DRIVEN BY business.json. It does not assume any vertical. Read the business profile first and let it decide which sections and metrics appear.
Historical context for trendlines (if present): historical/monthly-snapshots.tsv. This file is optional — if it is missing, skip trend commentary.
Step 0 — Read the business profile
Read business.json at the start. The relevant fields:
company.{name, product_name, industry, business_type, revenue_model}metrics.north_star— the single headline metric the deck leads withmetrics.key_metrics[]— the list of metrics to compare MoM (each entry typically has a name, optional unit/currency, and optional category)
Derive the report sections from revenue_model and key_metrics. Group key_metrics by their category (or infer a sensible grouping) and render one report section per group. Always lead with the north-star metric. Examples of how revenue_model shapes the default sections:
revenue_model | Suggested default sections (override with whatever key_metrics actually contains) |
|---|---|
subscription / SaaS | MRR/ARR, New vs Churned MRR, Net Revenue Retention, Activation, Active Users, Churn rate |
marketplace | GMV, Take rate, Net revenue, Active buyers, Active sellers, Liquidity / match rate |
transactional / e-commerce | Revenue, Orders, AOV, Conversion rate, Repeat-purchase rate, New vs returning customers |
advertising | Revenue, Impressions, Fill rate, eCPM, DAU/MAU, Session depth |
usage-based | Revenue, Consumption units, Active accounts, Expansion, Net Revenue Retention |
These are starting points only. The actual sections must reflect the metrics present in business.json — never hardcode a vertical.
If a metric needed for the deck is missing from business.json, ask the user once and write it back.
Step 1 — Resolve months
Default invocation: current calendar month vs previous calendar month based on today's date (e.g. invoked May 4 → Apr vs Mar). Override with explicit args: /monthly-analysis 2026-04 2026-03 (current, prior).
Bind:
YEAR_A,MONTH_A→ current/latest monthYEAR_B,MONTH_B→ prior month
Step 2 — Verify the data source is reachable
The skill reads metric values from whatever data store the business uses (SQL warehouse, analytics API, etc.). Confirm connectivity before querying. If the project uses a DB tunnel:
bash tools/setup-db-tunnel.sh status || bash tools/setup-db-tunnel.sh start
Read connection credentials from .env. Do not hardcode hosts, schemas, or credentials.
Step 3 — Pull the core comparison
Run a parameterized two-month comparison against your product's metrics store. See queries/monthly-comparison.sql for an example template — replace the placeholder table/column names with your own schema. Substitute :YEAR_A/:MONTH_A (current) and :YEAR_B/:MONTH_B (prior).
The query should return one row per (category, metric_name) with current_value, prior_value, and pct_change. The categories should map to the metric groups you derived in Step 0.
Data-availability check: if a category has notably fewer rows for the latest month than the prior month, some metrics weren't loaded yet. Render those as (data not available for {Month YYYY}) instead of computing a misleading delta. Never silently impute, average, or carry forward.
Step 4 — Pull retention / churn detail (optional)
If business.json lists retention or churn metrics (e.g. churn rate, reactivations, account/customer status buckets), pull them with a dedicated query. See queries/retention-churn-monthly.sql for an example template.
# Access to a separate analytics schema/API may be restricted for some users.
# If the query fails (e.g. "SELECT command denied"):
# 1. Try the analytics API path (API key in .env), if configured.
# 2. If that also fails, OMIT the retention/churn section entirely and add a
# single line in the report:
# "Retention/Churn: data not available for {Month YYYY}".
# Do NOT publish prior-month numbers under the latest-month header — that
# would mislead leadership. Missing > stale.
If both months have data, compute and render whatever retention metrics business.json defines, for example:
- Active account/customer count (start vs end)
- Net churn (raw delta + rate %)
- Churn rate, reactivation count
- Any status/engagement buckets the business tracks (e.g. cohorts by activity level)
- Commentary on whether a move was driven by a one-off event (e.g. a bulk billing run) vs a sustained trend
Step 5 — Render the report
Output a Markdown file at reports/monthly-analysis-{monthA-yy}-vs-{monthB-yy}.md. Structure (sections come from Step 0, so this is a skeleton — adapt the numbered sections to the business's actual metric groups):
- Title —
{Product} Monthly Analysis — {Month A YYYY} vs {Month B YYYY} - Summary — one paragraph leading with the north-star metric and the top 3–4 numbers
- Key Takeaways — table with columns
# | Signal | Verdict. Verdict is one of:Strong | Key Driver | Positive | Watch | New | Pending. 10–14 rows - Numbered metric sections — one per metric group derived from
key_metrics/revenue_model. Each section is a metric table with{Month B} | {Month A} | Changecolumns followed by a**Highlights:**paragraph. Order them with the north-star group first, then revenue, then engagement/retention, etc. - Root Cause Analysis — Major Changes (Data-Backed) — for every headline metric that moved >10% MoM, run a sliced variation of the source query (see
queries/source-queries-example.sql) across the dimensions the business cares about (e.g. segment, region, channel, plan, platform, day-of-month). Goal: explain WHY each move happened, not just THAT it happened. Include:- Gains (>10% increase) — one-row-per-metric narrative table with the data-backed reason
- Declines (>10% decrease) — one-row-per-metric narrative table with the data-backed reason
- For any move a segment/dimension slice doesn't explain, also drill on day-of-month (single-day spike vs sustained drift) and channel/platform.
- Retention/Churn section — only if Step 4 returned data for both months. Otherwise insert a single line:
Retention/Churn: data not yet available for {Month YYYY}.and continue. - Leadership Notes — Copy/Paste for Slide (REQUIRED — never skip)
- Footer —
Report generated: {date} | Data source: {your metrics store} | Generated via /monthly-analysis skill
Required Leadership Notes format (Section 7)
Each section is a header + multiple short observation lines (one observation per line, separated by single newlines so they render as separate paragraphs in Confluence). Format every metric as prior → current (+X.X%) with sign. No bullet symbols, no tables. Use one header per metric group, for example:
### Core Metrics ({Month A}'YY vs {Month B}'YY)
{4–6 short prose lines, one observation per line, north-star metric first}
### Revenue & Monetization ({Month A}'YY vs {Month B}'YY)
{6–7 short prose lines}
### Acquisition & Activation ({Month A}'YY vs {Month B}'YY)
{1 lead summary line, then 1 line per metric}
### Engagement ({Month A}'YY vs {Month B}'YY)
{1 lead line + 1 line per engagement metric}
### Retention / Churn ({Month A}'YY vs {Month B}'YY)
{If data available: 1 line per metric + 1 "Key takeaway:" paragraph at end}
{If data missing: a single line "Data not yet available for {Month YYYY}."}
(Use the section headers that match the business's metric groups — the above are illustrative.) This format must NOT be one big paragraph and must NOT be bullet-listed. It is short, dense, line-broken prose that the user copies section-by-section directly into a slide.
Missing-data rule (general): any metric where the latest month is null/zero must be rendered as (data not available for {Month YYYY}). Never silently impute, average, or carry forward.
Tone: terse, executive-style, numbers-first. Format currency amounts using the currency/unit declared in business.json (fall back to the metric's own unit). Use +X.X% deltas with sign. Never use emojis.
Step 6 — Auto-publish to Confluence (optional)
Create a new page under the parent of the existing Monthly Analysis series. Use the Atlassian MCP createPage:
- cloudId:
${CONFLUENCE_CLOUD_ID} - spaceId/spaceKey:
${CONFLUENCE_SPACE_KEY} - parentId:
${CONFLUENCE_PARENT_PAGE_ID}— or discover it by searching for an existingMonthly Analysispage and using its parent. If the lookup fails, ask the user once for the parent page id. - Title:
{Product} Monthly Analysis {MonthA YYYY} vs {MonthB YYYY} - contentFormat:
markdown - Body: contents of the Markdown file from Step 5
After publishing, return the URL to the user.
Confluence target
- spaceKey:
${CONFLUENCE_SPACE_KEY} - parentId:
${CONFLUENCE_PARENT_PAGE_ID} - cloudId:
${CONFLUENCE_CLOUD_ID}
Direct REST API path (fallback when MCP isn't available)
The Atlassian MCP createPage is preferred. If unavailable, post directly via REST:
import os, requests, markdown
from requests.auth import HTTPBasicAuth
html = markdown.markdown(open('REPORT.md').read(), extensions=['tables', 'fenced_code'])
auth = HTTPBasicAuth(os.environ['ATLASSIAN_EMAIL'], os.environ['ATLASSIAN_API_TOKEN'])
r = requests.post(f"{os.environ['ATLASSIAN_BASE_URL']}/wiki/api/v2/pages", auth=auth, json={
"spaceId": "${CONFLUENCE_SPACE_KEY}",
"parentId": "${CONFLUENCE_PARENT_PAGE_ID}",
"status": "current",
"title": "{Product} Monthly Analysis — {Month A YYYY} vs {Month B YYYY}",
"body": {"representation": "storage", "value": html}
})
Step 7 — Append to historical snapshot (optional)
If the latest month's data is fully populated, append a column to historical/monthly-snapshots.tsv (create it if absent). This keeps a long-tail trend file usable for future YoY analyses. Use the same metric names as business.json so the file stays generic.
Reference: data sources & known gaps
| Section | Source | Known gaps |
|---|---|---|
Core metric groups (from key_metrics) | Your product's metrics store / warehouse | Latest month may have fewer rows than prior month — loading lag |
| Retention / Churn detail | Separate analytics schema or API (if configured) | May not be auto-loaded; latest month may be missing for the first several days. Access may require additional DB grants — request from your data team or use the analytics API. |
| Segment / region breakdown | May require a separate aggregation if not in the main metrics table | Scope in if the user asks for segment-level analysis |
Self-check before publishing
- Sections were derived from
business.json(key_metrics+revenue_model), not hardcoded - North-star metric leads the Summary and the first metric section
- Every section either contains data OR explicitly says "data not available for {Month YYYY}"
- No prior-month numbers rendered under the latest-month header
- All currency figures use the unit declared in
business.json - Significant mix shifts (e.g. plan-mix, segment-mix) are called out
- Headline section names 3–5 wins and 2–3 watch-items for next month
- Confluence URL returned to the user (if publishing was requested)
- Leadership Notes — Copy/Paste for Slide section is present with
### Section ({MA}'YY vs {MB}'YY)headers and multiple short observation lines per section, one observation per line inprior → current (+X.X%)format. NOT a single dense paragraph; NOT bullet-listed