agent skills · featured

PPTX (Anthropic, official)

Anthropic's official PPTX skill from anthropics/skills — create, edit, read, split, and combine .pptx and .potx files via pptxgenjs (create), XML unzip-rezip (edit), markitdown (read), and LibreOffice (validate, convert). Fixed stack: pptxgenjs + markitdown[pptx] + Pillow + defusedxml + lxml + LibreOffice (soffice) + pdftoppm.
by Anthropic updated Sep 10, 2026 other
install via your agent of choice
❯ /plugin install document-skills@anthropic-agent-skills (Claude Code marketplace) — or register the whole repo as a marketplace first: /plugin marketplace add anthropics/skills. On Claude.ai, the document skills are pre-built for paid plans. On the API, attach via the container.skills parameter (requires code_execution_20250825): https://docs.claude.com/en/api/skills-guide

## what it does

tl;dr: one of the four document skills Anthropic ships under anthropics/skills (with docx, pdf, xlsx) — the SKILL.md is the router, the heavy lifting lives in scripts/ and in a tight dependency set. Create = pptxgenjs; edit = unzip → edit ppt/slides/slideN.xml → rezip; read = markitdown plus scripts/thumbnail.py for a visual grid.

What it actually does

The frontmatter triggers for any .pptx or .potx mention as input, output, or both: create decks, read/parse/extract text, edit existing decks, split/combine, work with templates/layouts/speaker notes/comments. The skill tells the agent which tool to reach for; it does not run on its own.

TaskTool
Create a new deckpptxgenjs script
Edit an existing deck or build from templateunzip → edit ppt/slides/slideN.xml → zip
Read contentmarkitdown deck.pptx (one block per slide under <!-- Slide number: N --> markers)
Visual grid of slidespython scripts/thumbnail.py deck.pptx [prefix]

Bundled scripts

Paths are relative to the skill directory. Everything else is plain Python / node / shell.

ScriptWhat it does
scripts/thumbnail.py deck.pptx [prefix]Labeled grid of every slide, for picking template layouts. .pptx only — copy .potx to .pptx first. Pass prefix — it defaults to thumbnails and silently overwrites grids from prior decks in the same directory.
scripts/add_slide.py unpacked/ slide2.xml [--after slideN.xml]Duplicate a slide (or a slideLayoutN.xml) with all the package bookkeeping. Also takes a .pptx directly with -o out.pptx (without -o it rewrites the input deck in place).
scripts/clean.py unpacked/Delete slides, media, and rels no longer referenced. Run after <p:sldIdLst> is final — anything missing from the list, including a slide you just wrote, gets removed.
scripts/office/validate.py deck.pptx [--original src.pptx]Schema, relationship, content-type, chart, and slide checks; each failure names its fix. Pass --original for any template-derived deck so the template’s own XSD errors don’t read as yours.
scripts/office/soffice.py --headless --convert-to pdf deck.pptxLibreOffice wrapper — bare soffice hangs in this sandbox.

Creating with pptxgenjs — gotchas (from SKILL.md)

pptxgenjs is preinstalled — do not run npm install first; write the script and require('pptxgenjs') directly. Only fall back to npm install pptxgenjs if that require fails.

  • Set pres.layout before adding slides. The default canvas is LAYOUT_16x9 = 10” × 5.625”, not 13.3” wide. Coordinates past the edge are written, not clamped — the shape just isn’t on the slide. LAYOUT_WIDE is 13.3” × 7.5”.
  • Hex colors: never #, never 8 digits. color: "FF0000". Both "#FF0000" and alpha baked into the hex ("00000020") corrupt the file. Translucency is transparency: 0-100 on fills/images and opacity: 0.0-1.0 on shadows — each is silently ignored on the other.
  • pptxgenjs mutates option objects in place (converts values to EMU on first use). Never share one shadow/options object across two add* calls — build a fresh object each time.
  • Shadow offset must be ≥ 0. Negative offsets corrupt the file. To cast upward, use angle: 270 with a positive offset.
  • letterSpacing is silently ignored — the real option is charSpacing.
  • Lists: bullet: true on each item, never a literal • (renders double bullets). Set breakLine: true on every array item except the last. Space bulleted paragraphs with paraSpaceAfter, not lineSpacing (huge gaps).
  • One new pptxgen() per output file — never reuse an instance.
  • rectRadius only works on ROUNDED_RECTANGLE, not RECTANGLE.
  • Gradient fills aren’t supported — use a gradient image as the background.
  • Text boxes have built-in internal padding — set margin: 0 whenever text must align with a shape/line/icon at the same x.
  • Speaker notes go in slide.addNotes("...") (plain text, once per slide), never in a text box on the slide.
  • Keep charts native via addChart() — only chart types PowerPoint has no native form for (Sankey, network, chord) go in as images.
  • Stacked bar/column dataLabelPosition must be ctr, inEnd, or inBase. outEnd corrupts the file.
  • Combo series using secondaryValAxis/secondaryCatAxis needs both valAxes and catAxes declared on chart options — pptxgenjs otherwise writes axis ids it never declares, and PowerPoint discards the chart as corrupt.
  • After writeFile(), run python scripts/office/validate.py deck.pptx. It reports the chart faults above and the slide-XML defects PowerPoint refuses, and names the fix for each. Fix in the generator, not by hand-editing packed XML.
  • Never reorder children of <p:presentation> — <p:notesMasterIdLst> lives right after <p:sldIdLst>; move the element and the same deck becomes unopenable.
  • Icons: render react-icons to SVG via ReactDOMServer.renderToStaticMarkup, rasterize with sharp at ≥256px, insert via addImage({ data: "image/png;base64," + buf.toString("base64") }) (the image/png;base64, prefix is required).

Editing existing decks

python3 -c "import sys,zipfile; zipfile.ZipFile(sys.argv[1]).extractall('unpacked')" deck.pptx
python scripts/add_slide.py unpacked/ slide2.xml --after slide2.xml   # duplicate a slide; prints the new slide's path
# reorder / delete slides = edit <p:sldIdLst> in ppt/presentation.xml
python scripts/clean.py unpacked/                                     # after deletions: removes orphaned slides/media/rels
# edit slide content in ppt/slides/slideN.xml
(cd unpacked && rm -f ../out.pptx && zip -Xr ../out.pptx .)           # zip from INSIDE the dir; rm first or deleted parts survive
python scripts/office/validate.py out.pptx --original deck.pptx
  • Do all structural work (add/delete/reorder) before editing any slide’s content. add_slide.py copies a slide file verbatim, so duplicating after you edit clones the edited content; clean.py deletes any slide missing from <p:sldIdLst>, including one you just wrote.
  • Never copy a slide file by hand. add_slide.py does every registration a new slide needs and reports what it made. A duplicated slide still references its source’s chart/SmartArt/embedded-object parts — editing one slide’s chart changes the other’s.
  • python-pptx won’t: duplicate a slide (its only entry point is add_slide(layout)), preserve formatting through text_frame.text = "..." (collapses the paragraph to one unstyled run — assign run.text instead), or read SVG/EMF most template art uses (add_picture raises UnidentifiedImageError).
  • Legacy .ppt must be converted first: python scripts/office/soffice.py --headless --convert-to pptx file.ppt. .potx templates unpack and pack identically — keep the .potx extension on the output.

QA loop (required)

The first render usually has real defects — overlaps, overflow, misalignment. Find and fix those, re-render only the slides you changed, and stop.

markitdown output.pptx                                                            # content QA
python scripts/office/validate.py output.pptx                                      # schema QA
python scripts/office/validate.py output.pptx --original src.pptx                  # template-derived: baselined against template
python scripts/office/soffice.py --headless --convert-to pdf output.pptx          # visual QA: PDF first
rm -f slide-*.jpg
pdftoppm -jpeg -r 150 output.pdf slide                                             # then rasterize
ls -1 "$PWD"/slide-*.jpg

Look at the rendered images, not the generator. Common user-visible defects to scan for: text overflow/cut-off, overlapping elements, source citations or footers colliding with content above, gaps < 0.3”, uneven gaps, slide-edge margins < 0.5”, misaligned columns, low-contrast text or icons, template decoration mispositioned after a title wrap, narrow text boxes that wrap excessively, leftover placeholders. For template-based decks, also markitdown output.pptx | grep -iE "\bx{3,}\b|lorem|ipsum|\bTODO|\[insert|this.*(page|slide).*layout" — any hits are leftover placeholder text.

Gotchas

  • pptxgenjs charts break PowerPoint in ways Python and LibreOffice happily accept — validate.py is the only thing that surfaces those. Don’t trust a deck that “opened fine in LibreOffice.”
  • scripts/thumbnail.py defaults to thumbnails for the prefix and silently overwrites grids from any other deck in the same directory. Pass a deck-named prefix every time, or the first deck’s grid is gone.
  • add_slide.py rewrites the input deck in place unless you pass -o. No backup, no confirmation.
  • LibreOffice (soffice) hangs in this sandbox without the scripts/office/soffice.py wrapper. Use the wrapper.
  • markitdown placeholders leak through template fills — grep for xxx|lorem|ipsum|TODO|[insert|this.*(page|slide).*layout after every fill.
  • License is Proprietary. LICENSE.txt restricts redistribution and derivative works. You use the skill; you don’t fork it.
  • .pptx is a ZIP of XML. A zip -Xr from outside the unpacked dir leaves deleted parts in the archive and PowerPoint reads them as conflicting. Always zip from inside.
  • pdftoppm zero-padding follows page count — slide-1.jpg for decks under 10, slide-01.jpg for 10–99, slide-001.jpg for 100+.

Dependencies (per SKILL.md)

pptxgenjs (npm, preinstalled — install only if require('pptxgenjs') fails) · markitdown[pptx], Pillow, defusedxml, lxml (pip — text dump, thumbnail, clean, validate) · LibreOffice (soffice, auto-configured via scripts/office/soffice.py) · pdftoppm (Poppler)

Install

# Claude Code (marketplace)
plugin marketplace add anthropics/skills      # register the repo as a marketplace
/plugin install document-skills@anthropic-agent-skills   # installs pdf + docx + pptx + xlsx

# Or, just the pptx skill, directly
/plugin install pptx@anthropic-agent-skills
// On the API — attach via container.skills; requires code_execution_20250825
{
  "model": "claude-opus-5",
  "max_tokens": 4096,
  "container": {
    "skills": [
      { "type": "anthropic", "skill_id": "pptx", "version": "latest" }
    ]
  },
  "messages": [
    { "role": "user", "content": "Build a 6-slide pitch deck for /mnt/seed-round.md" }
  ],
  "tools": [
    { "type": "code_execution_20250825", "name": "code_execution" }
  ]
}

## compatibility

claude-code ✓
cursor ?
cline ?
aider —

## embed this badge

cache ✓ in cache.directory
![cached](https://cache.directory/badge/anthropic-pptx.svg)