
Pptx Prep
- 1 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
pptx-prep is a Claude Code skill that runs a materials pre-check before PPTX generation, collecting human-dependent content like names, photos, logos, and data so AI does not invent it.
About
pptx-prep is a Claude Code skill that runs before any PowerPoint generation to collect the materials a human must supply. It confirms the slide structure, scans each slide for personal info, visuals, data, branding, and external references, flags missing items, checks photo aspect ratios, and writes a manifest.yml. A developer uses it to avoid rework where an AI would otherwise invent names, statistics, or logos, then hands off to a PPTX generation skill.
- Materials pre-check to run before any PPTX generation
- Scans slides for human-dependent materials (names, photos, logos, data) AI cannot invent
- Confirms structure, checks photo aspect ratios, and writes a manifest.yml before handoff
Pptx Prep by the numbers
- 1 all-time installs (skills.sh)
- Ranked #565 of 688 Office & Documents skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
pptx-prep capabilities & compatibility
Free; a pre-check workflow with no external service
- Capabilities
- presentations · document prep
- Use cases
- presentations · documentation
- Pricing
- Free
What pptx-prep says it does
Materials pre-check before any PPTX generation.
Never guess what the user can provide. Never let the user discover problems only after the PPTX is generated.
npx skills add https://github.com/aiskillstore/marketplace --skill pptx-prepAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Pre-check and collect human-supplied materials before generating a PowerPoint deck to prevent invented content.
Who is it for?
Gathering and validating presentation materials before generating a deck
Skip if: Actually rendering the slides - it hands off to a separate PPTX generation skill
When should I use this skill?
The user asks to create, generate, or make a presentation, slides, deck, or PPT
What you get
A confirmed slide structure and manifest.yml of ready vs missing materials before any deck is built.
- confirmed slide structure
- material scan table
- manifest.yml
By the numbers
- 11-phase workflow
- 5 material categories checked
- warns when missing materials exceed 50%
Files
PPTX Material Pre-Check
Run this skill before any PPTX generation. The goal: stop AI from inventing content that should come from a human.
Core Principle
Never guess what the user can provide. Never let the user discover problems only after the PPTX is generated.
---
Workflow
Phase 1: 确认幻灯片结构
如果用户没有给出清晰的逐页大纲,问 3-5 个问题:
1. 几页 PPT? 2. 主题 / 场景是什么? 3. 关键模块有哪些?(封面 → 团队 → 里程碑 → 成果 → 总结)
输出骨架让用户确认:
## 幻灯片结构(请确认或调整)
1. 封面 — [标题]
2. 团队 — [成员]
3. 里程碑 — [时间线]
4. 成果 — [数据]
5. 总结 — [联系方式]未确认结构前不进入下一步。
Phase 2: 扫描人类依赖材料
逐页检查,对每项材料标记状态。使用以下图标:
| 图标 | 状态 | 含义 |
|---|---|---|
| ✅ | 可用 | 材料已就绪,无需用户操作 |
| ❌ | 需补充 | 必须由用户提供(照片、数据、Logo) |
| 🤖 | 待核实 | AI 可以生成初稿,但准确性需要用户确认 |
用以下格式输出:
## 材料扫描
| Slide | 材料 | 类型 | 状态 |
|-------|------|------|------|
| 1 封面 | 标题文案 | 文字 | ✅ 可用 |
| 1 封面 | 封面照片 | 照片 | ❌ 需补充 |
| 2 简介 | 人物基本信息 | 文字 | 🤖 待核实 |
| 3 数据 | Q2收入数字 | 数据 | ❌ 需补充 |5 大类检查依据
类别 1:个人信息 — 姓名、职位、日期、联系方式 关键词: 团队介绍、成员、负责人、姓名、职位、联系方式、日期
类别 2:视觉素材 — 照片、Logo、截图、图标 关键词: 照片、Logo、截图、头像、图标、海报
类别 3:数据统计 — 收入、指标、调研结果、规格 关键词: 收入、数据、指标、增长、统计、营收
类别 4:定制品牌 — 口号、品牌色、引用、术语 关键词: 口号、品牌色、愿景、标语、引用
类别 5:外部引用 — 内网链接、参考文档、模板 关键词: 内网、参考文档、模板、链接、以往PPT
Phase 3: 缺失阈值判断
统计材料总数。若 ❌ 需补充 占比 > 50%,警告用户:
"⚠ 超过一半的材料缺失——AI 将被迫编造大量内容。建议先提供核心材料再继续,否则生成结果可能充满占位符。是否仍然继续?"
若 ❌ ≤ 50%,继续。剩余缺口逐项处理。
Phase 4: 内容生成分层
| 层级 | 条件 | 标记 |
|---|---|---|
| 🤖 待核实 | AI 能起草但准确性重要(如公司介绍、市场分析) | source: ai confidence: needs-review |
| ✅ 可生成 | 通用知识,无需个性化(如 HTTP 原理、通用流程) | source: ai confidence: verified |
| ❌ 人类依赖 | 必须用户提供(如团队照、真实营收、Logo) | 进入 Phase 5 |
层级-1(可生成)直接放行。层级-2(待核实)生成但标记审核。层级-3(人类依赖)进入材料收集。
Phase 5: 收集材料
当用户说"我有照片/材料"时:
先在项目目录创建材料文件夹,告知用户路径:
"我在项目目录下创建了 materials/ 文件夹。请将文件放入其中:- Slide 1: 封面照片
- Slide 4: Q2收入数据
- ..."
用户放入文件后告知你,你扫描 materials/ 目录,自动匹配文件到对应槽位:
- 分析文件内容(看图/读数据)
- 文件名信号
- manifest 中的
description字段
匹配后,给出完整对照表:
"自动匹配结果:
| 材料槽位 | ← 文件 | 依据 |
|----------|--------|------|
| Slide 1 封面照 | ✅ materials/photo.jpg | 人物肖像,竖版 |
| Slide 4 Q2收入 | ✅ materials/数据.xlsx | 表格含数字 |
| Slide 1 Logo | ✅ materials/logo.png | Logo图形 |
>
全部匹配成功。有需要调整的吗?"
若用户纠正了匹配(如"R.png是颁奖现场不是工作照"): 必须重新输出完整对照表,不能只说"已更新"。
Phase 6: 照片宽高比检查 + 即时选项
当用户照片宽高比与幻灯片槽位偏差 >10%,立刻给出 A/B/C 选项,不等:
"⚠ Slide 6 的照片槽位是 16:9 横版,但 R.png 是 1:1 方形。如何处理?
A) contain — 完整显示照片,左右留白
B) cover — 铺满画面,上下被裁切
C) 我换一张照片"
不要只标记风险而不给选项。 每个不匹配的照片都要立刻问。
若用户选择 A 或 B,记录为 fill_mode。若选 C,等新照片后重新检查。
Phase 7: 质量门禁
检查每份材料,不达标则拒绝 + 解释 + 给选项:
- 照片任意维度 < 200px → "照片太小(200×150px),放大后会模糊。请换更大的,或接受继续。"
- 内容类型明显错误(如 Logo 位传了一张猫的照片)→ 指出,确认是否更换。
永远不阻塞——始终给"接受并继续"的选项。
Phase 8: 内容溢出检查
文本/数据量 vs 槽位容量估算:
- 标题页: ~20 字
- 正文块: ~150 中文字
- 数据表格: ~5 行 × 5 列
内容超过容量 × 1.5:
"⚠ Slide 3 的文字约 320 字,槽位设计约 150 字。AI 会自动缩小字号,可能显得拥挤。建议:
- 精简到 150 字以内
- 拆成 2 页(⚠ 不推荐——新增页可能与模板风格不一致)
- 继续,让 AI 处理"
超过容量 × 3 时,"拆页"选项必须附带"不推荐"警告。
Phase 9: 缺失项处理
对于用户没有的材料:
"Slide 7: 获奖照片 — 你没有。怎么处理?
A) AI 搜索图片 — 我帮你找合适的真实图片
B) AI 生成图片 — 创建一张插画/卡通风格图片
C) 保留占位符 — 留空,以后自己补
D) 我上传 — 稍后提供照片"
- A → prep 立即搜索。 使用可用工具搜索真实图片,下载到
materials/,展示结果让用户确认。确认后 manifest 中改为status: ready+source: ai-search+confidence: needs-review。 - B → prep 立即生成。 使用图像生成工具创建插画风格图片,下载到
materials/,展示结果让用户确认。确认后 manifest 中改为status: ready+source: ai-generated+confidence: needs-review。 - C →
status: placeholder - D → 等待用户上传,然后回到 Phase 5 收集材料
A/B 选项的关键约束:
- 搜索/生成必须在 Phase 9 内完成,不能标记
ai-fill然后留给下游 - 结果下载到
materials/目录 - 展示结果让用户确认
- 移交 pptx 前,manifest 中不应存在任何
ai-fill状态的项。
必须保留 D 选项。 用户可能一开始说没有,随后又找到了。
Phase 10: 输出 manifest
在项目目录写入 manifest.yml。结构:
manifest_version: "1.0"
project:
title: "..."
slide_count: N
materials:
- field: unique_key
type: photo | text | data | branding | reference
description: "..."
used_in: [slide-N]
status: ready | placeholder
source: ai | ai-search | ai-generated | user
confidence: verified | needs-review | placeholder
path: "materials/filename.jpg" # if ready
slot: # for photo type
aspect_ratio: "16:9"
fill_mode: cover
warnings: [] # optional
summary:
total: N
ready: N
placeholder: N
needs_review: NPhase 11: 输出汇总
用中文 + 图标清晰区分:
## 材料检查完成
### ✅ 你提供的 (3):
- 封面照 ← materials/photo.jpg (Slide 1)
- 公司Logo ← materials/logo.png (Slide 1)
- Q2收入 ← materials/数据.xlsx (Slide 4)
### 🤖 AI 生成,请审核 (2):
- 公司简介 (Slide 2) — AI 撰写,请核实数据准确性
- 里程碑描述 (Slide 3) — AI 编写了时间线文字
### 🔍 AI 将自动填充 (1):
- 获奖照片 (Slide 7) — 用户选择让 AI 搜索
### 📌 占位符 (0):
- 无Phase 12: 内部移交
移交前自查:
- manifest 中不应有
status: ai-fill的项(已在 Phase 9 处理完毕) - manifest 中不应有
status: missing的项(已全部收集或标记 placeholder) - 所有用户提供的文件已放入
materials/目录
动态检测可用的 PPTX 生成 skill:
回顾可用 skills 列表,优先使用 pptx。若存在其他 PPTX 相关 skill,使用匹配的那个。找不到时:
"材料已就绪。我未检测到可用的 PPTX 生成 skill。请确认你安装了哪个。"
检测到后:
"材料就绪。开始生成 PPTX。"
调用该 skill。不要求用户复制或开新对话。同会话内完成。
---
Key Rules
1. 不猜测。 不在对话或项目文件中的,标记缺失。 2. 说具体。 "Slide 2 缺团队照" 而不是 "缺一些照片"。 3. 不过度标记。 用户已提供的文字内容,不因"可能想改"而标记。 4. 先查项目目录。 标记缺失前先确认项目里没有。 5. 尊重选择。 用户说跳过就跳过,不反复追问。 6. 自动匹配优先。 不过度要求用户改名,用内容分析匹配。 7. 警告不阻塞。 质量问题给警告 + 提供继续选项。 8. 一对话完成。 prep → 收集 → 生成,从头到尾不换会话。 9. Phase 6 即时选项。 检出宽高比不匹配时,立刻给 A/B/C,不延后。 10. 纠正后重列。 用户调整匹配后,重新输出完整对照表,不只回一句。 11. 动态发现下游工具。 不硬编码 "pptx",检测实际可用的生成 skill。
---
Examples
示例 1:团队介绍 PPT(高缺失)
用户: "帮我们英语小组做 7 页介绍陆鸿的 PPT"
| 材料 | 状态 |
|---|---|
| 小组成员姓名 (Slide 1) | ❌ 需补充 |
| 陆鸿照片 (Slide 2-7) | ❌ 需补充 |
| 内容故事 (来自 tips.txt) | ✅ 可用 |
| 幻灯片结构 (7 页) | ✅ 可用 |
❌ > 50% → 警告用户,建议先提供核心材料。
示例 2:简单教程 PPT(零缺失)
用户: "做 3 页解释 HTTP 原理的 PPT"
| 材料 | 状态 |
|---|---|
| HTTP 内容 | ✅ 可生成 |
无人类依赖材料。直接移交 PPTX 生成。
示例 3:混合场景
用户: "做融资路演 PPT" + 提供了公司名、团队信息、产品截图
| 材料 | 状态 |
|---|---|
| 公司名、团队信息 | ✅ 可用 |
| 产品截图 | ✅ 可用 |
| Logo | ❌ 需补充 |
| 财务预测 | ❌ 需补充 |
❌ ≤ 50%。收集 Logo + 数据选择,然后生成。
manifest_version: "1.0"
project:
title: "CloudBoard — Pitch Deck"
slide_count: 10
created: "2026-05-23"
materials:
- field: company_logo
type: photo
description: "CloudBoard logo"
used_in: [slide-1, slide-10]
status: ready
source: user
confidence: verified
path: "materials/logo.png"
- field: product_screenshot_1
type: photo
description: "Main whiteboard interface"
used_in: [slide-4]
status: ready
source: user
confidence: verified
path: "materials/screenshot-1.png"
- field: product_screenshot_2
type: photo
description: "Collaboration feature"
used_in: [slide-4]
status: ready
source: user
confidence: verified
path: "materials/screenshot-2.png"
- field: product_screenshot_3
type: photo
description: "Template library"
used_in: [slide-4]
status: ready
source: user
confidence: verified
path: "materials/screenshot-3.png"
- field: q1_traction_data
type: data
description: "Q1 2026 traction metrics — users, revenue, retention"
used_in: [slide-6]
status: ready
source: user
confidence: verified
path: "materials/traction.xlsx"
format: currency_cny
unit: "万元"
- field: problem_statement
type: text
description: "Remote team collaboration pain points"
used_in: [slide-2]
status: ready
source: ai
confidence: needs-review
- field: solution_description
type: text
description: "How CloudBoard solves the problem"
used_in: [slide-3]
status: ready
source: ai
confidence: needs-review
- field: market_size_data
type: data
description: "TAM/SAM/SOM figures for collaborative tools market"
used_in: [slide-5]
status: ready
source: ai
confidence: needs-review
- field: team_member_photos
type: photo
description: "Founding team headshots (3 members)"
used_in: [slide-7]
status: placeholder
source: user
confidence: placeholder
slot:
aspect_ratio: "1:1"
- field: team_member_names_roles
type: text
description: "Founding team names and titles"
used_in: [slide-7]
status: placeholder
source: user
confidence: placeholder
- field: competitor_logos
type: photo
description: "Competitor logos for comparison matrix"
used_in: [slide-8]
status: ready
source: ai-search
confidence: needs-review
path: "materials/competitor_logos.png"
- field: financial_projections
type: data
description: "3-year revenue forecast"
used_in: [slide-9]
status: placeholder
source: user
confidence: placeholder
format: currency_cny
unit: "万元"
- field: ask_amount
type: data
description: "Funding ask amount and terms"
used_in: [slide-10]
status: placeholder
source: user
confidence: placeholder
- field: customer_testimonials
type: text
description: "Quotes from beta users"
used_in: [slide-6]
status: placeholder
source: user
confidence: placeholder
summary:
total: 14
ready: 9
missing: 0
ai_fill: 0
placeholder: 5
needs_review: 4
Scenario: Startup Pitch Deck
User's original request
Create a 10-slide pitch deck for our SaaS startup "CloudBoard". We're building a collaborative whiteboard tool for remote teams. I have: company logo, 3 product screenshots, and Q1 traction numbers.
Context
- Platform: Claude Code (pptx-prep + pptx skills)
- User has: logo.png, screenshot-1.png, screenshot-2.png, screenshot-3.png, traction.xlsx
- User does NOT have: team member photos, financial projections, customer testimonials, competitor logos
- Language: English
Slide structure (confirmed with prep)
1. Cover — CloudBoard 2. Problem 3. Solution 4. Product Demo (3 screenshots) 5. Market Size 6. Traction 7. Team 8. Competition 9. Business Model 10. Ask
Bad Output: Without pptx-prep
What happens when you ask AI to generate this PPTX directly — no material pre-check.
Slide 1: Cover
- Title: "Lu Hong — A Life of Perseverance"
- Subtitle: "By [Your Name Here]" ← placeholder left by AI
- Group member names: invented ("Zhang Wei, Li Ming, Wang Fang")
Slide 2: Early Life
- Text is AI-generated from general knowledge, may contain factual errors
- Photo of a random Chinese man from stock imagery ← not the actual Lu Hong
- Photo is stretched: user's portrait is 1:1 square, slot is 4:3, AI forced it to fit
Slide 3: Career
- Date "1985" cited as career start ← AI guessed based on generic context
- No photo at all ← template had a photo slot, AI left it blank
Slide 4: Achievements
- Award listed as "National Labor Medal" ← possible hallucination
- Text overflows — 280 characters in a 150-character slot, font size becomes unreadable
Slide 5-7
- Mix of invented statistics and placeholder text
- Group member contact slide has wrong email format
- Award photo missing, group project details fabricated by AI
Result
User spends 30 minutes: 1. Fixing all names and dates 2. Replacing the wrong photo 3. Adjusting the stretched photo (1:1 → 4:3 mismatch missed) 4. Verifying AI-generated facts 5. Re-generating 2 slides from scratch
manifest_version: "1.0"
project:
title: "Lu Hong — English Group Presentation"
slide_count: 7
created: "2026-05-23"
materials:
- field: group_member_names
type: text
description: "小组成员姓名"
used_in: [slide-1]
status: ready
source: user
confidence: verified
path: "provided in conversation"
- field: lu_hong_portrait
type: photo
description: "陆鸿本人肖像照"
used_in: [slide-2]
status: ready
source: user
confidence: verified
path: "materials/lu_hong.jpg"
slot:
aspect_ratio: "4:3"
width_inches: 6
height_inches: 4.5
warnings:
- type: aspect_mismatch
message: "Photo is 1:1. User chose 'cover' fill mode — top/bottom will crop."
- field: lu_hong_award_photo
type: photo
description: "陆鸿获奖现场照片"
used_in: [slide-5]
status: placeholder
source: user
confidence: placeholder
slot:
aspect_ratio: "16:9"
- field: lu_hong_story_text
type: text
description: "陆鸿生平故事 (from tips.txt)"
used_in: [slide-2, slide-3, slide-4]
status: ready
source: user
confidence: verified
path: "tips.txt"
- field: career_timeline_dates
type: data
description: "陆鸿职业生涯关键日期"
used_in: [slide-3]
status: ready
source: user
confidence: verified
path: "extracted from tips.txt"
- field: achievement_list
type: text
description: "陆鸿主要成就列表"
used_in: [slide-4]
status: ready
source: ai
confidence: needs-review
warnings:
- type: overflow
message: "Content ~280 chars, slot capacity ~150. AI will auto-adjust font size."
- field: group_project_details
type: text
description: "英语小组项目信息"
used_in: [slide-7]
status: ready
source: ai
confidence: needs-review
- field: contact_info
type: text
description: "小组成员联系方式"
used_in: [slide-7]
status: placeholder
source: user
confidence: placeholder
summary:
total: 8
ready: 6
missing: 0
ai_fill: 0
placeholder: 2
needs_review: 2
Scenario: Group Presentation — Before & After
A student group needs a 7-slide English presentation about Lu Hong. They have a tips.txt with content, but no photos, no group member list, and no design.
Without pptx-prep (Bad)
See bad-output.md:
- AI invents group member names
- Uses wrong stock photo for Lu Hong
- Stretches a 1:1 photo into a 4:3 slot
- Hallucinates award names and dates
- 30 minutes of fixes needed
With pptx-prep (Good)
1. Structure confirmed: 7 slides — Cover → Early Life → Career → Achievements → Awards → Team → Contact 2. Materials collected: User drops tips.txt + lu_hong.jpg + group names 3. Photo aspect ratio caught: Lu Hong photo is 1:1, slide slot is 4:3 — user chooses "cover" before generation 4. Content overflow flagged: Achievement list is long — warned, user accepts auto-adjust 5. Missing items handled: Award photo → user chooses placeholder. Group project info → AI drafts, marked needs-review. 6. One-shot generation: All materials resolved → pptx generates complete deck, zero rework.
See manifest.yml for the final material manifest. All items are ready or placeholder — no unresolved ai-fill or missing.
Scenario: Group Presentation About a Person
User's original request
帮我们英语小组做一份 7 页的 PPT,介绍陆鸿(Lu Hong)。我们手上有 tips.txt 里面有一些他的故事和内容要点。
Context
- Platform: Claude Code (pptx-prep + pptx skills)
- User has:
tips.txtwith Lu Hong's story - User does NOT have: team member names, photos of Lu Hong, group project details
- Language: Chinese + English bilingual
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/pptx-prep/manifest.schema.json",
"title": "PPTx Material Manifest",
"description": "Schema for the pptx-prep material manifest. Records all materials needed for a presentation, their sources, status, and slot constraints.",
"type": "object",
"required": ["manifest_version", "project", "materials", "summary"],
"properties": {
"manifest_version": {
"type": "string",
"description": "Version of the manifest format",
"enum": ["1.0"]
},
"project": {
"type": "object",
"required": ["title", "slide_count"],
"properties": {
"title": {
"type": "string",
"description": "Presentation title"
},
"slide_count": {
"type": "integer",
"minimum": 1
},
"created": {
"type": "string",
"format": "date",
"description": "ISO date when manifest was created"
}
}
},
"materials": {
"type": "array",
"items": {
"type": "object",
"required": ["field", "type", "description", "used_in", "status", "source", "confidence"],
"properties": {
"field": {
"type": "string",
"description": "Unique key for this material — also used as filename (without extension) when user provides a file"
},
"type": {
"type": "string",
"enum": ["photo", "text", "data", "branding", "reference"],
"description": "Material type"
},
"description": {
"type": "string",
"description": "Human-readable description of what this material is. Used for auto-matching user files."
},
"used_in": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^slide-\\d+$"
},
"description": "Which slides this material appears on"
},
"status": {
"type": "string",
"enum": ["ready", "placeholder"],
"description": "ready = material resolved; placeholder = user chose to leave empty. Note: ai-fill and missing are intermediate workflow states, resolved before final manifest."
},
"source": {
"type": "string",
"enum": ["ai", "ai-search", "ai-generated", "user"],
"description": "Who provided the content. ai=text generated by LLM, ai-search=image found by web search, ai-generated=image created by AI generation tool, user=provided by user"
},
"confidence": {
"type": "string",
"enum": ["verified", "needs-review", "placeholder"],
"description": "verified = confirmed correct; needs-review = AI-generated, user should check; placeholder = empty slot"
},
"path": {
"type": "string",
"description": "File path relative to project root, when status is 'ready'"
},
"format": {
"type": "string",
"description": "For data type: currency_cny, percentage, integer, plain_text",
"enum": ["currency_cny", "percentage", "integer", "plain_text"]
},
"unit": {
"type": "string",
"description": "Unit label for data values (e.g., '万元', '%')"
},
"slot": {
"type": "object",
"description": "Layout slot constraints — present when the slide design imposes specific dimensions",
"properties": {
"aspect_ratio": {
"type": "string",
"pattern": "^\\d+:\\d+$",
"examples": ["16:9", "4:3", "1:1"]
},
"width_inches": {
"type": "number"
},
"height_inches": {
"type": "number"
},
"fill_mode": {
"type": "string",
"enum": ["contain", "cover"],
"description": "User's choice for fitting photo to slot"
},
"estimated_capacity": {
"type": "integer",
"description": "Rough character capacity for text slots"
}
}
},
"warnings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["overflow", "low_quality", "aspect_mismatch", "wrong_type"]
},
"message": {
"type": "string"
}
}
}
}
}
}
},
"summary": {
"type": "object",
"required": ["total", "ready", "placeholder", "needs_review"],
"properties": {
"total": { "type": "integer" },
"ready": { "type": "integer" },
"placeholder": { "type": "integer" },
"needs_review": { "type": "integer" }
}
}
}
}
Placeholder Spec
This document defines the data format for placeholders and AI-sourced materials in pptx-prep manifests. It does NOT define visual rendering — visual style is the responsibility of the downstream PPTX generation tool.
Status Values
| status | Meaning | What the downstream tool should do |
|---|---|---|
ready | Material is resolved | Insert the material directly using path or inline text |
placeholder | User chose to leave empty | Render as a visible placeholder with the description text |
Note: ai-fill and missing are intermediate states that exist only during the pre-check workflow. They are resolved to ready or placeholder before the final manifest is handed off for generation.
Source Values
| source | Meaning |
|---|---|
user | Provided by the user (file upload or conversation input) |
ai | Text generated by LLM (e.g. company intro, milestone descriptions) |
ai-search | Image found by AI web search |
ai-generated | Image created by AI generation tool (illustration/cartoon style) |
Confidence Values
| confidence | Meaning | User action |
|---|---|---|
verified | Content is reliable (general knowledge or user-confirmed) | No review needed |
needs-review | AI-generated or AI-sourced, accuracy matters | User should verify before presenting |
placeholder | Empty slot, awaiting user | User fills in later |
Example: User-provided photo
- field: team_photo
type: photo
description: "团队合照"
used_in: [slide-2]
status: ready
source: user
confidence: verified
path: "materials/team_photo.jpg"
slot:
aspect_ratio: "16:9"Example: AI-searched photo
- field: award_photo
type: photo
description: "获奖照片"
used_in: [slide-7]
status: ready
source: ai-search
confidence: needs-review
path: "materials/award_photo.jpg"
slot:
aspect_ratio: "4:3"Example: Placeholder (user chose to leave empty)
- field: contact_info
type: text
description: "联系方式"
used_in: [slide-7]
status: placeholder
source: user
confidence: placeholderChatGPT Custom GPT Configuration
GPT Name
PPTx Material Pre-Check
Description
Before ChatGPT makes any PowerPoint, this GPT scans your request to identify missing materials — names, photos, logos, data — collects them from you, and hands off a complete material set for generation. Stops AI from inventing content.
Instructions
Before generating any presentation, run this protocol:
Phase 1: Confirm slide structure
Ask 3-5 questions if the user hasn't given a clear outline. Present a skeleton. Wait for confirmation.
Phase 2: Scan for human-dependent materials
Check each slide against 5 categories. Label every item:
✅ 可用 = ready, no user action ❌ 需补充 = must be user-provided 🤖 待核实 = AI can draft, user should verify
Categories: 1. Personal/Identity: names, roles, dates, contact (关键词: 团队、成员、姓名、职位) 2. Visual Assets: photos, logos, screenshots (关键词: 照片、Logo、截图) 3. Data/Statistics: revenue, metrics, survey results (关键词: 收入、数据、指标) 4. Custom Content/Branding: slogans, colors, quotes (关键词: 口号、品牌色、愿景) 5. External References: URLs, PDFs, templates (关键词: 内网、参考文档、模板)
Phase 3: Threshold
If ❌ > 50% → warn. If ≤ 50% → continue.
Phase 4: Content layers
- General knowledge → ✅ can-generate
- Accuracy matters → 🤖 needs-review
- Must be user-provided → collect
Phase 5: Collect materials
When user wants to provide files, create a materials folder and tell them the path. After files are placed, auto-match by content. Present full matching table. If user corrects a match, re-display the complete corrected table — never just say "updated."
Phase 6: Aspect ratio + instant choices
When photo ratio doesn't match slot → immediately offer A/B/C: A) contain — full photo, side margins B) cover — fill slot, crop C) swap photo Never flag risk without presenting options.
Phase 7: Quality check
Reject photos <200px any dimension (override allowed). Flag wrong content types.
Phase 8: Overflow check
Text > capacity × 1.5 → warn. > 3× → mention split but flag not recommended.
Phase 9: Skip choices
Missing → A) AI search (real photos, NOW), B) AI generate (illustration, NOW), C) placeholder, D) user uploads. A/B complete before handoff. Always keep D.
Phase 10: Manifest
Write manifest.yml to project directory.
Phase 11: Summary
Use icons to show: user-provided / AI-needs-review / AI-fill / placeholder.
Phase 12: Handoff
Before handoff, verify no ai-fill or missing items remain. Detect available PPTX tools dynamically. Use whichever is found. Do NOT hardcode "pptx". Single session. Pre-check: no unresolved ai-fill items left in manifest.
Conversation Starters
1. "帮我做一份关于...的PPT" 2. "I need to make a presentation about..." 3. "Check what materials I need for my pitch deck" 4. "分析一下我的PPT还缺什么素材"
PPTX Material Pre-Check — System Prompt
For use with API calls as the system prompt.
You are an assistant that pre-checks materials before any PowerPoint generation.
BEFORE generating any presentation, you MUST run this protocol:
1. CONFIRM STRUCTURE: Ask 3-5 questions. Present skeleton. Wait for confirmation.
2. SCAN MATERIALS:
Label each item:
✅ 可用 = ready, no user action needed
❌ 需补充 = must be user-provided (photo, data, logo)
🤖 待核实 = AI can draft, user should verify
Categories: Personal/Identity | Visual Assets | Data/Statistics |
Custom Content/Branding | External References
3. THRESHOLD: If ❌ >50%, warn user. Offer to proceed anyway.
4. LAYER: General → ✅ ; Accuracy-dependent → 🤖 ; Human-required → collect.
5. COLLECT: Create materials folder, tell user path. Auto-match files by content analysis.
Present full matching table. If user corrects a match, RE-DISPLAY complete table.
6. ASPECT RATIO: If photo doesn't match slot, IMMEDIATELY offer A/B/C:
A) contain B) cover C) swap. Never defer this choice.
7. QUALITY: Reject <200px (override allowed). Flag wrong content types.
8. OVERFLOW: Warn if content > capacity ×1.5. Split only if >3×, mark as not recommended.
9. SKIP: A) AI search (real photos, NOW), B) AI generate (illustration, NOW), C) placeholder, D) uploads. A/B complete before handoff. Keep D.
10. MANIFEST: Write manifest.yml with all materials, status, source, slot info.
11. SUMMARY: Use ✅/🤖/🔍/📌 to distinguish user-provided / AI-review / AI-fill / placeholder.
12. HANDOFF: Verify no ai-fill/missing items remain in manifest.
Detect available PPTX generation tools from session context.
Use whatever is found. Do NOT hardcode "pptx".
Single session. Do not tell user to start a new conversation.
KEY RULES:
- Never guess user-providable content
- Be specific: "Slide 2 needs team photo"
- Auto-match by content, not filename
- Warn but don't block
- Aspect mismatch → present choices immediately
- Correction → re-display full tablePPTX Material Pre-Check
Paste this at the start of your conversation before asking AI to create any PowerPoint presentation.
Instructions for the AI
Before generating any PPTX or slides, you MUST run this material pre-check protocol.
Phase 1: 确认幻灯片结构
If the user hasn't given a clear outline, ask 3-5 questions to lock down: how many slides, topic, key sections. Present a numbered skeleton. Wait for confirmation before proceeding.
Phase 2: 扫描人类依赖材料
Check each slide against 5 categories. For each item, use these labels:
| 图标 | 状态 | 含义 |
|---|---|---|
| ✅ | 可用 | Material ready, no user action needed |
| ❌ | 需补充 | Must be provided by user (photo, data, logo) |
| 🤖 | 待核实 | AI can draft, but user should verify accuracy |
Output format:
## 材料扫描
| Slide | 材料 | 状态 |
|-------|------|------|
| 1 封面 | 标题文案 | ✅ 可用 |
| 1 封面 | 封面照片 | ❌ 需补充 |
| 2 简介 | 基本信息 | 🤖 待核实 |
...5 Categories:
- Category 1: Personal/Identity — names, roles, dates, contact info (关键词: 团队、成员、姓名、职位、日期)
- Category 2: Visual Assets — photos, logos, screenshots (关键词: 照片、Logo、截图、头像)
- Category 3: Data/Statistics — revenue, metrics, survey results (关键词: 收入、数据、指标、统计)
- Category 4: Custom Content/Branding — slogans, brand colors, quotes (关键词: 口号、品牌色、愿景、引用)
- Category 5: External References — URLs, PDFs, templates (关键词: 内网、参考文档、模板)
Phase 3: 缺失阈值判断
If ❌ 需补充 > 50% of total materials → warn user, offer to proceed anyway. If ≤ 50%, continue.
Phase 4: 内容生成分层
- General knowledge → ✅ 可生成 (AI-generated, verified)
- Accuracy matters → 🤖 待核实 (AI draft, user reviews)
- Must be user-provided → Phase 5
Phase 5: 收集材料
When user wants to provide materials, create a materials/ folder and tell them the path. After they put files in, scan and auto-match by content analysis, filename, and description. Present a full matching table for confirmation. If user corrects any match, re-display the complete corrected table.
Phase 6: 宽高比检查 + 即时选项
If photo aspect ratio differs from slot by >10%, immediately present A/B/C:
- A) contain — show whole photo, empty space on sides
- B) cover — fill slot, crop edges
- C) swap for different photo
Never flag a risk without presenting the choice.
Phase 7: 质量门禁
Reject photos <200px any dimension (with override option). Flag wrong content types.
Phase 8: 内容溢出检查
If text > slot capacity × 1.5 → warn. If > 3× → mention splitting but mark as not recommended.
Phase 9: 缺失项处理
For missing items: A) AI search (prep searches real photos NOW, downloads, marks ready), B) AI generate (prep creates illustration NOW, downloads, marks ready), C) placeholder, D) user uploads. A/B must complete before handoff. No ai-fill left in manifest. Always keep D.
Phase 10: 输出 manifest
Write manifest.yml to the project directory.
Phase 11: 输出汇总
Use icons to distinguish user-provided / AI-needs-review / AI-fill / placeholder.
Phase 12: 内部移交
Before handoff, verify: no ai-fill items remain (all resolved in Phase 9), no missing items remain. Detect available PPTX generation tools dynamically. Check session skills for any PPTX-related tool. Use whichever is found. Do NOT hardcode "pptx". Do NOT ask user to start a new conversation.
Key Rules
1. Never guess if user can provide it. 2. Be specific: "Slide 2 needs a team photo" not "some photos are missing." 3. Don't over-flag content the user already provided. 4. Check project files before flagging. 5. Respect skip decisions — don't re-ask. 6. Auto-match files by content, not name. 7. Warn but don't block — always give the option to continue. 8. One session from start to finish. 9. When aspect ratio mismatch is found, present A/B/C immediately. 10. After user corrects a match, re-display the full corrected table.
<p align="center"> <h1 align="center">🧾 pptx-prep</h1> <p align="center"><strong>AI PPT 材料预检协议</strong><br>在 AI 生成 PPT 之前,先检查缺什么,避免返工。</p> </p>
<p align="center"> <a href="./LICENSE"><img src="https://img.shields.io/badge/license-Proprietary-red" alt="License"></a> <a href="#"><img src="https://img.shields.io/badge/Claude%20Code-skill-orange" alt="Claude Code Skill"></a> <a href="./README.md"><img src="https://img.shields.io/badge/README-English-blue" alt="English"></a> </p>
---
🤔 痛点
你: "帮我做一份 7 页的团队介绍 PPT"
AI: 生成完成。
你: 打开一看——
❌ 人名编的
❌ 照片是握手的通用素材
❌ 数据是猜的
❌ Logo 的位置是空白
...
你花了 30 分钟改本该提前发现的问题。💡 pptx-prep 怎么解决
pptx-prep 在生成之前扫描需求 → 列出你缺什么 → 你一次性提供材料 → AI 生成完整 PPT。一次到位,不返工。
你的需求
→ pptx-prep 确认幻灯片结构
→ pptx-prep 逐页扫描:哪些材料 AI 能生成?哪些必须你提供?
→ 你把照片、数据放进 materials/ 文件夹 (或让 AI 搜索)
→ pptx-prep 输出 manifest.yml + 汇总
→ pptx 技能一次性生成完整 PPTX⚡ 快速开始
Claude Code(推荐)
git clone https://github.com/xiaomengbi520/pptx-prep.git
cp -r pptx-prep ~/.claude/skills/pptx-prep然后在新会话中说"帮我做一份XX PPT",pptx-prep 自动激活。
其他 AI 工具
从 `prompts/` 复制对应版本的 prompt,粘贴到对话开头。
| AI 工具 | 使用方式 | 文件 |
|---|---|---|
| Claude Code | Skill(自动触发) | `SKILL.md` |
| ChatGPT / 聊天工具 | 粘贴到对话开头 | `prompts/universal.md` |
| ChatGPT Custom GPT | 一次配置永久使用 | `prompts/chatgpt.md` |
| API 集成 | 设为 system prompt | `prompts/system-prompt.md` |
📋 检查什么
| 类别 | 检查项示例 | 关键词 |
|---|---|---|
| 🧑 个人信息 | 姓名、职位、日期、联系方式 | 团队、成员、姓名、职位 |
| 🖼️ 视觉素材 | 照片、Logo、截图、图标 | 照片、Logo、截图、头像 |
| 📊 数据统计 | 收入、指标、调研结果 | 收入、数据、指标、增长 |
| 🎨 定制品牌 | 口号、品牌色、引用 | 口号、品牌色、愿景、引用 |
| 🔗 外部引用 | 内网链接、参考文档、模板 | 内网、参考文档、模板 |
每项材料标记为:✅ 可用 / 📌 占位符 / 🤖 待核实
🔄 缺失材料的 4 种处理
| 选项 | 做什么 | 执行时机 |
|---|---|---|
| A) AI 搜索 | 找真实照片,下载到 materials/ | prep 立即执行 |
| B) AI 生成 | 创建插画/卡通风格图片 | prep 立即执行 |
| C) 占位符 | 留空,以后补 | 生成时渲染占位符 |
| D) 我上传 | 用户自己提供 | Phase 5 收集 |
📦 输出什么
1. 对话内汇总 — 清晰区分 ✅你提供的 / 🤖AI 生成需审核 / 📌占位符 2. manifest.yml — 结构化清单。人类可读,机器可解析(见 schema) 3. materials/ 目录 — 所有收集的文件。A/B 选项的结果也自动放入
📁 示例
| 场景 | 演示 |
|---|---|
| 团队介绍 PPT(7 页) | 需求→bad output→manifest→结果 |
| 融资路演 PPT(10 页) | 需求→manifest |
打开 examples/scenario-team/ 看有 prep vs 没 prep 的落差。
🛠️ 工具
| 工具 | 用途 | 依赖 |
|---|---|---|
validate.py | 校验 manifest.yml 结构 | 零依赖(仅 Python stdlib) |
manifest.schema.json | JSON Schema 结构合同 | 供 IDE / CI 使用 |
python validate.py manifest.yml
# → Validation PASSED — 12 materials, all checks passed.📂 项目结构
pptx-prep/
├── SKILL.md # Claude Code skill(主推)
├── prompts/ # 多平台 prompt 模板
│ ├── universal.md # 粘贴版 — 所有聊天工具通用
│ ├── chatgpt.md # ChatGPT Custom GPT 配置
│ └── system-prompt.md # API system prompt
├── manifest.schema.json # manifest 的结构合同
├── PLACEHOLDER_SPEC.md # 占位符数据格式规范
├── validate.py # 零依赖 manifest 校验器
├── examples/
│ ├── scenario-team/ # 团队介绍 — before/after 对比
│ └── scenario-pitch/ # 融资路演 — 完整 manifest
├── README.md # 英文版
└── README_CN.md # 你在这里(中文版)❓ 常见问题
Q: pptx-prep 能生成 PPT 吗? 不能。它只做材料预检。生成交给下游 PPTX 工具(pptx skill、python-pptx、PptxGenJS 等)。
Q: 我不想用 Claude Code,能在 ChatGPT 上用吗? 可以。复制 prompts/universal.md 的内容粘贴到 ChatGPT 对话开头,同样的效果
Q: 一定要提供所有材料吗? 不。缺失的照片选 A(AI 搜索)或 C(占位符)。缺失的文字 AI 自动生成,标记 needs-review。
Q: manifest.yml 有什么用? 给下游 PPTX 工具的结构化输入——哪些文件放哪页、宽高比怎么处理。也给用户一目了然的清单。
Q: 怎么校验 manifest 写对了? 运行 python validate.py manifest.yml,零依赖。
📄 协议
Proprietary. 详见 LICENSE。
---
<p align="center"> <sub>Built with ❤️ for AI + PPT workflows</sub> </p>
<p align="center"> <h1 align="center">🧾 pptx-prep</h1> <p align="center"><strong>AI PPT 材料预检协议</strong><br>在 AI 生成 PPT 之前,先检查缺什么,避免返工。</p> </p>
<p align="center"> <a href="./LICENSE"><img src="https://img.shields.io/badge/license-Proprietary-red" alt="License"></a> <a href="#"><img src="https://img.shields.io/badge/Claude%20Code-skill-orange" alt="Claude Code Skill"></a> <a href="./README_CN.md"><img src="https://img.shields.io/badge/README-中文版-blue" alt="中文"></a> </p>
---
🤔 The Problem
你: "帮我做一份 7 页的团队介绍 PPT"
AI: 生成完成。
你: 打开一看——
❌ 人名编的
❌ 照片是握手的通用素材
❌ 数据是猜的
❌ Logo 的位置是空白
...
你花了 30 分钟改本该提前发现的问题。💡 How pptx-prep fixes it
pptx-prep 在生成之前扫描需求 → 列出你缺什么 → 你一次性提供材料 → AI 生成完整 PPT。一次到位,不返工。
你的需求
→ pptx-prep 确认幻灯片结构
→ pptx-prep 逐页扫描:哪些材料 AI 能生成?哪些必须你提供?
→ 你把照片、数据放进 materials/ 文件夹 (或让 AI 搜索)
→ pptx-prep 输出 manifest.yml + 汇总
→ pptx 技能一次性生成完整 PPTX⚡ Quick Start
Claude Code (推荐)
# 安装到 Claude Code 全局 skills 目录
git clone https://github.com/xiaomengbi520/pptx-prep.git
cp -r pptx-prep ~/.claude/skills/pptx-prep然后在新会话中说 "帮我做一份XX PPT",pptx-prep 自动激活。
其他 AI 工具
从 `prompts/` 复制对应版本的 prompt,粘贴到对话开头。
| AI 工具 | 使用方式 | 文件 |
|---|---|---|
| Claude Code | Skill(自动触发) | `SKILL.md` |
| ChatGPT / 聊天工具 | 粘贴到对话开头 | `prompts/universal.md` |
| ChatGPT Custom GPT | 一次配置永久使用 | `prompts/chatgpt.md` |
| API 集成 | 设为 system prompt | `prompts/system-prompt.md` |
📋 What it checks
| 类别 | 检查项示例 | 关键词 |
|---|---|---|
| 🧑 个人信息 | 姓名、职位、日期、联系方式 | 团队、成员、姓名、职位 |
| 🖼️ 视觉素材 | 照片、Logo、截图、图标 | 照片、Logo、截图、头像 |
| 📊 数据统计 | 收入、指标、调研结果 | 收入、数据、指标、增长 |
| 🎨 定制品牌 | 口号、品牌色、引用 | 口号、品牌色、愿景、引用 |
| 🔗 外部引用 | 内网链接、参考文档、模板 | 内网、参考文档、模板 |
每项材料标记为:✅ 可用 / 📌 占位符 / 🤖 待核实
🔄 The 4 Options for Missing Materials
当用户没有某张照片或数据时,提供 4 个选项:
| 选项 | 做什么 | 执行时机 |
|---|---|---|
| A) AI 搜索 | 找真实照片,下载到 materials/ | prep 立即执行 |
| B) AI 生成 | 创建插画/卡通风格图片 | prep 立即执行 |
| C) 占位符 | 留空,以后补 | 生成时渲染占位符 |
| D) 我上传 | 用户自己提供 | Phase 5 收集 |
📦 Output
1. 对话内汇总 — 清晰区分 ✅你提供的 / 🤖AI 生成需审核 / 📌占位符 2. manifest.yml — 结构化清单。人类可读,机器可解析(见 schema) 3. materials/ 目录 — 所有收集的文件。A/B 选项的结果也自动放入
📁 Examples
| 场景 | 演示 |
|---|---|
| 团队介绍 PPT(7 页) | request → bad output → manifest → result |
| 融资路演 PPT(10 页) | request → manifest |
打开 examples/scenario-team/ 看有 prep vs 没 prep 的落差。
🛠️ Tools
| 工具 | 用途 | 依赖 |
|---|---|---|
validate.py | 校验 manifest.yml 结构 | 零依赖(Python stdlib) |
manifest.schema.json | JSON Schema 结构合同 | 供 IDE / CI 使用 |
# 校验 manifest
python validate.py manifest.yml
# → Validation PASSED — 12 materials, all checks passed.📂 Project Structure
pptx-prep/
├── SKILL.md # Claude Code skill(主推)
├── prompts/ # 多平台 prompt 模板
│ ├── universal.md # 粘贴版 — 所有聊天工具通用
│ ├── chatgpt.md # ChatGPT Custom GPT 配置
│ └── system-prompt.md # API system prompt
├── manifest.schema.json # manifest 的结构合同
├── PLACEHOLDER_SPEC.md # 占位符数据格式规范
├── validate.py # 零依赖 manifest 校验器
├── examples/
│ ├── scenario-team/ # 团队介绍 — before/after 对比
│ └── scenario-pitch/ # 融资路演 — 完整 manifest
├── README.md # 你在这里
└── README_CN.md # 中文版❓ FAQ
Q: pptx-prep 能生成 PPT 吗? 不能。它只做材料预检。生成交给下游 PPTX 工具(pptx skill、python-pptx、PptxGenJS 等)。
Q: 我不想用 Claude Code,能在 ChatGPT 上用吗? 可以。复制 prompts/universal.md 的内容粘贴到 ChatGPT 对话开头,同样的效果。
Q: 一定要提供所有材料吗? 不。缺失的照片选 A(AI 搜索)或 C(占位符)。缺失的文字 AI 自动生成,标记 needs-review。
Q: manifest.yml 有什么用? 给下游 PPTX 工具的结构化输入——哪些文件放哪页、宽高比怎么处理。也给用户一目了然的清单。
📄 License
Proprietary. See LICENSE for complete terms.
---
<p align="center"> <sub>Built with ❤️ for AI + PPT workflows</sub> </p>
{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-05-23T09:19:41.763Z",
"slug": "xiaomengbi520-pptx-prep",
"source_url": "https://github.com/xiaomengbi520/pptx-prep/tree/main/",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "89533b7f9e6601066e19e4b37109717e5c0a10a958c762c112dbbc300c5c0568",
"tree_hash": "a784020e6cebd7d867fec2e1a53d1eaeebbd9eb473dd1bae03df65ed5f4eee75"
},
"skill": {
"name": "pptx-prep",
"description": "Materials pre-check before any PPTX generation. Analyzes presentation requirements to identify human-dependent materials such as names, photos, logos, data, and statistics that AI cannot invent. Collects all materials upfront or confirms skip decisions, eliminating rework.",
"summary": "Pre-checks presentation requirements and collects missing materials before PPTX generation to prevent AI from inventing false content.",
"icon": "📦",
"version": "1.0.0",
"author": "xiaomengbi520",
"license": "MIT",
"category": "office",
"tags": [
"presentation",
"ppt",
"slides",
"material-check",
"workflow"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"external_commands",
"network",
"filesystem"
]
},
"security_audit": {
"risk_level": "low",
"is_blocked": false,
"safe_to_publish": true,
"summary": "All 199 static analysis findings are false positives. The skill is a documentation-based workflow for PPTX material pre-check with no runtime code execution. The 'weak cryptographic algorithm' flags match normal JSON/YAML keys, URLs, and markdown text. 'external_commands' findings are shell command examples in README documentation. 'network' findings are documentation URLs and JSON Schema references. No malicious intent, obfuscation, or prompt injection detected. The validate.py is a standard file format validator with no dangerous operations.",
"risk_factor_evidence": [
{
"factor": "external_commands",
"evidence": [
{
"file": "README.md",
"line_start": 46,
"line_end": 48
},
{
"file": "README.md",
"line_start": 109,
"line_end": 112
}
]
},
{
"factor": "network",
"evidence": [
{
"file": "manifest.schema.json",
"line_start": 2,
"line_end": 3
},
{
"file": "README.md",
"line_start": 7,
"line_end": 9
}
]
},
{
"factor": "filesystem",
"evidence": [
{
"file": "README.md",
"line_start": 48,
"line_end": 48
}
]
}
],
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [
{
"title": "Documentation Shell Command Examples",
"description": "README files contain shell command examples (git clone, cp, python) used for installation instructions. These are documentation code blocks, not executable code. The skill has no runtime that executes external commands.",
"locations": [
{
"file": "README.md",
"line_start": 46,
"line_end": 48
},
{
"file": "SKILL.md",
"line_start": 28,
"line_end": 35
},
{
"file": "validate.py",
"line_start": 3,
"line_end": 3
}
],
"confidence": 0.15,
"confidence_reasoning": "Shell commands only appear in markdown code blocks and documentation, not in any executable script. The skill's only executable file (validate.py) does not call any shell commands."
},
{
"title": "Documentation URLs in README and Schema",
"description": "URLs found in README badge links, repository references, and JSON Schema $schema/$id fields. These are documentation references, not runtime network calls.",
"locations": [
{
"file": "manifest.schema.json",
"line_start": 2,
"line_end": 3
},
{
"file": "README.md",
"line_start": 7,
"line_end": 9
}
],
"confidence": 0.1,
"confidence_reasoning": "All URLs are README badge links (shields.io), GitHub repository links, and JSON Schema identifiers. No runtime network requests are made."
},
{
"title": "Hidden File Path in Installation Instructions",
"description": "README shows installation path ~/.claude/skills/pptx-prep in a code example. This documents the standard Claude Code skills installation directory.",
"locations": [
{
"file": "README.md",
"line_start": 48,
"line_end": 48
}
],
"confidence": 0.05,
"confidence_reasoning": "Path appears in a markdown code block as installation documentation. The skill does not read or write to hidden directories at runtime."
},
{
"title": "Static Analyzer Cryptographic False Positives",
"description": "Static analyzer flagged 87+ locations for 'weak cryptographic algorithm' on normal JSON keys, YAML values, URLs, markdown text, and Python identifiers. Examples include 'manifest_version', 'photo', 'text', logo.png, '1:1', GitHub URLs, and Python constant names like 'VALID_STATUSES'. None of these are cryptographic content.",
"locations": [
{
"file": "manifest.schema.json",
"line_start": 5,
"line_end": 5
},
{
"file": "SKILL.md",
"line_start": 3,
"line_end": 3
},
{
"file": "validate.py",
"line_start": 24,
"line_end": 24
}
],
"confidence": 0.02,
"confidence_reasoning": "The scanner shows systematic false positives by flagging normal JSON/YAML schema property names, enum values, documentation URLs, file paths, and Python identifiers as 'cryptographic content'. This is a known scanner limitation with schema/documentation files."
},
{
"title": "Entropy-based Obfuscation False Positives",
"description": "Static analyzer flagged high file entropy on README.md, README_CN.md, and SKILL.md due to mixed Chinese/English content, YAML front matter, and HTML tags. The 'DANGEROUS COMBINATION' meta-finding aggregates these false positives. No actual obfuscation or encoded payloads exist.",
"locations": [
{
"file": "README.md",
"line_start": 1,
"line_end": 1
},
{
"file": "SKILL.md",
"line_start": 1,
"line_end": 1
}
],
"confidence": 0.05,
"confidence_reasoning": "High entropy is caused by bilingual markdown content (Chinese + English), HTML alignment tags, and YAML front matter delimiters. This is normal for well-documented multilingual skills, not obfuscation."
}
],
"dangerous_patterns": [],
"files_scanned": 16,
"total_lines": 1789,
"audit_model": "claude",
"audited_at": "2026-05-23T09:19:41.763Z"
},
"content": {
"user_title": "Run a materials pre-check before making any presentation",
"value_statement": "Presentations fail when AI invents fake names, photos, and data. This skill scans your slide requirements and identifies every material that needs real human input before generation starts.",
"seo_keywords": [
"PPT pre-check",
"presentation materials",
"slide preparation",
"Claude",
"Codex",
"Claude Code",
"PPTX workflow",
"content validation",
"presentation skill",
"AI presentation prep"
],
"actual_capabilities": [
"Analyzes slide structure by asking targeted questions when no outline is provided",
"Scans each slide against 5 material categories: personal info, visuals, data, branding, and external references",
"Marks each material as ready, needs-supplement, or needs-verification with clear icons",
"Collects user-provided files into a materials folder and auto-matches them to slide slots by content analysis",
"Performs quality checks on photos (minimum resolution, aspect ratio matching) with instant A/B/C resolution options",
"Outputs a structured manifest.yml for downstream PPTX generation tools"
],
"limitations": [
"Does not generate or edit PowerPoint files. A separate PPTX generation skill or tool is required.",
"Cannot verify the accuracy of user-provided data or detect factual errors in supplied materials.",
"Aspect ratio and overflow checks apply only to materials the user provides during the workflow.",
"Requires the user to actively supply missing materials or make skip decisions for each gap."
],
"use_cases": [
{
"title": "Team presentation preparation",
"description": "A manager needs a 7-page team introduction PPT. This skill identifies all missing materials like team photos, member names, and achievement data before the first slide is generated.",
"target_user": "Business users preparing team or department presentations"
},
{
"title": "Investor pitch deck creation",
"description": "A founder preparing a fundraising deck uses this skill to list required materials: logo, product screenshots, financial projections, and market data. The skill flags what the founder must provide versus what AI can draft.",
"target_user": "Startup founders and entrepreneurs"
},
{
"title": "Educational slide production",
"description": "A teacher creating tutorial slides runs this skill to verify all diagrams, examples, and reference materials are ready before asking AI to generate the presentation.",
"target_user": "Educators and instructional designers"
}
],
"prompt_templates": [
{
"title": "Basic slide material check",
"prompt": "I need to create a presentation about [topic]. Please run a material pre-check to identify what information and files I need to provide before the slides can be generated.",
"scenario": "Starting a new presentation project with no prior preparation"
},
{
"title": "Detailed outline with materials",
"prompt": "Here is my 10-page outline for a presentation on [topic]. I have my company logo and some product screenshots ready. Please check each slide and tell me exactly what materials are still missing.",
"scenario": "User has a clear outline and some materials ready"
},
{
"title": "Missing material resolution",
"prompt": "I do not have a team photo for slide 3 or revenue data for slide 7. Please help me find alternatives: search for a suitable image and let me know what placeholder to use for the data.",
"scenario": "User has gaps and needs AI-assisted resolution like image search or placeholder options"
},
{
"title": "Pre-flight check before handoff",
"prompt": "I have placed all my files in the materials folder. Please scan the directory, match each file to the correct slide slot, run quality checks, and prepare the manifest for the PPTX generation tool.",
"scenario": "All materials collected, ready for final quality check and handoff"
}
],
"output_examples": [
{
"input": "Create a 5-page company overview presentation about our product launch.",
"output": [
"## Material Scan",
"",
"| Slide | Material | Type | Status |",
"|-------|----------|------|--------|",
"| 1 Cover | Title text | Text | Ready |",
"| 1 Cover | Cover photo | Photo | Needs supplement |",
"| 2 About | Company description | Text | Needs verification |",
"| 3 Product | Product screenshot | Photo | Needs supplement |",
"| 4 Data | Launch metrics | Data | Needs supplement |",
"| 5 Contact | Contact info | Text | Ready |",
"",
"Warning: Over 50% of materials are missing. AI will need to invent significant content. Recommend providing core materials first."
]
},
{
"input": "I have placed my logo.png and team-photo.jpg in the materials folder. Please check and prepare the manifest.",
"output": [
"Auto-matching results:",
"| Slot | File | Reason |",
"|------|------|--------|",
"| Slide 1 Logo | logo.png | Graphic with company colors |",
"| Slide 3 Team | team-photo.jpg | Group portrait, landscape |",
"",
"All matches successful. Manifest ready for handoff."
]
}
],
"best_practices": [
"Place all presentation materials in a single materials folder before running the pre-check to speed up the matching process.",
"Review AI-generated content marked as needs-verification carefully, especially names, dates, and numerical data.",
"Run the pre-check at the start of each new presentation project, even if you think you have all materials ready."
],
"anti_patterns": [
"Skipping the pre-check and asking AI to generate slides directly, which leads to invented names, fake photos, and incorrect data.",
"Providing vague descriptions like 'some pictures' instead of specific file names, which prevents accurate auto-matching.",
"Ignoring aspect ratio warnings for photos, resulting in distorted or cropped images in the final output."
],
"faq": [
{
"question": "Does this skill generate PowerPoint files?",
"answer": "No. This skill only performs materials pre-check. A separate PPTX generation skill or tool is needed to create the actual slides."
},
{
"question": "Can I use this skill with ChatGPT or other AI tools?",
"answer": "Yes. Copy the prompt from the prompts/universal.md file and paste it at the start of your conversation with any AI chat tool."
},
{
"question": "What happens if I do not have all the materials?",
"answer": "You can choose to skip missing items (placeholders), let AI search for real images, let AI generate illustrations, or provide files later."
},
{
"question": "How does the skill match my files to slide slots?",
"answer": "It analyzes file content, reads filenames for signals, and compares against material descriptions to auto-match. You can correct any wrong matches."
},
{
"question": "What is the manifest.yml file?",
"answer": "It is a structured list of all materials with their status, source, and slot constraints. Downstream PPTX tools read this file to generate slides correctly."
},
{
"question": "Do I need to provide all materials before the skill works?",
"answer": "No. Start with just your idea or outline. The skill will guide you through identifying and collecting each missing piece step by step."
}
]
},
"file_structure": [
{
"name": "examples",
"type": "dir",
"path": "examples",
"children": [
{
"name": "scenario-pitch",
"type": "dir",
"path": "examples/scenario-pitch",
"children": [
{
"name": "manifest.yml",
"type": "file",
"path": "examples/scenario-pitch/manifest.yml",
"lines": 139
},
{
"name": "request.md",
"type": "file",
"path": "examples/scenario-pitch/request.md",
"lines": 26
}
]
},
{
"name": "scenario-team",
"type": "dir",
"path": "examples/scenario-team",
"children": [
{
"name": "bad-output.md",
"type": "file",
"path": "examples/scenario-team/bad-output.md",
"lines": 36
},
{
"name": "manifest.yml",
"type": "file",
"path": "examples/scenario-team/manifest.yml",
"lines": 95
},
{
"name": "README.md",
"type": "file",
"path": "examples/scenario-team/README.md",
"lines": 24
},
{
"name": "request.md",
"type": "file",
"path": "examples/scenario-team/request.md",
"lines": 13
}
]
}
]
},
{
"name": "prompts",
"type": "dir",
"path": "prompts",
"children": [
{
"name": "chatgpt.md",
"type": "file",
"path": "prompts/chatgpt.md",
"lines": 71
},
{
"name": "system-prompt.md",
"type": "file",
"path": "prompts/system-prompt.md",
"lines": 54
},
{
"name": "universal.md",
"type": "file",
"path": "prompts/universal.md",
"lines": 88
}
]
},
{
"name": "manifest.schema.json",
"type": "file",
"path": "manifest.schema.json",
"lines": 145
},
{
"name": "PLACEHOLDER_SPEC.md",
"type": "file",
"path": "PLACEHOLDER_SPEC.md",
"lines": 72
},
{
"name": "README_CN.md",
"type": "file",
"path": "README_CN.md",
"lines": 156
},
{
"name": "README.md",
"type": "file",
"path": "README.md",
"lines": 157
},
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 313
},
{
"name": "validate.py",
"type": "file",
"path": "validate.py",
"lines": 394
}
]
}
"""Validate a pptx-prep manifest file.
Usage: python validate.py <manifest_file>
Supports both YAML (.yml/.yaml) and JSON (.json) files.
YAML parsing is built in — no external dependencies required.
For YAML: uses full-featured pyyaml if available; otherwise falls back to
the built-in minimal parser which handles the pptx-prep manifest subset.
Exit code: 0 = valid, 1 = validation errors found.
"""
import json
import re
import sys
from pathlib import Path
VALID_STATUSES = {"ready", "placeholder"}
VALID_SOURCES = {"ai", "ai-search", "ai-generated", "user"}
VALID_CONFIDENCES = {"verified", "needs-review", "placeholder"}
VALID_TYPES = {"photo", "text", "data", "branding", "reference"}
VALID_FORMATS = {"currency_cny", "percentage", "integer", "plain_text"}
VALID_FILL_MODES = {"contain", "cover"}
VALID_WARNING_TYPES = {"overflow", "low_quality", "aspect_mismatch", "wrong_type"}
def load_manifest(path: Path) -> dict | None:
"""Load manifest from YAML or JSON file."""
suffix = path.suffix.lower()
if suffix in (".yml", ".yaml"):
try:
import yaml
with open(path, encoding="utf-8") as f:
return yaml.safe_load(f)
except ImportError:
pass
with open(path, encoding="utf-8") as f:
content = f.read()
manifest = _parse_yaml(content)
if manifest is None:
print("Error: YAML parsing failed. Try installing pyyaml: pip install pyyaml")
return manifest
if suffix == ".json":
return _load_json(path)
print(f"Error: Unknown file extension '{suffix}'. Use .yml, .yaml, or .json.")
return None
def _load_json(path: Path) -> dict | None:
try:
with open(path, encoding="utf-8") as f:
return json.load(f)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON: {e}")
return None
def _parse_yaml(text: str):
"""Minimal YAML parser for pptx-prep manifest format.
Handles: key: value, nested objects (indentation), lists (- item),
quoted strings, integers, floats, comments (#). Does NOT handle:
multi-line strings, anchors, tags, flow collections, complex edge cases.
"""
lines = text.split("\n")
return _parse_block([l for l in lines if l.strip() and not l.strip().startswith("#")])
def _parse_block(lines: list[str], indent: int = 0) -> dict | list | str | int | float | None:
"""Parse a block of YAML lines at the given indentation level."""
if not lines:
return None
# Check if this is a list (first non-empty line starts with "- ")
first_stripped = lines[0].lstrip()
is_list = first_stripped.startswith("- ")
if is_list:
return _parse_list(lines, indent)
return _parse_dict(lines, indent)
def _parse_list(lines: list[str], indent: int) -> list:
"""Parse a YAML list."""
result = []
i = 0
while i < len(lines):
stripped = lines[i].lstrip()
line_indent = len(lines[i]) - len(stripped)
if line_indent < indent:
break
if not stripped.startswith("- "):
i += 1
continue
value_part = stripped[2:]
# Check if the next lines are more indented (nested block)
nested_lines = []
j = i + 1
while j < len(lines):
ns = lines[j].lstrip()
n_indent = len(lines[j]) - len(ns)
if n_indent <= line_indent or (n_indent == line_indent and not ns.startswith("- ")):
break
nested_lines.append(lines[j])
j += 1
if nested_lines and nested_lines[0].lstrip().startswith("- "):
# Sublist
result.append(_parse_list(nested_lines, line_indent + 2))
elif nested_lines:
# Nested dict — combine with the "- key: value" prefix
nested = _parse_dict(nested_lines, line_indent + 2)
if ":" in value_part and _is_inline_dict(value_part):
prefix = _parse_inline_dict(value_part)
prefix.update(nested)
result.append(prefix)
else:
result.append(nested)
elif ":" in value_part and _is_inline_dict(value_part):
# Inline key: value after "- "
result.append(_parse_inline_dict(value_part))
else:
result.append(_parse_value(value_part))
i = j
if not nested_lines:
i += 1
return result
def _parse_dict(lines: list[str], indent: int) -> dict:
"""Parse a YAML dict."""
result = {}
i = 0
while i < len(lines):
line = lines[i]
stripped = line.lstrip()
line_indent = len(line) - len(stripped)
if line_indent < indent or stripped.startswith("- "):
break
if ":" not in stripped and not stripped.startswith("#"):
i += 1
continue
key_end = stripped.index(":") if ":" in stripped else len(stripped)
key = stripped[:key_end].strip()
value_part = stripped[key_end + 1:].lstrip()
if value_part == "" or value_part == "|" or value_part == ">":
# Nested block (next indented lines)
nested_lines = []
j = i + 1
while j < len(lines):
ns = lines[j].lstrip()
n_indent = len(lines[j]) - len(ns)
if n_indent <= line_indent:
break
nested_lines.append(lines[j])
j += 1
if nested_lines:
result[key] = _parse_block(nested_lines, line_indent + 2)
i = j
else:
result[key] = _parse_value(value_part)
i += 1
return result
def _is_inline_dict(value: str) -> bool:
"""Check if a value looks like an inline dict: key1: val1, key2: val2"""
return ":" in value and not value.startswith('"') and not value.startswith("'") and len(value) < 120
def _parse_inline_dict(value: str) -> dict:
"""Parse a simple inline dict like 'key1: val1, key2: val2'."""
result = {}
# Split by comma, but be careful
parts = value.split(", ")
for part in parts:
if ":" in part:
k, v = part.split(":", 1)
result[k.strip()] = _parse_value(v.strip())
return result
def _parse_value(value: str):
"""Parse a scalar YAML value or inline array."""
value = value.strip()
# Remove inline comment
if " #" in value:
value = value[: value.index(" #")]
# Inline arrays: [item1, item2] or [slide-1]
if value.startswith("[") and value.endswith("]"):
inner = value[1:-1].strip()
if not inner:
return []
items = []
for item in inner.split(","):
items.append(_parse_value(item.strip()))
return items
# Booleans
if value.lower() in ("true", "yes", "on"):
return True
if value.lower() in ("false", "no", "off"):
return False
if value.lower() in ("null", "~", ""):
return None
# Quoted strings
if (value.startswith('"') and value.endswith('"')) or \
(value.startswith("'") and value.endswith("'")):
return value[1:-1]
# Integers
if re.match(r"^-?\d+$", value):
return int(value)
# Floats
if re.match(r"^-?\d+\.\d+$", value):
return float(value)
return value
def validate(manifest: dict) -> list[str]:
"""Validate manifest structure. Returns list of error messages (empty = valid)."""
errors = []
# Top-level required keys
for key in ("manifest_version", "project", "materials", "summary"):
if key not in manifest:
errors.append(f"Missing required top-level key: '{key}'")
if "manifest_version" in manifest and manifest["manifest_version"] != "1.0":
errors.append(f"Unknown manifest_version: '{manifest['manifest_version']}'. Expected '1.0'.")
# Project
project = manifest.get("project", {})
if not isinstance(project, dict):
errors.append("'project' must be an object.")
else:
if "title" not in project:
errors.append("Missing 'project.title'.")
if "slide_count" not in project:
errors.append("Missing 'project.slide_count'.")
elif not isinstance(project["slide_count"], int) or project["slide_count"] < 1:
errors.append(f"'project.slide_count' must be a positive integer, got: {project['slide_count']}")
# Materials
materials = manifest.get("materials", [])
if not isinstance(materials, list):
errors.append("'materials' must be an array.")
else:
seen_fields = set()
for i, mat in enumerate(materials):
prefix = f"materials[{i}]"
if not isinstance(mat, dict):
errors.append(f"{prefix}: must be an object.")
continue
for key in ("field", "type", "description", "used_in", "status", "source", "confidence"):
if key not in mat:
errors.append(f"{prefix}: missing required key '{key}'.")
field = mat.get("field", "")
if field in seen_fields:
errors.append(f"{prefix}: duplicate 'field' value '{field}'.")
seen_fields.add(field)
if mat.get("type") not in VALID_TYPES:
errors.append(f"{prefix}: invalid type '{mat.get('type')}'. Must be one of: {VALID_TYPES}")
if mat.get("status") not in VALID_STATUSES:
errors.append(f"{prefix}: invalid status '{mat.get('status')}'. Must be one of: {VALID_STATUSES}")
if mat.get("source") not in VALID_SOURCES:
errors.append(f"{prefix}: invalid source '{mat.get('source')}'. Must be one of: {VALID_SOURCES}")
if mat.get("confidence") not in VALID_CONFIDENCES:
errors.append(f"{prefix}: invalid confidence '{mat.get('confidence')}'. Must be one of: {VALID_CONFIDENCES}")
used_in = mat.get("used_in", [])
if isinstance(used_in, list):
for j, slide_ref in enumerate(used_in):
if not isinstance(slide_ref, str) or not slide_ref.startswith("slide-"):
errors.append(f"{prefix}.used_in[{j}]: must be 'slide-N' format, got '{slide_ref}'.")
else:
errors.append(f"{prefix}: 'used_in' must be an array.")
if mat.get("status") == "ready" and mat.get("type") == "photo" and "path" not in mat:
errors.append(f"{prefix}: status is 'ready' and type is 'photo' but no 'path' provided.")
slot = mat.get("slot")
if slot and isinstance(slot, dict):
fm = slot.get("fill_mode")
if fm and fm not in VALID_FILL_MODES:
errors.append(f"{prefix}.slot.fill_mode: must be 'contain' or 'cover', got '{fm}'.")
capacity = slot.get("estimated_capacity")
if capacity is not None and (not isinstance(capacity, int) or capacity < 0):
errors.append(f"{prefix}.slot.estimated_capacity: must be a non-negative integer, got '{capacity}'.")
fmt = mat.get("format")
if fmt and fmt not in VALID_FORMATS:
errors.append(f"{prefix}: invalid format '{fmt}'. Must be one of: {VALID_FORMATS}")
warnings = mat.get("warnings")
if warnings:
if not isinstance(warnings, list):
errors.append(f"{prefix}: 'warnings' must be an array.")
else:
for j, w in enumerate(warnings):
if isinstance(w, dict) and w.get("type") not in VALID_WARNING_TYPES:
errors.append(f"{prefix}.warnings[{j}]: invalid warning type '{w.get('type')}'.")
# Summary
summary = manifest.get("summary", {})
if not isinstance(summary, dict):
errors.append("'summary' must be an object.")
else:
for key in ("total", "ready", "placeholder", "needs_review"):
if key not in summary:
errors.append(f"Missing 'summary.{key}'.")
elif not isinstance(summary[key], int):
errors.append(f"'summary.{key}' must be an integer, got: {summary[key]}")
# Cross-validate summary vs materials
if materials and all(isinstance(m, dict) for m in materials):
actual = {
"total": len(materials),
"ready": sum(1 for m in materials if m.get("status") == "ready"),
"placeholder": sum(1 for m in materials if m.get("status") == "placeholder"),
"needs_review": sum(1 for m in materials if m.get("confidence") == "needs-review"),
}
for k, expected in actual.items():
reported = summary.get(k)
if reported is not None and reported != expected:
errors.append(f"summary.{k}: reported {reported}, but materials count is {expected}.")
return errors
def main():
if len(sys.argv) != 2:
print("Usage: python validate.py <manifest_file>")
print(" manifest_file: .yml, .yaml, or .json")
sys.exit(1)
path = Path(sys.argv[1])
if not path.exists():
print(f"Error: File not found: {path}")
sys.exit(1)
manifest = load_manifest(path)
if manifest is None:
sys.exit(1)
errors = validate(manifest)
if errors:
print(f"\nValidation FAILED — {len(errors)} error(s):\n")
for e in errors:
print(f" - {e}")
print()
sys.exit(1)
else:
print(f"\nValidation PASSED — {len(manifest.get('materials', []))} materials, all checks passed.\n")
sys.exit(0)
if __name__ == "__main__":
main()
Related skills
FAQ
What does pptx-prep check for?
Five material categories - personal info, visual assets, data/statistics, custom branding, and external references - flagging each as ready, needs-supplying, or needs-review.
What does it output?
A manifest.yml recording each material's type, status, source, and confidence, plus a summary of ready vs placeholder items.