DEV Community

陈旭元
陈旭元

Posted on

I Built an AI Agent Skill That Edits PowerPoint Speaker Notes via XML — Here's How

Most AI + PPTX tools create slides. I built one that only edits speaker notes — the text presenters read while presenting.

Here's the technical deep dive.

The Problem

30-slide quarterly review deck, slides are done, speaker notes are empty on all 30 pages. Manual writing: 3-4 hours. python-pptx script: 1-2 hours of debugging XML mapping and escape characters.

There are 300+ AI presentation tools. 99% focus on creating slides. Almost none touch speaker notes.

PPTX Internals: What You Need to Know

PPTX files are ZIP archives of XML following ECMA-376 (ISO/IEC 29500). Unzip one and you'll see:

pptx-unpacked/
├── ppt/
│   ├── slides/
│   │   ├── slide1.xml
│   │   └── _rels/
│   │       └── slide1.xml.rels
│   ├── notesSlides/
│   │   ├── notesSlide1.xml
│   │   └── notesSlide2.xml
│   └── _rels/
│       └── presentation.xml.rels
└── [Content_Types].xml
Enter fullscreen mode Exit fullscreen mode

Notes text lives in <a:t> tags (DrawingML namespace) inside ppt/notesSlides/notesSlideN.xml.

The notesSlide Mapping Trap

Here's the non-obvious part: notesSlide3.xml is NOT always slide 3.

When you delete, reorder, or edit slides across different PowerPoint versions, notes file numbering gets gaps or misalignments. The real mapping is in .rels files:

<!-- slide5.xml.rels -->
<Relationship Id="rId2"
  Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide"
  Target="../notesSlides/notesSlide3.xml"/>
Enter fullscreen mode Exit fullscreen mode

This means slide 5's notes are in notesSlide3.xml. Edit by number, and you'll modify the wrong page.

The skill resolves this automatically:

for f in pptx-unpacked/ppt/slides/_rels/slide*.xml.rels; do
  slide=$(basename "$f" .xml.rels)
  notes=$(grep -o 'notesSlide[0-9]*\.xml' "$f" | head -1)
  [ -n "$notes" ] && echo "$slide -> $notes"
done
Enter fullscreen mode Exit fullscreen mode

How the Skill Works

Unpack PPTX → Resolve mapping → Read ALL slides → Generate drafts → User confirms → Write XML → Repack + verify
Enter fullscreen mode Exit fullscreen mode

The critical design decision: read the whole deck before writing any notes. This prevents the common problem where page-by-page generation produces repetitive, disconnected notes.

XML Escape Handling

Notes text may contain special characters that must be escaped:

Character XML Escape Required
& &amp; Always
< &lt; Always
> &gt; Recommended
" &quot; In attributes

Multi-paragraph notes use separate <a:p> elements, each with its own <a:t> tag. You must preserve the full tag structure when editing.

Comparison with python-pptx

Aspect python-pptx pptx-notes-editor
Programming required Python None (natural language)
Mapping detection Manual Automatic
Context analysis Not supported Reads whole deck first
XML escaping Library handles Skill handles
Writing styles Fixed template 4 styles + custom
Interactive confirm No Page-by-page approval
Notes export Requires code One command to Markdown

Install

mkdir -p ~/.claude/skills/pptx-notes-editor && curl -fsSL https://raw.githubusercontent.com/cm8421/pptx-notes-editor/main/SKILL.md -o ~/.claude/skills/pptx-notes-editor/SKILL.md

/skill install @cm8421/pptx-notes-editor
Enter fullscreen mode Exit fullscreen mode

Usage

Just say what you want:

"Rewrite speaker notes in narrative style"
"Export all notes to markdown"
"Add verbatim scripts to pages 5-10"

All operations are local — no file uploads, no API calls.

GitHub: https://github.com/cm8421/pptx-notes-editor

Top comments (0)