hands-on-deck
Agent-native PowerPoint manipulation. One CLI — deck.py — lets AI agents inspect, edit, create, and verify .pptx files with the fidelity of a human operator: atomic JSON patches in, linted decks out.
→ everyinc.github.io/hands-on-deck
Packaged as an Agent Skill, so it drops into Claude Code, claude.ai, and any other agent platform that supports the skills format — and because the tool itself is just a CLI, any agent that can run a shell command can use it.
# the whole edit loop, in four commands
python deck.py deck.pptx inspect --slide 3 --brief # what's there (one line per shape)
python deck.py deck.pptx apply patch.json -o out.pptx --fix --render img/
python deck.py out.pptx diff deck.pptx # what changed
python deck.py docs # the full reference, no file needed
Why this exists
A .pptx is a zip of XML. Agents that edit it directly hand-write OOXML — fragile, token-hungry, and one namespace typo from a corrupt file. Agents that regenerate decks from scratch lose everything a template encodes: brand, layout craft, image treatments.
hands-on-deck takes a third path: the agent writes a declarative patch; the tool executes it.
{"ops": [
{"op": "replace-text", "scope": "master", "from": "Globex", "to": "Acme"},
{"op": "set-text", "slide": 3, "shape": "s12", "text": ["Q3 results", "Tokens down 84%"]},
{"op": "swap-image", "slide": 4, "shape": "s9", "image": "screenshot.png"},
{"op": "duplicate", "slide": 5, "shape": "s31", "offset": [0, 1.2], "text": ["Fourth pillar"]}
]}
New text inherits the old text's formatting automatically. Image swaps keep aspect ratio. The duplicate keeps every bit of styling and gets fresh ids. And if any op is invalid, nothing is written.
Built around how agents actually fail
The interesting part isn't that it's a CLI — it's that every design choice targets a known LLM failure mode:
Errors teach instead of scold. Reference a shape that doesn't exist and the error includes the slide's real shape inventory — ids, types, geometry, text previews — so the agent can correct without another round trip:
PATCH REJECTED — 2 validation error(s), nothing was modified:
- op[0] set-text: shape 's9999' not found on slide 0.
shapes on slide 0:
s16 PICTURE [-1.25,-0.91 15.0x8.44in] (image image3.png)
s18 AUTO_SHAPE [7.00,5.17 2.6x0.25in] Session Management
s19 TEXT_BOX [0.60,1.00 4.0x0.4in] USING CLAUDE CODE
...
- op[1] add-slide: layout 'Nonexistent' not found — available: 'DEFAULT', 'Blank'
All errors at once, atomically. Every op is pre-validated; a 9-op patch with 9 mistakes returns 9 actionable errors and writes zero bytes. No partially-edited decks, ever — runtime failures abort the whole patch too.
The linter watches the agent's hands. After every apply, the deck is re-measured and only new or worsened geometry problems are reported — text overflowing its box, shapes off the slide, text-on-text overlaps, text trapped under a picture (it renders clipped — the defect a thumbnail never shows), and edges that almost line up — each with exact inch values and the exact fix command to run.
It catches the near-miss, not the design. Alignment bugs are a hair off, never a mile: nobody means "3px short of the card edge." The linter discovers the deck's implicit grid (clusters the edges several shapes actually share) and flags the lone edge sitting in the uncanny valley beside a gridline — s14 right=10.52" — 0.14" short of the cluster at 10.66" (4 shapes). It never needs to know what the design should be; it only needs to know that an edge is trying to align and failing. Purely advisory — intentional asymmetry is real, so it ranks by suspicion and never fails the build.
Repair is honest. fix deterministically grows boxes, shrinks fonts (with a readability floor), and nudges shapes back on-slide — then re-measures. Anything still broken is reported as residue with a suggested op, not claimed as fixed. Pictures bleeding off-slide are never auto-moved (it might be intentional design).
Tokens are a budget. inspect --brief gives one line per shape for orientation; full JSON only when writing a patch. docs prints the complete op reference so agents never read source. render --slide 3 --crop 1,2,6,1.5 --scale 2 zooms into the exact region under suspicion instead of re-rendering everything. diff verifies edits with no rendering at all.
Verification is visual. Slides render to slide-<index>.jpg (0-based, matching every other index in the tool) so the agent can look at what it changed — the same way a human would check their work.
What it covers