Install
$ agentstack add skill-adobe-skills-cja-executive-briefing ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Executive Briefing (Customer Journey Analytics)
Produce a polished, leadership-ready performance document. Executives do not read data tables — they read narratives that answer "are we growing?", "what changed?", and "what do we do about it?"
This skill converts CJA data into a briefing that a VP or C-suite leader can read in under 3 minutes, with supporting data available for those who want to dig deeper.
Tone: business impact, not technical metrics. Write "Revenue grew 12% driven by a strong Paid Search week" not "metrics/revenue increased by 0.12 per metrics/sessions."
CJA MCP Tools Used
describeCja(DATAVIEW_CONTEXT_GUIDE)— understand the business context of the data viewlistComponentUsage— identify the north-star and supporting KPIsfindMetrics— resolve user-specified or discovered metric IDsfindCalculatedMetrics— include custom business KPIsrunReport— pull KPI values for current and comparison periodsearchDimensionItems— identify top driver dimension values
Phase 0 — Setup
- Call
findDataViewsto list available data views. - If the user hasn't specified a data view, present the list and ask which to use.
- Call
setDefaultSessionDataViewIdwith the chosen ID. - Confirm the reporting period (default: last 7 days) and the audience for the briefing (executive, board, team lead).
Phase 1 — Establish Context
1.1 Load data view context
Call describeCja("DATAVIEW_CONTEXT_GUIDE") to understand:
- What business the data view represents (e-commerce, media, SaaS, etc.)
- The primary conversion event and revenue metric
- Calendar conventions and timezone. Record these values — they are
inputs to every date computation in 1.2:
WEEK_START_DOW— day of week each week starts on (Sunday, Monday, …).
Default: Monday (ISO 8601) if the context guide doesn't specify.
FISCAL_YEAR_START_MONTH— month the fiscal year begins. Default:
January (calendar year) if the context guide doesn't specify.
TIMEZONE— for example,America/Los_Angeles.CALENDAR_SOURCE— one of"context guide"(values came fromdescribeCja),
"default fallback" (the context guide didn't expose them and you used the defaults above), or "user override" (the user explicitly specified them).
This context determines what counts as the "north-star metric" and what language to use in the narrative (e.g., "subscribers" vs "customers" vs "users").
1.2 Determine reporting period
Infer the period type from the user's request. Do not stop to ask — proceed immediately.
The principle
Two runs of this skill on the same data view, period type, and prompt MUST produce identical current and comparison date ranges. Determinism comes from (a) reading calendar conventions from 1.1 instead of improvising, and (b) applying the alignment rule for the period type without taste calls.
Period type → alignment rule
Pick exactly one period type from the user's request:
| User request | PERIOD_TYPE | Current period | Comparison period | |---|---|---|---| | "last week" / unspecified | weekly | Most recent full week ending before today, aligned to WEEK_START_DOW (exactly 7 days) | The week immediately before, same alignment | | "this month" / "MTD" | month-to-date | 1st of current month → today | 1st of prior month → same day-of-month as today | | "last month" | monthly | Prior full calendar month (1st → last day) | The month before that | | "this quarter" / "QTD" | quarter-to-date | Start of current fiscal quarter → today; fiscal quarters derived from FISCAL_YEAR_START_MONTH | Same days into the prior fiscal quarter | | "last quarter" / "Q[N]" | quarterly | Prior full fiscal quarter | The fiscal quarter before that | | Custom date range | custom | Use as specified | Equal-length window ending the day before current.startDate |
Universal invariants (must hold for every period type)
Before calling runReport, verify all six:
- `current.startDate T00:00:00",
endDate: "T00:00:00", dimensionIds: "variables/daterangeday", metricIds: "metrics/visits,metrics/orders11,metrics/revenue1,...", page: 0, limit: 1 ) runReport( startDate: "T00:00:00", endDate: "T00:00:00", dimensionIds: "variables/daterangeday", metricIds: "metrics/visits,metrics/orders11,metrics/revenue1,...", page: 0, limit: 1 )
Read `summaryData.filteredTotals` from each response — the values correspond to
the metrics in the order they were specified in `metricIds`.
Compute for each KPI:
- `current` value
- `prior` value
- `delta` = current − prior
- `pctChange` = delta / prior × 100
- `direction`: up / down / flat (using ±3% threshold)
- `polarity`: positive if higher is better, negative if lower is better
- `signal`: green (favorable), red (unfavorable), yellow (mixed/flat)
---
## Phase 4 — Find What Drove the Movement
For the 2 KPIs with the largest absolute % change, find the top driver:
Run current and prior period breakdown reports in parallel:
runReport( startDate: "", endDate: "", dimensionIds: "variables/marketingchannel", metricIds: "", limit: 5 ) runReport( startDate: "", endDate: "", dimensionIds: "variables/marketingchannel", metricIds: "", limit: 5 )
Compare channel-level values between periods to find which dimension value's delta
most closely mirrors the overall metric change. This becomes the "driven by" phrase
in the narrative.
Only run dimension breakdowns for the 2 most-moved metrics (by absolute % change).
This constraint exists because: (a) more breakdowns add latency without adding
executive value, and (b) the two largest movers are what leadership will ask about
first. The remaining KPIs get context from the narrative without needing attribution.
If `variables/marketing_channel` returns no useful breakdown (e.g., only one
channel has data), try `variables/page_type` or `variables/product_category`
as alternative driver dimensions.
---
## Phase 5 — Write the Executive Narrative
Compose 3–5 bullet points as the narrative. Each bullet follows this structure:
**[Signal emoji] [Metric]: [Value] ([+/-pctChange%] vs [prior period]) — [Plain-English context]**
Guidelines:
- Open with the most important finding (highest-impact metric, positive or negative)
- Use business language: "revenue," "customers," "conversions" — not "metrics/revenue"
- Name the driver when known: "driven by Paid Search," "led by Product Page improvements"
- Include one forward-looking note if relevant: "This trend should be monitored..."
- For negative trends: be direct but not alarming. Suggest investigation, not panic.
Examples of well-written bullets:
- "Revenue reached $1.24M last week, up 8.2% vs prior week — Paid Search drove the majority of the gain (+$82K)."
- "Conversion Rate declined to 2.1% (−0.4pp), primarily on mobile. Desktop conversion remained stable at 3.4%."
- "Sessions were flat at 540K (+1.1%) — organic and direct traffic offset a reduction in email campaign sends."
- "Bounce Rate ticked up to 43% (+2pp). No single driver identified; worth monitoring through end of month."
---
## Phase 6 — Generate the HTML Briefing Document
Generate the briefing inline. Write to `/tmp/cja_executive_briefing_.html`.
This document should look polished enough to share with leadership — not a
developer tool output.
### Rendering rules — apply consistently across runs
Two runs of this skill on the same data view + period must render identically
(modulo the generation timestamp). The rules below pin the formatting choices
that the AI would otherwise drift on.
#### Number formatting
- **KPI values** (the big number in each tile) — use full digits with
thousands separators (`8,160`, `77,584`, `1,250,000`). Do **NOT** use SI
suffixes like `K` or `M`, even for large values. Executives want exact
numbers, not abbreviations.
- **Percent change** (in pills and narrative bullets) — always one decimal
place, rounded **half-away-from-zero**. For example, `−23.55%` displays as
`−23.6%`, never `−23.5%`. Compute on full-precision values; round only at
display time.
- **Percentage-point change** (for already-percentage metrics like Conversion
Rate or Bounce Rate) — same rounding, suffix `pp`. Example: `+0.40 pp`.
- **Currency** — `$` prefix with thousands separators and no decimals for
values ≥ $100 (`$1,240,000`); cents only when value
Performance Briefing — {ORG_NAME} — {PERIOD}
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f5f4f1;
--surface: #ffffff;
--ink: #1a1a1a;
--ink-muted: #6b6b6b;
--border: #e5e2dc;
--header-bg: #0e0e10;
--header-warm: #3a1010;
--accent-red: #c8312f;
--accent-red-bright: #ff6b68;
--accent-red-soft: #fdecea;
--accent-green: #1f7a4d;
--accent-yellow: #d4a017;
}
body { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg); color: var(--ink); line-height: 1.5;
-webkit-font-smoothing: antialiased; }
/* === Header === */
header { background: linear-gradient(120deg, var(--header-bg) 0%, #1a0d0d 55%, var(--header-warm) 100%);
color: #fff; padding: 56px 56px 44px; position: relative; overflow: hidden; }
header::after { content: ""; position: absolute; right: -140px; top: -140px;
width: 460px; height: 460px;
background: radial-gradient(circle, rgba(200,49,47,.35) 0%, transparent 70%);
pointer-events: none; }
.header-inner { max-width: 1080px; margin: 0 auto; position: relative; z-index: 1; }
.eyebrow { display: inline-flex; align-items: center; gap: 8px;
padding: 6px 14px; border: 1px solid rgba(255,107,104,.55);
border-radius: 999px; color: var(--accent-red-bright);
font-size: 11px; font-weight: 600; letter-spacing: 1.2px;
text-transform: uppercase; margin-bottom: 24px;
background: rgba(200,49,47,.10); }
.eyebrow::before { content: ""; width: 6px; height: 6px;
background: var(--accent-red-bright); border-radius: 50%; }
header h1 { font-family: "Playfair Display", Georgia, serif;
font-size: 56px; font-weight: 700; letter-spacing: -1.5px;
line-height: 1.05; margin-bottom: 14px; }
header .lede { font-size: 16px; max-width: 560px;
color: rgba(255,255,255,.80); margin-bottom: 24px;
line-height: 1.55; }
header .meta { display: flex; flex-wrap: wrap; gap: 22px;
font-size: 13px; color: rgba(255,255,255,.60); }
header .meta span { display: inline-flex; align-items: center; gap: 6px; }
header .meta .icon { opacity: .8; }
/* === Tabs === */
nav { background: var(--surface); border-bottom: 1px solid var(--border);
padding: 0 56px; display: flex; gap: 28px;
position: sticky; top: 0; z-index: 50; }
nav a { display: block; padding: 16px 0; font-size: 14px;
color: var(--ink); text-decoration: none;
border-bottom: 2px solid transparent;
transition: border-color .15s ease; }
nav a:hover { border-bottom-color: var(--accent-red); }
/* === Container === */
.container { max-width: 1080px; margin: 0 auto; padding: 36px 56px 60px; }
/* === Callout === */
.callout { background: var(--accent-red-soft);
border-left: 4px solid var(--accent-red);
border-radius: 6px;
padding: 18px 22px; margin-bottom: 32px;
display: flex; gap: 14px; align-items: flex-start; }
.callout .warn-icon { font-size: 22px; line-height: 1; flex-shrink: 0;
color: var(--accent-yellow); }
.callout-title { font-weight: 700; color: var(--accent-red);
margin-bottom: 4px; font-size: 15px; }
.callout-body { font-size: 14px; color: #4a2222; line-height: 1.55; }
.callout.note { background: #fdf6e7; border-left-color: var(--accent-yellow); }
.callout.note .callout-title { color: #8a5a08; }
.callout.note .callout-body { color: #5a4108; }
/* === Section label === */
.section-label { font-size: 11px; font-weight: 700;
text-transform: uppercase; letter-spacing: 1.4px;
color: var(--ink-muted); margin-bottom: 14px;
padding-bottom: 10px; border-bottom: 1px solid var(--border); }
/* === KPI grid === */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px; margin-bottom: 36px; }
.kpi-tile { background: var(--surface); border-radius: 8px;
padding: 22px 22px 20px;
border-top: 3px solid #b9b6ae;
box-shadow: 0 1px 3px rgba(0,0,0,.05); }
.kpi-tile.down { border-top-color: var(--accent-red); }
.kpi-tile.up { border-top-color: var(--accent-green); }
.kpi-tile.flat { border-top-color: #b9b6ae; }
.kpi-head { display: flex; justify-content: space-between;
align-items: center; margin-bottom: 10px; }
.kpi-label { font-size: 11px; font-weight: 700;
text-transform: uppercase;
color: var(--ink-muted); letter-spacing: 1px; }
.kpi-value { font-family: "Playfair Display", Georgia, serif;
font-weight: 700; font-size: 38px;
line-height: 1; color: var(--ink);
margin-bottom: 12px; }
.pill { display: inline-flex; align-items: center; gap: 4px;
padding: 3px 9px; border-radius: 4px;
font-size: 12px; font-weight: 600; line-height: 1.4; }
.pill.down { background: var(--accent-red-soft); color: var(--accent-red); }
.pill.up { background: #ebf5ef; color: var(--accent-green); }
.pill.flat { background: #f1efea; color: var(--ink-muted); }
.prior { display: block; margin-top: 10px;
font-size: 12px; color: var(--ink-muted); }
/* === Narrative === */
.narrative-card { background: var(--surface); border-radius: 8px;
padding: 32px 36px;
box-shadow: 0 1px 3px rgba(0,0,0,.04);
margin-bottom: 24px; }
.narrative-card h2 { font-family: "Playfair Display", Georgia, serif;
font-size: 24px; font-weight: 700;
margin-bottom: 18px;
padding-bottom: 12px;
border-bottom: 1px solid var(--border); }
.bullet-list { list-style: none; }
.bullet-list li { padding: 14px 0; font-size: 15px; line-height: 1.65;
border-bottom: 1px solid #f1eeea; }
.bullet-list li:last-child { border-bottom: none; }
.bullet-list .signal { margin-right: 6px; }
.bullet-list .metric-highlight { font-weight: 700; }
.bullet-list .driver { color: var(--accent-red); font-style: italic; }
/* === Sections (collapsible tables) === */
.section { background: var(--surface); border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,.04);
margin-bottom: 22px; overflow: hidden; }
.section-header { padding: 18px 28px; border-bottom: 1px solid var(--border);
display: flex; justify-content: space-between;
align-items: center; cursor: pointer; }
.section-header h2 { font-family: "Playfair Display", Georgia, serif;
font-size: 18px; font-weight: 700; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th { background: #faf8f4; padding: 12px 22px;
text-align: left; font-weight: 600;
text-transform: uppercase; letter-spacing: .6px;
font-size: 11px; color: var(--ink-muted);
border-bottom: 1px solid var(--border); }
tbody td { padding: 12px 22px; border-bottom: 1px solid #f4f1eb; }
tbody tr:last-child td { border-bottom: none; }
.badge { display: inline-block; padding: 3px 9px; border-radius: 4px;
font-size: 11px; font-weight: 600; }
.badge.green {
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [adobe](https://github.com/adobe)
- **Source:** [adobe/skills](https://github.com/adobe/skills)
- **License:** Apache-2.0
- **Homepage:** https://www.adobe.com/ai/overview.html
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.