This folder contains a tightly controlled before/after comparison of two approaches to building a single financial-summary slide:
- Track A — renderer-first. The LLM writes only a JSON spec and calls
IBRenderer().render_financial_summary(spec). NoInches(), noPt(), noRGBColor(), no shape manipulation. The renderer owns every pixel. - Track B — prompt-guided spatial code. The LLM writes
python-pptxcode directly, making every position, size, alignment, and color decision in the same file.
The goal is to isolate the architectural variable — how much spatial code the LLM is responsible for — and observe the consequences on a single concrete task.
The obvious comparison would be against Anthropic's financial-services-plugins.
That comparison is not what this folder contains, because that plugin does not
expose a "build one financial_summary slide from this fixed data" primitive.
Forcing an apples-to-apples run against a plugin that is solving a slightly
different task would either (a) require a lot of adapter code that would itself
become the variable under test, or (b) produce a misleading result.
What this comparison does instead: hold the task and the input fixed, vary
only the architecture. The Track B build script is what someone would plausibly
write starting from input/prompt.txt, python-pptx documentation, and no
reference to an existing renderer. That is the condition any LLM operates under
when it is asked to produce a slide without a slide library.
- Fixed task. Build one PPTX slide containing Addus HomeCare's 3-year historical financials, formatted to standard IB conventions.
- Fixed input.
input/financial_summary_spec.json(and the natural-language version,input/prompt.txt) are the two inputs. Both contain identical data — one is structured JSON for the renderer path, one is natural language for the prompt-guided path. - Fixed output target. Single
.pptxfile with one slide, 13.33 × 7.5 inches. - Three runs. Each track is run three times. The three output files per
track are hashed after normalizing away volatile PPTX metadata (see
../tests/normalize.py). - Honest accounting of what the determinism test shows. Running the same
.pyfile three times is expected to be deterministic for both tracks. That test does not measure "would an LLM write the same code three times?" andRESULTS.mdsays so plainly.
comparison/
├── README.md # this file
├── RESULTS.md # criteria table and findings
├── input/
│ ├── financial_summary_spec.json # fixed input: JSON spec
│ └── prompt.txt # fixed input: natural-language prompt
├── track_a_renderer/
│ ├── build.py # loads spec, calls IBRenderer
│ ├── run1.pptx, run2.pptx, run3.pptx # outputs
│ └── hashes.txt # normalized content hashes
├── track_b_prompt_guided/
│ ├── build.py # hand-written python-pptx
│ ├── run1.pptx, run2.pptx, run3.pptx # outputs
│ └── hashes.txt # normalized content hashes
└── screenshots/
├── track_a_run1.png # Quick Look render of track_a run1
└── track_b_run1.png # Quick Look render of track_b run1
# Track A
cd track_a_renderer
python3 build.py
# Track B
cd ../track_b_prompt_guided
python3 build.pyEach script writes run1.pptx, run2.pptx, run3.pptx into its own directory
and prints a summary to stdout.
To regenerate the screenshots (macOS only):
qlmanage -t -s 1600 -o /tmp/ql_a track_a_renderer/run1.pptx
qlmanage -t -s 1600 -o /tmp/ql_b track_b_prompt_guided/run1.pptx
cp /tmp/ql_a/run1.pptx.png screenshots/track_a_run1.png
cp /tmp/ql_b/run1.pptx.png screenshots/track_b_run1.pngOn this single slide, both tracks produce visually acceptable output. The difference lives in the code size the LLM is responsible for:
- Track A: 0 lines of spatial code. The LLM writes an 18-line JSON spec.
- Track B: 166 non-blank code lines, including 32
Inches()calls, 12Pt()calls, and 10RGBColor()calls.
Both tracks produce deterministic output across 3 runs of the same file. That
test does not capture LLM generation variance, and the conclusion in
RESULTS.md is careful to say so.
See RESULTS.md for the full criteria table and the honest framing of what
this comparison does and does not establish.