BundledProductivityVersion 1.1.0

PowerPoint Skill Guide: Create, Read, and Edit .pptx with python-pptx

Create, read, edit .pptx decks with python-pptx.

Written by Neura Market from the official Hermes Agent documentation for Powerpoint. Commands, paths, and version numbers are reproduced from the source unchanged.

Read the official documentation

The PowerPoint skill for Hermes Agent turns a plain-text JSON spec into a full .pptx deck, reads an existing presentation back as structured JSON, and edits decks in place without ever opening PowerPoint. It is the tool to reach for when a user asks for a slide deck, a report presentation, or a pitch deck, or when you need to pull text, notes, tables, chart data, or images out of a .pptx someone handed you. Everything runs offline, so there is no dependency on a GUI or a Microsoft Office installation.

What it does

This skill bundles five Python scripts that sit on top of the python-pptx library. Together they cover the full lifecycle of a presentation:

  • Create a deck from a JSON specification, with control over layout, text, bullets, backgrounds, images, tables, shapes, charts, and speaker notes.
  • Read a deck back as JSON: slide size, layout inventory, every shape's text, table cells, image inventory, chart data, and notes.
  • Edit an existing deck in one pass: replace text, patch chart data, swap images, duplicate or remove slides, reorder slides, set backgrounds, footers, hyperlinks, and speaker notes.
  • Build from a template by filling {{token}} placeholders in a brand .pptx, so new slides inherit the master's fonts and colors.
  • Render slides to PNG images for visual verification, using LibreOffice and poppler if they are installed.

All scripts print JSON to stdout and exit non-zero on failure, which makes them easy to chain in an agent workflow. You write the JSON specs with write_file and inspect the output with read_file.

Before you start

The skill requires Python 3.10 or newer with the python-pptx package installed. Install it with:

pip install python-pptx

Rendering slides to PNGs and exporting to PDF are optional. They need LibreOffice (soffice) and poppler (pdftoppm or pdftocairo). The render script detects both with shutil.which and degrades gracefully: if either is missing, it reports {"rendered": false, "missing": [...]} and exits 0. All create, read, and edit operations work without these tools.

To check what is available on the host, run:

python -c "import pptx; print(pptx.__version__)" && which soffice pdftoppm

One hard rule: this skill does not handle legacy .ppt files. Convert them first with soffice --convert-to pptx old.ppt if LibreOffice is available.

How to run the scripts

All scripts live in scripts/, take --help, print JSON to stdout, and exit non-zero on failure. Run them with the terminal tool. Here is the full command set:

python scripts/pptx_create.py deck.json out.pptx
python scripts/pptx_read.py deck.pptx --outline      # full JSON outline
python scripts/pptx_read.py deck.pptx --notes        # speaker notes
python scripts/pptx_read.py deck.pptx --images ./img # export pictures
python scripts/pptx_edit.py deck.pptx --replace-text "Old Corp" "New Corp"
python scripts/pptx_edit.py deck.pptx --chart-data update.json
python scripts/pptx_edit.py deck.pptx --duplicate-slide 2
python scripts/pptx_edit.py deck.pptx --remove-slide 3 --move-slide 2 0
python scripts/pptx_from_template.py brand.pptx out.pptx --values vals.json
python scripts/pptx_render.py deck.pptx --outdir ./render  # slide PNGs

Author the JSON specs with write_file, then inspect the script output and generated JSON with read_file.

Quick reference

The table below summarizes the most common operations. Use it as a cheat sheet while working through the procedures.

TaskCommand
New deck from specpptx_create.py spec.json out.pptx
16:9 vs 4:3"slide_size": "16:9" or "4:3" in the spec
Outline as JSONpptx_read.py deck.pptx --outline
Export imagespptx_read.py deck.pptx --images DIR
Replace textpptx_edit.py deck.pptx --replace-text OLD NEW
Replace chart datapptx_edit.py deck.pptx --chart-data spec.json
Patch one seriessame flag, spec with "ops" (see below)
Swap picturepptx_edit.py deck.pptx --swap-image N NAME new.png
Duplicate slidepptx_edit.py deck.pptx --duplicate-slide N
Remove slidepptx_edit.py deck.pptx --remove-slide N
Reorder slidepptx_edit.py deck.pptx --move-slide FROM TO
Slide backgroundpptx_edit.py deck.pptx --set-background N RRGGBB
Hyperlink runspptx_edit.py deck.pptx --hyperlink N TEXT URL
Slide number onpptx_edit.py deck.pptx --enable-slide-number N
Footer textpptx_edit.py deck.pptx --set-footer N TEXT
Set notespptx_edit.py deck.pptx --set-notes N TEXT
Append notespptx_edit.py deck.pptx --append-notes N TEXT
Fill templatepptx_from_template.py tpl.pptx out.pptx --values v.json
Render slide PNGspptx_render.py deck.pptx --outdir DIR

Procedure

1. Create a deck

Write a JSON spec (see pptx_create.py --help for the full format), then run pptx_create.py. Per slide you can set: layout (title, title_content, section, two_content, title_only, blank), title, subtitle, bullets (strings, or dicts with level 0-4, size pt, bold, italic, font, color hex, link URL for a hyperlink), background (solid hex), footer (text; enables the layout's footer placeholder), slide_number (true; enables the layout's slide-number placeholder), images (path + left/top/width/height in inches), tables (rows as list-of-lists), shapes (rectangle, rounded_rectangle, oval, diamond, right_arrow, chevron, with fill hex + optional text), charts (bar, bar_h, line, pie with categories + series), and notes (speaker notes).

This is the fastest path to a brand-new deck. You describe the whole thing declaratively, and the script does the layout work. For a first run, start with a single title slide and one content slide, then expand the spec as you confirm the output matches your intent.

2. Read a deck

pptx_read.py deck.pptx --outline returns slide size, layout inventory, and per slide: layout name, all shape texts, table cells, image inventory (filename/ext/bytes), chart categories/series/values, and speaker notes. Use --images DIR to dump embedded pictures to files, then vision_analyze on any exported image if you need to see its content.

This is your primary inspection tool. Run it after any create or edit to confirm the deck matches what you asked for. It is also the fallback when rendering tools are missing, because it verifies content and structure even if it cannot show you visuals.

3. Edit a deck

pptx_edit.py combines operations in one pass; use --output to keep the original. Text replacement scans slide shapes, table cells, and notes. Image swap retargets the picture's relationship id so position and size are preserved. Slide removal drops the relationship and the entry; reorder moves the element within `` (python-pptx has no public API for either, so the script does the XML-level work). --duplicate-slide N appends an independent deep copy of slide N: shape XML plus image/media/hyperlink relationships are cloned and rIds remapped, so editing the copy never touches the original. Chart slides are refused (see Pitfalls). --set-notes/--append-notes edit speaker notes; --set-background, --hyperlink, --enable-slide-number, and --set-footer handle deck polish.

Chart updates take a JSON spec via --chart-data. Full replace: {"slide": 0, "chart": 0, "categories": [...], "series": {...}}. For surgical edits, pass "ops" instead, a list of {"op": "update_series", "name": ..., "values": [...]}, add_series, remove_series, rename_category (from/to or index), and set_title. python-pptx can only swap a chart's entire dataset (replace_data), so ops are implemented as read-existing → modify → replace; the per-part UX is a wrapper, and any chart data not expressible as categories + numeric series will be normalized by the round-trip.

This is the workhorse script. Most real-world requests land here: updating a quarterly report, fixing a typo in a pitch deck, or refreshing a chart with new numbers. Because operations combine in one pass, you can do several edits in a single invocation, which keeps the workflow fast.

4. Build from a template

pptx_from_template.py opens a brand .pptx, replaces every {{token}} from a values JSON across slides/tables/notes, and can append new slides that use the template's own layouts (by layout name or index) so they inherit the master's fonts and colors. Tip: to start from a template with zero slides, delete existing ones afterward with pptx_edit.py --remove-slide.

This is the on-brand path. If your organization has a standard template with a specific master, you can produce decks that match it exactly. The token replacement works across slides, tables, and notes, so you can fill in a full presentation from a single values file.

5. Visual verification

pptx_render.py deck.pptx --outdir ./render converts the deck to PDF with soffice --headless and splits it into one PNG per slide with pdftoppm (or pdftocairo). Output JSON lists the PNG paths, review each with vision_analyze. When either tool is missing the script exits 0 with {"rendered": false, "missing": [...]} and guidance; fall back to the JSON outline from pptx_read.py, which verifies content and structure, just not visuals.

Rendering is the only way to catch visual problems like overlapping shapes, truncated text, or color issues. The JSON outline cannot show you those. If the render tools are absent, the script tells you so, and you rely on the outline instead.

Converting to PDF

If LibreOffice is installed, export the finished deck to PDF directly:

soffice --headless --convert-to pdf --outdir ./out deck.pptx

The output lands at ./out/deck.pdf. Fonts not installed on the host are substituted, so render-verify (Procedure step 5) before shipping the PDF. There is no offline pure-Python .pptx→PDF path; if soffice is absent, say so rather than approximating.

Pitfalls

  • Run splitting: PowerPoint fragments paragraph text into runs at spell-check and edit boundaries. --replace-text first merges adjacent runs whose formatting is identical, so matches split across such runs are replaced with formatting fully preserved. Only when a match spans genuinely differently-formatted runs is the paragraph rewritten with the first run's formatting, so verify those slides after replacement.
  • Chart slides cannot be duplicated: each chart relationship embeds a separate XLSX workbook part; cloning that graph reliably is not supported, so --duplicate-slide refuses chart slides cleanly instead of corrupting the deck. Rebuild the chart on a new slide instead. External-hyperlink and image/media rels are carried over; layout and notes rels are recreated fresh.
  • Chart ops are a wrapper: python-pptx replaces the whole dataset; "ops" round-trips existing plot data through replace_data, and changing chart type is not possible.
  • Reordering is XML-level: python-pptx has no supported reorder API. --move-slide manipulates `` directly; safe for ordinary decks but re-read the deck afterward to confirm.
  • Copying slides between decks is unsupported: duplication works only within one deck, where layouts and masters are shared.
  • Footer/slide-number enablement copies the placeholder from the slide's layout; on layouts without those placeholders, --set-footer fails with a clear message (add a textbox instead).
  • Hyperlinks apply to whole runs; --hyperlink links every run containing the given text on that slide.
  • The default python-pptx template is 4:3; the create script sets 16:9 unless the spec says otherwise. Custom templates keep their own size.
  • Layout indexes vary by template. For brand templates, list layout names first: pptx_read.py template.pptx --outline (layouts_available).
  • slide.shapes.title is None on blank layouts, the create script handles this, but remember it when writing ad-hoc python-pptx code.
  • Always pass encoding="utf-8" when writing spec files; tokens like {{city}} may be filled with non-ASCII values.

Verification

  1. After any create/edit, run pptx_read.py OUT.pptx --outline and check slide count, texts, tables, notes, and chart values match intent.
  2. --images DIR then file-size check confirms pictures embedded.
  3. Render every slide with pptx_render.py deck.pptx --outdir ./render and review each PNG with vision_analyze, which catches overlapping shapes, truncated text, and color problems the outline cannot. If the render tools are missing, the script says so; rely on the outline.
  4. The bundled test suite is the full contract: python -m pytest tests/ -q (requires python-pptx + pytest).

When not to use it

Do not use this skill for legacy .ppt files. The scripts only understand the modern .pptx format. Convert the file first with soffice --convert-to pptx old.ppt if LibreOffice is available. Also, if you need to copy slides between two different decks, this skill will not help, because duplication works only within a single deck where layouts and masters are shared.

Limits and gotchas

The biggest practical limit is chart handling. You cannot duplicate a slide that contains a chart, and you cannot change a chart's type through the ops interface. The ops are a convenience wrapper over python-pptx's whole-dataset replacement, so anything that does not fit the categories-plus-numeric-series model gets normalized. Reordering slides manipulates XML directly, so always re-read the deck afterward to confirm the order is right. Finally, rendering depends on external tools; without LibreOffice and poppler you get a clean JSON outline but no visual check.

What pairs with this

The related skills in the same family are docx, xlsx, and pdf. If you are producing a full report, you will likely create the document in docx, the spreadsheet in xlsx, and the slide deck here, then export the final version to PDF. The pdf skill can also help if you need to inspect or manipulate the PDF output from the render step.

Skills the docs pair this with

More Productivity skills