PRD

April 12, 2026 · View on GitHub

Product: A library-first, CLI-second tool for AI agents (and humans) to inspect, edit, and render pptx decks with aggressive transparency.

Status: Draft v0.1 Last updated: 2026-04-11


1. Problem statement

AI agents 越来越多地被要求修改 pptx 文件 —— 写 slide、改 speaker notes、更新 agenda、插入图表、给客户改 proposal。今天的做法有三种,每一种都不好:

做法 A:AI 让用户手动改 —— AI 输出修改建议,用户自己打开 PowerPoint 一个个改。这种方式不具备可扩展性,每次修改都需要人类操作,且人类会引入错误或遗漏。

做法 B:AI 用 pandoc 或类似工具从头生成 pptx —— 把整个 deck 写成 markdown,用 pandoc -o deck.pptx 转。这种方式丧失了已有 deck 的 layout 和视觉设计,生成出来的 deck 模板化、不能直接用于客户交付,也不支持 "在已有 deck 上做 surgical 修改"。

做法 C:AI 直接写 python-pptx 脚本 —— 每次都现场写一段 Python 代码操作 pptx。这是最接近我们想要的方式,但有三个问题:

  1. python-pptx 的 API 是 OO 风格的,对 AI 不够 shell-friendly;AI 每次都要先做 "shape 树遍历" 才能找到目标
  2. 没有视觉反馈 —— AI 改完后无法 "看一眼" slide 真实长什么样。这意味着 AI 在开环模式下工作:能执行修改,但无法验证结果。每次改动都需要人类打开 PowerPoint 看一眼,把截图发给 AI,AI 才能判断是否需要进一步调整。人类变成了不可或缺的"渲染后端",AI 无法自主闭环完成一个任务。
  3. 没有 aggressive transparency —— 同一段代码在不同 deck 上可能有完全不同的效果,难以预测

我们需要的不仅是"能改 pptx 的工具",而是让 AI 能自主完成"改 → 看 → 调"闭环的工具:保留已有 deck 的所有设计,支持精细 surgical 修改,改完能渲染成图片自我检查,不满足就继续调,直到结果正确再交付给人类。

2. Goals

2.1 Primary goals

  1. 让 AI 能可靠地修改已有 pptx deck,每次修改的结果可预测、可解释、可审计
  2. 提供 shell-friendly 的 CLI,覆盖 80% 的高频修改任务,AI 一行命令搞定
  3. 提供 Python library,让 AI 能写 30 行脚本完成复杂的组合操作(批量修改、循环、条件判断)
  4. 提供渲染能力,让 AI 能自主闭环工作: 改完 slide 后渲染成 PNG,AI 自己"看一眼"判断效果,不满意就继续调,满意再交付。没有渲染,AI 只能开环工作 —— 每次改动都需要人类打开 PowerPoint 截图反馈,AI 才能知道结果对不对
  5. 贯彻 aggressive transparency: 每一步的 before/after 可见,错误不被吞,操作可复现

2.2 Secondary goals

  1. 字体归一化: 把 Calibri / PingFang 等平台专有字体替换成跨平台字体(Inter + Noto Sans SC),让 LibreOffice 渲染接近 PowerPoint 的视觉效果
  2. 字体度量 overflow 检查: 不依赖渲染,用字体度量数学精确判断文字会不会溢出 shape
  3. 结构化 dump: 把 slide 的 shape 树 dump 成 JSON / Markdown,让 AI 能做离线审计
  4. Escape hatch: 对于 python-pptx API 没覆盖的 OOXML 操作,提供 raw-xml-patch 直接改 XML

3. Non-goals

下面这些明确不做,是为了让 scope 收敛:

  1. 不做从 markdown 到 deck 的一键生成 —— 如果 AI 要从 md 生成 deck,让它自己写 loop 调库函数,不提供 generate-deck-from-md 这种黑盒命令
  2. 不做 pixel-perfect 保真渲染 —— LibreOffice 的渲染和 PowerPoint 有差异(字体 fallback、阴影算法),render 输出是 "近似的 reality check",不是 "金标准"
  3. 不做复杂视觉效果的重建 —— SmartArt、Chart、3D effect、animation / transition、WordArt 非线性变形、OMML 公式都不支持。碰到这些告诉用户直接手动在 PowerPoint 改
  4. 不做 Keynote / Google Slides 格式 —— 只处理 pptx(OOXML)。keynote / gslides 导出的 pptx 可以读,但 roundtrip 质量依赖导出器
  5. 不做 pptx → md 的 "完美" 反向转换 —— to-md 只提供粗略 structured text 导出,供 AI 做快速内容扫描,不期望可以从 md 还原出原 deck
  6. 不做网络调用 —— 所有操作都在本地文件上进行,不上传、不调外部 API
  7. 不做 GUI —— 只有 CLI 和 library

4. Users & use cases

4.1 Primary user: AI agent modifying an existing deck

Example: 用户要求 "把 slide 1 议程里 Part 4 的时长从 30 分钟改成 15 分钟,并把标题从 'Technical Demo · 实战案例现场演示' 改成 '两个实战案例 · 落地方式'"。

AI 应该能:

  1. list-slides 看到 deck 有多少 slide
  2. dump-slide 1 --format json 看 slide 1 的所有 shape 和 text
  3. 找到对应的两个 text shape 的 shape_id
  4. set-text 两次(或写一个 5 行 Python 脚本)完成修改
  5. render-slide 1 渲染成 PNG 检查视觉效果
  6. 完成

4.2 Secondary user: human developer writing a custom script

Example: 用户要在 deck 里批量插入 20 张 before/after 对比图。

用户(或 AI)应该能:

  1. 写一个 30 行 Python 脚本,from pptx_skill import Deck
  2. 打开 deck, loop 20 次调用 deck.add_slide(...)slide.add_picture(...)
  3. 保存

4.3 Tertiary user: human auditing AI's changes

Example: 用户给 AI 一个 deck 让它改,改完想看看具体改了什么。

用户应该能:

  1. 通过 diff .bak 和当前版本的 JSON dump 看到结构化 diff
  2. 通过 render-slide 的前后 PNG 做视觉对比
  3. 不需要安装 PowerPoint 就能审计

5. Success criteria

5.1 Functional 验收标准

  1. 可以用 CLI 在一分钟内修改一个已知 deck 的 slide 议程字段,且修改后的 deck 在 PowerPoint 里打开视觉上和手动修改没有明显差异
  2. 可以把 deck 的任一 slide 渲染成 PNG,AI 能从 PNG 中识别 slide 的 layout、主要文字、整体结构(即使字体 fallback 导致细节偏差)
  3. 可以通过 Python 脚本插入新 slide 并复制已有 slide 的 layout,新 slide 放在指定位置,不破坏其他 slide
  4. 可以 dump 任一 slide 成 JSON 并恢复到原文件的 shape 结构(roundtrip test)

5.2 Transparency 验收标准

  1. 每一个写操作在执行前后都打印 before / after 状态到 stderr
  2. 没有任何命令会 silently 修改 deck —— 修改前 stderr 宣告 "will modify X",修改后 stderr 打印 "saved"
  3. 错误信息保留原始细节 —— 如果 libreoffice 渲染失败,stderr 直接显示 soffice 的原始错误输出,不包装成 "rendering failed" 之类的笼统信息
  4. 可以用 --dry-run 看每个写操作会改什么,但不实际写盘

5.3 Library 验收标准

  1. library 的每一个 public 函数都有对应的 CLI subcommand(1:1 映射)
  2. library 的调用可以在 Python REPL 里手工跑,不需要 CLI 做任何前置配置
  3. library 的所有函数都是 pure 函数或明确的 in-place 修改,没有隐藏 state 或全局副作用

5.4 Testability 验收标准

  1. 所有 write 操作都有 roundtrip test —— 改完之后 dump,和期望结构对比
  2. render 操作有 smoke test —— 能生成一个非零大小的 PNG,内容不空白(纯用 libreoffice,不做像素比对)
  3. 字体度量 heuristic 有 unit test —— 构造一段已知宽度的文字和 shape,验证 overflow 判断符合预期
  4. 所有测试在没有 LibreOffice 的环境下默认 pass(渲染测试走 pytest marker 跳过)

6. Feature list

按优先级排序。Phase 1 (MVP) 包括所有 P0 和 P1 功能,Phase 2 再考虑 P2。

Phase 1 / P0 · 基础读写

功能CLI 命令Library API说明
打开 deck 并验证可读doctor <deck>Deck.open(path)健康检查,报告 slide 数、layout、依赖状态
列出 slide 概要list-slides <deck>deck.slides每张 slide 的索引、layout 名、shape 数
列出某 slide 的 shapelist-shapes <deck> <slide_idx>slide.shapesshape 的 index、name、type、位置、大小、文字摘要
Dump slide 完整结构dump-slide <deck> <slide_idx> --format json|mdslide.to_dict() / slide.to_markdown()给 AI 或人看的完整 structured 输出
Dump 整个 deckdump-deck <deck> --format json|mddeck.to_dict()一次性 dump 所有 slide
读 shape 的文字get-text <deck> <slide_idx> --shape <id>shape.text支持按 shape id / shape name 定位
读 speaker notesget-notes <deck> <slide_idx>slide.notes
写 shape 的文字set-text <deck> <slide_idx> --shape <id> --text "..."shape.set_text(...)打印 before/after,单个 run 或整个 text frame
写 speaker notesset-notes <deck> <slide_idx> --text "..."slide.set_notes(...)覆盖整个 notes
保存 deck(自动 in-place,或 --out)deck.save(path)默认 in-place 保存,加 --out 另存

Phase 1 / P0 · 基础编辑

功能CLI 命令Library API说明
改 shape 的位置set-position <deck> <slide_idx> --shape <id> --left 1.5in --top 2inshape.move(...)支持 in / cm / pt / px 单位
改 shape 的大小set-size <deck> <slide_idx> --shape <id> --width 4in --height 2inshape.resize(...)
改 shape 的填充色set-fill <deck> <slide_idx> --shape <id> --color "#DC2626"shape.set_fill(...)纯色 only,渐变走 raw-xml-patch
改 text run 的字体属性set-font <deck> <slide_idx> --shape <id> --run <i> --name Inter --size 14 --bold --color "#FFFFFF"run.set_font(...)

Phase 1 / P0 · 渲染(AI 闭环的基础设施)

渲染是让 AI 从"能改"变成"能改完自己检查"的关键能力。没有渲染,AI 是开环的:改了 slide,不知道效果,只能等人类反馈。有了渲染,AI 可以自主完成 改 → 渲染 → 看图 → 调整 → 再渲染 的闭环,直到结果满意再交付。

功能CLI 命令Library API说明
渲染 slide 成 PNGrender-slide <deck> <slide_idx> --out /tmp/slide.pngslide.render_png(...)基于 LibreOffice headless,warning 说明保真度限制
渲染整个 deck 成 PNGrender-deck <deck> --out-dir /tmp/slides/deck.render_png(...)一次性生成所有 slide

Phase 1 / P1 · 字体与 overflow

功能CLI 命令Library API说明
字体归一化normalize-fonts <deck> --en Inter --zh "Noto Sans SC"deck.normalize_fonts(...)把 Calibri 等平台字体替换成跨平台字体
Overflow heuristic 检查check-overflow <deck> --slide <idx>slide.check_overflow()用 fonttools 读字体度量算宽度,判断会不会溢出

Phase 1 / P1 · 添加 / 删除 slide

功能CLI 命令Library API说明
添加新 slideadd-slide <deck> --after <idx> [--clone-from <idx>]deck.add_slide(...)可以克隆已有 slide 作为 template
删除 slidedelete-slide <deck> --slide <idx>deck.delete_slide(...)危险操作,要求 --yes 确认
移动 slide 位置move-slide <deck> --from <idx> --to <idx>deck.move_slide(...)

Phase 1 / P1 · 图片操作

功能CLI 命令Library API说明
添加图片add-picture <deck> <slide_idx> --file img.png --left 1in --top 2in [--width 4in]slide.add_picture(...)如果只给 width / height 一个,按原图比例算另一个
替换图片replace-picture <deck> <slide_idx> --shape <id> --file new.pngpicture.replace(...)

Phase 1 / P2 · Escape hatch

功能CLI 命令Library API说明
直接操作 OOXMLraw-xml-patch <deck> <slide_idx> --xpath "..." --xml-fragment "..."slide.raw_xml_patch(...)给 AI 突破 python-pptx API 边界的最后手段

Phase 2 / 未来

  • 多 backend 渲染: 支持 --backend=msoffice 走 Mac AppleScript 调用真实 PowerPoint
  • Diff 功能: diff <old_deck> <new_deck> 产生 structured diff
  • 模板系统: add-slide --from-template my_template.pptx 从外部模板加 slide
  • 批量操作: apply-patch <deck> <patch.yaml> 读一个 YAML 描述的修改列表

7. Aggressive transparency 在 PPT skill 上的具体体现

"Aggressive transparency" 是本项目的核心设计原则。它在这个 skill 上有五个具体体现:

7.1 Before / after 可见

任何 write 命令在 stdout / stderr 打印:

[pptx-skill] set-text slide=0 shape-id=15
  before: "Technical Demo · 实战案例现场演示"
  after:  "两个实战案例 · 落地方式"
[pptx-skill] saved deck.pptx (18 slides, 2.3 MB)

每一个写操作都有这三个 line,绝不 silent。

7.2 可预测的操作范围

命令只做它 name 明确说的事情。set-text 只改目标 shape,不 auto-fit 其他 shape 让它们 "看起来更好";set-position 只改 left/top 两个数,不做 snap-to-grid 或 auto-align。

如果 AI 要做复合操作(比如 "改文字的同时自动 resize 到适合的宽度"),它要自己写 script 组合两个命令。skill 不替 AI 做 "聪明" 决策。

7.3 错误透传

任何底层错误都原样抛出,不被 wrap 成笼统信息:

$ pptx-skill render-slide deck.pptx 3
[pptx-skill] render-slide slide=3
soffice error: conversion failed for /tmp/deck.pptx with reason:
  com.sun.star.task.ErrorCodeIOException: SfxBaseModel::impl_store <.../out.png> failed: 0x81a(Error Area:Io Class:Access Code:26)

不包装成 rendering failed, please try again。AI 看到原始错误能立刻定位到是 LibreOffice 的 IO 权限问题。

7.4 Dry-run 支持

每个写命令都支持 --dry-run flag:

$ pptx-skill set-text deck.pptx 0 --shape 15 --text "New" --dry-run
[pptx-skill] DRY RUN set-text slide=0 shape-id=15
  would change: "Technical Demo · 实战案例现场演示"
  to:           "New"
  (no write performed)

AI 可以先 dry-run 确认要做什么,再真的执行。

7.5 结构化输出选项

每个读命令都支持 --format json 输出机器可解析结果,便于 AI 把结果 pipe 给下一个命令或 load 进 Python:

$ pptx-skill list-shapes deck.pptx 0 --format json | jq '.[] | select(.type == "AUTO_SHAPE")'

同时 stderr 和 stdout 不混 —— 结构化输出走 stdout,进度信息和 warning 走 stderr。AI pipe 时永远不会被进度文字污染 stdout。

8. Design constraints

8.1 LibreOffice 是 optional,不是 required

没装 LibreOffice 的系统上,除了 render-slide / render-deck 外,所有命令都能正常工作doctor 命令会明确报告 "LibreOffice not found, render commands will fail",但不阻止其他命令运行。

8.2 不要和 python-pptx 竞争 API

python-pptx 是一个成熟的库,有它自己的 OO API 风格。pptx-skill 的 library 不是 re-implementing 它,而是在它之上加一层 "AI-friendly" 的包装:

  • 扁平化 shape 查找: 提供按 id / name / text 的直接查找,不需要遍历 slide.shapes
  • 统一单位: 所有位置 / 大小参数接受 "1.5in" / "4cm" / "100pt" 这种字符串,内部转换成 EMU
  • Dict-like dump: 把 OO 对象树序列化成 dict,让 JSON dump 变成一行

底层所有真正的操作都委托给 python-pptx,pptx-skill 不重写 pptx 读写逻辑。

8.3 中英文字体混排

v5 deck 的一个关键观察是 shape 里同时包含中文和英文,用的是同一个 font.name (Calibri)。PowerPoint 会对中文做字体 fallback(通常到 PingFang SC 或 Microsoft YaHei)。

pptx-skill 的 set-font 命令应该支持两个参数:

  • --name <font> 设置西文字体
  • --zh-name <font> 单独设置东亚字体

底层走 OOXML 的 <a:rFont> + <a:ea typeface="..."> 分离机制。

8.4 保存是 in-place + .bak 备份

默认每次 save 自动保留一个 .bak 文件(上次的版本)。--no-backup 显式关闭。这是为了避免 AI 跑错命令后无法回滚。

只保留最近一次 .bak(不搞多版本 snapshot),避免目录污染。

9. Risk & mitigation

9.1 LibreOffice render 保真度不够

风险: AI 根据 render 的 PNG 判断 "这段文字放进去 overflow 了",但实际 PowerPoint 打开不 overflow,结果 AI 做了错误的压缩决策。

缓解:

  1. render 命令在 stderr 明确警告 "font fallback may differ from PowerPoint",降低对 render 的信任度
  2. 提供独立的 check-overflow 命令基于字体度量而非 render,给 AI 另一个数据源
  3. 提供 normalize-fonts 命令,鼓励把 deck 字体换成跨平台字体以减小渲染差异

9.2 python-pptx API 覆盖不全

风险: AI 想做某个 OOXML 级别的操作(比如改 slide background、加 animation),python-pptx 不支持。

缓解:

  1. 提供 raw-xml-patch 作为 escape hatch —— AI 可以直接写 OOXML XML 片段
  2. doctor 命令报告当前 python-pptx 版本和已知的功能缺失
  3. README 和 AGENTS.md 明确列出 "做不到的事",让 AI 不浪费时间尝试

9.3 跨平台 font 和 layout 差异

风险: 一个 deck 在 Mac 上改,Windows 上打开 layout 变了。

缓解:

  1. 推荐 normalize-fonts 预处理步骤
  2. doctor 里报告 deck 使用的所有字体,标记 "platform-specific" 的那些
  3. AGENTS.md 里写明这是 known trade-off,不是 skill 的 bug

9.4 AI 误改导致 deck 损坏

风险: AI 跑错命令(比如 delete 错了 slide),deck 被破坏,没 git 备份。

缓解:

  1. 默认每次保存自动生成 .bak
  2. 危险命令(delete-slide)要求 --yes 显式确认
  3. 所有写命令支持 --dry-run,AI 可以先试跑
  4. doctor 命令能验证 deck 可读性,失败时给出原始错误

10. Open questions

下面几个问题留给 RFC 或实现阶段解决,目前 PRD 层面不做决定:

  1. Shape ID 的稳定性: python-pptx 的 shape 没有稳定的 "id"。我们要用 shape_id(OOXML 的 <p:sp>/<p:nvSpPr>/<p:cNvPr id="...">)还是 index in slide.shapes?前者在 deck 被编辑过之后更稳定,后者更直观。倾向用 shape_id,fallback 到 index
  2. Text 的粒度: text frame 有 paragraphsruns 两层。set-text 命令改哪一层?整个 text frame?某个 paragraph?某个 run?倾向默认改整个 text frame(最简单),--paragraph / --run 是 opt-in
  3. CLI 的 argparse vs click: 两个都是标准选择。倾向 argparse(标准库,没有额外依赖)
  4. Error exit code 的语义: 成功 = 0,argparse 错误 = 2,其他?倾向 simple: 任何 library raise = 1,argparse 错误 = 2,其他 = 3
  5. Logging vs print: 走 logging 模块还是直接 print 到 stderr?倾向 print 到 stderr,因为每个命令的输出格式是 contract,不是 "日志"
  6. Unit 解析: 1.5in / 4cm / 100pt 的解析用哪个库?倾向自己写一个简单的 regex 解析,不引入新依赖

12. Timeline 估计

这是一个 skill,不是一个正式产品,没有严格 deadline。估计:

  • Day 1: Scaffolding(目录结构、pyproject、AGENTS)、PRD、RFC
  • Day 2: Core library(Deck / Slide / Shape 抽象、读操作、基本写操作)、CLI 框架
  • Day 3: Render、font normalize、overflow check、tests
  • Day 4: 用 skill 真正改一个真实 deck 作为 end-to-end 验证,修复暴露的问题
  • Day 5: 写 README / AGENTS.md 文档

Day 4 是一个关键节点: 如果 skill 能够真的改真实 deck 并且结果对,这个 skill 就 "working",可以开始用了。


Appendix · 程序化生成 deck 的兼容性

用代码生成的 deck(所有 shape 都是 RECTANGLE auto shape 或 PICTURE,没有 SmartArt / Chart / 3D / animation)100% 可以用 python-pptx 读写

最常见的坑是字体:如果所有文字用平台专有字体(如 Calibri),中文靠 PowerPoint 自己 fallback 到 PingFang SC(Mac)或 Microsoft YaHei(Windows),LibreOffice 渲染时会 fallback 到 Liberation Sans,导致字宽差异。这也是为什么 normalize-fonts 是 P1 feature。