← Adobe CJACONTENT HISTORY

Update to Adobe CJA

Snapshot Sep 30, 2026 · 22:53 UTC · version 2.0.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "name": "cja-kpi-pulse",
  "description": "Produces a compact KPI digest showing how key metrics changed over a period and what's driving the movement. Use this skill when someone asks for a performance summary, a weekly recap, a morning briefing, a KPI update, or any variation of \"how did we do this week/month.\" Also trigger for requests like \"give me a performance overview,\" \"what moved in the last 7 days,\" \"pull our KPI report,\" or \"summarize our metrics.\"\n",
  "included_files": [
    {
      "relative_path": "evals/evals.json",
      "size_in_bytes": 1654
    },
    {
      "relative_path": "template.html",
      "size_in_bytes": 10369
    }
  ],
  "skill_md_contents": "---\nname: cja-kpi-pulse\ndescription: >\n  Produces a compact KPI digest showing how key metrics changed over a period and\n  what's driving the movement. Use this skill when someone asks for a performance\n  summary, a weekly recap, a morning briefing, a KPI update, or any variation of\n  \"how did we do this week/month.\" Also trigger for requests like \"give me a\n  performance overview,\" \"what moved in the last 7 days,\" \"pull our KPI report,\"\n  or \"summarize our metrics.\"\nlicense: Apache-2.0\nmetadata:\n  author: Adobe\n  version: \"1.0\"\n---\n\n# KPI Pulse (Customer Journey Analytics)\n\nProduce a compact KPI digest in under 2 minutes. The goal is a crisp answer to\n\"how did we do?\" — not a deep-dive, not a data dump. Each KPI gets a scorecard\nshowing current value, period-over-period change, trend direction, and the top\ndimension breakdown that explains any movement.\n\n---\n\n## CJA MCP Tools Used\n\n- `describeCja(DATAVIEW_CONTEXT_GUIDE)` — understand the data view context\n- `listComponentUsage` — find the most-used metrics (the org's real KPIs)\n- `findMetrics` — resolve metric IDs from user-specified names\n- `findCalculatedMetrics` — include custom KPIs if present\n- `runReport` — pull metric values for current and prior periods\n- `searchDimensionItems` — top dimension breakdown for movers\n\n---\n\n## Phase 0 — Setup\n\n1. Call `findDataViews` to list available data views.\n2. If the user hasn't specified a data view, present the list and ask which to use.\n3. Call `setDefaultSessionDataViewId` with the chosen ID.\n4. Call `describeCja(\"DATAVIEW_CONTEXT_GUIDE\")` to load data view context.\n   Record the data view's first-day-of-week as `WEEK_START_DOW` and timezone\n   as `TIMEZONE`. If the context guide does not return a week-start value,\n   default to **Monday** (ISO 8601). You will use both in Phase 1.1.\n5. Clarify the monitoring scope: which KPIs to track and the comparison period (e.g., WoW, MoM, vs. target).\n\n## Phase 1 — Clarify Scope\n\n### 1.1 Determine the reporting period\n\nIf the user did not specify a period, ask one question:\n> \"What time window would you like? Options: last 7 days, last 30 days, this\n> week vs last week, this month vs last month, or a custom range.\"\n\nDefault to **this week vs last week** if no answer is given.\n\nMap the answer to two date ranges:\n- **Period A** (current): e.g., \"thisWeek\", \"thisMonth\", last 7 days\n- **Period B** (comparison): e.g., \"lastWeek\", \"lastMonth\", prior 7 days\n\n**Calendar rule (mandatory):**\n\nUse `WEEK_START_DOW` from Phase 0 to define what \"week\" means. The current\nperiod (Period A) and the comparison period (Period B) MUST use the same\nfirst-day-of-week — i.e., both periods' `startDate` fall on the same\nday-of-week, both are exactly equal length, and the comparison period ends\nimmediately before the current period starts. Never mix conventions\n(e.g., a Mon–Sun current with a Sun–Sat prior) within the same pulse run.\nPick the boundary once, then derive both periods from it. For custom date\nranges, compute Period B as the equal-length window ending immediately\nbefore Period A starts.\n\n**Sanity check before calling `runReport`:** confirm `periodA.startDate` and\n`periodB.startDate` are the same day-of-week and that\n`periodA.startDate - periodB.endDate == 1 day`. If not, recompute.\n\n### 1.2 Determine the metrics\n\nIf the user named specific metrics, resolve them with `findMetrics` or\n`findCalculatedMetrics`. Otherwise, discover the top 5–8 KPIs automatically:\n\n```\nlistComponentUsage(componentType: \"metric\")\nlistComponentUsage(componentType: \"calculatedMetric\")\n```\n\nNote: `listComponentUsage` may return an empty list for data views with no\nusage history. If it returns empty, fall back to:\n```\nfindMetrics(searchQuery: \"sessions visits revenue orders\")\nfindMetrics(searchQuery: \"page views cart conversion\")\n```\nPick the most business-relevant metrics from the results (sessions, orders,\nrevenue, product views, cart views, people — in that priority order).\n\nDeduplicate: if a built-in metric and a calculated metric measure the same\nthing, keep only the calculated metric (it's more intentional).\n\nFinal list: 5–8 metrics. More than 8 KPIs in a pulse report is noise.\n\n---\n\n## Phase 2 — Pull Current and Prior Period Data\n\nRun a single `runReport` call per period with all KPI metrics included.\nUse one call for Period A and one for Period B to minimize round-trips.\nUse a summary dimension (e.g., `variables/daterangeday`) and limit: 1 to\nget aggregate totals from `summaryData.totals` in the response.\n\n```\nrunReport(\n  dimensionIds: \"variables/daterangeday\",\n  metricIds: \"metrics/visits,metrics/visitors,metrics/orders_1_1,metrics/productListItems.priceTotal,metrics/cart_views\",\n  startDate: \"<periodA start>T00:00:00\",\n  endDate: \"<periodA end>T23:59:59\",\n  page: 0,\n  limit: 1\n)\n```\n\n```\nrunReport(\n  dimensionIds: \"variables/daterangeday\",\n  metricIds: \"metrics/visits,metrics/visitors,metrics/orders_1_1,metrics/productListItems.priceTotal,metrics/cart_views\",\n  startDate: \"<periodB start>T00:00:00\",\n  endDate: \"<periodB end>T23:59:59\",\n  page: 0,\n  limit: 1\n)\n```\n\nRead aggregate totals from `summaryData.totals` (not row data), which\ngives you the full-period sum for each metric in the order they were listed.\n\nCapture for each metric:\n- `valueA` (current period)\n- `valueB` (comparison period)\n- `delta` = valueA − valueB\n- `pctChange` = (delta / valueB) × 100, rounded to 1 decimal\n\n---\n\n## Phase 3 — Classify Trends\n\nFor each KPI, assign a trend indicator:\n- **↑ Up** if pctChange > +3%\n- **↓ Down** if pctChange < −3%\n- **→ Flat** if −3% ≤ pctChange ≤ +3%\n\nAssign a signal color:\n- For \"higher is better\" metrics: ↑ = green, ↓ = red, → = grey\n- For \"lower is better\" metrics (bounce rate, error rate): ↑ = red, ↓ = green\n\n---\n\n## Phase 4 — Top Mover Drill-Down\n\nFor the 1–2 metrics with the largest absolute % change, find what's driving\nthe movement. Run a dimension breakdown for the current period:\n\n```\nrunReport(\n  dimensionIds: \"variables/marketing_channel\",\n  metricIds: \"<moving metric id>\",\n  startDate: \"<periodA start>T00:00:00\",\n  endDate: \"<periodA end>T23:59:59\",\n  page: 0,\n  limit: 5\n)\n```\n\nNote: Use `variables/marketing_channel` (not `variables/marketingchannel`) — \nverify the exact dimension ID with `findDimensions(searchQuery: \"marketing channel\")`\nif unsure.\n\nCompare dimension values between Period A and Period B to identify the top\ncontributor to the change. This becomes the \"What drove it\" entry in the report.\n\n---\n\n## Phase 5 — Generate HTML Report\n\nGenerate the KPI Pulse HTML report INLINE — do not use a Python script.\nBuild the HTML string directly from the collected data and output it as a\ncode block the user can save, or write it to `/tmp/cja_kpi_pulse_report_<YYYY-MM-DD_HHMMSS>.html`\nusing a one-line bash command.\n\n\n### Rendering rules — apply consistently across runs\n\nTwo runs of this skill on the same data view + period must render identically\n(modulo the generation timestamp). The rules below pin the formatting choices\nthat the AI would otherwise drift on.\n\n#### Number formatting\n\n- **KPI values** (the big number in each tile) — use full digits with\n  thousands separators (`8,160`, `77,584`, `1,250,000`). Do **NOT** use SI\n  suffixes like `K` or `M`, even for large values. Executives want exact\n  numbers, not abbreviations.\n- **Percent change** (in pills and narrative bullets) — always one decimal\n  place, rounded **half-away-from-zero**. For example, `−23.55%` displays as\n  `−23.6%`, never `−23.5%`. Compute on full-precision values; round only at\n  display time.\n- **Percentage-point change** (for already-percentage metrics like Conversion\n  Rate or Bounce Rate) — same rounding, suffix `pp`. Example: `+0.40 pp`.\n- **Currency** — `$` prefix with thousands separators and no decimals for\n  values ≥ $100 (`$1,240,000`); cents only when value < $100 (`$45.20`).\n\n#### Null / missing data handling\n\nA KPI tile must reflect what the data view actually returned. The AI must\n**not** silently substitute a different metric or hide a tile to make the\nreport look cleaner.\n\n- **Both periods return 0 or NULL** for a KPI being rendered: render the tile\n  with `kpi-value` = `Data unavailable`, pill class `flat`, pill text\n  `⚠ N/A`, and `prior` text = `Both periods returned no data — validate\n  instrumentation`. The tile stays in the grid; do not omit it.\n- **One period returns valid data, the other 0 / NULL**: render the tile with\n  the valid value as `kpi-value`, pill class `flat`, pill text `⚠ N/A`, and\n  `prior` text = `Prior {period_noun}: no data`.\n- **Never** substitute a derived metric (e.g., adding \"Conversion Rate\"\n  because Revenue came back $0). The visible KPI set MUST match the metrics\n  selected for this run.\n\n\n### HTML Template\n\nRead [`template.html`](template.html) and use it verbatim. Do not improvise the\nHTML structure or CSS — only fill in the `{PLACEHOLDER}` tokens (`{ORG_NAME}`,\n`{PERIOD_LABEL}`, `{COMPARISON_LABEL}`, `{DATA_VIEW}`, `{GENERATED_DATE}`,\n`{METRIC_NAME}`, `{FORMATTED_VALUE_A}`, `{FORMATTED_VALUE_B}`, `{PCT_CHANGE}`,\n`{VALUE_A}`, `{VALUE_B}`, `{DELTA}`, `{ARROW}`) and repeat the KPI tile / detail\nrow / mover row blocks once per data item. Preserve the `.up | .down | .flat`\nand `.green | .red | .yellow | .grey` modifier classes per the trend rules in\nPhase 3.\n\n\n---\n\n## Phase 6 — Deliver the Report\n\nAfter generating the HTML:\n1. Write it to `/tmp/cja_kpi_pulse_report_<YYYY-MM-DD_HHMMSS>.html`\n2. Open with `open /tmp/cja_kpi_pulse_report_<YYYY-MM-DD_HHMMSS>.html`\n3. Provide a 3–5 line text summary inline in the chat:\n\n```\nKPI Pulse — This Week vs Last Week\n\n↑ Revenue: $1.24M (+8.2%)  — Paid Search drove most of the gain\n↓ Conversion Rate: 2.1% (−0.4pp) — Drop in mobile checkout\n→ Sessions: 540K (+1.1%)  — Flat week-over-week\n↑ Orders: 11,340 (+6.7%)  — Product page improvements appear to be working\n↓ Bounce Rate: 43.2% (+2.1pp) — Worth monitoring next week\n```\n\nThe text summary gives immediate value even without opening the HTML file.\n\n---\n\n## Important Guardrails\n\n- **Read-only monitoring.** Never modify metrics, segments, or projects.\n- **Use consistent date ranges.** Week-over-week and month-over-month comparisons must use equal-length periods.\n- **Flag anomalies, don't diagnose them.** The pulse report surfaces significant deviations — deep root cause analysis belongs in the anomaly triage skill.\n- **Respect business calendar.** Holiday periods, campaigns, and seasonal patterns affect normal variance — note context when flagging anomalies.\n- **Cap metric count.** Monitor up to 10–15 KPIs per pulse; more than that dilutes focus. Ask the user to prioritize if they specify too many.\n- **Note data freshness.** If the most recent data point is older than expected, warn the user before presenting the pulse.\n\n## Example Interaction\n\n> \"Give me a quick pulse on our key metrics for this week.\"\n\n1. **Setup:** Confirm data view with `findDataViews`. User selects their main data view. Call `setDefaultSessionDataViewId`.\n2. **Scope:** Ask \"Which KPIs should I include?\" User says: \"Sessions, Revenue, Conversion Rate, and Average Order Value.\"\n3. **Data pull:** Run `runReport` for current week vs. prior week for all four metrics.\n4. **Analysis:** Sessions +8% WoW (within normal range). Revenue +3% WoW. Conversion Rate -12% WoW — flagged as anomalous. AOV +17% WoW — notable positive.\n5. **Summary:** Present a KPI scorecard with traffic-light status (green/yellow/red), highlight the Conversion Rate drop as needing investigation, and note that the AOV increase partially offsets it.\n\n## Error Handling\n\n- If `runReport` returns no data for Period B (comparison is too far in the\n  past or data view lacks history), show \"N/A\" for the delta and flag it with\n  a grey badge.\n- If a metric returns null, display \"—\" rather than 0 to avoid false\n  impressions of zero performance.\n- If fewer than 3 metrics are available, warn the user that the pulse may be\n  incomplete and suggest they verify the data view is correctly configured.\n"
}

SHA-256: eaebe231fd1ec8b2bb349c1593d2078287fb71a4562159f6face91790657330d