When using an existing presentation as a template:
-
Analyze existing slides:
python scripts/thumbnail.py template.pptx python -m markitdown template.pptx
Review
thumbnails.jpgto see layouts, and markitdown output to see placeholder text. -
Plan slide mapping: For each content section, choose a template slide.
⚠️ USE VARIED LAYOUTS — monotonous presentations are a common failure mode. Don't default to basic title + bullet slides. Actively seek out:- Multi-column layouts (2-column, 3-column)
- Image + text combinations
- Full-bleed images with text overlay
- Quote or callout slides
- Section dividers
- Stat/number callouts
- Icon grids or icon + text rows
Avoid: Repeating the same text-heavy layout for every slide.
Match content type to layout style (e.g., key points → bullet slide, team info → multi-column, testimonials → quote slide).
-
Unpack:
python scripts/office/unpack.py template.pptx unpacked/ -
Build presentation (do this yourself, not with subagents):
- Delete unwanted slides (remove from
<p:sldIdLst>) - Duplicate slides you want to reuse (
add_slide.py) - Reorder slides in
<p:sldIdLst> - Complete all structural changes before step 5
- Delete unwanted slides (remove from
-
Edit content: Update text in each
slide{N}.xml. Use subagents here if available — slides are separate XML files, so subagents can edit in parallel. -
Clean:
python scripts/clean.py unpacked/ -
Pack:
python scripts/office/pack.py unpacked/ output.pptx --original template.pptx
| Script | Purpose |
|---|---|
unpack.py |
Extract and pretty-print PPTX |
add_slide.py |
Duplicate slide or create from layout |
clean.py |
Remove orphaned files |
pack.py |
Repack with validation |
thumbnail.py |
Create visual grid of slides |
python scripts/office/unpack.py input.pptx unpacked/Extracts PPTX, pretty-prints XML, escapes smart quotes.
python scripts/add_slide.py unpacked/ slide2.xml # Duplicate slide
python scripts/add_slide.py unpacked/ slideLayout2.xml # From layoutPrints <p:sldId> to add to <p:sldIdLst> at desired position.
python scripts/clean.py unpacked/Removes slides not in <p:sldIdLst>, unreferenced media, orphaned rels.
python scripts/office/pack.py unpacked/ output.pptx --original input.pptxValidates, repairs, condenses XML, re-encodes smart quotes.
python scripts/thumbnail.py input.pptx [output_prefix] [--cols N]Creates thumbnails.jpg with slide filenames as labels. Default 3 columns, max 12 per grid.
Use for template analysis only (choosing layouts). For visual QA, use soffice + pdftoppm to create full-resolution individual slide images—see SKILL.md.
Slide order is in ppt/presentation.xml → <p:sldIdLst>.
Reorder: Rearrange <p:sldId> elements.
Delete: Remove <p:sldId>, then run clean.py.
Add: Use add_slide.py. Never manually copy slide files—the script handles notes references, Content_Types.xml, and relationship IDs that manual copying misses.
Subagents: If available, use them here (after completing step 4). Each slide is a separate XML file, so subagents can edit in parallel. In your prompt to subagents, include:
- The slide file path(s) to edit
- "Use the Edit tool for all changes"
- The formatting rules and common pitfalls below
For each slide:
- Read the slide's XML
- Identify ALL placeholder content—text, images, charts, icons, captions
- Replace each placeholder with final content
Use the Edit tool, not sed or Python scripts. The Edit tool forces specificity about what to replace and where, yielding better reliability.
- Bold all headers, subheadings, and inline labels: Use
b="1"on<a:rPr>. This includes:- Slide titles
- Section headers within a slide
- Inline labels like (e.g.: "Status:", "Description:") at the start of a line
- Never use unicode bullets (•): Use proper list formatting with
<a:buChar>or<a:buAutoNum> - Bullet consistency: Let bullets inherit from the layout. Only specify
<a:buChar>or<a:buNone>.
When source content has fewer items than the template:
- Remove excess elements entirely (images, shapes, text boxes), don't just clear text
- Check for orphaned visuals after clearing text content
- Run visual QA to catch mismatched counts
When replacing text with different length content:
- Shorter replacements: Usually safe
- Longer replacements: May overflow or wrap unexpectedly
- Test with visual QA after text changes
- Consider truncating or splitting content to fit the template's design constraints
Template slots ≠ Source items: If template has 4 team members but source has 3 users, delete the 4th member's entire group (image + text boxes), not just the text.
If source has multiple items (numbered lists, multiple sections), create separate <a:p> elements for each — never concatenate into one string.
❌ WRONG — all items in one paragraph:
<a:p>
<a:r><a:rPr .../><a:t>Step 1: Do the first thing. Step 2: Do the second thing.</a:t></a:r>
</a:p>✅ CORRECT — separate paragraphs with bold headers:
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 1</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" .../><a:t>Do the first thing.</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 2</a:t></a:r>
</a:p>
<!-- continue pattern -->Copy <a:pPr> from the original paragraph to preserve line spacing. Use b="1" on headers.
Handled automatically by unpack/pack. But the Edit tool converts smart quotes to ASCII.
When adding new text with quotes, use XML entities:
<a:t>the “Agreement”</a:t>| Character | Name | Unicode | XML Entity |
|---|---|---|---|
“ |
Left double quote | U+201C | “ |
” |
Right double quote | U+201D | ” |
‘ |
Left single quote | U+2018 | ‘ |
’ |
Right single quote | U+2019 | ’ |
- Whitespace: Use
xml:space="preserve"on<a:t>with leading/trailing spaces - XML parsing: Use
defusedxml.minidom, notxml.etree.ElementTree(corrupts namespaces)