- name
- moody-s-rating-analysis
- description
- Produce a Rating Pitch Deck for a company using Moody's GenAI MCP tools, delivered as an editable PowerPoint (.pptx) saved to disk. Use this skill whenever the user asks to create a rating pitch, rating pitch deck, credit pitch, rating presentation, or rating pitch report. Also trigger when they ask for a comprehensive credit overview combining sector analysis, company financials, SWOT, peer comparison, and ESG into a single deck or presentation. Trigger even if they just name a company and say "pitch deck", "rating deck", or "credit deck".
# Rating Pitch Skill
Generates a Moody's Rating Pitch Deck as an editable PowerPoint (.pptx) from a single MCP
data pass. The Python builder (`scripts/build_pptx.py`) opens the official Moody's Corp 2026
PowerPoint template, removes its demo slides, and populates the template's built-in layouts
(Cover, Agenda, Dividers, 1/2/3-column content, Back Cover, Disclaimer) with the resolved
payload data. The builder produces native, editable PowerPoint charts and tables end-to-end —
no HTML preview, no in-chat artifact.
> ## ⚠️ CRITICAL — NON-NEGOTIABLE OUTPUT CONTRACT
>
> Every run of this skill MUST produce an editable `.pptx`. Specifically:
>
> - The skill **MUST** save the resolved `payload.json` to
> `~/Desktop/rating-pitch/<company>-<YYYYMMDD-HHMMSS>/` and run `scripts/build_pptx.py`
> against it to produce the editable `rating_pitch.pptx` alongside it.
> - The LLM **MUST NOT** stream the deck content as inline HTML, Markdown, JSON dumps, or
> any other in-chat artifact in lieu of building the `.pptx`. The `.pptx` itself is the
> deliverable.
> - The final assistant message **MUST** point the user at the full path to the generated
> `rating_pitch.pptx` so they can open it.
> - If data gathering fails partially, still build the `.pptx` from the partial payload
> using `"--"` placeholders for missing values — never skip the build.
>
> Treat any other output shape as a hard failure of the skill.
## Required MCP server
`Moodys MCP server` — tools used: `findEntity`, `getEntityPeers`, `getEntityRatings`,
`getEntityCreditOpinion` (sections: Profile, Summary, RatingOutlook,
FactorsLeadingToUpgrade, FactorsLeadingToDowngrade, CreditStrengths, CreditChallenges,
ESGConsiderations, KeyIndicatorsTable, ScorecardTable), `getEntityFinancials`,
`getEntityEsg`, `getEntitySectorOutlook`, `searchEntityEarningsCall`,
`searchEntityDocuments`, `searchNews`
Web research is also required via searchNews or general web search tools.
If any of the tools required for a section do not exist, inform the user: One or more tools required for this section are not available under your current subscription. Unlock more of the expert insights, data, and analytics you trust. Get Link:https://www.moodys.com/web/en/us/capabilities/gen-ai/ai-ready-data.html with us to learn more.
## Bundled files
- `scripts/build_pptx.py` — the deck builder. Takes a JSON payload and emits a `.pptx`.
- `scripts/requirements.txt` — Python dependencies (`python-pptx`). Unchanged.
- `assets/Moody_Corp_Template.pptx` — official Moody's 2026 Corp PowerPoint template.
The builder opens this file, clears its demo slides, and populates its layouts.
**Do not modify.**
- `assets/sample_payload.json` — reference payload showing every field populated. Read this
if you're ever unsure what a field should look like.
## Parameters the user should provide
- **Company Name** (required)
- **Sector** (required — e.g., "Aerospace/Defense", "Consumer Products"). Infer it from
the company if the user doesn't say.
- **Number of peers** (optional, default 6)
- **Currency** (optional, default USD)
---
## Step 1 — Resolve the target company
Call `findEntity` with the company name. Store the canonical entity name and ID.
## Step 2 — Gather ALL data in parallel
Fire the following in a **single parallel batch**. Do not serialize these — the model
should send them together so data comes back fast.
### Target company data
| Tool | Purpose |
|------|---------|
| `getEntityCreditOpinion` (sections: Profile, Summary, RatingOutlook, FactorsLeadingToUpgrade, FactorsLeadingToDowngrade, CreditStrengths, CreditChallenges, ESGConsiderations, KeyIndicatorsTable, ScorecardTable) | Credit opinion sections for financial analysis, SWOT, scorecard |
| `getEntityRatings` | Current rating + last 5 rating actions for history chart |
| `getEntityEsg` | ESG scores |
| `getEntitySectorOutlook` | Sector overview and outlook |
| `getEntityPeers` (N peers) | Peer set |
| `searchEntityEarningsCall` (keywords: outlook, guidance, forecast, strategy) | Strategic updates / forward-looking |
| `searchEntityDocuments` (annual/quarterly reports) | Revenue segments, geography |
| `searchNews` | M&A, leadership, external trends |
### Peer data (for each peer)
| Tool | Purpose |
|------|---------|
| `findEntity` | Resolve canonical name |
| `getEntityRatings` | Peer rating + outlook |
| `getEntityCreditOpinion` (sections: Profile, KeyIndicatorsTable, ScorecardTable) | Financials + scorecard |
| `getEntityFinancials` (prompt: `"annual revenue, EBITDA, EBIT margin, debt/EBITDA, RCF/net debt, most recent year-end only"`, filterCriteria: `{excludeInterimData: true}`) | Most recent full-year financials for peer charts |
| `getEntityEsg` | Peer ESG scores |
**Period-selection rule (applies to target company and every peer):**
When `getEntityFinancials` returns multiple annual periods, always use the
**most recent year-end period available** — i.e. the column with the highest
calendar or fiscal year. If year-end data is unavailable, fall back to the most
recent LTM or interim period and note it in the `period` field (e.g. `"LTM Mar 2025"`).
Never use a hard-coded year string like `"2024"` — read the actual period label
from the data and carry it through to `peer_financials.rows[].period` and
`peer_profitability_charts` / `peer_debt_charts` entries.
---
## Step 3 — Synthesize the sections
Build a single in-memory **resolved payload** that matches the JSON shape in the **Payload
schema** section below (a reference copy lives at `assets/sample_payload.json`). This
payload drives the `.pptx` build (Step 4) — fill it completely before moving on.
Content rules for each section:
> **`commentary` type rule — applies to every section without exception:**
> All `commentary` fields in the payload MUST be a **JSON array of strings** — never a
> bare string. A bare string passed to the `.pptx` builder is iterated character-by-character,
> producing one bullet per character (the `• C \n • o \n • m` bug). Always write:
> `"commentary": ["Sentence one.", "Sentence two."]` — even for a single sentence.
### Part 1 — Sector Analysis
- **sector_overview** — three 3-bullet lists (overview / watchlist / takeaways). Keep
bullets punchy, ≤25 words each.
- **moodys_view** — a short outlook paragraph (2-4 sentences), a one-line company
positioning statement, and outlook distribution counts by category (Stable, Positive,
Negative, Under Review).
- **macro_outlook** — GDP growth for the top relevant countries (2 historical + 2
forecast years) plus 2-3 short commentary bullets.
- **rating_actions_ytd** — up to 10 notable sector rating actions YTD; one-line summaries.
### Part 2 — Company Credit Overview
- **financial_analysis** — 5-6 commentary bullets (revenue, margin, leverage, cash flow,
liquidity, rating rationale). Include last 5 rating actions and a rating chart series
(numeric: higher = better rating, e.g., Aaa=21, Baa3=10, Caa1=4).
**`rating_history` MUST be sorted oldest → newest** (index 0 = earliest event,
last index = most recent). `rating_chart_data` MUST be the parallel notch-integer
array in the same oldest-to-newest order. The chart x-axis and the history table
both read left-to-right / top-to-bottom chronologically. `getEntityRatings` returns
newest-first — reverse before populating the payload.
- **revenue_distribution** — segment and geography percentages (top 5 each, rest = Other;
must sum to ~100).
- **swot** — 3 items per quadrant, 15-25 words each.
- **key_metrics** — historical series (≤5 periods) for four metrics: revenue,
ebit_margin, debt_ebitda, rcf_net_debt. Arrays must match the `periods` array length.
Use `null` (not omission) for missing points.
- **strategic_updates** — `recent` (3-5) and `forward` (3-5, strictly future-looking).
- **news_mna** / **external_trends** — structured list form:
`[{"category": "...", "items": ["...", "..."]}]`. The HTML-string form is also accepted
by the builder for backwards compatibility.
### Part 3 — Company Positioning vs. Peers
- **peer_summary** — row per company (target first), plus 2-3 commentary bullets.
- **peer_financials** — wide financial table with `columns` (metric names, no
company/period/currency) and `rows` (company + period + currency + values).
Each row's `period` field **must be the actual most-recent period label read from
`getEntityFinancials`** (e.g. `"FY2025"`, `"FY2024"`, `"LTM Mar 2025"`). Never
default all rows to the same hard-coded year. Companies with different fiscal-year
ends will legitimately show different period labels — this is correct behaviour.
- **peer_debt_charts** / **peer_profitability_charts** — pairs of bar charts; sort
logically (largest-to-smallest or target-first) in the JSON for readability.
Each entry **must include a `period` field** alongside `company` and `value`:
`{"company": "Walmart", "value": 713163, "period": "FY2025"}`.
The `period` is used as a sub-label on the bar. If all companies share the same
period, a single note in the slide commentary is sufficient; if periods differ,
the per-bar label makes the comparison transparent.
- **peer_scatter** — two scatter series (`margin_vs_leverage`, `fcf_vs_rcf`), each a list
of `{company, x, y}` points. Drop extreme outliers that would distort the axes.
- **scorecard** — `factors` (row labels, including group headers), `is_header` boolean
flags per row, `companies` (column headers), and `values` as a 3D array: outer = rows,
middle = columns, inner = `[measure, score]` or `[]` for header rows.
- **esg_analysis** — table of CIS/E/S/G scores plus 3-5 commentary bullets.
Target first in every peer table.
---
## Step 4 — Build the editable .pptx
**Default output location: always save runs to the user's Desktop** so they're easy to
find. Use `~/Desktop/rating-pitch/<company>-<YYYYMMDD-HHMMSS>/` as the `<output-dir>`.
Only use a different path if the user explicitly asks for one.
1. Save your resolved payload to `<output-dir>/payload.json`.
2. Ensure `python-pptx` is available. If the user doesn't have it:
```bash
python3 -m venv .venv && .venv/bin/pip install -r <skill-dir>/scripts/requirements.txt
```
or simply `pip install python-pptx` if their environment allows it.
3. Run the builder:
```bash
python3 <skill-dir>/scripts/build_pptx.py <output-dir>/payload.json <output-dir>/rating_pitch.pptx
```
4. Open the deck: `open <output-dir>/rating_pitch.pptx`
5. The final assistant message gives the full `<output-dir>/rating_pitch.pptx` path so the
user can open the editable deck.
If any section data is missing, still include the section in the payload (empty arrays
are fine) — the builder handles empties gracefully and the deck will stay well-formed.
---
## Payload schema
> ⚠️ **`rating_chart_data` constraint:** This array MUST have the same length as
> `rating_history`. Index `i` must match: `rating_history[i] ↔ rating_chart_data[i]`.
> Both arrays must be sorted **oldest → newest**.
```json
{
"report_date": "April 15, 2026",
"target_company": "Boeing Company (The)",
"sector": "Aerospace/Defense",
"currency": "USD",
"companies": ["Boeing", "RTX", "Northrop Grumman", "..."],
"sources": [
{"title": "", "source": "", "date": "", "url": "", "tool": ""}
],
"sections": {
"sector_overview": {
"overview_bullets": ["...", "...", "..."],
"watchlist_bullets": ["...", "...", "..."],
"takeaway_bullets": ["...", "...", "..."]
},
"moodys_view": {
"outlook_summary": "Two to four sentences (plain text or <p>...</p>).",
"company_positioning": "One-line positioning statement.",
"outlook_distribution": [
{"category": "Stable", "count": 11, "color": "#BDBFC3"},
{"category": "Positive", "count": 5, "color": "#5EB6BB"},
{"category": "Negative", "count": 3, "color": "#F09613"},
{"category": "Under Review", "count": 1, "color": "#ED1B2E"}
]
},
"macro_outlook": {
"gdp_table": {
"year_columns": ["2023", "2024", "2025F", "2026F"],
"rows": [{"country": "United States", "values": ["2.9", "2.8", "2.0", "1.8"]}]
},
"gdp_commentary": ["...", "...", "..."]
},
"rating_actions_ytd": [
{"date": "Nov 20, 2025", "company": "...", "summary": "..."}
],
"financial_analysis": {
"commentary": ["...", "..."],
"rating_history": [
{"date": "Sep 2025", "rating": "Baa3", "outlook": "Negative",
"direction": "Affirmation", "reason": "..."}
],
"rating_chart_data": [8, 8, 7, 7, 7]
},
"revenue_distribution": {
"by_segment": [{"name": "Commercial Airplanes", "percentage": 45.2}],
Ver no GitHub