Executive-ready insights with trend analysis and visualizations — a FULL-FISCAL-YEAR narrative deck — multi-slide PowerPoint presentation plus a supporting Excel data book. For a one-month KPI snapshot use dashboard; for a 10-sheet analysis workbook (no PowerPoint) use intelligence.
Generate executive-ready insights with trend analysis, KPI dashboards, and professional visualizations.
Creates both PowerPoint presentations (for meetings) and Excel data books (for detailed analysis).
| Argument | Description | Default |
|---|---|---|
--year <YYYY> | Calendar year to analyze | Latest complete fiscal year in the data (see data-scope preamble) |
--quarter <Q#> | Quarter: Q1, Q2, Q3, Q4 | None — full-year scope unless given |
--period <period> | Combined period: YYYY-QX or YYYY-MM | Auto-determined |
--output-pptx <file> | PowerPoint output path | tmp/Insights_TIMESTAMP.pptx |
--output-xlsx <file> | Excel output path | tmp/Insights_Data_TIMESTAMP.xlsx |
Render only KPIs you can source. A KPI may come from (a) the org's metric catalog —
list_business_metrics(ungated) for discovery; theget_business_metric_*data tools are feature-gated and may be absent, and USER-kind metrics often return empty — or (b) aggregation over the discovered P&L grain (revenue, expense buckets, gross/operating margin when COGS/OpEx-like buckets exist). SaaS/unit-economics metrics (ARR, MRR, churn, LTV, CAC, burn, runway, NRR) are not derivable from a P&L table — include them only if discovered as populated metrics; otherwise omit the card/slide entirely. Never render a placeholder, estimate, or fabricated value for a KPI you could not source.
The KPIs below come from the org's metric catalog and are included only when discovered as populated metrics — otherwise their cards and slides are omitted entirely:
Catalog-sourced only — rendered when discovered as populated metrics, omitted otherwise:
Professional presentation, up to 7 slides — any KPI card or slide whose metrics could not be sourced is omitted (see the KPI-honesty rule under Key Performance Indicators):
Comprehensive workbook includes:
Summary Sheet
Recommendations Sheet
Metrics Sheet
Detailed Trends
Data Sources
start_aggregation_by_alias (or by-id) → poll
get_aggregation_result_by_alias (or by-id) with the handle until
ready (async-fetch pattern) — scoped to the requested period
(default: latest complete fiscal year or trailing 12 closed months),
filtered to the discovered scenario and P&L grain (data-scope
preamble, items 1–3)list_business_metrics;
compute P&L-derivable KPIs (revenue, expense buckets, margins) by
aggregating the financials table over the discovered grain
(start_aggregation_by_alias / start_aggregation_by_id → poll the
matching get_aggregation_result_by_* until ready).
Catalog-only KPIs are included solely when sourced — see the
KPI-honesty rule under Key Performance IndicatorsIf you already discovered these earlier in THIS conversation, reuse them — skip to fetching data. Discovery is cheap but not free; do it once per conversation, then carry the values forward.
list_data_models. Pick the financials table: the one whose name
(or alias) matches /financial|cube|p&?l|ledger|gl/i; if none match,
the largest by row count. Note both its numeric id
(<financials_table_id>) and its alias (the alias may be empty).
Prefer the alias path when an alias exists — friendlier field
names, far fewer tokens. For named KPIs (ARR, churn, LTV/CAC, etc.),
also call list_business_metrics and keep the flat list — each entry
carries id, name, description, category, kind,
dimensions[], status_info{}.
Fields. If the table has an alias, list_aliased_fields(<alias>);
otherwise get_fields_by_id(<financials_table_id>) (capture each
field's numeric id — the by-id tools address fields by id). Bind
these by case-insensitive match on the field alias/name (respecting
the noted type):
<amount_field> — numeric: ^amount$ → transaction_amount → value<scenario_field> — categorical: ^scenario$ → ^version$<date_field> — date/timestamp: reporting_date → posting_date → ^date$<account_level_fields> — categorical: all account-hierarchy
level fields, shallowest to deepest (names/aliases matching
patterns like dr_acc_l1/dr_acc_l2 → account_l1/account_l2
→ account_group_l1). Capture every level — do not assume the
L1-style level is the P&L grain; the grain is chosen from distinct
values in step 3 (a deeper level is often the detail dimension)Alias coverage is per field, not per table. A table having an alias does not mean its fields are aliased — real orgs often expose only a handful of aliased fields (e.g. ~5 of ~185 on a mapped financials table), and the load-bearing fields (
amount,scenario, account groups, dates) are frequently not among them. Treat the alias/by-id choice per field:get_fields_by_id(<id>)returns every field with its numericidand itsalias(empty if none). Address a field by alias (via the*_by_aliastools) when it has one, else by numericid(via the*_by_idtools). By-id always works — never abandon the query because the aliased set is thin.
If <amount_field> or <scenario_field> has no clear match, ask the
user which field to use, then continue.
Async fetch — aggregations and distinct values run as start → poll.
start_aggregation_by_id/_by_aliasandstart_distinct_values_by_id/_by_aliastake the same arguments as the retired blocking calls (dimensions/metrics/filters; table id + field id, or alias + field alias) and return immediately with{"status": "pending", "handle": {...}}. Echo thathandleback verbatim to the matchingget_aggregation_result_by_*/get_distinct_values_result_by_*tool: a{"status": "running", "retry_after_seconds": N}response means poll again with the same handle after ~N seconds (≈5s) — it is not an error, and large jobs may take several polls; when ready, the result arrives in the familiar shape (for distinct values, passlimitto the result tool). An expired/unknown-handle error means restart with thestart_*tool. Transitional fallback: if thestart_*tools aren't available on the connector (older server), the blocking twinsget_aggregated_data_by_*/get_distinct_values_by_*still work with the same arguments.
Data-scope discovery — run before any aggregate (reuse anything already discovered this conversation).
- Scenario domain. Pull distinct values of the scenario field (
start_distinct_values_by_alias/_by_id→ poll the matching result tool) — never assume a scenario name exists (Budgetfrequently doesn't; many orgs carry only{Actuals, Forecast}). For budget/plan questions, if no budget-like scenario exists, look for a planning-version-like field (alias/name matching/plan|version|cycle|budget/i) and use its versions as the plan side; if neither exists, say so and offer a comparison across the scenarios that do exist.- Account grain. Pull distinct values of each account-hierarchy level field (L0/L1/L2-like). Use the level whose values partition P&L flows into revenue/COGS/opex-like buckets — on many orgs the top level is the balance-sheet equation (ASSET/LIABILITY/EQUITY/INCOME) and P&L line items live one level deeper. For P&L work, scope to P&L flows and exclude balance-sheet buckets; never present asset/liability/equity totals as revenue or expenses.
- Period scope. Discover the date field's range (distinct values of the reporting-month field, or MIN and MAX in two separate calls — one aggregation per field per call). Default every P&L question to the latest complete fiscal year (or trailing 12 closed months) — never an unscoped all-time total: financials tables are multi-year cumulative and mix balance-sheet stock with P&L flow. Label every output with the period + scenario it covers.
- Reading GROUP BY responses. Each response returns exactly one row per requested group — no subtotal rows and no grand-total row. A total is obtained by summing the rows — there is no total row to read. Null groups arrive explicitly labeled
[null]and are real groups; read null counts from that bucket. Defensive filter: keep only rows in which every requested dimension key is present — a roll-up row omits one or more keys entirely, whereas a genuine null is present with the value[null]. On a correct response this is a no-op; it guards against a stale cached response still carrying legacy subtotal and grand-total rows, each of which equals the whole total and would inflate any sum. When COUNT-ing rows per group, aggregate a different field than the GROUP BY dimension itself — a same-field COUNT of the grouped dimension can 500.- Truncated results. Any data tool may return
{"data": [...], "truncated": true, "total_rows": N, "returned_rows": M, "guidance": "..."}when the result exceeds the response size limit (~100 KB). Thedataprefix is incomplete — never compute totals, shares, or trends from it, and never present it as the full result. Follow theguidance: narrow the query (fewer dimensions, more filters, fewer selected columns) or use a business metric for a named KPI, then re-fetch.
Bind the P&L grain and its category values (preamble item 2 above):
pull distinct values of each account-level field, shallowest first —
start_distinct_values_by_alias(<alias>, <field>) (or
start_distinct_values_by_id(<financials_table_id>, <field_id>)) →
poll the matching get_distinct_values_result_by_*(handle, limit)
until ready (async-fetch pattern).
If a distinct call errors, fall back to
get_data_by_alias(<alias>, select=[<field>], limit=500)
(or the by-id twin) and collect the distinct values. The level whose
values partition P&L flows into revenue/COGS/opex-like buckets is
<account_grain_field>. Match its values:
<revenue_value> ← /revenue|sales|income/i<cogs_value> ← /cogs|cost of goods|cost of sales|direct cost/i<opex_value> ← /operating|opex|expense|sg&a/iScope every P&L figure to these flow buckets and exclude balance-sheet buckets (asset/liability/equity-like values). If a category has several candidates at the grain, pick the broadest one; if genuinely ambiguous, ask the user once.
Aggregation-field failures are handled reactively (see Error Handling), not pre-probed. On auth/connection failure during discovery: show the reconnect message and STOP — do not generate reports without fresh data.
[null] bucketWhen generating Excel or PowerPoint files, apply Datarails brand styling:
Font: Poppins (fall back to Calibri if unavailable). Weights: 400 regular, 600 semibold, 700 bold.
Colors:
| Role | Hex | Use |
|---|---|---|
| Navy | 0C142B | Header/banner background |
| Main text | 333333 | Primary text |
| Secondary | 6D6E6F | Muted/subtitle text |
| Border | 9EA1AA | Cell borders |
| Section bg | F2F2FB | Section header / row header background (lavender) |
| Input bg | EAEAFF | Editable/input cell background |
| Input text | 4646CE | Editable cell text (indigo) |
| Favorable | 2ECC71 | Positive variance / good KPI delta |
| Unfavorable | E74C3C | Negative variance / bad KPI delta |
| Chart 1 | 0C142B | Actuals (navy) |
| Chart 2 | F93576 | Budget (hot pink) |
| Chart 3 | 00B4D8 | Teal |
| Chart 4 | FFA30F | Amber |
Excel layout:
Number formats: _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) (default), $#,##0 (dollars), $#,##0.0,,"M" (millions), 0.0% (percent)
Variance coloring: Any cell showing a delta/change: green (2ECC71) if favorable, red (E74C3C) if unfavorable. Apply automatically based on value sign and metric context.
PowerPoint: Navy (0C142B) background, 16:9 widescreen, Poppins font, white text, amber (FFA30F) accent lines, card backgrounds 001F37.
If asked to add live / refreshable Datarails formulas (DR.GET) to a generated workbook, the only valid form is:
=DR.GET(Value, "[DimensionName]", CellRef, "[DimensionName]", CellRef, ...)=DR.GET(Value,"financials","Amount","SUM",...)
is invented syntax that the Datarails Add-in cannot parse or refresh."[Scenario]").
Dimension values are always cell references, never hardcoded strings.Value
referring to the string constant "Value"
(wb.defined_names.add(DefinedName("Value", attr_text='"Value"'))) —
otherwise Excel autocorrects the bare token to its built-in VALUE() and
the formula breaks.=DR.GET(...) only — never wrapped in IFERROR/IF/ROUND.The get-formula skill (/dr-get-formula) is the full reference — parameter
cells, validated dimension values, report layouts. Prefer it for whole formula
workbooks; apply this contract when adding DR.GET formulas to a workbook here.
/dr-insightsOutput (period and scenario values are illustrative — both come from discovery):
📊 Generating insights for FY2025 (latest complete fiscal year) · Scenario: Actuals...
📊 Fetching P&L trends...
📈 Fetching KPI metrics...
💡 Calculating insights...
📄 Generating PowerPoint presentation...
📋 Generating Excel data book...
✅ Insights generated successfully
==================================================
INSIGHTS GENERATED
==================================================
Period: FY2025 · Scenario: Actuals
Key Findings: 5
Outputs:
PowerPoint: tmp/Insights_2026-02-03_143022.pptx
Excel: tmp/Insights_Data_2026-02-03_143022.xlsx
==================================================/dr-insights --year 2025 --quarter Q4/dr-insights --period 2026-01/dr-insights --year 2025 --quarter Q4 \
--output-pptx reports/Q4_2025_Insights.pptx \
--output-xlsx reports/Q4_2025_Data.xlsx/dr-insights --quarter Q4 --year 2025
# Use PowerPoint for board meeting# Weekly insights
/dr-insights# Comprehensive analysis for stakeholders
/dr-insights --year 2025 --quarter Q4# Professional presentation for investors
/dr-insights --quarter Q4 --year 2025# Share with teams for transparency
/dr-insightsPer the KPI-honesty rule (see Key Performance Indicators): P&L-derived metrics render whenever the discovered grain supports them; catalog-only metrics render only when discovered as populated metrics — otherwise their cards and slides are omitted entirely, never estimated.
Growth Metrics (revenue growth is P&L-derived; ARR is catalog-only):
Profitability Metrics (P&L-derived when COGS/OpEx-like buckets exist at the discovered grain):
Unit Economics (catalog-only — omitted unless sourced):
Cash Metrics (catalog-only — omitted unless sourced):
Churn & Retention (catalog-only — omitted unless sourced):
Fast processing via efficient MCP aggregation tools.
"Not authenticated" error
Aggregation field rejected (500)
"No KPI data found" warning
list_business_metrics returned no named KPIs, or the financials
table had no usable data to compute them — agent adapts and focuses
on P&L trends"Incomplete data for period" warning
/dr-anomalies-report - Data quality assessment/dr-reconcile - P&L vs KPI validation/dr-dashboard - Executive KPI monitoring/dr-extract - Full financial data extraction# Schedule weekly insights
0 8 * * 1 /dr-insights --env app --output-pptx tmp/weekly_insights.pptx# Generate for multiple quarters
/dr-insights --year 2025 --quarter Q1 --output-pptx tmp/Q1.pptx
/dr-insights --year 2025 --quarter Q2 --output-pptx tmp/Q2.pptx
# Compare side-by-side# Export data in custom location
/dr-insights --env app \
--output-xlsx /shared/reports/latest_analysis.xlsx \
--output-pptx /shared/reports/latest_presentation.pptxInsights adapt automatically to whatever the discovery step (Phase 1) finds in the client's environment:
list_business_metrics surfaces)No setup or profile file is needed — the skill rediscovers the table and fields on each cold session.
Reports include generation timestamp. Data reflects:
For historical comparison, generate reports for multiple periods.
0a038a3
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.