Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Extract a PowerPoint (.pptx) file into the user's plain-text slide authoring format: a Markdown title + body per slide, presenter instructions in [brackets], a `===` separator, then speaker notes, with `---` between slides. Use this whenever the user uploads or points to a .pptx and wants the slides "as text", "in my slide format", reverse-engineered back into editable source, or wants the bullets / notes / animations / images pulled out of an existing deck. Trigger even if they just say "turn t
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 106% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 42% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 142% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 29% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 108% | 0% |
Convert an existing .pptx back into the plain-text format the user writes slides in, so a finished deck becomes editable source again.
One block per slide. --- separates slides; === separates slide content from speaker notes. Presenter instructions (images, animations, demos) live in [brackets] inside the content area. If the deck has sections, each section begins with a [Section N: Section Name] label before the first slide in that section.
[Section 1: Introduction]
[Slide 1]
# Slide Title
Slide content in markdown: bullets, numbered lists, tables, **bold**, *italic*, ~~strikethrough~~, [links](url).
[image: assets/slide3_img1.png — "alt text"]
[animation — 2 click steps:
click 1: entrance of "First point"
click 2: entrance of "Second point"]
===
**Speaker Notes:**
Notes in markdown.
---
[Slide 2]
# Next Slide Title
...
===
**Speaker Notes:**
*(none)*Each slide is preceded by a [Slide N] label (N is the slide's position in the deck, so a subset extraction keeps the original numbers). --- separates slides and === separates content from notes, as before.
Blank lines between elements ensure Markdown viewers render each block as a separate paragraph rather than collapsing consecutive lines into soft-wrapped text.
The user also uses [^] inside speaker notes to mark a click. See the note on animations below for why extraction puts animation detail in the content area rather than fabricating [^] positions in the notes.
The work is done by scripts/extract.py (Python 3; needs python-pptx and lxml). lxml normally arrives as a dependency of python-pptx, but the script imports it directly (from lxml import etree), so it is declared in its own right in requirements.txt.
bashpip install python-pptx lxml --break-system-packages # if not already present python scripts/extract.py <input.pptx> -o <output.md>
Options:
-o, --output — output path (default: <input-stem>.md in the cwd).--slides — subset to extract, e.g. --slides 3-20 or --slides 1,4,7-9(1-based; default: all). Numbers in [Slide N] stay absolute.
--images-dir DIR — where to write extracted images (default:<output-stem>_images/ next to the output file).
--no-images — don't write image files; still emit [image: filename] inline.After running, read the output file and make it available to the user. Surface the generated .md (and the images folder) using whatever file-sharing mechanism your runtime offers — a file preview or attachment if one exists, otherwise point the user to the output path. Don't paste a huge deck inline if it's long — write the file and show a representative excerpt.
# Heading (from the slide's title placeholder).-, nested with two spaces),numbered lists for auto-numbered paragraphs, plain paragraphs when a paragraph has no bullet. Run formatting becomes **bold**, *italic*, ***both***, ~~strikethrough~~, and [text](url) for hyperlinks. Adjacent runs with the same formatting are merged; soft line breaks within a paragraph become spaces.
[image: <path> — "<alt text>"] (alt text included when the shape has it).
[chart: <type> — "<title>"] (not the underlying data).[SmartArt/diagram — text: ...] when text isreachable, otherwise a note that the text isn't extractable.
**Speaker Notes:** (*(none)* if empty).[hidden slide].[Section N: Name] emitted before the first slide of eachsection (only when the deck actually uses sections).
title hoisted to the top.
PowerPoint stores animations as a time-node tree (<p:timing>) that python-pptx does not expose, so the script parses the raw slide XML. Be honest with the user about the boundaries:
each step reveals (the script maps the animated paragraph range back to its text). Build-by-paragraph reveals (one bullet per click) come through.
preset-ID → name mapping is version-dependent and easy to get wrong, so the script deliberately reports only the category rather than guessing.
[animation — …] block in thecontent area (matching the user's convention that presenter instructions live in brackets). The script does not insert [^] click markers into the notes, because where each click belongs in the authored notes prose is not stored in the file and can't be reconstructed faithfully. If the user wants [^] markers in the notes, offer to add them using the click count as a guide.
[animation present — could not parse (…)] instead of failing.
Decks often split one idea across several consecutive slides: a list that grows one bullet per slide, or a fixed background with different things overlaid. The script flags runs of consecutive slides that share a title and prints them to stderr under BUILD SEQUENCES DETECTED, classifying each as either an additive build or a shared base with changing overlays.
Always extract these as separate slides (one block each, as normal) — do not merge them automatically. But after extraction, tell the user which sequences were detected and offer to compact each into a single slide with the build expressed as progressive-disclosure instructions and [^] click markers in the notes. Only compact if the user agrees. This applies to additive lists, overlay-style sequences, and restyled finales (e.g. a slide that repeats the previous one with text struck through).
files and, if the user wants, replace [image: file] with a short description.
be a heading came through as a bullet, or vice-versa), the slide XML can be inspected directly; bullet detection relies on explicit buNone/buChar/ buAutoNum formatting and falls back to "body placeholders bullet, everything else is plain", which is a heuristic, not a guarantee.
they carry text).
# (Slide N — untitled).Other measured skills in the registry, with their headline benchmark lift.