PPTX creation, editing, and analysis
Execution Rules
- ALL code execution MUST use the
code_interpreter tool. Do NOT use the shell tool.
- NEVER call
!pip install. python-pptx, boto3, Pillow, lxml, matplotlib, numpy, requests, markitdown are pre-installed in the AgentCore Code Interpreter sandbox. Import directly. If an import fails, stop and report the error to the user — do not attempt to install anything.
- Build the presentation INCREMENTALLY across multiple small
code_interpreter calls, one or two slides per call. Do NOT cram the entire deck into a single 30+ KB script. See the Incremental Workflow below.
- EVERY
code_interpreter call MUST end with a print(...) that reports progress. Empty stdout is interpreted by the runtime as a failure. Always print at least one line describing what was accomplished.
- Before calling
code_interpreter, call artifact_path(filename="presentation.pptx") to get the S3 bucket and key.
- After the final upload, report the
artifact_ref to the user.
- If
code_interpreter fails with an error, do NOT retry automatically. Report the error to the user and ask for clarification or guidance. Do not make multiple retry attempts without user input.
Incremental Workflow
The AgentCore Code Interpreter preserves session state between calls — files written to /tmp in one code_interpreter invocation remain available in the next call of the same session. Use this to build the deck one slide at a time instead of generating all slides in a single monolithic script.
Benefits:
- Each call is small (~1–3 KB of code) and generates in ~15–25 seconds instead of 4+ minutes.
- Failures affect only one slide — previous slides stay saved in
/tmp/deck.pptx.
- Users see real-time progress: "slide 3/12 added" appears in the UI after each call.
Call sequence (typical 10-slide deck)
artifact_path(filename="presentation.pptx") — get S3 URI (ONCE)
- Call #1 — Create empty deck, set slide size/theme, save to
/tmp/deck.pptx
- Call #2 — Load deck, add slide 1 (title slide), save
- Call #3 — Load deck, add slide 2 (content), save
- ... one call per slide (or two slides per call if small) ...
- Call #N+1 — Load deck, upload
/tmp/deck.pptx to S3
- Report
artifact_ref
Call #1 — Create empty deck
from pptx import Presentation
from pptx.util import Inches
pres = Presentation()
pres.slide_width = Inches(13.333) # 16:9
pres.slide_height = Inches(7.5)
pres.save('/tmp/deck.pptx')
print(f"Created blank deck: 16:9, 0 slides. Target total: 10 slides.")
Call #2 — Title slide
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
pres = Presentation('/tmp/deck.pptx') # load existing
slide = pres.slides.add_slide(pres.slide_layouts[6]) # blank layout
# Title
title_box = slide.shapes.add_textbox(Inches(0.5), Inches(2.8), Inches(12.3), Inches(1.5))
tf = title_box.text_frame
p = tf.paragraphs[0]
p.text = "<presentation title>"
p.alignment = PP_ALIGN.CENTER
p.runs[0].font.size = Pt(44)
p.runs[0].font.bold = True
p.runs[0].font.color.rgb = RGBColor(0x1F, 0x39, 0x64)
# Subtitle
sub_box = slide.shapes.add_textbox(Inches(0.5), Inches(4.5), Inches(12.3), Inches(0.8))
sub_p = sub_box.text_frame.paragraphs[0]
sub_p.text = "<subtitle / author / date>"
sub_p.alignment = PP_ALIGN.CENTER
sub_p.runs[0].font.size = Pt(20)
sub_p.runs[0].font.color.rgb = RGBColor(0x66, 0x66, 0x66)
pres.save('/tmp/deck.pptx')
print(f"Slide 1/{TOTAL} (title) added. Deck now has {len(pres.slides)} slides.")
Call #3…N — Each content slide follows the same load → add → save → print pattern
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
pres = Presentation('/tmp/deck.pptx')
slide = pres.slides.add_slide(pres.slide_layouts[6])
# Slide title
title = slide.shapes.add_textbox(Inches(0.5), Inches(0.3), Inches(12.3), Inches(0.8))
t_p = title.text_frame.paragraphs[0]
t_p.text = "<slide title>"
t_p.runs[0].font.size = Pt(28)
t_p.runs[0].font.bold = True
t_p.runs[0].font.color.rgb = RGBColor(0x1F, 0x39, 0x64)
# Body content (bullet list example — replace bullets with actual content)
body = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(12.3), Inches(5.5))
body_tf = body.text_frame
body_tf.word_wrap = True
bullets = ["<bullet 1>", "<bullet 2>", "<bullet 3>"]
for i, bullet in enumerate(bullets):
p = body_tf.add_paragraph() if i > 0 else body_tf.paragraphs[0]
p.text = f"• {bullet}"
p.runs[0].font.size = Pt(20)
pres.save('/tmp/deck.pptx')
print(f"Slide {len(pres.slides)}/{TOTAL} added.")
Call #N+1 — Upload
import boto3
S3_URI = "s3://idp-v2-agent-storage-008165007574/user/proj/artifacts/art_xxx/deck.pptx" # paste from artifact_path
BUCKET, KEY = S3_URI.replace("s3://", "").split("/", 1)
s3 = boto3.client('s3')
with open('/tmp/deck.pptx', 'rb') as f:
s3.upload_fileobj(
f, BUCKET, KEY,
ExtraArgs={
'ContentType': 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
}
)
# Verify
from pptx import Presentation
final = Presentation('/tmp/deck.pptx')
print(f"✅ Uploaded {len(final.slides)} slides to s3://{BUCKET}/{KEY}")
Then report the artifact_ref to the user.
Important rules for the incremental workflow
- Always load the deck from
/tmp/deck.pptx at the start of each call — do NOT create a new Presentation() except in call #1.
- Always save back to
/tmp/deck.pptx at the end of each call (except the upload call).
- Each call MUST
print() at least once — the runtime treats empty stdout as failure.
- Use the same filename
/tmp/deck.pptx throughout — do not rename between calls.
- Hardcode the S3 URI string in the upload call (sandbox cannot access agent variables).
- Do not split a single slide across multiple calls — always complete one slide per call at minimum.
- For 2+ slides per call, group logically related slides (e.g., two comparison slides together). Keep total code under ~5 KB per call.
- If a call errors out, the previous successful saves are still on disk. You can resume from the failed slide.
Quick Reference
| Task |
Approach |
| Read/analyze content |
Download from S3 → markitdown or python-pptx in code_interpreter |
| Create new presentation |
Read python-pptx.md, use code_interpreter |
| Edit existing presentation |
Read editing.md, unpack → edit XML → repack in code_interpreter |
Charts
When the user requests charts or visualizations, always attempt to embed charts directly using python-pptx first. Only use the chart skill if direct embedding is not possible or the chart type is unsupported by python-pptx.
from pptx.util import Inches
from pptx.chart.data import ChartData
from pptx import chart as pptx_chart
chart_data = ChartData()
chart_data.categories = ['Q1', 'Q2', 'Q3', 'Q4']
chart_data.add_series('Revenue', (100, 120, 140, 160))
slide.shapes.add_chart(
pptx_chart.XL_CHART_TYPE.BAR_CLUSTERED,
Inches(1), Inches(1.5), Inches(8), Inches(3.5),
chart_data
)
Reading Content
Read .pptx files by downloading from the given S3 path and using tools in code_interpreter.
import boto3
s3 = boto3.client('s3')
s3.download_file(bucket, key, 'presentation.pptx')
# Text extraction
import subprocess
result = subprocess.run(['python', '-m', 'markitdown', 'presentation.pptx'], capture_output=True, text=True)
print(result.stdout)
# Visual overview (thumbnail grid)
import subprocess
subprocess.run(['python', 'scripts/thumbnail.py', 'presentation.pptx'])
# Raw XML inspection
subprocess.run(['python', 'scripts/office/unpack.py', 'presentation.pptx', 'unpacked/'])
Creating from Scratch
Read python-pptx.md for full details.
Use when no template or reference presentation is available.
Editing Workflow
Read editing.md for full details.
- Analyze template with
thumbnail.py
- Unpack → manipulate slides → edit content → clean → pack
Design Ideas
Don't create boring slides. Plain bullets on a white background won't impress anyone. Consider ideas from this list for each slide.
Before Starting
- Pick a bold, content-informed color palette: The palette should feel designed for THIS topic. If swapping your colors into a completely different presentation would still "work," you haven't made specific enough choices.
- Dominance over equality: One color should dominate (60-70% visual weight), with 1-2 supporting tones and one sharp accent. Never give all colors equal weight.
- Dark/light contrast: Dark backgrounds for title + conclusion slides, light for content ("sandwich" structure). Or commit to dark throughout for a premium feel.
- Commit to a visual motif: Pick ONE distinctive element and repeat it — rounded image frames, icons in colored circles, thick single-side borders. Carry it across every slide.
Color Palettes
Choose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:
| Theme |
Primary |
Secondary |
Accent |
| Midnight Executive |
1E2761 (navy) |
CADCFC (ice blue) |
FFFFFF (white) |
| Forest & Moss |
2C5F2D (forest) |
97BC62 (moss) |
F5F5F5 (cream) |
| Coral Energy |
F96167 (coral) |
F9E795 (gold) |
2F3C7E (navy) |
| Warm Terracotta |
B85042 (terracotta) |
E7E8D1 (sand) |
A7BEAE (sage) |
| Ocean Gradient |
065A82 (deep blue) |
1C7293 (teal) |
21295C (midnight) |
| Charcoal Minimal |
36454F (charcoal) |
F2F2F2 (off-white) |
212121 (black) |
| Teal Trust |
028090 (teal) |
00A896 (seafoam) |
02C39A (mint) |
| Berry & Cream |
6D2E46 (berry) |
A26769 (dusty rose) |
ECE2D0 (cream) |
| Sage Calm |
84B59F (sage) |
69A297 (eucalyptus) |
50808E (slate) |
| Cherry Bold |
990011 (cherry) |
FCF6F5 (off-white) |
2F3C7E (navy) |
For Each Slide
Every slide needs a visual element — image, chart, icon, or shape. Text-only slides are forgettable.
Layout options:
- Two-column (text left, illustration on right)
- Icon + text rows (icon in colored circle, bold header, description below)
- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)
- Half-bleed image (full left or right side) with content overlay
Data display:
- Large stat callouts (big numbers 60-72pt with small labels below)
- Comparison columns (before/after, pros/cons, side-by-side options)
- Timeline or process flow (numbered steps, arrows)
Visual polish:
- Icons in small colored circles next to section headers
- Italic accent text for key stats or taglines
Images
Presentations are visual — use real images to make slides compelling.
Tool selection:
- If
image___search_image is available in your tool list, use it to find relevant images before calling code_interpreter.
- If
image___search_image is NOT available, use generate_image to create custom images that fit each slide's message.
Workflow:
- Before
code_interpreter, plan which slides need images and call image___search_image (or generate_image if unavailable) for each topic.
- Collect the returned image URLs.
- Inside
code_interpreter, download each URL and embed with add_picture().
import requests
from io import BytesIO
from pptx.util import Inches
# Download image from URL (obtained via image___search_image or generate_image)
resp = requests.get(image_url)
slide.shapes.add_picture(BytesIO(resp.content), Inches(5.2), Inches(1.2), Inches(4.5), Inches(3))
Guidelines:
- Use images on slides with
image_right, image_left, or image_center layouts
- Match image content to the slide's topic — generic stock photos weaken the message
- Max 1 image per slide — multiple images per slide cause clutter
- Max 8 images per presentation — too many slows download and increases file size
- Always specify both width and height, or use aspect ratio preservation (see python-pptx.md)
- If
image___search_image returns no good results, use generate_image as fallback
- For data-heavy slides, prefer charts over images
Typography
Choose an interesting font pairing — don't default to Arial. Pick a header font with personality and pair it with a clean body font.
| Header Font |
Body Font |
| Georgia |
Calibri |
| Arial Black |
Arial |
| Calibri |
Calibri Light |
| Cambria |
Calibri |
| Trebuchet MS |
Calibri |
| Impact |
Arial |
| Palatino |
Garamond |
| Consolas |
Calibri |
| Element |
Size |
| Slide title |
36-44pt bold |
| Section header |
20-24pt bold |
| Body text |
14-16pt |
| Captions |
10-12pt muted |
Spacing
- 0.5" minimum margins
- 0.3-0.5" between content blocks
- Leave breathing room—don't fill every inch
Avoid (Common Mistakes)
- Don't repeat the same layout — vary columns, cards, and callouts across slides
- Don't center body text — left-align paragraphs and lists; center only titles
- Don't skimp on size contrast — titles need 36pt+ to stand out from 14-16pt body
- Don't default to blue — pick colors that reflect the specific topic
- Don't mix spacing randomly — choose 0.3" or 0.5" gaps and use consistently
- Don't style one slide and leave the rest plain — commit fully or keep it simple throughout
- Don't create text-only slides — add images, icons, charts, or visual elements; avoid plain title + bullets
- Don't forget text box padding — when aligning lines or shapes with text edges, set
margin: 0 on the text box or offset the shape to account for padding
- Don't use low-contrast elements — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds
- NEVER use accent lines under titles — these are a hallmark of AI-generated slides; use whitespace or background color instead
- Max 6 bullet points per slide — more than 6 makes slides dense and hard to read
Layout Reference
All positions in Inches(x, y, width, height). Slide size: 10" x 5.625" (16:9)
Position Table
| Layout |
Title |
Content |
Image/Special |
| title_slide |
(0.5, 2, 9, 1) |
subtitle: (0.5, 3.2, 9, 0.6) |
bg: primaryColor |
| default |
(0.5, 0.3, 9, 0.8) |
(0.5, 1.3, 9, 4) |
- |
| two_column |
(0.5, 0.3, 9, 0.8) |
L:(0.5, 1.3, 4.3, 4) R:(5.2, 1.3, 4.3, 4) |
- |
| image_right |
(0.5, 0.3, 9, 0.8) |
(0.5, 1.3, 4.5, 4) |
img:(5.2, 1.2, 4.5, 3) |
| image_left |
(0.5, 0.3, 9, 0.8) |
(5.2, 1.3, 4.5, 4) |
img:(0.3, 1.2, 4.5, 3) |
| image_center |
(0.5, 0.3, 9, 0.8) |
caption below |
img:(2.5, 1.2, 5, 3) |
| comparison |
(0.5, 0.3, 9, 0.8) |
table:(0.5, 1.3, 9, 3.5) |
- |
| quote |
- |
quote:(1, 1.5, 8, 3) |
bg:(245,245,245), "\u201C" at (0.5, 0.8) |
| end |
(0.5, 2, 9, 1) centered |
- |
bg: primaryColor |
Layout Details
- title_slide: Dark background (primaryColor), white text, centered title (44pt) + subtitle (24pt)
- default: Standard content slide with title (32pt) and bullet points (20pt)
- two_column: Title + two equal columns. Use for pros/cons, comparisons, before/after
- image_right/left: Content on one side, image on other
- image_center: Large centered image with title above and optional caption below
- comparison: Table layout — header row with primaryColor background and white text, data rows with white background
- quote: Light gray background, large quote mark "\u201C" (120pt, gray), quote text centered
- end: Same style as title_slide, "Thank You" (48pt) or custom closing message
Design Tokens
Default design token values when no specific theme is chosen:
| Token |
Value |
| Primary (titles/headers) |
RGBColor(0, 51, 102) — Navy blue |
| White |
RGBColor(255, 255, 255) |
| Light gray (placeholder bg) |
RGBColor(230, 230, 230) |
| Medium gray (secondary text) |
RGBColor(128, 128, 128) |
| Quote bg |
RGBColor(245, 245, 245) |
| Title slide main |
Pt(44) |
| Title slide subtitle |
Pt(24) |
| Slide titles |
Pt(32) |
| Body text |
Pt(20) |
| Attribution |
Pt(8) |
| Bullet spacing |
space_before = Pt(12) |
QA (Required)
Assume there are problems. Your job is to find them.
Your first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.
Content QA
import subprocess
result = subprocess.run(['python', '-m', 'markitdown', 'output.pptx'], capture_output=True, text=True)
print(result.stdout)
Check for missing content, typos, wrong order.
When using templates, check for leftover placeholder text:
import subprocess
result = subprocess.run(['python', '-m', 'markitdown', 'output.pptx'], capture_output=True, text=True)
import re
matches = re.findall(r'(?i)(xxxx|lorem|ipsum|this.*(page|slide).*layout)', result.stdout)
print(matches)
If matches are found, fix them before declaring success.
Structural QA
Run the structural QA script to check layout issues programmatically:
import subprocess
result = subprocess.run(['python', 'scripts/structural_qa.py', 'output.pptx'], capture_output=True, text=True)
print(result.stdout)
This checks for:
- Overlapping elements (bounding box intersection)
- Insufficient margin from slide edges (< 0.5")
- Elements too close (< 0.3" gaps)
- Estimated text overflow (text volume vs box size)
- Leftover placeholder content (xxxx, lorem, ipsum, etc.)
Verification Loop
- Generate slides → Convert to images → Inspect
- List issues found (if none found, look again more critically)
- Fix issues
- Re-verify affected slides — one fix often creates another problem
- Repeat until a full pass reveals no new issues
Do not declare success until you've completed at least one fix-and-verify cycle.
Dependencies
python-pptx, markitdown, Pillow, lxml, boto3, matplotlib, requests are pre-installed in the Code Interpreter sandbox. Do NOT call !pip install — import directly.
1---2name: pptx3description: PowerPoint presentation (.pptx) creation, editing, reading, and manipulation skill. Use when the user wants to create, read, edit, or manipulate PowerPoint presentations (.pptx files). Triggers include: any mention of 'slides', 'deck', 'presentation', '.pptx', or requests for slide decks, pitch decks. Also for deliverables as .pptx. When an S3 URI with .pptx extension is provided. Do NOT use for PDFs, Word documents, or Google Slides.4---56# PPTX creation, editing, and analysis78## Execution Rules910- **ALL code execution MUST use the `code_interpreter` tool.** Do NOT use the `shell` tool.11- **NEVER call `!pip install`.** `python-pptx`, `boto3`, `Pillow`, `lxml`, `matplotlib`, `numpy`, `requests`, `markitdown` are pre-installed in the AgentCore Code Interpreter sandbox. Import directly. If an import fails, stop and report the error to the user — do not attempt to install anything.12- **Build the presentation INCREMENTALLY across multiple small `code_interpreter` calls, one or two slides per call.** Do NOT cram the entire deck into a single 30+ KB script. See the Incremental Workflow below.13- **EVERY `code_interpreter` call MUST end with a `print(...)` that reports progress.** Empty stdout is interpreted by the runtime as a failure. Always print at least one line describing what was accomplished.14- Before calling `code_interpreter`, call `artifact_path(filename="presentation.pptx")` to get the S3 bucket and key.15- After the final upload, report the `artifact_ref` to the user.16- **If `code_interpreter` fails with an error, do NOT retry automatically.** Report the error to the user and ask for clarification or guidance. Do not make multiple retry attempts without user input.1718## Incremental Workflow1920The AgentCore Code Interpreter preserves session state between calls — files written to `/tmp` in one `code_interpreter` invocation remain available in the next call of the same session. Use this to build the deck one slide at a time instead of generating all slides in a single monolithic script.2122**Benefits:**23- Each call is small (~1–3 KB of code) and generates in ~15–25 seconds instead of 4+ minutes.24- Failures affect only one slide — previous slides stay saved in `/tmp/deck.pptx`.25- Users see real-time progress: "slide 3/12 added" appears in the UI after each call.2627### Call sequence (typical 10-slide deck)28291. `artifact_path(filename="presentation.pptx")` — get S3 URI (ONCE)302. **Call #1** — Create empty deck, set slide size/theme, save to `/tmp/deck.pptx`313. **Call #2** — Load deck, add slide 1 (title slide), save324. **Call #3** — Load deck, add slide 2 (content), save335. ... one call per slide (or two slides per call if small) ...346. **Call #N+1** — Load deck, upload `/tmp/deck.pptx` to S3357. Report `artifact_ref`3637### Call #1 — Create empty deck3839```python40from pptx import Presentation41from pptx.util import Inches4243pres = Presentation()44pres.slide_width = Inches(13.333) # 16:945pres.slide_height = Inches(7.5)46pres.save('/tmp/deck.pptx')47print(f"Created blank deck: 16:9, 0 slides. Target total: 10 slides.")48```4950### Call #2 — Title slide5152```python53from pptx import Presentation54from pptx.util import Inches, Pt55from pptx.dml.color import RGBColor56from pptx.enum.text import PP_ALIGN5758pres = Presentation('/tmp/deck.pptx') # load existing59slide = pres.slides.add_slide(pres.slide_layouts[6]) # blank layout6061# Title62title_box = slide.shapes.add_textbox(Inches(0.5), Inches(2.8), Inches(12.3), Inches(1.5))63tf = title_box.text_frame64p = tf.paragraphs[0]65p.text = "<presentation title>"66p.alignment = PP_ALIGN.CENTER67p.runs[0].font.size = Pt(44)68p.runs[0].font.bold = True69p.runs[0].font.color.rgb = RGBColor(0x1F, 0x39, 0x64)7071# Subtitle72sub_box = slide.shapes.add_textbox(Inches(0.5), Inches(4.5), Inches(12.3), Inches(0.8))73sub_p = sub_box.text_frame.paragraphs[0]74sub_p.text = "<subtitle / author / date>"75sub_p.alignment = PP_ALIGN.CENTER76sub_p.runs[0].font.size = Pt(20)77sub_p.runs[0].font.color.rgb = RGBColor(0x66, 0x66, 0x66)7879pres.save('/tmp/deck.pptx')80print(f"Slide 1/{TOTAL} (title) added. Deck now has {len(pres.slides)} slides.")81```8283### Call #3…N — Each content slide follows the same load → add → save → print pattern8485```python86from pptx import Presentation87from pptx.util import Inches, Pt88from pptx.dml.color import RGBColor8990pres = Presentation('/tmp/deck.pptx')91slide = pres.slides.add_slide(pres.slide_layouts[6])9293# Slide title94title = slide.shapes.add_textbox(Inches(0.5), Inches(0.3), Inches(12.3), Inches(0.8))95t_p = title.text_frame.paragraphs[0]96t_p.text = "<slide title>"97t_p.runs[0].font.size = Pt(28)98t_p.runs[0].font.bold = True99t_p.runs[0].font.color.rgb = RGBColor(0x1F, 0x39, 0x64)100101# Body content (bullet list example — replace bullets with actual content)102body = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(12.3), Inches(5.5))103body_tf = body.text_frame104body_tf.word_wrap = True105bullets = ["<bullet 1>", "<bullet 2>", "<bullet 3>"]106for i, bullet in enumerate(bullets):107 p = body_tf.add_paragraph() if i > 0 else body_tf.paragraphs[0]108 p.text = f"• {bullet}"109 p.runs[0].font.size = Pt(20)110111pres.save('/tmp/deck.pptx')112print(f"Slide {len(pres.slides)}/{TOTAL} added.")113```114115### Call #N+1 — Upload116117```python118import boto3119120S3_URI = "s3://idp-v2-agent-storage-008165007574/user/proj/artifacts/art_xxx/deck.pptx" # paste from artifact_path121BUCKET, KEY = S3_URI.replace("s3://", "").split("/", 1)122123s3 = boto3.client('s3')124with open('/tmp/deck.pptx', 'rb') as f:125 s3.upload_fileobj(126 f, BUCKET, KEY,127 ExtraArgs={128 'ContentType': 'application/vnd.openxmlformats-officedocument.presentationml.presentation'129 }130 )131132# Verify133from pptx import Presentation134final = Presentation('/tmp/deck.pptx')135print(f"✅ Uploaded {len(final.slides)} slides to s3://{BUCKET}/{KEY}")136```137138Then report the `artifact_ref` to the user.139140### Important rules for the incremental workflow141142- **Always load the deck from `/tmp/deck.pptx` at the start of each call** — do NOT create a new `Presentation()` except in call #1.143- **Always save back to `/tmp/deck.pptx` at the end of each call** (except the upload call).144- **Each call MUST `print()` at least once** — the runtime treats empty stdout as failure.145- **Use the same filename `/tmp/deck.pptx` throughout** — do not rename between calls.146- **Hardcode the S3 URI string** in the upload call (sandbox cannot access agent variables).147- **Do not split a single slide across multiple calls** — always complete one slide per call at minimum.148- **For 2+ slides per call**, group logically related slides (e.g., two comparison slides together). Keep total code under ~5 KB per call.149- **If a call errors out**, the previous successful saves are still on disk. You can resume from the failed slide.150151---152153## Quick Reference154155| Task | Approach |156|------|----------|157| Read/analyze content | Download from S3 → `markitdown` or `python-pptx` in code_interpreter |158| Create new presentation | Read [python-pptx.md](python-pptx.md), use code_interpreter |159| Edit existing presentation | Read [editing.md](editing.md), unpack → edit XML → repack in code_interpreter |160161## Charts162163**When the user requests charts or visualizations, always attempt to embed charts directly using `python-pptx` first.** Only use the `chart` skill if direct embedding is not possible or the chart type is unsupported by python-pptx.164165```python166from pptx.util import Inches167from pptx.chart.data import ChartData168from pptx import chart as pptx_chart169170chart_data = ChartData()171chart_data.categories = ['Q1', 'Q2', 'Q3', 'Q4']172chart_data.add_series('Revenue', (100, 120, 140, 160))173174slide.shapes.add_chart(175 pptx_chart.XL_CHART_TYPE.BAR_CLUSTERED,176 Inches(1), Inches(1.5), Inches(8), Inches(3.5),177 chart_data178)179```180181---182183## Reading Content184185Read .pptx files by downloading from the given S3 path and using tools in `code_interpreter`.186187```python188import boto3189190s3 = boto3.client('s3')191s3.download_file(bucket, key, 'presentation.pptx')192193# Text extraction194import subprocess195result = subprocess.run(['python', '-m', 'markitdown', 'presentation.pptx'], capture_output=True, text=True)196print(result.stdout)197```198199```python200# Visual overview (thumbnail grid)201import subprocess202subprocess.run(['python', 'scripts/thumbnail.py', 'presentation.pptx'])203204# Raw XML inspection205subprocess.run(['python', 'scripts/office/unpack.py', 'presentation.pptx', 'unpacked/'])206```207208---209210## Creating from Scratch211212**Read [python-pptx.md](python-pptx.md) for full details.**213214Use when no template or reference presentation is available.215216---217218## Editing Workflow219220**Read [editing.md](editing.md) for full details.**2212221. Analyze template with `thumbnail.py`2232. Unpack → manipulate slides → edit content → clean → pack224225---226227## Design Ideas228229**Don't create boring slides.** Plain bullets on a white background won't impress anyone. Consider ideas from this list for each slide.230231### Before Starting232233- **Pick a bold, content-informed color palette**: The palette should feel designed for THIS topic. If swapping your colors into a completely different presentation would still "work," you haven't made specific enough choices.234- **Dominance over equality**: One color should dominate (60-70% visual weight), with 1-2 supporting tones and one sharp accent. Never give all colors equal weight.235- **Dark/light contrast**: Dark backgrounds for title + conclusion slides, light for content ("sandwich" structure). Or commit to dark throughout for a premium feel.236- **Commit to a visual motif**: Pick ONE distinctive element and repeat it — rounded image frames, icons in colored circles, thick single-side borders. Carry it across every slide.237238### Color Palettes239240Choose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:241242| Theme | Primary | Secondary | Accent |243|-------|---------|-----------|--------|244| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |245| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |246| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |247| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |248| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |249| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |250| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |251| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |252| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |253| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |254255### For Each Slide256257**Every slide needs a visual element** — image, chart, icon, or shape. Text-only slides are forgettable.258259**Layout options:**260- Two-column (text left, illustration on right)261- Icon + text rows (icon in colored circle, bold header, description below)262- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)263- Half-bleed image (full left or right side) with content overlay264265**Data display:**266- Large stat callouts (big numbers 60-72pt with small labels below)267- Comparison columns (before/after, pros/cons, side-by-side options)268- Timeline or process flow (numbered steps, arrows)269270**Visual polish:**271- Icons in small colored circles next to section headers272- Italic accent text for key stats or taglines273274### Images275276Presentations are visual — use real images to make slides compelling.277278**Tool selection:**279- If `image___search_image` is available in your tool list, use it to find relevant images *before* calling `code_interpreter`.280- If `image___search_image` is NOT available, use `generate_image` to create custom images that fit each slide's message.281282**Workflow:**2831. **Before** `code_interpreter`, plan which slides need images and call `image___search_image` (or `generate_image` if unavailable) for each topic.2842. Collect the returned image URLs.2853. **Inside** `code_interpreter`, download each URL and embed with `add_picture()`.286287```python288import requests289from io import BytesIO290from pptx.util import Inches291292# Download image from URL (obtained via image___search_image or generate_image)293resp = requests.get(image_url)294slide.shapes.add_picture(BytesIO(resp.content), Inches(5.2), Inches(1.2), Inches(4.5), Inches(3))295```296297**Guidelines:**298- Use images on slides with `image_right`, `image_left`, or `image_center` layouts299- Match image content to the slide's topic — generic stock photos weaken the message300- **Max 1 image per slide** — multiple images per slide cause clutter301- **Max 8 images per presentation** — too many slows download and increases file size302- Always specify both width and height, or use aspect ratio preservation (see python-pptx.md)303- If `image___search_image` returns no good results, use `generate_image` as fallback304- For data-heavy slides, prefer charts over images305306### Typography307308**Choose an interesting font pairing** — don't default to Arial. Pick a header font with personality and pair it with a clean body font.309310| Header Font | Body Font |311|-------------|-----------|312| Georgia | Calibri |313| Arial Black | Arial |314| Calibri | Calibri Light |315| Cambria | Calibri |316| Trebuchet MS | Calibri |317| Impact | Arial |318| Palatino | Garamond |319| Consolas | Calibri |320321| Element | Size |322|---------|------|323| Slide title | 36-44pt bold |324| Section header | 20-24pt bold |325| Body text | 14-16pt |326| Captions | 10-12pt muted |327328### Spacing329330- 0.5" minimum margins331- 0.3-0.5" between content blocks332- Leave breathing room—don't fill every inch333334### Avoid (Common Mistakes)335336- **Don't repeat the same layout** — vary columns, cards, and callouts across slides337- **Don't center body text** — left-align paragraphs and lists; center only titles338- **Don't skimp on size contrast** — titles need 36pt+ to stand out from 14-16pt body339- **Don't default to blue** — pick colors that reflect the specific topic340- **Don't mix spacing randomly** — choose 0.3" or 0.5" gaps and use consistently341- **Don't style one slide and leave the rest plain** — commit fully or keep it simple throughout342- **Don't create text-only slides** — add images, icons, charts, or visual elements; avoid plain title + bullets343- **Don't forget text box padding** — when aligning lines or shapes with text edges, set `margin: 0` on the text box or offset the shape to account for padding344- **Don't use low-contrast elements** — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds345- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead346- **Max 6 bullet points per slide** — more than 6 makes slides dense and hard to read347348---349350## Layout Reference351352All positions in `Inches(x, y, width, height)`. Slide size: 10" x 5.625" (16:9)353354### Position Table355356| Layout | Title | Content | Image/Special |357|--------|-------|---------|---------------|358| title_slide | (0.5, 2, 9, 1) | subtitle: (0.5, 3.2, 9, 0.6) | bg: primaryColor |359| default | (0.5, 0.3, 9, 0.8) | (0.5, 1.3, 9, 4) | - |360| two_column | (0.5, 0.3, 9, 0.8) | L:(0.5, 1.3, 4.3, 4) R:(5.2, 1.3, 4.3, 4) | - |361| image_right | (0.5, 0.3, 9, 0.8) | (0.5, 1.3, 4.5, 4) | img:(5.2, 1.2, 4.5, 3) |362| image_left | (0.5, 0.3, 9, 0.8) | (5.2, 1.3, 4.5, 4) | img:(0.3, 1.2, 4.5, 3) |363| image_center | (0.5, 0.3, 9, 0.8) | caption below | img:(2.5, 1.2, 5, 3) |364| comparison | (0.5, 0.3, 9, 0.8) | table:(0.5, 1.3, 9, 3.5) | - |365| quote | - | quote:(1, 1.5, 8, 3) | bg:(245,245,245), "\u201C" at (0.5, 0.8) |366| end | (0.5, 2, 9, 1) centered | - | bg: primaryColor |367368### Layout Details369370- **title_slide**: Dark background (primaryColor), white text, centered title (44pt) + subtitle (24pt)371- **default**: Standard content slide with title (32pt) and bullet points (20pt)372- **two_column**: Title + two equal columns. Use for pros/cons, comparisons, before/after373- **image_right/left**: Content on one side, image on other374- **image_center**: Large centered image with title above and optional caption below375- **comparison**: Table layout — header row with primaryColor background and white text, data rows with white background376- **quote**: Light gray background, large quote mark "\u201C" (120pt, gray), quote text centered377- **end**: Same style as title_slide, "Thank You" (48pt) or custom closing message378379---380381## Design Tokens382383Default design token values when no specific theme is chosen:384385| Token | Value |386|-------|-------|387| Primary (titles/headers) | `RGBColor(0, 51, 102)` — Navy blue |388| White | `RGBColor(255, 255, 255)` |389| Light gray (placeholder bg) | `RGBColor(230, 230, 230)` |390| Medium gray (secondary text) | `RGBColor(128, 128, 128)` |391| Quote bg | `RGBColor(245, 245, 245)` |392| Title slide main | `Pt(44)` |393| Title slide subtitle | `Pt(24)` |394| Slide titles | `Pt(32)` |395| Body text | `Pt(20)` |396| Attribution | `Pt(8)` |397| Bullet spacing | `space_before = Pt(12)` |398399---400401## QA (Required)402403**Assume there are problems. Your job is to find them.**404405Your first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.406407### Content QA408409```python410import subprocess411result = subprocess.run(['python', '-m', 'markitdown', 'output.pptx'], capture_output=True, text=True)412print(result.stdout)413```414415Check for missing content, typos, wrong order.416417**When using templates, check for leftover placeholder text:**418419```python420import subprocess421result = subprocess.run(['python', '-m', 'markitdown', 'output.pptx'], capture_output=True, text=True)422import re423matches = re.findall(r'(?i)(xxxx|lorem|ipsum|this.*(page|slide).*layout)', result.stdout)424print(matches)425```426427If matches are found, fix them before declaring success.428429### Structural QA430431Run the structural QA script to check layout issues programmatically:432433```python434import subprocess435result = subprocess.run(['python', 'scripts/structural_qa.py', 'output.pptx'], capture_output=True, text=True)436print(result.stdout)437```438439This checks for:440- Overlapping elements (bounding box intersection)441- Insufficient margin from slide edges (< 0.5")442- Elements too close (< 0.3" gaps)443- Estimated text overflow (text volume vs box size)444- Leftover placeholder content (xxxx, lorem, ipsum, etc.)445446### Verification Loop4474481. Generate slides → Convert to images → Inspect4492. **List issues found** (if none found, look again more critically)4503. Fix issues4514. **Re-verify affected slides** — one fix often creates another problem4525. Repeat until a full pass reveals no new issues453454**Do not declare success until you've completed at least one fix-and-verify cycle.**455456---457458## Dependencies459460`python-pptx`, `markitdown`, `Pillow`, `lxml`, `boto3`, `matplotlib`, `requests` are pre-installed in the Code Interpreter sandbox. Do NOT call `!pip install` — import directly.