Skip to content

Commit f68c190

Browse files
committed
Truth-align docs, add determinism tests, create missing reference files
Credibility pass addressing external review feedback. Every claim in the repo now matches shipping code. Docs truth-alignment: - '14 templates' -> '12 templates' in README, SKILL, plugin.json, marketplace.json, ib-deck command (the demo full_deck.py still produces 14 slides because section_divider is reused 3 times; this is now noted explicitly) - Removed speculative cross_audit claims from README (moved to roadmap) - Removed bundled xlsxwriter / edgartools claims (kept only as troubleshooting guidance and roadmap items, since neither is implemented in v0.1.0) - Reframed /ib-extract as a 'guided workflow for structuring financials' rather than an automated SEC EDGAR pipeline - Reframed /ib-deck as an orchestration workflow rather than an autonomous command - Toned down 'their plugin is structurally broken' rhetoric; now describes the renderer-first architecture as 'an alternative worth considering' - Added explicit 'What this plugin does NOT do (yet)' section and a versioned roadmap Missing referenced files created: - skills/ib-deck-engine/reference/examples/stacked_bar_table.json - skills/ib-deck-engine/reference/examples/trading_comps.json - skills/ib-deck-engine/reference/examples/dual_chart.json - skills/ib-deck-engine/reference/examples/sensitivity.json - skills/ib-deck-engine/reference/style-guide.md - skills/ib-deck-engine/reference/architecture.md Determinism tests added: - tests/normalize.py - PPTX content hashing that strips volatile ZIP metadata (creation timestamps, last-modified fields) before hashing. Only the parts of the output that affect appearance go into the hash. - tests/test_determinism.py - 13 tests: * 12 per-template determinism tests (each template rendered twice, normalized content hashes compared) * 1 stability test (render_financial_summary rendered 10 times, all 10 content hashes must be identical) - pytest.ini - test runner config - .github/workflows/tests.yml - run tests on push + PR All 13 tests pass locally. The architectural claim 'fixed input, repeated renders, identical output' is now backed by code, not narrative.
1 parent 12763ae commit f68c190

18 files changed

Lines changed: 1038 additions & 144 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{
88
"name": "ib-deck-engine",
99
"source": "./ib-deck-engine",
10-
"description": "14-template investment banking slide library with JSON spec → deterministic pixel rendering. Solves cross-model desync, openpyxl corruption, and spatial execution failures. Includes /ib-deck, /ib-extract, /ib-financial, /ib-football, /ib-comps, /ib-sources-uses, /ib-sensitivity slash commands."
10+
"description": "12-template investment banking slide library with a renderer-first architecture. LLM fills structured JSON specs; a deterministic Python renderer handles layout. Includes /ib-deck, /ib-extract, /ib-financial, /ib-football, /ib-comps, /ib-sources-uses, and /ib-sensitivity workflow commands."
1111
}
1212
]
1313
}

.github/workflows/tests.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: "3.12"
24+
25+
- name: Install dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install python-pptx pytest
29+
30+
- name: Run determinism tests
31+
run: python -m pytest tests/ -v

README.md

Lines changed: 85 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
# IB Deck Engine — Claude Code Plugin
22

3-
> A Claude Code plugin that ships a 14-template investment banking slide library with a JSON spec → deterministic pixel rendering architecture.
3+
[![Tests](https://github.com/gorajing/ib-deck-plugin/actions/workflows/tests.yml/badge.svg)](https://github.com/gorajing/ib-deck-plugin/actions/workflows/tests.yml)
44

5-
**Why this exists:** Other AI slide tools ask the LLM to write spatial code (`Inches(2.5), Pt(11)`). That's why their output has misaligned tables, disproportional bar charts, and reference label collisions. This plugin separates content reasoning (LLM's strength) from spatial rendering (deterministic code's strength). Right-alignment is guaranteed by the template, not hoped for.
5+
> A Claude Code plugin with a 12-template investment banking slide library built on a renderer-first architecture: the LLM fills structured JSON specs and a deterministic Python renderer handles every pixel.
6+
7+
**The core idea:** separate content reasoning (LLM's strength) from spatial rendering (deterministic code's strength). The LLM never writes `Inches()`, `Pt()`, or EMU values. It picks a template and passes data. The renderer guarantees right-alignment, proportional chart bars, and collision-free label placement by construction.
8+
9+
This plugin is an alternative architecture worth considering alongside [`anthropics/financial-services-plugins`](https://github.com/anthropics/financial-services-plugins). Different tradeoffs, smaller scope, tighter guarantees on the things it does cover.
10+
11+
## Status
12+
13+
**Version 0.1.0 — early prototype.** What's shipped today is the 12-template rendering library and slash-command workflows that guide Claude through filling the JSON specs. It's installable and runnable. Extraction, full model building, and cross-model auditing are workflow guides (not automated pipelines) in this version — see [Roadmap](#roadmap) for what's coming.
614

715
## Installation
816

@@ -25,10 +33,12 @@ claude plugin list | grep ib-deck
2533

2634
## Available commands
2735

36+
Each command loads the `ib-deck-engine` skill, which walks Claude through picking the right template, filling a JSON spec from your data, and calling the renderer. The commands are workflow guides — not autonomous pipelines.
37+
2838
| Command | Purpose |
2939
|---------|---------|
30-
| `/ib-deck [TICKER]` | Build a complete 14-slide IB pitch deck for a public company |
31-
| `/ib-extract [TICKER]` | Pull a 10-K from SEC EDGAR into a structured JSON master file |
40+
| `/ib-deck [TICKER]` | Walk through building a complete IB pitch deck (orchestrates multiple templates) |
41+
| `/ib-extract [TICKER]` | Guided workflow: extract 10-K data into the master JSON schema the templates expect |
3242
| `/ib-financial [COMPANY]` | Build a single financial summary table slide |
3343
| `/ib-football [COMPANY]` | Build a football field valuation summary slide |
3444
| `/ib-comps [TARGET]` | Build a trading comparables peer multiples table |
@@ -37,72 +47,32 @@ claude plugin list | grep ib-deck
3747

3848
## Quick start
3949

40-
```bash
41-
# In Claude Code, after installing the plugin:
42-
/ib-deck ADUS
43-
```
44-
45-
Claude will:
46-
1. Pull Addus HomeCare's most recent 10-K from SEC EDGAR via `edgartools`
47-
2. Extract financials into a structured JSON master file
48-
3. Fill JSON specs for 14 slide templates
49-
4. Render a pixel-perfect PPTX using the IBRenderer
50-
5. Save to `ADUS_pitch_deck.pptx`
51-
52-
The entire pipeline takes one prompt.
53-
54-
## What this plugin solves that the existing financial-services-plugins doesn't
55-
56-
I built this after analyzing the source code of `anthropics/financial-services-plugins`. Here are the specific gaps it fills:
50+
After installing the plugin and restarting Claude Code:
5751

58-
### 1. Cross-model desync ✗ → ✓
59-
The existing plugins build DCF and LBO independently. There's nothing guaranteeing both use the same revenue, EBITDA, share count, or tax rate. In a Medpace case study, the DCF used 15% effective tax and the LBO used 21% statutory with no documentation.
60-
61-
**This plugin's fix:** `/ib-extract` produces a single master JSON. Every downstream model and slide references it. A `cross_audit` function verifies consistency across DCF, LBO, and slides.
62-
63-
### 2. openpyxl corruption ✗ → ✓
64-
The existing DCF skill (line 21) defaults to openpyxl for standalone xlsx generation. This produces files that trigger Excel's "We found a problem" recovery dialog.
65-
66-
**This plugin's fix:** Uses `xlsxwriter` by default for new file creation. openpyxl is only for reading existing files.
67-
68-
### 3. Spatial execution ceiling ✗ → ✓
69-
The existing skills tell the LLM to write `python-pptx` code directly. The LLM has to remember `Inches(2.5), Pt(11)` for every cell. Failures: right-alignment inconsistent, bar heights not proportional, reference labels overlapping titles.
70-
71-
**This plugin's fix:** The LLM never writes spatial code. It picks a template (`render_financial_summary`) and fills a JSON spec. The IBRenderer guarantees:
72-
- Right-alignment on all numeric columns
73-
- Proportional bar heights (`value / max_value × chart_height`)
74-
- Tables are real PowerPoint table objects (not text with tabs)
75-
- Reference labels never overlap (collision detection built-in)
76-
- Source text dynamically positioned below content
77-
78-
### 4. Generic titles ✗ → ✓
79-
The existing plugins don't enforce action titles. You get "Financial Summary" instead of "Consistent Revenue Growth With Expanding EBITDA Margin Expansion".
80-
81-
**This plugin's fix:** SKILL.md explicitly requires action titles on every slide and gives examples.
82-
83-
### 5. No template library ✗ → ✓
84-
The existing plugins make Claude generate slides from scratch each time. No reusable patterns.
52+
```
53+
/ib-financial ADUS
54+
```
8555

86-
**This plugin's fix:** 14 pre-built templates for the most common IB slide types, each with a documented JSON schema.
56+
Claude will load the skill, ask for the historical financials (or pull them from a JSON you provide), fill out the `render_financial_summary` JSON spec, and call the renderer. The output is a single PPTX slide with right-aligned numerics, bold subtotals, italic gray % rows, and a navy section header — rendered by deterministic Python code, not by the model guessing coordinates.
8757

88-
## The 14 templates
58+
## The 12 templates
8959

9060
| # | Template | Pattern | Reference |
9161
|---|----------|---------|-----------|
92-
| 1 | `render_cover` | Cover with confidential mark + bank badge | GS board pres format |
93-
| 2 | `render_section_divider` | Full navy bg with section title | GS / Moelis style |
62+
| 1 | `render_cover` | Cover with confidential mark + bank badge | GS board presentation format |
63+
| 2 | `render_section_divider` | Full navy background with section title | GS / Moelis style |
9464
| 3 | `render_toc` | Numbered agenda with light blue bands | GS agenda slides |
9565
| 4 | `render_exec_summary` | Blue callout + ■ / — bullet hierarchy | GS executive summary |
96-
| 5 | `render_investment_highlights` | 4-card 2×2 grid with numbered headers | GS / GS analyst format |
66+
| 5 | `render_investment_highlights` | 4-card 2×2 grid with numbered headers | GS highlights format |
9767
| 6 | `render_financial_summary` | Historical P&L with bold subtotals | Standard IB financials |
9868
| 7 | `render_stacked_bar_table` | Stacked bars + data table below | Moelis revenue by segment |
9969
| 8 | `render_dual_chart` | Two bar charts side by side with CAGR | GS dual analysis |
100-
| 9 | `render_football_field` | Valuation methodologies with range bars | Evercore / Moelis |
70+
| 9 | `render_football_field` | Valuation methodologies with range bars | Evercore / Moelis valuation |
10171
| 10 | `render_sensitivity` | WACC × TGR grid with base case highlight | Standard DCF sensitivity |
10272
| 11 | `render_sources_uses` | LBO capital structure (two-column) | Standard LBO |
10373
| 12 | `render_trading_comps` | Peer multiples with target highlighted | Standard comps table |
10474

105-
See `skills/ib-deck-engine/reference/template-catalog.md` for the full pattern catalog and JSON schemas.
75+
See `skills/ib-deck-engine/reference/template-catalog.md` for the full pattern catalog.
10676

10777
## Architecture
10878

@@ -116,7 +86,7 @@ See `skills/ib-deck-engine/reference/template-catalog.md` for the full pattern c
11686
│ - Cite the source │
11787
└────────────────┬────────────────────┘
11888
119-
│ Output: structured JSON
89+
│ Output: structured JSON spec
12090
12191
12292
┌─────────────────────────────────────┐
@@ -133,28 +103,77 @@ See `skills/ib-deck-engine/reference/template-catalog.md` for the full pattern c
133103
134104
┌─────────────────────────────────────┐
135105
│ DETERMINISTIC RENDERER │
136-
│ - Right-alignment ALWAYS
137-
│ - Proportional bars by math
138-
│ - Real table objects
139-
│ - Pixel-perfect by construction
106+
│ - Right-alignment of numeric cells
107+
│ - Bar heights computed from data
108+
│ - Real PPT table objects │
109+
│ - Layout rules enforced in code
140110
└────────────────┬────────────────────┘
141111
142112
143113
output.pptx
144114
```
145115

146-
This is the same architecture used by Beautiful.ai, Gamma, Pitch, UpSlide, and Macabacus. The LLM never touches pixels.
116+
The LLM never writes `Inches()`, `Pt()`, `RGBColor()`, or pixel coordinates. Layout rules live in the renderer functions, enforced by code.
147117

148-
## Companion repo
118+
This is the same pattern used by Beautiful.ai, Gamma, and UpSlide: layout is a function of data, not a prompt-time decision.
119+
120+
## Tests
121+
122+
Determinism is the core promise of the architecture, so every template has a test that verifies it:
123+
124+
```bash
125+
python -m pytest tests/ -v
126+
```
127+
128+
13 tests pass:
129+
- 12 per-template determinism tests (each template rendered twice, normalized content hashes compared)
130+
- 1 stability test (`render_financial_summary` rendered 10 times, all 10 content hashes identical)
131+
132+
The tests use a [normalized PPTX hash](tests/normalize.py) that strips volatile ZIP metadata (creation timestamps, last-modified fields) before hashing, so only the parts of the output that affect appearance are compared.
133+
134+
This is the evidence trail for the "fixed input, repeated renders, identical output" claim. If any of those tests fail, the architecture's core promise is broken.
135+
136+
## What this architecture optimizes for
137+
138+
**Repeatability.** Same input → same output. The renderer doesn't depend on what the LLM felt like typing in any particular run.
149139

150-
The standalone Python library (without the plugin packaging) is at:
151-
**https://github.com/gorajing/ib-deck-engine**
140+
**Evaluability.** "Did the LLM pick the right template and fill the right data?" is a simpler test than "did the LLM write correct python-pptx code for this specific slide?"
141+
142+
**Maintainability.** New templates are code, not prompts. They can be reviewed, versioned, and tested.
143+
144+
**Lower failure surface.** Every pixel decision the LLM doesn't make is a pixel decision that can't be wrong.
145+
146+
## What this plugin does not do (yet)
147+
148+
Being honest about the scope of v0.1.0:
149+
150+
- **No end-to-end SEC EDGAR extraction.** `/ib-extract` is a guided workflow that instructs Claude on the target JSON schema. A fully automated extraction command is on the roadmap.
151+
- **No Excel model generation.** The companion standalone repo includes DCF and LBO `xlsx` build scripts for the ADUS case study, but they're not wired into the plugin as commands yet.
152+
- **No cross-model audit command.** A programmatic 20-check audit exists in the companion repo for the ADUS case study. Making it a `/ib-audit` slash command is on the roadmap.
153+
- **No Office JS / in-PowerPoint support.** The renderer is python-pptx. It produces `.pptx` files from outside PowerPoint. An Office JS port would be needed for Cowork / in-PowerPoint use.
154+
- **Only 12 templates.** Real IB decks use ~25-30 patterns. See the [roadmap](#roadmap) for what's coming next.
155+
156+
## Roadmap
157+
158+
v0.2.0 goals:
159+
- Expand template library to 20+ (add precedent transactions, multi-chart dashboard, share price chart, debt schedule, value creation bridge, process timeline, buyer universe grid)
160+
- Automated `/ib-extract` that calls `edgartools` and produces the master JSON
161+
- Automated `/ib-dcf-model` and `/ib-lbo-model` using xlsxwriter
162+
- `/ib-audit` cross-model consistency check
163+
164+
v0.3.0 goals:
165+
- Bank style variants (Moelis, Evercore, McKinsey presets)
166+
- MCP server wrapper so the renderer works in Claude Desktop and Cowork
167+
- Determinism test expansion to every template
168+
- GitHub Pages gallery
169+
170+
## Companion repo
152171

153-
It includes a complete worked example for Addus HomeCare Corp (ADUS) — DCF model, LBO model, master JSON, and rendered 14-slide deck.
172+
The standalone Python library (without the plugin packaging) and the complete ADUS case study artifacts live at **[gorajing/ib-deck-engine](https://github.com/gorajing/ib-deck-engine)**. That repo includes the DCF model (401 formulas), LBO model (244 formulas), master JSON extraction example, and a 14-slide rendered ADUS deck.
154173

155174
## Disclaimer
156175

157-
This is a learning case study and template library. Models are simplified. Numbers in the example case study are illustrative. Always verify financial data against primary sources before relying on it for investment decisions.
176+
This is a learning project and early prototype. Models in the companion case study are simplified. Example numbers are illustrative. Always verify financial data against primary sources before relying on it for any investment decision.
158177

159178
## License
160179

ib-deck-engine/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "ib-deck-engine",
33
"version": "0.1.0",
4-
"description": "Investment banking slide template library with JSON spec → deterministic pixel rendering. Solves cross-model desync, openpyxl corruption, and spatial execution failures by separating content reasoning from layout execution.",
4+
"description": "Investment banking slide template library with a renderer-first architecture. LLM fills structured JSON specs; a deterministic Python renderer handles layout. 12 templates covering the common IB slide patterns.",
55
"author": {
66
"name": "gorajing"
77
}

ib-deck-engine/commands/ib-deck.md

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,45 @@
11
---
2-
description: Build a complete investment banking pitch deck for a public company
2+
description: Build a complete IB pitch deck using the 12-template library
33
argument-hint: "[company ticker or name]"
44
---
55

6-
# IB Deck — Full Pitch Book
6+
# IB Deck — Full Pitch Book Workflow
77

8-
Build a complete 14-slide IB pitch deck for the specified company using the IB Deck Engine
9-
template library. The architecture: extract data → fill JSON specs → deterministic rendering.
8+
Orchestrates a complete IB pitch deck using the 12 templates in the IB Deck Engine
9+
library. The typical deck is ~14 slides (12 distinct template types plus three reused
10+
section dividers between the Financial, Valuation, and LBO sections).
11+
12+
This command is a **workflow guide**, not an automated pipeline. It walks Claude
13+
through the steps to pick templates, fill JSON specs, and call the renderer. The
14+
user supplies (or Claude helps assemble) the underlying financial data — this
15+
version does not include an autonomous SEC EDGAR extractor.
1016

1117
## Workflow
1218

13-
Load the `ib-deck-engine` skill to access the template library and follow this workflow:
19+
Load the `ib-deck-engine` skill to access the template library.
1420

1521
### Step 1: Confirm the deal
1622

1723
If a company name/ticker is provided as $1, use it. Otherwise ask:
1824
- "What company would you like to build a pitch deck for?"
1925
- "Sell-side or buy-side mandate?"
20-
- "Any specific assumptions to use (or should I use reasonable defaults)?"
26+
- "Do you already have the financials, or should we work through them together?"
27+
28+
### Step 2: Assemble the master JSON
29+
30+
Get the underlying financial data into the master JSON schema documented in
31+
`skills/ib-deck-engine/reference/template-catalog.md`. Options:
2132

22-
### Step 2: Extract financial data
33+
- User supplies existing JSON / CSV / financials
34+
- Manual entry during the conversation
35+
- One-off extraction script using `edgartools` (not bundled with this plugin in
36+
v0.1.0 — see the companion repo at github.com/gorajing/ib-deck-engine for a
37+
reference extraction)
2338

24-
For public US companies, use `edgartools` to pull the most recent 10-K:
25-
- Revenue, COGS, gross profit, operating income, EBITDA, net income (3 years)
26-
- Balance sheet (cash, AR, debt, equity)
27-
- Cash flow statement (CFO, CapEx, financing)
28-
- Segment revenue if available
29-
- Diluted share count
30-
- Save as `{ticker}_master.json` — single source of truth
39+
The JSON should include: 3 years of historical IS/BS/CF, segment revenue if
40+
available, debt detail, and diluted share count.
3141

32-
### Step 3: Build the 14-slide deck
42+
### Step 3: Build the deck
3343

3444
Use the IBRenderer templates in this order:
3545

@@ -50,23 +60,24 @@ Use the IBRenderer templates in this order:
5060

5161
### Step 4: Verify and deliver
5262

53-
- Confirm 14 slides generated
54-
- Verify source text on each content slide
63+
- Confirm slide count
64+
- Spot-check source text on each content slide
5565
- Save as `{ticker}_pitch_deck.pptx`
5666
- Report the file path to the user
5767

5868
## Critical rules
5969

6070
- **Action titles only** — never "Financial Summary," always "Consistent Revenue Growth With Expanding Margins"
6171
- **Every number sourced** — trace each value to a source file or note "Estimated"
62-
- **Cross-model consistency** — DCF and LBO must use the same revenue, EBITDA, share count
63-
- **Right-alignment automatic**handled by templates, don't override
72+
- **Cross-model consistency** — DCF and LBO should use the same revenue, EBITDA, share count. Document any intentional differences (e.g., LBO using statutory vs effective tax rate).
73+
- **Right-alignment is handled by the templates**don't override it in the JSON spec
6474

6575
## Example: ADUS
6676

6777
```
6878
/ib-deck ADUS
6979
```
7080

71-
Builds a complete 14-slide pitch book for Addus HomeCare Corp using SEC EDGAR data.
72-
See `skills/ib-deck-engine/reference/examples/full_deck.py` for the full worked example.
81+
Walks through building a pitch book for Addus HomeCare Corp. A complete worked
82+
example (including the ADUS master JSON and the generated PPTX) lives at the
83+
companion repo: github.com/gorajing/ib-deck-engine.

0 commit comments

Comments
 (0)