{"id":9596,"plugin_id":"plugin_asdk_app_6a215179debc8191a28dd0f3723c0646","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T22:55:15.044Z","digest":"3c3f5e7ed809bb46868e56c01a4406536332bd52eb5b64455d980a73a0b0f483","against":null,"payload":{"description":"Produce a Rating Pitch Report for a company using Moody's GenAI MCP tools, delivered as a self-contained HTML file saved to disk. Use this skill whenever the user asks to create a rating pitch, rating pitch deck, credit pitch, rating presentation, rating pitch report, or rating HTML report. Also trigger when they ask for a comprehensive credit overview combining sector analysis, company financials, SWOT, peer comparison, and ESG into a single report or presentation. Trigger even if they just name a company and say \"pitch deck\", \"rating deck\", \"credit deck\", or \"rating report\".","included_files":[{"relative_path":"__MACOSX/._SKILL.md","size_in_bytes":163},{"relative_path":"__MACOSX/._assets","size_in_bytes":163},{"relative_path":"__MACOSX/._evals","size_in_bytes":163},{"relative_path":"__MACOSX/._scripts","size_in_bytes":163},{"relative_path":"__MACOSX/assets/._sample_payload.json","size_in_bytes":163},{"relative_path":"__MACOSX/assets/._template.html","size_in_bytes":163},{"relative_path":"__MACOSX/evals/._evals.json","size_in_bytes":163},{"relative_path":"__MACOSX/scripts/._build_html.py","size_in_bytes":163},{"relative_path":"__MACOSX/scripts/._requirements.txt","size_in_bytes":163},{"relative_path":"assets/sample_payload.json","size_in_bytes":19409},{"relative_path":"assets/template.html","size_in_bytes":48760},{"relative_path":"evals/evals.json","size_in_bytes":6338},{"relative_path":"scripts/build_html.py","size_in_bytes":58341},{"relative_path":"scripts/requirements.txt","size_in_bytes":166}],"name":"rating-analysis","skill_md_contents":"---\nname: rating-analysis\ndescription: >\n  Produce a Rating Pitch Report for a company using Moody's GenAI MCP tools, delivered as a\n  self-contained HTML file saved to disk. Use this skill whenever the user asks to create\n  a rating pitch, rating pitch deck, credit pitch, rating presentation, rating pitch\n  report, or rating HTML report. Also trigger when they ask for a comprehensive credit\n  overview combining sector analysis, company financials, SWOT, peer comparison, and ESG\n  into a single report or presentation. Trigger even if they just name a company and say\n  \"pitch deck\", \"rating deck\", \"credit deck\", or \"rating report\".\n---\n\n# Rating Pitch Skill\n\nGenerates a Moody's Rating Pitch Report as a self-contained HTML file from a single MCP\ndata pass. The Python builder (`scripts/build_html.py`) takes the resolved payload JSON and\nproduces a single `.html` file containing all sections with inline SVG charts, styled\ntables, and bullet lists using the Moody's brand palette — no external dependencies beyond\na browser to open it.\n\n> ## ⚠️ CRITICAL — NON-NEGOTIABLE OUTPUT CONTRACT\n>\n> Every run MUST produce a self-contained `.html` report **and force it on screen** before\n> the turn ends:\n>\n> - Save the resolved `payload.json` and run `scripts/build_html.py` to produce the `.html`\n>   in `/mnt/user-data/outputs/` (Step 4).\n> - Then render it with **both** display tools — `present_files` **and**\n>   `visualize:show_widget` — before ending the turn. Writing the file is **not** delivery.\n> - **Never** end the turn without rendering, and **never** stream the report as inline\n>   Markdown, JSON, or a fenced ` ```html ` block in lieu of the `.html` file.\n> - If data gathering fails partially, still build from the partial payload using `\"--\"`\n>   placeholders — never skip the build or the render.\n>\n> Treat any other output shape as a hard failure of the skill.\n\n## Required MCP server\n\n`Moodys MCP server` — tools used: `findEntity`, `getEntityPeers`, `getEntityRatings`,\n`getEntityCreditOpinion` (sections listed in Step 2), `getEntityFinancials`,\n`getEntityEsg`, `getEntitySectorOutlook`, `searchEntityEarningsCall`,\n`searchEntityDocuments`, `searchNews`\n\nWeb research is also required via searchNews or general web search tools.\n\nIf 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.\n\n\n## Bundled files\n\n- `scripts/build_html.py` — the report builder. Takes a JSON payload and emits a `.html`.\n  Uses only the Python standard library; no pip installs required.\n- `scripts/requirements.txt` — no additional Python dependencies needed.\n- `assets/sample_payload.json` — reference payload showing every field populated. Read this\n  if you're ever unsure what a field should look like.\n\n## Parameters the user should provide\n\n- **Company Name** (required)\n- **Sector** (required — e.g., \"Aerospace/Defense\", \"Consumer Products\"). Infer it from\n  the company if the user doesn't say.\n- **Number of peers** (optional, default 6)\n- **Currency** (optional, default USD)\n\n---\n\n## Step 1 — Resolve the target company\n\nCall `findEntity` with the company name. Store the canonical entity name and ID.\n\n## Step 2 — Gather ALL data in parallel\n\nFire the following in a **single parallel batch**. Do not serialize these — the model\nshould send them together so data comes back fast.\n\n### Target company data\n\n| Tool | Purpose |\n|------|---------|\n| `getEntityCreditOpinion` (sections: Profile, Summary, RatingOutlook, FactorsLeadingToUpgrade, FactorsLeadingToDowngrade, CreditStrengths, CreditChallenges, ESGConsiderations, KeyIndicatorsTable, ScorecardTable) | Credit opinion sections for financial analysis, SWOT, scorecard |\n| `getEntityRatings` | Current rating + last 5 rating actions for history chart |\n| `getEntityEsg` | ESG scores |\n| `getEntitySectorOutlook` | Sector overview and outlook |\n| `getEntityPeers` (N peers) | Peer set |\n| `searchEntityEarningsCall` (keywords: outlook, guidance, forecast, strategy) | Strategic updates / forward-looking |\n| `searchEntityDocuments` (annual/quarterly reports) | Revenue segments, geography |\n| `searchNews` | M&A, leadership, external trends |\n\n### Peer data (for each peer)\n\n| Tool | Purpose |\n|------|---------|\n| `findEntity` | Resolve canonical name |\n| `getEntityRatings` | Peer rating + outlook |\n| `getEntityCreditOpinion` (sections: Profile, KeyIndicatorsTable, ScorecardTable) | Financials + scorecard |\n| `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 |\n| `getEntityEsg` | Peer ESG scores |\n\n**Period-selection rule (applies to target company and every peer):**\nWhen `getEntityFinancials` returns multiple annual periods, always use the\n**most recent year-end period available** — i.e. the column with the highest\ncalendar or fiscal year. If year-end data is unavailable, fall back to the most\nrecent LTM or interim period and note it in the `period` field (e.g. `\"LTM Mar 2025\"`).\nNever use a hard-coded year string like `\"2024\"` — read the actual period label\nfrom the data and carry it through to `peer_financials.rows[].period` and\n`peer_profitability_charts` / `peer_debt_charts` entries.\n\n---\n\n## Step 3 — Synthesize the sections\n\nBuild a single in-memory **resolved payload** that matches the JSON shape in the **Payload\nschema** section below (a reference copy lives at `assets/sample_payload.json`). This\npayload drives the .html build (Step 4) — fill it completely before moving on.\n\nContent rules for each section:\n\n> **`commentary` type rule — applies to every section without exception:**\n> All `commentary` fields in the payload MUST be a **JSON array of strings** — never a\n> bare string. A bare string passed to the .html builder is iterated character-by-character,\n> producing one bullet per character (the `• C \\n • o \\n • m` bug). Always write:\n> `\"commentary\": [\"Sentence one.\", \"Sentence two.\"]` — even for a single sentence.\n\n### Part 1 — Sector Analysis\n\n- **sector_overview** — three 3-bullet lists (overview / watchlist / takeaways). Keep\n  bullets punchy, ≤25 words each.\n- **moodys_view** — a short outlook paragraph (2-4 sentences), a one-line company\n  positioning statement, and outlook distribution counts by category (Stable, Positive,\n  Negative, Under Review).\n- **macro_outlook** — GDP growth for the top relevant countries (2 historical + 2\n  forecast years) plus 2-3 short commentary bullets.\n- **rating_actions_ytd** — up to 10 notable sector rating actions YTD; one-line summaries.\n\n### Part 2 — Company Credit Overview\n\n- **financial_analysis** — 5-6 commentary bullets (revenue, margin, leverage, cash flow,\n  liquidity, rating rationale). Include last 5 rating actions and a rating chart series\n  (numeric: higher = better rating, e.g., Aaa=21, Baa3=10, Caa1=4).\n  **`rating_history` MUST be sorted oldest → newest** (index 0 = earliest event,\n  last index = most recent). `rating_chart_data` MUST be the parallel notch-integer\n  array in the same oldest-to-newest order. The chart x-axis and the history table\n  both read left-to-right / top-to-bottom chronologically. `getEntityRatings` returns\n  newest-first — reverse before populating the payload.\n- **revenue_distribution** — segment and geography percentages (top 5 each, rest = Other;\n  must sum to ~100).\n- **swot** — 3 items per quadrant, 15-25 words each.\n- **key_metrics** — historical series (≤5 periods) for four metrics: revenue,\n  ebit_margin, debt_ebitda, rcf_net_debt. Arrays must match the `periods` array length.\n  Use `null` (not omission) for missing points.\n- **strategic_updates** — `recent` (3-5) and `forward` (3-5, strictly future-looking).\n- **news_mna** / **external_trends** — structured list form:\n  `[{\"category\": \"...\", \"items\": [\"...\", \"...\"]}]`. The HTML-string form is also accepted\n  by the builder for backwards compatibility.\n\n### Part 3 — Company Positioning vs. Peers\n\n- **peer_summary** — row per company (target first), plus 2-3 commentary bullets.\n- **peer_financials** — wide financial table with `columns` (metric names, no\n  company/period/currency) and `rows` (company + period + currency + values).\n  Each row's `period` field **must be the actual most-recent period label read from\n  `getEntityFinancials`** (e.g. `\"FY2025\"`, `\"FY2024\"`, `\"LTM Mar 2025\"`). Never\n  default all rows to the same hard-coded year. Companies with different fiscal-year\n  ends will legitimately show different period labels — this is correct behaviour.\n- **peer_debt_charts** / **peer_profitability_charts** — pairs of bar charts; sort\n  logically (largest-to-smallest or target-first) in the JSON for readability.\n  Each entry **must include a `period` field** alongside `company` and `value`:\n  `{\"company\": \"Walmart\", \"value\": 713163, \"period\": \"FY2025\"}`.\n  The `period` is used as a sub-label on the bar. If all companies share the same\n  period, a single note in the slide commentary is sufficient; if periods differ,\n  the per-bar label makes the comparison transparent.\n- **peer_scatter** — two scatter series (`margin_vs_leverage`, `fcf_vs_rcf`), each a list\n  of `{company, x, y}` points. Drop extreme outliers that would distort the axes. Each\n  company renders as a filled diamond in its own brand colour with the company name in\n  white bold text centred inside; there is no separate legend.\n- **scorecard** — `factors` (row labels, including group headers), `is_header` boolean\n  flags per row, `companies` (column headers), and `values` as a 3D array: outer = rows,\n  middle = columns, inner = `[measure, score]` or `[]` for header rows.\n  > **SCORECARD CONTRACT — READ CAREFULLY:**\n  > - `companies` must list **the target company first, followed by peer entities** (e.g.\n  >   `[\"Boeing\", \"Airbus\", \"RTX\", \"Lockheed Martin\"]`). Never put two time-horizons of the\n  >   same company here — that produces a scorecard with no peers. The first entry is the\n  >   target; its LTM scorecard data goes at `values[row][1]`.\n  > - `values[row]` is **1-indexed against `companies`**: index `0` in every row is always `[]`\n  >   (a silent placeholder the builder skips). `companies[0]` maps to `values[row][1]`,\n  >   `companies[1]` maps to `values[row][2]`, and so on. Omitting the `[]` at index 0 will\n  >   shift every peer column one position and silently misalign the data.\n  > - Header rows (`is_header=true`) use `values[row] = [[], [], [], ...]` — one `[]` per company\n  >   plus one for the placeholder. Length must equal `len(companies) + 1`.\n  > - **Quick checklist before writing the scorecard payload:**\n  >   1. `len(companies)` = number of peer entities (not counting the target).\n  >   2. Every non-header `values[row]` has length `len(companies) + 1`.\n  >   3. `values[row][0]` is always `[]`.\n  >   4. `values[row][i+1]` contains `[\"metric_value\", \"ScoreLabel\"]` for `companies[i]`.\n- **esg_analysis** — table of CIS/E/S/G scores plus 3-5 commentary bullets.\n\nTarget first in every peer table.\n\n---\n\n## Step 4 — Build the HTML report\n\n**Output location: always build into `/mnt/user-data/outputs/`** so the display tools can\nrender the report in Step 5. Use `/mnt/user-data/outputs/` as the `<output-dir>`. Only use a\ndifferent path if the user explicitly asks for one.\n\n1. Save your resolved payload to `<output-dir>/payload.json`.\n2. No additional Python packages are required — `build_html.py` uses only the standard\n   library. Verify Python 3 is available:\n   ```bash\n   python3 --version\n   ```\n3. Run the builder, emitting the report to a company-slugged filename in the output dir:\n   ```bash\n   python3 <skill-dir>/scripts/build_html.py <output-dir>/payload.json <output-dir>/<company-slug>_rating_pitch.html\n   ```\n   `<company-slug>` is the target company's canonical name lowercased with spaces and\n   special characters replaced by underscores (e.g. `boeing_company_rating_pitch.html`).\n\nIf any section data is missing, still include the section in the payload (empty arrays\nare fine) — the builder handles empties gracefully and the deck will stay well-formed.\n\n---\n\n## Step 5 — Output and presentation (required final steps)\n\n> ## ⚠️ CRITICAL — NOT COMPLETE UNTIL THE REPORT IS VISIBLY RENDERED\n>\n> Building the file is **not** delivery. Render it with every display tool available, in\n> order, before saying anything else. Do not end your turn until it is on screen.\n\nFollow this exact sequence. Do not skip a step, reorder, or substitute alternatives:\n\n1. **Confirm the built file.** The `rating_pitch.html` produced by `build_html.py` in Step 4\n   lives at `/mnt/user-data/outputs/<company-slug>_rating_pitch.html`. This exact path is\n   what you render — do not re-emit or re-write the HTML inline.\n2. **Present the file.** Immediately call `present_files` on that exact path to surface the\n   artifact to the user.\n3. **Show the widget.** Immediately call `visualize:show_widget` on the same file to render\n   the report visually. Call this even if `present_files` already succeeded — firing both\n   renderers is what guarantees the report always appears.\n4. **Confirm in one short sentence.** Only after the renderers return, add a single brief\n   sentence in chat (e.g. `Rating Pitch for {Company} — the report is available above as a\n   self-contained HTML artifact.`). Nothing more.\n\nIf a display tool call fails or is unavailable, immediately try the other one rather than\nstopping. Never end your turn after building the file, and never paste the HTML into chat or\nsuggest shell commands (`open`, etc.) in lieu of rendering.\n\n---\n\n## Payload schema\n\n**Read `assets/sample_payload.json` for the full, every-field-populated reference** — copy\nits exact shapes. The summary below lists the top-level keys and the non-obvious contracts;\nthe sample is authoritative for field names and nesting.\n\nTop level: `report_date`, `target_company`, `sector`, `currency`, `companies` (target first),\n`sources` (`[{id?, title, source, date, url}]`, rendered as `[n]` citations), and `sections`.\n\n`sections` keys and shapes:\n\n- `sector_overview` — `overview_bullets` / `watchlist_bullets` / `takeaway_bullets` (string arrays).\n- `moodys_view` — `outlook_summary` (string), `company_positioning` (string),\n  `outlook_distribution` (`[{category, count, color}]`).\n- `macro_outlook` — `gdp_table.year_columns`, `gdp_table.rows` (`[{country, values[]}]`), `gdp_commentary[]`.\n- `rating_actions_ytd` — `[{date, company, summary}]`.\n- `financial_analysis` — `commentary[]`, `rating_history` (`[{date, rating, outlook, direction, reason}]`),\n  `rating_chart_data` (int notch array).\n- `revenue_distribution` — `by_segment` / `by_geography` (`[{name, percentage}]`), `commentary[]`.\n- `swot` — `strengths` / `weaknesses` / `opportunities` / `threats` (string arrays).\n- `key_metrics` — `periods[]`, `revenue[]`, `ebit_margin[]`, `debt_ebitda[]`, `rcf_net_debt[]`\n  (all same length as `periods`; use `null` for gaps).\n- `strategic_updates` — `recent[]`, `forward[]`.\n- `news_mna` / `external_trends` — `[{category, items[]}]`.\n- `peer_summary` — `table` (`[{company, country, market_cap, rating, outlook, business_mix}]`), `commentary[]`.\n- `peer_financials` — `columns[]` (metric names only), `rows` (`[{company, period, currency, values[]}]`).\n- `peer_debt_charts` — `rcf_net_debt` / `debt_ebitda` (`[{company, value, period}]`), `commentary[]`.\n- `peer_profitability_charts` — `revenue` / `ebit_margin` (`[{company, value, period}]`), `commentary[]`.\n- `peer_scatter` — `margin_vs_leverage` / `fcf_vs_rcf` (`[{company, x, y}]`), `commentary[]`.\n- `scorecard` — `factors[]`, `is_header[]` (bool per row), `companies[]` (target first),\n  `values` (3D: outer=rows, middle=columns, inner=`[measure, score]` or `[]`). See the\n  scorecard contract in Step 3.\n- `esg_analysis` — `table` (`[{company, cis, environmental, social, governance}]`), `commentary[]`.\n\n> ⚠️ **`rating_chart_data` constraint:** same length as `rating_history`, index-aligned\n> (`rating_history[i] ↔ rating_chart_data[i]`), both sorted **oldest → newest**.\n\n---\n\n## Report structure\n\nThe Python builder emits these 26 sections as HTML, in this order:\n\n1. Cover\n2. Agenda\n3. Part 1 divider\n4. Sector Overview (3-column chips)\n5. Moody's View (outlook text + positioning + outlook pie)\n6. Global Macro Outlook (GDP table + takeaways)\n7. Rating Actions YTD (table)\n8. Part 2 divider\n9. Financial Analysis (bullets + rating history line chart + rating rationale)\n10. Revenue Distribution (two pie charts + commentary)\n11. SWOT (2×2)\n12. Key Financial Metrics (four bar charts in 2×2 grid)\n13. Strategic Updates (2 columns)\n14. News, M&A & Leadership\n15. External Trends, Pressures & Risks\n16. Part 3 divider\n17. Peer Comparison Summary (table + commentary)\n18. Detailed Peer Comparison (wide financial table)\n19. Peer Comparison — Debt (two horizontal bar charts)\n20. Peer Comparison — Profitability (two horizontal bar charts)\n21. Peer Scatter Plots (two scatter charts)\n22. Scorecard Comparison (multi-column factor table)\n23. ESG Analysis (table + commentary)\n24. Citations (appendix — canonical numbered [n] references with hyperlinked titles)\n25. Thank You\n26. Disclaimer\n\nChart palette (Moody's official, priority order): `#005eff`, `#5eb6bc`, `#c7ab21`,\n`#5c068c`, `#ba0168`, `#c64809`, `#bed6ff`, then `#040826` / `#e1e2e1`.\n\nOutlook pie uses **semantic** colors (case-insensitive):\n`Stable → #e1e2e1` (light gray), `Positive → #5eb6bc` (teal),\n`Negative → #f09615` (amber), `Under Review → #005eff` (bright blue).\nAll other multi-series charts consume the palette above in priority order (series 0 first).\n\nCharts are **pure inline SVG** computed in `build_html.py` — no Chart.js, no JS, no external\nlibraries — because the report renders inside a sandboxed `about:srcdoc` iframe (Teams /\nM365 Copilot) that blocks CDN scripts and can't be relied on to run JS. SVG renders\neverywhere (srcdoc, PDF, print, email). Entrance animations use CSS `@keyframes` only, so\nthey stay JS-free and respect `prefers-reduced-motion`. The file is fully self-contained.\n\n---\n\n## Tips\n\n- Run ALL data-gathering tool calls in a single parallel batch.\n- Keep the target company first in every peer table.\n- `rating_chart_data` is numeric (`Aaa=21 … C=1`); both it and `rating_history` must be\n  oldest-to-newest. `getEntityRatings` returns newest-first — reverse before use.\n- Pie percentages must sum to 100 — bucket small categories into \"Other\".\n- `key_metrics` arrays must match `periods` length. Use `null` for missing points.\n- Scorecard: see the full contract in Step 3.\n- If you can't get real data for a section, leave arrays empty — the builder degrades\n  gracefully rather than erroring.\n- Dates are just strings; format however reads best (e.g., \"Nov 20, 2025\").\n- Output `.html` filename: lower-cased with spaces/special chars as underscores, in\n  `/mnt/user-data/outputs/` so the display tools can render it.\n- Delivery is not complete until rendered with **both** `present_files` and\n  `visualize:show_widget` (Step 5). Never paste HTML into chat or suggest `open <path>`.\n- Revenue bar labels use `\"#,##0\"` as `y_format` (comma thousands, zero decimals).\n- **Never copy `period` values from `sample_payload.json`** — it uses `\"FY2024\"` only as a\n  fixed example. Read each company's actual period label from `getEntityFinancials`;\n  anchoring on the sample year is a silent data-accuracy bug.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}