dsh-office-kit 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/CAPABILITY.md +147 -68
  2. package/README.md +3 -1
  3. package/assets/skills/excel-live-control/SKILL.md +234 -0
  4. package/assets/skills/excel-live-control/container_tools/live_excel.py +1589 -0
  5. package/assets/skills/excel-live-control/domain_guidance/financial_models.md +86 -0
  6. package/assets/skills/excel-live-control/domain_guidance/healthcare.md +58 -0
  7. package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +53 -0
  8. package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +53 -0
  9. package/assets/skills/excel-live-control/references/office-automation.md +207 -0
  10. package/assets/skills/excel-live-control/references/read_only_qna.md +59 -0
  11. package/assets/skills/excel-live-control/style_guidelines.md +87 -0
  12. package/assets/skills/excel-live-control/workflows/create_workflows.md +78 -0
  13. package/assets/skills/excel-live-control/workflows/edit_workflows.md +72 -0
  14. package/assets/skills/office-documents/SKILL.md +90 -77
  15. package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +86 -0
  16. package/assets/skills/office-documents/ooxml/comments.md +40 -0
  17. package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +66 -0
  18. package/assets/skills/office-documents/ooxml/rels_and_content_types.md +62 -0
  19. package/assets/skills/office-documents/ooxml/tracked_changes.md +53 -0
  20. package/assets/skills/office-documents/references/docx-structure.md +83 -0
  21. package/assets/skills/office-documents/references/template-elicitation.md +49 -0
  22. package/assets/skills/office-documents/references/writing-quality.md +49 -0
  23. package/assets/skills/office-documents/render_docx.py +99 -0
  24. package/assets/skills/office-documents/scripts/a11y_audit.py +201 -0
  25. package/assets/skills/office-documents/scripts/accept_tracked_changes.py +158 -0
  26. package/assets/skills/office-documents/scripts/add_tracked_replacements.py +155 -0
  27. package/assets/skills/office-documents/scripts/append_blocks.py +115 -0
  28. package/assets/skills/office-documents/scripts/apply_template_styles.py +111 -0
  29. package/assets/skills/office-documents/scripts/captions_and_crossrefs.py +109 -0
  30. package/assets/skills/office-documents/scripts/comments_add.py +143 -0
  31. package/assets/skills/office-documents/scripts/comments_apply_patch.py +121 -0
  32. package/assets/skills/office-documents/scripts/comments_extract.py +92 -0
  33. package/assets/skills/office-documents/scripts/comments_strip.py +81 -0
  34. package/assets/skills/office-documents/scripts/content_controls.py +199 -0
  35. package/assets/skills/office-documents/scripts/core_properties.py +131 -0
  36. package/assets/skills/office-documents/scripts/docx_kit.py +594 -0
  37. package/assets/skills/office-documents/scripts/docx_ooxml_patch.py +232 -0
  38. package/assets/skills/office-documents/scripts/docx_table_to_csv.py +106 -0
  39. package/assets/skills/office-documents/scripts/fields_materialize.py +73 -0
  40. package/assets/skills/office-documents/scripts/fields_report.py +66 -0
  41. package/assets/skills/office-documents/scripts/flatten_ref_fields.py +69 -0
  42. package/assets/skills/office-documents/scripts/footnotes_report.py +84 -0
  43. package/assets/skills/office-documents/scripts/google_docs_title_sanitize.py +103 -0
  44. package/assets/skills/office-documents/scripts/heading_audit.py +88 -0
  45. package/assets/skills/office-documents/scripts/images_audit.py +87 -0
  46. package/assets/skills/office-documents/scripts/insert_note.py +133 -0
  47. package/assets/skills/office-documents/scripts/insert_ref_fields.py +97 -0
  48. package/assets/skills/office-documents/scripts/insert_toc.py +91 -0
  49. package/assets/skills/office-documents/scripts/internal_nav.py +153 -0
  50. package/assets/skills/office-documents/scripts/make_fixtures.py +176 -0
  51. package/assets/skills/office-documents/scripts/merge_docx_append.py +246 -0
  52. package/assets/skills/office-documents/scripts/privacy_scrub.py +138 -0
  53. package/assets/skills/office-documents/scripts/redact_docx.py +120 -0
  54. package/assets/skills/office-documents/scripts/render_and_diff.py +108 -0
  55. package/assets/skills/office-documents/scripts/replace_text.py +161 -0
  56. package/assets/skills/office-documents/scripts/section_audit.py +98 -0
  57. package/assets/skills/office-documents/scripts/set_protection.py +99 -0
  58. package/assets/skills/office-documents/scripts/style_lint.py +118 -0
  59. package/assets/skills/office-documents/scripts/style_normalize.py +110 -0
  60. package/assets/skills/office-documents/scripts/table_geometry.py +174 -0
  61. package/assets/skills/office-documents/scripts/watermark_add.py +55 -0
  62. package/assets/skills/office-documents/scripts/watermark_audit_remove.py +74 -0
  63. package/assets/skills/office-documents/scripts/xlsx_to_docx_table.py +124 -0
  64. package/assets/skills/office-documents/tasks/accessibility_a11y.md +45 -0
  65. package/assets/skills/office-documents/tasks/captions_crossrefs.md +49 -0
  66. package/assets/skills/office-documents/tasks/clean_tracked_changes.md +49 -0
  67. package/assets/skills/office-documents/tasks/comments_manage.md +59 -0
  68. package/assets/skills/office-documents/tasks/compare_diff.md +40 -0
  69. package/assets/skills/office-documents/tasks/create_edit.md +107 -0
  70. package/assets/skills/office-documents/tasks/equations.md +59 -0
  71. package/assets/skills/office-documents/tasks/fields_update.md +44 -0
  72. package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +50 -0
  73. package/assets/skills/office-documents/tasks/footnotes_endnotes.md +38 -0
  74. package/assets/skills/office-documents/tasks/forms_content_controls.md +48 -0
  75. package/assets/skills/office-documents/tasks/headings_numbering.md +55 -0
  76. package/assets/skills/office-documents/tasks/images_figures.md +63 -0
  77. package/assets/skills/office-documents/tasks/multi_doc_merge.md +43 -0
  78. package/assets/skills/office-documents/tasks/navigation_internal_links.md +38 -0
  79. package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +45 -0
  80. package/assets/skills/office-documents/tasks/protection_restrict_editing.md +41 -0
  81. package/assets/skills/office-documents/tasks/read_review.md +50 -0
  82. package/assets/skills/office-documents/tasks/redaction_anonymization.md +42 -0
  83. package/assets/skills/office-documents/tasks/sections_layout.md +54 -0
  84. package/assets/skills/office-documents/tasks/style_lint_normalize.md +44 -0
  85. package/assets/skills/office-documents/tasks/tables_spreadsheets.md +64 -0
  86. package/assets/skills/office-documents/tasks/templates_style_packs.md +53 -0
  87. package/assets/skills/office-documents/tasks/toc_workflow.md +39 -0
  88. package/assets/skills/office-documents/tasks/verify_render.md +50 -0
  89. package/assets/skills/office-documents/tasks/watermarks_background.md +35 -0
  90. package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +47 -0
  91. package/assets/skills/office-documents/troubleshooting/run_splitting.md +36 -0
  92. package/assets/skills/office-pdf/SKILL.md +73 -56
  93. package/assets/skills/office-pdf/references/form-fields.md +56 -0
  94. package/assets/skills/office-pdf/references/geometry.md +44 -0
  95. package/assets/skills/office-pdf/references/layout-quality.md +41 -0
  96. package/assets/skills/office-pdf/references/limits.md +58 -0
  97. package/assets/skills/office-pdf/scripts/extract_text.py +172 -0
  98. package/assets/skills/office-pdf/scripts/forms.py +556 -0
  99. package/assets/skills/office-pdf/scripts/metadata.py +161 -0
  100. package/assets/skills/office-pdf/scripts/page_ops.py +198 -0
  101. package/assets/skills/office-pdf/scripts/redact_region.py +347 -0
  102. package/assets/skills/office-pdf/scripts/render_pages.py +207 -0
  103. package/assets/skills/office-pdf/scripts/split_pages.py +155 -0
  104. package/assets/skills/office-pdf/scripts/stamp_overlay.py +199 -0
  105. package/assets/skills/office-pdf/tasks/annotations.md +98 -0
  106. package/assets/skills/office-pdf/tasks/create.md +75 -0
  107. package/assets/skills/office-pdf/tasks/edit-pages.md +71 -0
  108. package/assets/skills/office-pdf/tasks/forms.md +67 -0
  109. package/assets/skills/office-pdf/tasks/read.md +62 -0
  110. package/assets/skills/office-pdf/tasks/redact.md +72 -0
  111. package/assets/skills/office-pdf/tasks/stamp.md +60 -0
  112. package/assets/skills/office-presentations/SKILL.md +141 -87
  113. package/assets/skills/office-presentations/container_tools/add_slides.py +143 -0
  114. package/assets/skills/office-presentations/container_tools/core_properties.py +127 -0
  115. package/assets/skills/office-presentations/container_tools/create_montage.py +133 -0
  116. package/assets/skills/office-presentations/container_tools/inspect_presentation_layout_geometry.py +292 -0
  117. package/assets/skills/office-presentations/container_tools/inspect_presentation_package_integrity.py +164 -0
  118. package/assets/skills/office-presentations/container_tools/native_chart_title_gate.py +151 -0
  119. package/assets/skills/office-presentations/container_tools/native_quantitative_chart_gate.py +206 -0
  120. package/assets/skills/office-presentations/container_tools/native_table_arithmetic_gate.py +219 -0
  121. package/assets/skills/office-presentations/container_tools/ooxml_helpers.py +352 -0
  122. package/assets/skills/office-presentations/container_tools/preview_render.py +382 -0
  123. package/assets/skills/office-presentations/container_tools/render_slides.py +146 -0
  124. package/assets/skills/office-presentations/container_tools/replace_text.py +175 -0
  125. package/assets/skills/office-presentations/container_tools/template_source_fidelity_gate.py +236 -0
  126. package/assets/skills/office-presentations/domain_guidance/finance.md +66 -0
  127. package/assets/skills/office-presentations/recipes/README.md +71 -0
  128. package/assets/skills/office-presentations/recipes/autolayout.md +88 -0
  129. package/assets/skills/office-presentations/recipes/connectors.md +83 -0
  130. package/assets/skills/office-presentations/recipes/images.md +80 -0
  131. package/assets/skills/office-presentations/recipes/master-and-layouts.md +127 -0
  132. package/assets/skills/office-presentations/recipes/native-charts.md +87 -0
  133. package/assets/skills/office-presentations/recipes/rich-text-runs.md +86 -0
  134. package/assets/skills/office-presentations/recipes/speaker-notes.md +65 -0
  135. package/assets/skills/office-presentations/recipes/tables.md +88 -0
  136. package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +71 -0
  137. package/assets/skills/office-presentations/recipes/theme-tokens.md +87 -0
  138. package/assets/skills/office-presentations/references/authoring-workflow.md +65 -0
  139. package/assets/skills/office-presentations/references/finalization.md +63 -0
  140. package/assets/skills/office-presentations/references/native-bullets.md +78 -0
  141. package/assets/skills/office-presentations/references/native-evidence.md +67 -0
  142. package/assets/skills/office-presentations/references/style-guidelines.md +66 -0
  143. package/assets/skills/office-presentations/references/templates.md +76 -0
  144. package/assets/skills/office-presentations/routing/google_slides.md +45 -0
  145. package/assets/skills/office-presentations/tasks/apply-annotations.md +83 -0
  146. package/assets/skills/office-presentations/tasks/charts-tables-notes.md +79 -0
  147. package/assets/skills/office-presentations/tasks/create-deck.md +106 -0
  148. package/assets/skills/office-presentations/tasks/edit-deck.md +93 -0
  149. package/assets/skills/office-presentations/tasks/inspect-and-verify.md +107 -0
  150. package/assets/skills/office-presentations/tasks/template-following.md +132 -0
  151. package/assets/skills/office-presentations/template_following_scripts/check_template_fidelity.py +183 -0
  152. package/assets/skills/office-presentations/template_following_scripts/inspect_template_deck.py +161 -0
  153. package/assets/skills/office-presentations/template_following_scripts/make_contact_sheet.py +118 -0
  154. package/assets/skills/office-presentations/template_following_scripts/prepare_template_starter_deck.py +246 -0
  155. package/assets/skills/office-presentations/template_following_scripts/validate_template_plan.py +192 -0
  156. package/assets/skills/office-spreadsheets/SKILL.md +105 -101
  157. package/assets/skills/office-spreadsheets/container_tools/add_chart.py +243 -0
  158. package/assets/skills/office-spreadsheets/container_tools/add_image.py +114 -0
  159. package/assets/skills/office-spreadsheets/container_tools/append_rows.py +129 -0
  160. package/assets/skills/office-spreadsheets/container_tools/diff_workbooks.py +313 -0
  161. package/assets/skills/office-spreadsheets/container_tools/inspect_workbook.py +405 -0
  162. package/assets/skills/office-spreadsheets/container_tools/recalc_gate.py +287 -0
  163. package/assets/skills/office-spreadsheets/container_tools/set_cells.py +142 -0
  164. package/assets/skills/office-spreadsheets/container_tools/sheet_ops.py +141 -0
  165. package/assets/skills/office-spreadsheets/container_tools/style_cells.py +140 -0
  166. package/assets/skills/office-spreadsheets/recipes/charts.md +66 -0
  167. package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +69 -0
  168. package/assets/skills/office-spreadsheets/recipes/data-tables.md +58 -0
  169. package/assets/skills/office-spreadsheets/recipes/named-ranges.md +41 -0
  170. package/assets/skills/office-spreadsheets/recipes/number-formats.md +72 -0
  171. package/assets/skills/office-spreadsheets/recipes/sparklines.md +43 -0
  172. package/assets/skills/office-spreadsheets/references/charts.md +63 -0
  173. package/assets/skills/office-spreadsheets/references/domain/financial-models.md +40 -0
  174. package/assets/skills/office-spreadsheets/references/domain/healthcare.md +22 -0
  175. package/assets/skills/office-spreadsheets/references/domain/marketing.md +28 -0
  176. package/assets/skills/office-spreadsheets/references/domain/research.md +22 -0
  177. package/assets/skills/office-spreadsheets/references/formula-patterns.md +78 -0
  178. package/assets/skills/office-spreadsheets/references/style-guidelines.md +69 -0
  179. package/assets/skills/office-spreadsheets/references/workbook-structure.md +60 -0
  180. package/assets/skills/office-spreadsheets/routing/google-sheets.md +36 -0
  181. package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +37 -0
  182. package/assets/skills/office-spreadsheets/tasks/annotations.md +51 -0
  183. package/assets/skills/office-spreadsheets/tasks/create-workbook.md +66 -0
  184. package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +38 -0
  185. package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +69 -0
  186. package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +38 -0
  187. package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +57 -0
  188. package/assets/skills/shared/annotation-recipes.md +252 -0
  189. package/assets/skills/shared/check_runtime.py +260 -0
  190. package/assets/skills/shared/common-workflow.md +139 -0
  191. package/assets/skills/shared/scripts/ensure_raster_image.py +187 -0
  192. package/dist/client.js +4 -4
  193. package/dist/client.js.map +1 -1
  194. package/dist/index.js +246 -89
  195. package/package.json +1 -1
  196. package/postinstall.mjs +92 -82
  197. package/python/office_cli.py +213 -254
@@ -0,0 +1,87 @@
1
+ # Theme tokens
2
+
3
+ ## Mechanics
4
+
5
+ The theme part (`ppt/theme/theme1.xml`) holds two palettes and two font lists:
6
+
7
+ - `dk1/lt1/dk2/lt2/accent1..6/hlink/folHlink` — every `RGBColor` you *do not*
8
+ set falls back to one of these, and PowerPoint's "theme colors" picker edits
9
+ them for the whole deck.
10
+ - `majorFont` / `minorFont` — the heading and body typefaces inherited by every
11
+ run without an explicit font.
12
+
13
+ So: write `RGBColor.rgb` when a colour must never change, and reference a theme
14
+ colour when the user may re-skin the deck. A deck with hard-coded hex
15
+ everywhere cannot be re-branded, which is usually why the user supplied a
16
+ template.
17
+
18
+ ## Recipe: define the palette once, use it everywhere
19
+
20
+ ```python
21
+ "<python>" - <<'PY'
22
+ from pptx import Presentation
23
+ from pptx.dml.color import RGBColor
24
+ from pptx.util import Inches, Pt
25
+ from pptx.enum.dml import MSO_THEME_COLOR
26
+
27
+ PALETTE = {
28
+ "ink": RGBColor(0x16, 0x1D, 0x28),
29
+ "muted": RGBColor(0x5F, 0x6B, 0x7A),
30
+ "accent": RGBColor(0xD9, 0x8B, 0x1E),
31
+ "rule": RGBColor(0xD6, 0xDC, 0xE4),
32
+ }
33
+ TYPE = {"title": Pt(34), "body": Pt(18), "caption": Pt(12)}
34
+
35
+ prs = Presentation()
36
+ prs.slide_width, prs.slide_height = Inches(13.333), Inches(7.5)
37
+ slide = prs.slides.add_slide(prs.slide_layouts[6])
38
+
39
+ def put(text, left, top, width, size, colour, bold=False):
40
+ box = slide.shapes.add_textbox(Inches(left), Inches(top), Inches(width), Inches(0.6))
41
+ frame = box.text_frame
42
+ frame.word_wrap = True
43
+ frame.margin_left = frame.margin_right = 0
44
+ run = frame.paragraphs[0].add_run()
45
+ run.text = text
46
+ run.font.size = size
47
+ run.font.bold = bold
48
+ run.font.color.rgb = PALETTE[colour]
49
+ return box
50
+
51
+ put("Automation Review", 0.9, 2.4, 11.5, TYPE["title"], "ink", bold=True)
52
+ put("Warehouse network · FY2026", 0.9, 3.3, 11.5, TYPE["body"], "muted")
53
+ put("Source: FY2026 capital plan", 0.9, 6.7, 6.0, TYPE["caption"], "muted")
54
+ prs.save("themed.pptx")
55
+ print("palette keys:", sorted(PALETTE), "theme colour sample:", MSO_THEME_COLOR.ACCENT_1)
56
+ PY
57
+ ```
58
+
59
+ ## Reading the theme you were given
60
+
61
+ ```python
62
+ from pptx import Presentation
63
+ prs = Presentation("template.pptx")
64
+ theme = prs.slide_masters[0].part.part_related_by(
65
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
66
+ )
67
+ blob = theme.blob.decode("utf-8", "ignore")
68
+ print("accent1" in blob, "majorFont" in blob)
69
+ ```
70
+
71
+ `template_following_scripts/inspect_template_deck.py` already reports the font
72
+ names it finds in the theme, so check there before introducing a new typeface.
73
+
74
+ ## Pitfalls this avoids
75
+
76
+ - Two similar hexes drifting apart across slides (`#161d28` on one slide,
77
+ `#171e29` on the next) because the colour was retyped instead of referenced.
78
+ - A serif body font set from taste rather than from the theme, so the deck
79
+ contradicts the template it was built in.
80
+ - `font.color.theme_color = MSO_THEME_COLOR.ACCENT_1` *and* `font.color.rgb`
81
+ on the same run: the last assignment wins and the theme reference vanishes.
82
+
83
+ ## CLI fast path
84
+
85
+ `pptx create` uses the default template's theme. For a branded deck, start from
86
+ the supplied template (see [master-and-layouts](master-and-layouts.md)) rather
87
+ than recolouring a blank deck.
@@ -0,0 +1,65 @@
1
+ # Authoring workflow
2
+
3
+ ## What a deck is, mechanically
4
+
5
+ A `.pptx` is a zip of XML parts: one `presentation.xml` naming the slide order, one
6
+ part per slide, a slide master per theme, a layout per family, chart parts with
7
+ embedded workbooks, notes parts, and a media folder. Everything the reader sees
8
+ comes from those parts, which is why the verification loop reads the file back
9
+ instead of trusting the code that wrote it.
10
+
11
+ Three consequences shape the whole workflow:
12
+
13
+ 1. **Geometry is explicit.** Nothing reflows on open except autofit. If two
14
+ shapes overlap in the XML, they overlap on screen.
15
+ 2. **Inheritance is real.** A slide draws its background, type sizes and bullet
16
+ glyphs from its layout and master. Overriding at slide level is a per-slide
17
+ decision; overriding at master level is a deck decision.
18
+ 3. **Data can stay alive.** A native chart or table keeps its numbers in the
19
+ file and can be checked; a screenshot cannot.
20
+
21
+ ## The loop
22
+
23
+ 1. **Decide the story**: one sentence per slide, in order, before any XML. A
24
+ slide without a sentence is a slide the audience will not read.
25
+ 2. **Pick the frame**: slide size from the target (`13.333 × 7.5 in` is the 16:9
26
+ default; check `prs.slide_width` of a supplied template, never assume).
27
+ 3. **Place, top-down**: background, chrome, title, body, evidence. Later shapes
28
+ paint over earlier ones.
29
+ 4. **Fill or delete every placeholder.** An empty placeholder is visible in edit
30
+ view and prints "Click to add text".
31
+ 5. **Render, look, fix.** `container_tools/render_slides.py` then `read_image` on
32
+ every PNG. Repeat until nothing surprises you.
33
+
34
+ ## The numbers that keep a deck readable
35
+
36
+ | Element | Value | Why |
37
+ |---|---|---|
38
+ | Slide size | 13.333 × 7.5 in | 16:9; 10 × 5.625 in for 16:9 in "wide" templates |
39
+ | Margin | 0.6–0.9 in | Below 0.5 in a projector crops it |
40
+ | Title | 28–36 pt, bold | 44 pt only on covers |
41
+ | Body | 18 pt minimum | The back row rule |
42
+ | Caption / source | 12–14 pt | Never below 11 pt |
43
+ | Line spacing | 1.1–1.2 | Tighter crowds ascenders |
44
+ | Gap between blocks | 0.2–0.4 in | The eye groups by proximity |
45
+ | Footer zone | bottom 0.55 in | Keep text out of it |
46
+
47
+ Convert once and keep the numbers in EMU or inches, not mixed: `Inches(x)` in
48
+ code, `x * 914400` when you must talk to the XML directly.
49
+
50
+ ## Deciding slide count
51
+
52
+ One idea per slide. If a slide has two headlines competing, it is two slides. If
53
+ it has one headline and a table too large to read at 14 pt, the table becomes an
54
+ appendix slide and the body slide states the conclusion in one line.
55
+
56
+ A presentation of N minutes needs roughly N/2 content slides at 60–90 seconds
57
+ each, plus a cover and a closing ask.
58
+
59
+ ## Where the detail lives
60
+
61
+ - Type, colour, density and cover art: [style-guidelines](style-guidelines.md).
62
+ - Bullets that read as sentences: [native-bullets](native-bullets.md).
63
+ - Charts, tables and notes as evidence: [native-evidence](native-evidence.md).
64
+ - Supplied templates: [templates](templates.md).
65
+ - Pre-delivery checklist: [finalization](finalization.md).
@@ -0,0 +1,63 @@
1
+ # Finalization checklist
2
+
3
+ Run this before `present`. It exists because every item on it has shipped a
4
+ broken deck at least once.
5
+
6
+ ## The file
7
+
8
+ - [ ] Opens: `"<python>" "<cli>" pptx read --input deck.pptx` returns slides.
9
+ - [ ] Package is coherent:
10
+ `"<python>" "<skill>/container_tools/inspect_presentation_package_integrity.py" --input deck.pptx`
11
+ → `passed: true`, no dangling relationships, media and charts present.
12
+ - [ ] Slide count matches the intent; nothing left over from an earlier draft.
13
+ - [ ] Core properties set:
14
+ `"<python>" "<skill>/container_tools/core_properties.py" --input deck.pptx --title "..." --author "..."`
15
+ (an untitled deck shows up as "PowerPoint Presentation" in every file list).
16
+
17
+ ## The content
18
+
19
+ - [ ] Every placeholder is filled or deleted — no "Click to add text".
20
+ - [ ] No default chart title ("Chart Title") survives:
21
+ `"<python>" "<skill>/container_tools/native_chart_title_gate.py" --input deck.pptx`.
22
+ - [ ] Totals are arithmetic:
23
+ `"<python>" "<skill>/container_tools/native_table_arithmetic_gate.py" --input deck.pptx --contracts totals.json`.
24
+ - [ ] Charts have their data in the file (portable mode passes) and categories
25
+ are in a meaningful order.
26
+ - [ ] Numbers in the deck agree with the numbers in the source data, at the
27
+ precision shown.
28
+ - [ ] Speaker notes carry the provenance of the non-obvious numbers.
29
+
30
+ ## The layout
31
+
32
+ - [ ] Geometry gate passes:
33
+ `"<python>" "<skill>/container_tools/inspect_presentation_layout_geometry.py" --input deck.pptx --json-out geometry.json`
34
+ → `passed: true`; review findings read and consciously accepted.
35
+ - [ ] Nothing outside the slide edge, nothing overlapping the footer zone.
36
+ - [ ] Titles are one or two lines; no title ends in a full stop.
37
+ - [ ] Body text is at least 18 pt, captions at least 12 pt.
38
+ - [ ] One idea per slide, one emphasis per paragraph.
39
+
40
+ ## The look
41
+
42
+ - [ ] Rendered at viewing size and actually looked at:
43
+ `"<python>" "<skill>/container_tools/render_slides.py" --input deck.pptx --out-dir preview`
44
+ then `read_image` on each PNG (or on the contact sheet from
45
+ `"<skill>/template_following_scripts/make_contact_sheet.py`).
46
+ - [ ] Text is not clipped, ellipsised or shrunk to illegibility.
47
+ - [ ] Photographs are not stretched; their sources are listed.
48
+ - [ ] Charts read at thumbnail size: the point is visible before any label.
49
+ - [ ] The cover and closing slide both say something.
50
+
51
+ ## Delivery
52
+
53
+ - [ ] The file lives in the user's workspace, not in a temp directory.
54
+ - [ ] Output name is either new (`deck.pptx`) or `<original>-edited.pptx`.
55
+ - [ ] `present` called; the reply states what changed in one sentence and, for
56
+ edits, both paths.
57
+
58
+ ## When rendering is unavailable
59
+
60
+ `render_slides.py --engine draft` draws a geometry preview with PyMuPDF when no
61
+ office suite is installed. It is honest about being approximate: type is drawn
62
+ at declared sizes in a substitute face, and layout chrome is not rendered. Use
63
+ it to catch overlap, overflow and placement — not to judge typography.
@@ -0,0 +1,78 @@
1
+ # Bullets that read as sentences
2
+
3
+ ## The shape of a bullet
4
+
5
+ A bullet is a claim, not a label. Two forms work:
6
+
7
+ - **Claim + consequence**: "Picking is 41% of floor labour hours — travel is the
8
+ cost, not the pick."
9
+ - **Number + meaning**: "12 minutes per order lost to aisle travel."
10
+
11
+ Forms that do not work: a single noun ("Efficiency"), a truncated clause
12
+ ("Picking accounts for…"), a list of three adjectives, or a bullet that restates
13
+ the slide title.
14
+
15
+ ## Length and count
16
+
17
+ - One line, two at the absolute maximum, per bullet on a 16:9 slide.
18
+ - Three to five bullets. Six is a signal to split; eight is a document.
19
+ - No sub-sub-bullets. If a bullet needs a child, the parent was a section.
20
+ - Keep bullets grammatically parallel: all sentences, or all noun phrases.
21
+
22
+ ## Native bullet glyphs
23
+
24
+ Bullets in PowerPoint are paragraph properties, not characters. A bullet
25
+ character typed into the text ("• Picking…") is a bullet that cannot re-indent,
26
+ cannot change level, and looks different from every other bullet in the deck.
27
+
28
+ Set them properly:
29
+
30
+ ```python
31
+ "<python>" - <<'PY'
32
+ from pptx import Presentation
33
+ from pptx.util import Inches, Pt
34
+ from pptx.enum.text import PP_ALIGN
35
+
36
+ prs = Presentation()
37
+ prs.slide_width, prs.slide_height = Inches(13.333), Inches(7.5)
38
+ slide = prs.slides.add_slide(prs.slide_layouts[6])
39
+ box = slide.shapes.add_textbox(Inches(0.9), Inches(1.8), Inches(11.0), Inches(3.6))
40
+ frame = box.text_frame
41
+ frame.word_wrap = True
42
+
43
+ for index, text in enumerate((
44
+ "Picking is 41% of floor labour hours",
45
+ "Aisle travel costs 12 minutes per order",
46
+ "Manual cycle counts stop the line twice a week",
47
+ )):
48
+ paragraph = frame.paragraphs[0] if index == 0 else frame.add_paragraph()
49
+ paragraph.text = text
50
+ paragraph.font.size = Pt(20)
51
+ paragraph.space_after = Pt(12)
52
+ paragraph.level = 0
53
+ paragraph.alignment = PP_ALIGN.LEFT
54
+ # PowerPoint's own bullet: a literal glyph in the paragraph's pPr
55
+ paragraph._pPr.set("marL", str(Inches(0.3)))
56
+ paragraph._pPr.set("indent", str(-Inches(0.3)))
57
+ bu = paragraph._pPr.makeelement(
58
+ "{http://schemas.openxmlformats.org/drawingml/2006/main}buChar", {"char": "•"}
59
+ )
60
+ paragraph._pPr.append(bu)
61
+
62
+ prs.save("bullets.pptx")
63
+ print("bullets:", len(frame.paragraphs))
64
+ PY
65
+ ```
66
+
67
+ The `marL`/`indent` pair is what pulls the second line of a wrapped bullet under
68
+ the text instead of under the glyph — the most common "malformed bullet" defect
69
+ in generated decks.
70
+
71
+ ## Anti-patterns
72
+
73
+ - Bullets as a script: a slide is not a transcript, the speaker notes are.
74
+ - Fake bullets via "– " or "→ " prefixes in the text; they do not indent.
75
+ - Six bullets of equal weight where one is the actual point. Make the point the
76
+ title and the bullets the evidence.
77
+ - Numbered lists where the order does not matter, and bullet lists where it
78
+ does.
@@ -0,0 +1,67 @@
1
+ # Evidence on slides: charts, tables, notes
2
+
3
+ "Evidence" is anything on a slide that claims a fact: a number, a chart, a
4
+ table, a quotation. The rules below keep it checkable.
5
+
6
+ ## Native or it did not happen
7
+
8
+ | Claim | Correct form | Wrong form |
9
+ |---|---|---|
10
+ | Trend over time | Native chart with categories and series | Screenshot of a chart |
11
+ | Exact figures | Native table | Image of a spreadsheet |
12
+ | A single number | A bold run in a sentence | A one-bar chart |
13
+ | A process | Shapes plus connectors | Image of a flowchart |
14
+
15
+ The wrong column has one shared defect: the audience cannot read it at projector
16
+ size and nobody can verify it. Native charts and tables also keep their numbers
17
+ in the package, which is what lets `container_tools/native_quantitative_chart_gate.py`
18
+ and `container_tools/native_table_arithmetic_gate.py` check them.
19
+
20
+ ## Charts
21
+
22
+ - The chart title says what the chart means. The slide title says the conclusion.
23
+ Two titles, two jobs — if they are the same sentence, drop the chart title
24
+ (`chart.has_title = False`) rather than repeat it.
25
+ - Bars start at zero. Lines may start elsewhere only if the axis is labelled.
26
+ - Categories in the order the audience thinks in (Q1..Q4, not alphabetised).
27
+ - Label the few numbers that matter, not every point. Ten data labels is a
28
+ table with rounded corners.
29
+ - One axis. Two y-axes on a slide chart is a way to imply a correlation that may
30
+ not exist.
31
+ - Source and window in the caption: "Driver logs, FY2026, 12 sites".
32
+
33
+ ## Tables
34
+
35
+ - Column order follows the reader's question: what, then how much, then change.
36
+ - Header row is bold and distinct; total row is bold and separated.
37
+ - Numbers right-aligned, one decimal convention per column.
38
+ - A total is arithmetic the reader can check. Fill it from the data, never by
39
+ eye, and let the table arithmetic gate confirm it.
40
+ - Do not put units in every cell; put them in the header.
41
+ - A table with more than about 7 rows belongs in an appendix, with the slide
42
+ stating the conclusion.
43
+
44
+ ## Speaker notes as provenance
45
+
46
+ Notes are where "where did this number come from" lives, so the presenter can
47
+ answer without the slide turning into a footnote.
48
+
49
+ - One note per non-obvious number: source, date range, and any caveat.
50
+ - The sentence you will actually say, in spoken words.
51
+ - No bullet-stacking in notes; notes are prose.
52
+ - Notes are invisible to the render loop — verify them from the file, not the
53
+ PNGs. `container_tools/inspect_presentation_package_integrity.py` counts
54
+ `notesSlides`, and the package dump shows their text.
55
+
56
+ ## Fidelity gates
57
+
58
+ Before presenting a deck that carries numbers:
59
+
60
+ ```bash
61
+ "<python>" container_tools/native_quantitative_chart_gate.py --input deck.pptx --all-slides
62
+ "<python>" container_tools/native_table_arithmetic_gate.py --input deck.pptx --contracts totals.json
63
+ "<python>" container_tools/native_chart_title_gate.py --input deck.pptx
64
+ ```
65
+
66
+ Each prints one JSON object whose `passed` field is the decision. A failing gate
67
+ is not advisory: it means the slide asserts something the file cannot support.
@@ -0,0 +1,66 @@
1
+ # Style guidance
2
+
3
+ ## The type scale
4
+
5
+ Three sizes are enough: title, body, caption. A fourth size is a decision the
6
+ audience has to make, and they will make it wrongly.
7
+
8
+ | Role | Size | Weight | Colour |
9
+ |---|---|---|---|
10
+ | Cover title | 40–48 pt | Bold | Ink |
11
+ | Slide title | 28–36 pt | Bold or semibold | Ink |
12
+ | Body | 18–22 pt | Regular | Ink |
13
+ | Lead-in number | Same as body + bold | Bold | Accent |
14
+ | Caption, source | 12–14 pt | Regular | Muted |
15
+
16
+ Rules that carry the rest:
17
+
18
+ - One typeface family. A second family means "different voice", so use it for
19
+ one thing (a quote, a code line) and nothing else.
20
+ - Bold is emphasis, not decoration: at most one bold phrase per paragraph.
21
+ - All-caps for a 2–4 word label is a design choice; all-caps for a sentence is
22
+ a readability tax.
23
+ - Left-align body text. Centred paragraphs longer than two lines are hard to
24
+ track back to the next line.
25
+
26
+ ## Colour
27
+
28
+ - One ink, one muted, one accent, plus the template's own rule colour. More
29
+ than that and the accent stops meaning "look here".
30
+ - Contrast is a correctness issue: body text on white needs a dark ink
31
+ (roughly luminance ratio 4.5:1), and text over a photograph needs a scrim,
32
+ not luck.
33
+ - Never encode meaning in colour alone — an accent bar showing the direction of
34
+ a metric also needs an arrow or a word.
35
+ - Chart series colours come from the theme; a sixth series colour is a signal
36
+ that the chart has too many series.
37
+
38
+ ## Density
39
+
40
+ - Body blocks stop at about 6 lines of 18 pt on a 16:9 slide before the eye
41
+ stops at the middle.
42
+ - A table on a slide reads at up to about 7 rows × 4 columns. Beyond that it is
43
+ an appendix, and the slide should carry the one row that matters.
44
+ - Whitespace is a layout element, not leftover space: leave at least 0.6 in
45
+ between content blocks and the slide edge.
46
+ - One idea per slide. If the title needs "and", split.
47
+
48
+ ## Cover art direction
49
+
50
+ A cover carries three things: the title, the context line, and the visual that
51
+ sets the tone. Keep them separate roles.
52
+
53
+ - Abstract geometry, a photograph of the actual subject, or a flat colour field
54
+ all work. Clip art of a handshake does not.
55
+ - If the visual is photographic, darken it (a scrim at 40–60% black) under the
56
+ text rather than hoping the text lands on a dark region.
57
+ - If no suitable image exists, use a colour field plus an accent rule. An
58
+ invented diagram pretending to be a photograph is worse than a plain cover.
59
+ - Encode the deck's palette: if the accent is amber, the cover visual should
60
+ contain amber, not a random sunset.
61
+ - Never ship a screenshot of a tool, a UI or another slide as cover art.
62
+
63
+ ## Closing slides
64
+
65
+ The last slide restates the ask in one line and nothing else. "Thank you" alone
66
+ wastes the slot the audience is still looking at while they gather their things.
@@ -0,0 +1,76 @@
1
+ # Working from a supplied template
2
+
3
+ ## Why templates win
4
+
5
+ A template already answers branding, type scale, slide families and chrome. The
6
+ cheapest correct deck puts the user's content into the template's own slides
7
+ and leaves the design alone. Rebuilding the look from a screenshot produces a
8
+ near-miss that reads as "someone remade our deck in a hurry".
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Inspect the template** before judging it:
13
+
14
+ ```bash
15
+ "<python>" "<skill>/template_following_scripts/inspect_template_deck.py" --template brand.pptx --out-dir template-inspect
16
+ ```
17
+
18
+ It writes `template-inspect.ndjson` (per slide: layout, placeholders with
19
+ index, kind, rect and text, background art) and `template-manifest.json`
20
+ (slide size, aspect, layout names, theme fonts, which slides carry
21
+ full-bleed art).
22
+
23
+ 2. **Choose the slide families you need** — cover, section, content, table,
24
+ chart, closing. You want the *fewest* source slides that cover those roles.
25
+
26
+ 3. **Write the frame map** — a JSON plan that names, per output slide, which
27
+ source slide it duplicates and what happens to each element
28
+ (`rewrite`, `rewrite-and-reposition`, `fill-placeholder`, `replace`,
29
+ `delete`, `keep`).
30
+
31
+ 4. **Validate the plan** before building:
32
+
33
+ ```bash
34
+ "<python>" "<skill>/template_following_scripts/validate_template_plan.py" --plan frame-map.json
35
+ ```
36
+
37
+ It rejects unknown actions, out-of-range zones, new primitives without an
38
+ explicit justification, and any attempt to edit a brand or chrome element.
39
+
40
+ 5. **Build the starter deck**, then fill it:
41
+
42
+ ```bash
43
+ "<python>" "<skill>/template_following_scripts/prepare_template_starter_deck.py" --template brand.pptx --plan frame-map.json --out starter.pptx
44
+ ```
45
+
46
+ The starter deck contains only the slides you kept, in your order, with the
47
+ placeholders filled. From there `container_tools/add_slides.py` and the
48
+ recipes extend it.
49
+
50
+ 6. **Check fidelity** against the source:
51
+
52
+ ```bash
53
+ "<python>" "<skill>/template_following_scripts/check_template_fidelity.py" --template brand.pptx --final starter.pptx --plan frame-map.json
54
+ "<python>" "<skill>/container_tools/template_source_fidelity_gate.py" --template brand.pptx --final starter.pptx --requirements fidelity.json
55
+ ```
56
+
57
+ Both print JSON with a `passed` boolean. Leftover placeholders, drifted
58
+ layout rects and opaque panels covering inherited artwork are failures, not
59
+ style opinions.
60
+
61
+ ## Reading a template's own geometry
62
+
63
+ `container_tools/inspect_presentation_layout_geometry.py --input brand.pptx`
64
+ prints every shape's rect in inches, which is what you address when a slide's
65
+ placeholder needs a value that fits its frame.
66
+
67
+ ## Rules
68
+
69
+ - Placeholders keep their index; fill by index rather than adding a textbox on
70
+ top of a placeholder.
71
+ - Never restyle the master to match a screenshot you were given. If the brand
72
+ colours are wrong, ask; guessing produces a deck the brand team rejects.
73
+ - If the template has no suitable family for a slide (say, a two-column
74
+ comparison), say which family you added and why, rather than silently
75
+ inventing a look.
76
+ - Keep the template's slide size. Changing it invalidates every inherited rect.
@@ -0,0 +1,45 @@
1
+ # Handing a deck to Google Slides
2
+
3
+ Google Slides imports `.pptx`, and mostly survives it. What it does not survive
4
+ is worth designing around.
5
+
6
+ ## What converts cleanly
7
+
8
+ - Text frames, bullet levels, speaker notes, slide size and order.
9
+ - Native tables and native charts (data comes across with the chart).
10
+ - Pictures, shapes, solid fills and theme colours.
11
+
12
+ ## What converts badly
13
+
14
+ | Feature | What happens | Do instead |
15
+ |---|---|---|
16
+ | Custom `buChar` glyphs and `marL/indent` | Indent shifts, glyphs fall back | Use plain paragraph levels; check the bullet indent after import |
17
+ | Elbow/curved connectors | Re-anchored or detached | Straight connectors between facing sides |
18
+ | Font not on the reader's machine | Substituted, wider, text reflows | Stick to fonts both environments have, and re-check overflow after import |
19
+ | Text-to-fit-shape autosize | Keeps the shrunk size | Fixed frames with measured text |
20
+ | Animations and transitions | Partially dropped | Do not rely on them for meaning |
21
+ | Embedded workbook charts | Data retained, formatting re-derived | Re-apply axis/label settings in Slides if they matter |
22
+ | Master-level chrome via spTree surgery | Usually kept, occasionally duplicated | Prefer layout-level placeholders |
23
+
24
+ ## The workflow
25
+
26
+ 1. Build the deck as a normal `.pptx` — nothing Slides-specific is needed.
27
+ 2. Render and inspect the PNGs locally first; fix overflow before importing.
28
+ 3. Upload to Drive, open with Google Slides, and check these in order: title
29
+ wrapping, bullet indentation, connector attachment, chart axes, notes.
30
+ 4. If the deck will be edited by other people in Slides, keep shapes distinct
31
+ and named (right-click → rename) so comments and edits are unambiguous.
32
+
33
+ ## Sharing
34
+
35
+ - "Anyone with the link" plus a view-only role is the default for a deck that
36
+ should not be edited in place.
37
+ - Export back to `.pptx` when the user needs a file; Slides' export does not
38
+ preserve everything either, so state which version is authoritative.
39
+ - Comments and suggestions do not travel in the `.pptx` round trip.
40
+
41
+ ## When the user asks for a Slides-native link
42
+
43
+ Deliver the `.pptx` (that is what this pack produces), state the upload path,
44
+ and list the three things to check after import: font substitution, bullet
45
+ indent, chart axes. Claiming a clean conversion without those checks is a guess.
@@ -0,0 +1,83 @@
1
+ # Task: apply an annotation payload
2
+
3
+ The user draws on a rendered slide and sends back an `office-annotations` block.
4
+ Treat it as a change request with coordinates, not as editor state.
5
+
6
+ ## 1. Re-create the geometry the user drew on
7
+
8
+ Annotations refer to the preview the user saw. Render the same way so the
9
+ coordinates mean the same thing:
10
+
11
+ ```bash
12
+ "<python>" "<skill>/container_tools/render_slides.py" --input deck.pptx --out-dir preview
13
+ ```
14
+
15
+ Slide index = `page` in the payload, 1-based. Keep the PNGs — you will compare
16
+ the same slide before and after.
17
+
18
+ ## 2. Resolve each annotation to shapes
19
+
20
+ The region is normalised 0–1 on that slide image. Map it to inches:
21
+
22
+ ```
23
+ left_in = region.left * slide_width_in
24
+ top_in = region.top * slide_height_in
25
+ width_in = region.width * slide_width_in
26
+ height_in = region.height * slide_height_in
27
+ ```
28
+
29
+ Then select candidate shapes whose bounding box overlaps that rect, largest
30
+ overlap first:
31
+
32
+ ```bash
33
+ "<python>" "<skill>/container_tools/inspect_presentation_layout_geometry.py" --input deck.pptx --json-out geometry.json
34
+ ```
35
+
36
+ `geometry.json` lists every shape per slide with `left`, `top`, `width`,
37
+ `height` in inches, plus its text. Two overlapping shapes (a title over a
38
+ background panel) are common: use the annotation's `text` to disambiguate —
39
+ match it against each candidate's text, and prefer an exact or prefix match.
40
+
41
+ ## 3. Decide the smallest edit
42
+
43
+ | Requirement reads like | Do this |
44
+ |---|---|
45
+ | "change this wording" | run-level replace on that shape ([edit-deck](edit-deck.md)) |
46
+ | "move this down" | set `left/top` on that shape only |
47
+ | "make this bigger" | set font size on the runs of that shape, then re-check fit |
48
+ | "this overlaps the table" | resize the shape, or the table, not the whole slide |
49
+ | "recolour" | change the run colour, not the theme |
50
+ | "add a line here" | the rect is a position, not an insertion point: add the shape at that rect, matching nearby type |
51
+
52
+ Never restyle a slide to satisfy a region. The region identifies *what*, the
53
+ requirement says *how much*.
54
+
55
+ ## 4. Apply, write a copy, re-render
56
+
57
+ Mutations go through this pack's tools (`replace_text.py`, `add_slides.py`,
58
+ `core_properties.py`) or a focused `python-pptx` snippet — always to
59
+ `<original>-edited.pptx`.
60
+
61
+ ```bash
62
+ "<python>" "<skill>/container_tools/replace_text.py" --input deck.pptx --find "old" --replace "new" --out deck-edited.pptx
63
+ "<python>" "<skill>/container_tools/render_slides.py" --input deck-edited.pptx --out-dir preview-after
64
+ ```
65
+
66
+ ## 5. Confirm, in words
67
+
68
+ Open the same slide number and check the region now looks right. Report which
69
+ shape you changed, what changed, and the slide number.
70
+
71
+ ## When it cannot be mapped
72
+
73
+ - Empty region, or no shape overlaps it → say that the region covers blank
74
+ space and ask what object was meant.
75
+ - Overlapping candidates that `text` does not disambiguate → name both and ask.
76
+ - The requirement is about something the file has no geometry for (a font that
77
+ is not installed, a transition) → say so plainly.
78
+ - The region covers a chart or table whose values would need to change → state
79
+ that values come from the data, and ask for the corrected figures rather than
80
+ editing the rendered numbers.
81
+
82
+ Never guess silently. "I changed the title on slide 3; the region also touched
83
+ the subtitle, which I left alone" is a good answer. Silence plus a diff is not.