A CLI tool for programmatic PowerPoint (.pptx) editing using Microsoft's Open XML SDK. Takes a .pptx file and a JSON edit manifest, produces a modified presentation with text replacements, shape edits, speaker notes, slide manipulation, and comments — no macros, no compatibility issues.
Ships as a single ~12MB native binary. No runtime, no Docker required.
We evaluated three approaches for programmatic presentation editing:
| Approach | Text Editing | Slide Ops | Notes/Comments | Formatting |
|---|---|---|---|---|
| Open XML SDK (.NET) | ✅ 100% | ✅ 100% | ✅ 100% | ✅ Preserved |
| python-pptx | ✅ Good | ✅ Preserved | ||
| LibreOffice CLI | ❌ None | ❌ None |
Open XML SDK is the gold standard — it's Microsoft's own library for manipulating Office documents. Text replacement handles multi-run spans, formatting is always preserved, and all slide operations work correctly.
brew install henrybloomingdale/tools/pptx-reviewgit clone https://github.com/henrybloomingdale/pptx-review.git
cd pptx-review
make install # Builds + installs to /usr/local/binRequires .NET 8 SDK for building (brew install dotnet@8). The resulting binary is self-contained — no .NET runtime needed to run it.
make docker # Builds Docker image
docker run --rm -v "$(pwd):/work" -w /work pptx-review input.pptx edits.json -o edited.pptx# Basic usage
pptx-review input.pptx edits.json -o edited.pptx
# Pipe JSON from stdin
cat edits.json | pptx-review input.pptx -o edited.pptx
# Custom author name
pptx-review input.pptx edits.json -o edited.pptx --author "Dr. Smith"
# Dry run (validate without modifying)
pptx-review input.pptx edits.json --dry-run
# JSON output for pipelines
pptx-review input.pptx edits.json -o edited.pptx --json
# Read presentation content
pptx-review input.pptx --read --json{
"author": "Reviewer Name",
"changes": [
{
"type": "replace_text",
"find": "old text",
"replace": "new text"
},
{
"type": "replace_text",
"find": "slide-specific text",
"replace": "new text",
"slide": 2
},
{
"type": "set_text",
"slide": 1,
"shape": "Title 1",
"text": "New Title"
},
{
"type": "set_notes",
"slide": 1,
"text": "Speaker notes for slide 1"
},
{
"type": "delete_slide",
"slide": 5
},
{
"type": "duplicate_slide",
"slide": 3
},
{
"type": "reorder_slide",
"slide": 2,
"position": 5
},
{
"type": "add_slide",
"layout": "Blank",
"position": 3
}
],
"comments": [
{
"slide": 1,
"text": "This slide needs a better title"
}
]
}| Type | Required Fields | Optional Fields | Description |
|---|---|---|---|
replace_text |
find, replace |
slide |
Find and replace text. If slide specified, only that slide; otherwise all slides. |
set_text |
slide, shape, text |
Set text content of a named shape (e.g., "Title 1") | |
set_notes |
slide, text |
Set or replace speaker notes for a slide | |
delete_slide |
slide |
Delete slide by number (1-indexed) | |
duplicate_slide |
slide |
position |
Duplicate a slide, optionally place at position |
reorder_slide |
slide, position |
Move slide to a new position | |
add_slide |
layout, position |
Add new slide (layout name optional, position optional — defaults to end) |
Each comment needs:
slide— slide number (1-indexed) to attach the comment totext— the comment content
Compare two .pptx files semantically — detects slide content changes, speaker notes differences, comment modifications, shape additions/removals, and image changes.
# Compare two presentations
pptx-review --diff old.pptx new.pptx
# JSON output for automation
pptx-review --diff old.pptx new.pptx --json
# Use as a git textconv driver
pptx-review --textconv presentation.pptxTrack .pptx changes in git with human-readable diffs:
# Print setup instructions
pptx-review --git-setupAdd to .gitattributes:
*.pptx diff=pptx
Add to .gitconfig:
[diff "pptx"]
textconv = pptx-review --textconvNow git diff shows readable text diffs for PowerPoint files.
| Category | Details |
|---|---|
| Slide text | Word-level changes within matched shapes across slides |
| Speaker notes | Added, removed, or modified notes per slide |
| Comments | New, removed, or changed comments |
| Shapes | Added or removed shapes (by name and type) |
| Images | Content changes detected via SHA-256 hash comparison |
| Slide structure | Added or removed slides (matched by content similarity) |
| Flag | Description |
|---|---|
-o, --output <path> |
Output file path (default: <input>_edited.pptx) |
--author <name> |
Author name for comments (overrides manifest author) |
--json |
Output results as JSON (for scripting/pipelines) |
--dry-run |
Validate the manifest without modifying the presentation |
--read |
Read presentation content (combine with --json for structured output) |
--diff |
Compare two presentations semantically |
--textconv |
Git textconv driver (normalized text output) |
--git-setup |
Print .gitattributes and .gitconfig setup instructions |
-v, --version |
Show version |
-h, --help |
Show help |
Extract presentation content as structured JSON:
pptx-review input.pptx --read --jsonOutput:
{
"slides": [
{
"number": 1,
"layout": "Title Slide",
"shapes": [
{"name": "Title 1", "type": "textbox", "text": "Presentation Title"},
{"name": "Subtitle 2", "type": "textbox", "text": "By Author Name"}
],
"notes": "Speaker notes here",
"comments": []
}
],
"slide_count": 10
}make # Build native binary for current platform (~12MB, self-contained)
make install # Build + install to /usr/local/bin
make all # Cross-compile for macOS ARM64, macOS x64, Linux x64, Linux ARM64
make docker # Build Docker image
make test # Run test (requires TEST_PPTX=path/to/presentation.pptx)
make test-read # Read a presentation (requires TEST_PPTX=path/to/presentation.pptx)
make clean # Remove build artifacts
make help # Show all targets
0— All changes and comments applied successfully (or read mode completed)1— One or more edits failed (partial success possible)
With --json, the tool outputs structured results:
{
"input": "presentation.pptx",
"output": "presentation_edited.pptx",
"author": "Dr. Smith",
"changes_attempted": 5,
"changes_succeeded": 5,
"comments_attempted": 2,
"comments_succeeded": 2,
"success": true,
"results": [
{ "index": 0, "type": "comment", "success": true, "message": "Comment added to slide 1" },
{ "index": 0, "type": "replace_text", "success": true, "message": "Replaced 3 occurrence(s) across all slides" }
]
}- Copies the input
.pptxto the output path - Opens the presentation using Open XML SDK (
PresentationDocument) - Adds comments first (before changes modify the slide structure)
- Applies changes (text replacement, shape edits, notes, slide operations)
- Handles multi-run text matching (text spanning multiple XML runs)
- Preserves original formatting (RunProperties cloned from source)
- Saves and reports results
- Slides →
SlidePartobjects linked viaSlideIdList - Shapes →
Shapeelements inShapeTree, identified byNonVisualDrawingProperties.Name - Text →
TextBody→Paragraph→Run→Text - Notes →
NotesSlidePartwith body placeholder - Comments →
SlideCommentsPart+CommentAuthorsPart - Layouts →
SlideLayoutPartlinked throughSlideMasterPart
# Build native binary (requires .NET 8 SDK)
make build
# Build and run locally
dotnet run -- input.pptx edits.json -o edited.pptx
# Read a presentation
dotnet run -- input.pptx --read --json
# Cross-compile all platforms
make all
# → build/osx-arm64/pptx-review (macOS Apple Silicon)
# → build/osx-x64/pptx-review (macOS Intel)
# → build/linux-x64/pptx-review (Linux x64)
# → build/linux-arm64/pptx-review (Linux ARM64)MIT — see LICENSE.
Built by CinciNeuro for AI-assisted presentation editing workflows.