dsh-office-kit 0.4.2 → 0.4.3

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 (113) hide show
  1. package/assets/skills/excel-live-control/SKILL.md +119 -152
  2. package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
  3. package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
  4. package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
  5. package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
  6. package/assets/skills/excel-live-control/references/office-automation.md +127 -153
  7. package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
  8. package/assets/skills/excel-live-control/style_guidelines.md +56 -64
  9. package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
  10. package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
  11. package/assets/skills/office-documents/SKILL.md +24 -60
  12. package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
  13. package/assets/skills/office-documents/ooxml/comments.md +8 -8
  14. package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
  15. package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
  16. package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
  17. package/assets/skills/office-documents/references/docx-structure.md +11 -13
  18. package/assets/skills/office-documents/references/template-elicitation.md +11 -13
  19. package/assets/skills/office-documents/references/writing-quality.md +20 -20
  20. package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
  21. package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
  22. package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
  23. package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
  24. package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
  25. package/assets/skills/office-documents/tasks/create_edit.md +14 -16
  26. package/assets/skills/office-documents/tasks/equations.md +17 -28
  27. package/assets/skills/office-documents/tasks/fields_update.md +14 -16
  28. package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
  29. package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
  30. package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
  31. package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
  32. package/assets/skills/office-documents/tasks/images_figures.md +15 -25
  33. package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
  34. package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
  35. package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
  36. package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
  37. package/assets/skills/office-documents/tasks/read_review.md +9 -20
  38. package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
  39. package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
  40. package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
  41. package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
  42. package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
  43. package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
  44. package/assets/skills/office-documents/tasks/verify_render.md +11 -23
  45. package/assets/skills/office-documents/tasks/watermarks_background.md +11 -15
  46. package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +6 -6
  47. package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
  48. package/assets/skills/office-pdf/SKILL.md +36 -51
  49. package/assets/skills/office-pdf/references/form-fields.md +20 -20
  50. package/assets/skills/office-pdf/references/geometry.md +10 -10
  51. package/assets/skills/office-pdf/references/layout-quality.md +13 -13
  52. package/assets/skills/office-pdf/references/limits.md +12 -56
  53. package/assets/skills/office-pdf/tasks/annotations.md +5 -5
  54. package/assets/skills/office-pdf/tasks/create.md +6 -9
  55. package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
  56. package/assets/skills/office-pdf/tasks/forms.md +15 -15
  57. package/assets/skills/office-pdf/tasks/read.md +9 -9
  58. package/assets/skills/office-pdf/tasks/redact.md +18 -18
  59. package/assets/skills/office-pdf/tasks/stamp.md +10 -10
  60. package/assets/skills/office-presentations/SKILL.md +71 -91
  61. package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
  62. package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
  63. package/assets/skills/office-presentations/recipes/README.md +24 -35
  64. package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
  65. package/assets/skills/office-presentations/recipes/connectors.md +11 -12
  66. package/assets/skills/office-presentations/recipes/images.md +11 -12
  67. package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
  68. package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
  69. package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
  70. package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
  71. package/assets/skills/office-presentations/recipes/tables.md +14 -14
  72. package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
  73. package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
  74. package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
  75. package/assets/skills/office-presentations/references/finalization.md +10 -12
  76. package/assets/skills/office-presentations/references/native-bullets.md +14 -18
  77. package/assets/skills/office-presentations/references/native-evidence.md +18 -32
  78. package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
  79. package/assets/skills/office-presentations/references/templates.md +31 -60
  80. package/assets/skills/office-presentations/routing/google_slides.md +4 -4
  81. package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
  82. package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
  83. package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
  84. package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
  85. package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
  86. package/assets/skills/office-presentations/tasks/template-following.md +23 -28
  87. package/assets/skills/office-spreadsheets/SKILL.md +32 -39
  88. package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
  89. package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
  90. package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
  91. package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
  92. package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
  93. package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
  94. package/assets/skills/office-spreadsheets/references/charts.md +15 -34
  95. package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
  96. package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
  97. package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
  98. package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
  99. package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
  100. package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
  101. package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
  102. package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
  103. package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
  104. package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
  105. package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
  106. package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
  107. package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
  108. package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
  109. package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
  110. package/assets/skills/shared/annotation-recipes.md +98 -120
  111. package/assets/skills/shared/common-workflow.md +70 -80
  112. package/dist/index.js +1 -1
  113. package/package.json +1 -1
@@ -1,7 +1,6 @@
1
1
  # Task: charts, tables and speaker notes
2
2
 
3
- Three things that look like one job and share one rule: the numbers must be
4
- checkable from the file.
3
+ One rule across all three: the numbers must be checkable from the file.
5
4
 
6
5
  ## Charts
7
6
 
@@ -11,19 +10,18 @@ Native, always:
11
10
  "<python>" "<cli>" pptx create --spec with-chart.json --out charted.pptx
12
11
  ```
13
12
 
14
- or the recipe when you need control of axis, labels or legend:
15
- [native-charts](../recipes/native-charts.md).
13
+ Or the [native-charts recipe](../recipes/native-charts.md) when you need control
14
+ of axis, labels or legend.
16
15
 
17
- Spec keys the builder accepts: `type` (`bar`/`column`/`line`/`pie`, where bar and
18
- column both render as a clustered column), `title`, `categories`,
19
- `series[{name, values}]`, `left`, `top`, `width`, `height`.
16
+ Spec keys: `type` (`bar`/`column`/`line`/`pie`; bar and column both render as a
17
+ clustered column), `title`, `categories`, `series[{name, values}]`, `left`,
18
+ `top`, `width`, `height`.
20
19
 
21
20
  - The chart title says what the chart means; the slide title states the
22
21
  conclusion. If both say the same thing, drop the chart title.
23
- - Categories in the order the reader thinks in.
24
- - Bars start at zero.
25
- - A chart that duplicates a table on a neighbouring slide is a review finding,
26
- not a second view — pick one.
22
+ - Categories in the order the reader thinks in. Bars start at zero.
23
+ - A chart duplicating a table on a neighbouring slide is a review finding, not a
24
+ second view — pick one.
27
25
 
28
26
  Verify:
29
27
 
@@ -35,8 +33,8 @@ Verify:
35
33
  ## Tables
36
34
 
37
35
  Spec form (`{"headers": [...], "rows": [[...]]}`) puts the table at the cursor,
38
- full width; the [tables recipe](../recipes/tables.md) gives you the rect, column
39
- widths, alignment and the total row styling.
36
+ full width; the [tables recipe](../recipes/tables.md) gives the rect, column
37
+ widths, alignment and total-row styling.
40
38
 
41
39
  Rules: numbers right-aligned, units in the header, total row computed not typed,
42
40
  seven rows maximum on a slide.
@@ -47,8 +45,8 @@ Declare each total so it can be proved:
47
45
  "<python>" "<skill>/container_tools/native_table_arithmetic_gate.py" --input charted.pptx --contracts totals.json
48
46
  ```
49
47
 
50
- A mismatch exit code is a data bug or a rounding bug. Fix the number or declare
51
- the rounding; never lower the tolerance to make it pass.
48
+ A mismatch is a data bug or a rounding bug. Fix the number or declare the
49
+ rounding; never lower the tolerance to make it pass.
52
50
 
53
51
  ## Speaker notes
54
52
 
@@ -65,15 +63,14 @@ confirm they landed:
65
63
  "<python>" "<skill>/container_tools/inspect_presentation_package_integrity.py" --input deck-notes.pptx
66
64
  ```
67
65
 
68
- `notesSlides` in the part counts should equal the number of slides you wrote
69
- notes for.
66
+ `notesSlides` must equal the number of slides you wrote notes for.
70
67
 
71
- Notes carry: the sentence you will say, the provenance of any non-obvious
72
- number, and the answer to the question the slide invites. Nothing that belongs
73
- on the slide.
68
+ Notes carry: the sentence you will say, the provenance of any non-obvious number,
69
+ and the answer to the question the slide invites. Nothing that belongs on the
70
+ slide.
74
71
 
75
72
  ## Putting them together
76
73
 
77
- A results slide usually wants: one claim as the title, one chart as the
78
- evidence, one caption as the source, and the detail in notes. If it needs a
79
- chart *and* a table, it is two slides — or the table is an appendix.
74
+ A results slide wants one claim as the title, one chart as the evidence, one
75
+ caption as the source, and the detail in notes. If it needs a chart *and* a
76
+ table, it is two slides — or the table is an appendix.
@@ -5,10 +5,10 @@
5
5
  - Audience and setting: live talk, read-on-its-own PDF, or both. A read-only
6
6
  deck needs more words; a live deck needs fewer.
7
7
  - Length: number of slides or minutes.
8
- - Brand: a template file, a colour, or nothing (then use the defaults in
9
- [style-guidelines](../references/style-guidelines.md)).
10
- - Evidence: numbers, charts, tables and images the user already has. Never
11
- invent a metric — if a number is needed and missing, say so.
8
+ - Brand: a template file, a colour, or the defaults in
9
+ [style-guidelines](../references/style-guidelines.md).
10
+ - Evidence: numbers, charts, tables, images the user has. Never invent a metric —
11
+ if a number is needed and missing, say so.
12
12
 
13
13
  ## Route
14
14
 
@@ -65,21 +65,20 @@ For the ordinary deck (cover, bullets, section, table, chart, image, closing):
65
65
  }
66
66
  ```
67
67
 
68
- Layouts map to `title`, `bullets`, `section`, `title_only`, `blank`. Tables are
69
- placed at 0.8 in from the left at the running cursor and cannot be positioned —
70
- put a table on its own slide, or use the [tables recipe](../recipes/tables.md).
68
+ Layouts: `title`, `bullets`, `section`, `title_only`, `blank`. Tables sit 0.8 in
69
+ from the left at the running cursor and cannot be positioned — give a table its
70
+ own slide, or use the [tables recipe](../recipes/tables.md).
71
71
 
72
72
  ### Everything else: build it with the recipes
73
73
 
74
- Anything at a coordinate, any crop, any connector, any master change is a
75
- `python-pptx` snippet:
76
-
77
- - [textbox at a coordinate](../recipes/textbox-at-coordinate.md)
78
- - [auto-layout rules](../recipes/autolayout.md)
79
- - [tables](../recipes/tables.md) · [native charts](../recipes/native-charts.md)
80
- - [images](../recipes/images.md) · [connectors](../recipes/connectors.md)
81
- - [rich text runs](../recipes/rich-text-runs.md) · [theme tokens](../recipes/theme-tokens.md)
82
- - [speaker notes](../recipes/speaker-notes.md) · [masters and layouts](../recipes/master-and-layouts.md)
74
+ Anything at a coordinate, any crop, connector or master change is a `python-pptx`
75
+ snippet: [textbox at a coordinate](../recipes/textbox-at-coordinate.md),
76
+ [auto-layout](../recipes/autolayout.md), [tables](../recipes/tables.md) ·
77
+ [native charts](../recipes/native-charts.md), [images](../recipes/images.md) ·
78
+ [connectors](../recipes/connectors.md), [rich text
79
+ runs](../recipes/rich-text-runs.md) · [theme tokens](../recipes/theme-tokens.md),
80
+ [speaker notes](../recipes/speaker-notes.md) · [masters and
81
+ layouts](../recipes/master-and-layouts.md).
83
82
 
84
83
  Extending a deck you already built:
85
84
 
@@ -100,7 +99,8 @@ template's look by hand.
100
99
 
101
100
  ## Writing the slides
102
101
 
103
- Story first. Write the one-sentence claim for every slide, in order, then fill
104
- the frames. If a claim needs two sentences, it is two slides. Keep bullets as
105
- claims ([native-bullets](../references/native-bullets.md)) and evidence native
102
+ Story first: the one-sentence claim for every slide, in order, then fill the
103
+ frames (loop in [authoring-workflow](../references/authoring-workflow.md)). A
104
+ claim needing two sentences is two slides. Bullets are claims
105
+ ([native-bullets](../references/native-bullets.md)); evidence is native
106
106
  ([native-evidence](../references/native-evidence.md)).
@@ -2,7 +2,7 @@
2
2
 
3
3
  Editing is mutation, and mutation lives in this pack's tools, not in the helper
4
4
  CLI: `container_tools/replace_text.py`, `add_slides.py`, `core_properties.py`,
5
- plus the recipes for everything structural.
5
+ plus the recipes for anything structural.
6
6
 
7
7
  **Never write over the original.** Every tool defaults to
8
8
  `<original>-edited.pptx`; keep that default unless the user names a path.
@@ -14,9 +14,8 @@ plus the recipes for everything structural.
14
14
  "<python>" "<skill>/container_tools/inspect_presentation_layout_geometry.py" --input deck.pptx
15
15
  ```
16
16
 
17
- `pptx read` gives titles, text, tables and chart data per slide. The geometry
18
- gate gives every shape's rect in inches, which is what you need to decide
19
- whether a new block fits.
17
+ `pptx read` gives titles, text, tables and chart data per slide; the geometry
18
+ gate gives every shape's rect in inches, to decide whether a new block fits.
20
19
 
21
20
  ## 2. Text changes: run-level replace
22
21
 
@@ -41,11 +40,11 @@ Batch form:
41
40
  "<python>" "<skill>/container_tools/replace_text.py" --input deck.pptx --spec replacements.json
42
41
  ```
43
42
 
44
- Semantics that matter: a pattern only matches **inside a single run**. Text that
45
- PowerPoint split for formatting ("**Q4** 2025") will not match "Q4 2025" and the
46
- report lists it under `unmatched`. When a pattern cannot match, that is the
47
- signal to edit that paragraph with a run-level snippet
48
- ([rich text runs](../recipes/rich-text-runs.md)) rather than widening the match.
43
+ A pattern matches **inside a single run** only. Text PowerPoint split for
44
+ formatting ("**Q4** 2025") will not match "Q4 2025" and the report lists it under
45
+ `unmatched`. When a pattern cannot match, edit that paragraph with a run-level
46
+ snippet ([rich text runs](../recipes/rich-text-runs.md)) rather than widening the
47
+ match.
49
48
 
50
49
  Exit code 1 means a pattern matched nothing; the file is still written, so read
51
50
  `unmatched` before delivering.
@@ -56,10 +55,9 @@ Exit code 1 means a pattern matched nothing; the file is still written, so read
56
55
  "<python>" "<skill>/container_tools/add_slides.py" --input deck.pptx --spec extra-slides.json
57
56
  ```
58
57
 
59
- The spec is the same slide object as `pptx create` (`layout`, `title`,
60
- `subtitle`, `bullets`, `table`, `chart`, `image`). For anything outside that
61
- vocabulary, add the slide with `add_slides.py` and then place content with a
62
- recipe.
58
+ The spec uses the same slide object as `pptx create` (`layout`, `title`,
59
+ `subtitle`, `bullets`, `table`, `chart`, `image`). Outside that vocabulary, add
60
+ the slide with `add_slides.py`, then place content with a recipe.
63
61
 
64
62
  ## 4. Metadata
65
63
 
@@ -72,7 +70,7 @@ recipe.
72
70
 
73
71
  | Change | Route |
74
72
  |---|---|
75
- | Move or resize a shape | recipe: set `.left/.top/.width/.height` on the shape from `slide.shapes` |
73
+ | Move or resize a shape | set `.left/.top/.width/.height` from `slide.shapes` |
76
74
  | Restyle a family | [masters and layouts](../recipes/master-and-layouts.md) |
77
75
  | Add notes | [speaker notes](../recipes/speaker-notes.md) |
78
76
  | Replace a chart's data | [native charts](../recipes/native-charts.md) — edit the series, do not paste a picture |
@@ -89,5 +87,5 @@ relational:
89
87
  "<python>" "<skill>/container_tools/render_slides.py" --input deck-edited.pptx --out-dir preview
90
88
  ```
91
89
 
92
- Then look at the changed pages. A text replacement that pushes a title onto a
93
- third line is a layout change, not a text change.
90
+ Then look at the changed pages. A replacement that pushes a title onto a third
91
+ line is a layout change, not a text change.
@@ -1,7 +1,7 @@
1
1
  # Task: inspect and verify a deck
2
2
 
3
- Verification is reading the artefact back and looking at it. The tools below
4
- print one JSON object each; `passed` is the decision.
3
+ Verification is reading the file back and looking at it. Each tool prints one
4
+ JSON object; `passed` is the decision.
5
5
 
6
6
  ## 1. What is in the file
7
7
 
@@ -10,8 +10,7 @@ print one JSON object each; `passed` is the decision.
10
10
  ```
11
11
 
12
12
  Per slide: title, all text, tables as rows, charts with type/title/categories/
13
- series, image count. This is the cheapest sanity check that the content you
14
- meant to write is the content that was written.
13
+ series, image count. Cheapest check that what was written is what was intended.
15
14
 
16
15
  ## 2. Is the package coherent
17
16
 
@@ -19,10 +18,10 @@ meant to write is the content that was written.
19
18
  "<python>" "<skill>/container_tools/inspect_presentation_package_integrity.py" --input deck.pptx
20
19
  ```
21
20
 
22
- Checks required parts, slide/master presence, dangling relationships, XML that
23
- does not parse, slide count drift and duplicate parts, then reports part counts
24
- (`slides`, `layouts`, `masters`, `charts`, `notesSlides`, `media`,
25
- `embeddings`). A chart with an `embeddings` count of zero has lost its data.
21
+ Checks required parts, slide/master presence, dangling relationships, unparseable
22
+ XML, slide-count drift, duplicate parts; reports part counts (`slides`, `layouts`,
23
+ `masters`, `charts`, `notesSlides`, `media`, `embeddings`). Zero `embeddings` on a
24
+ chart means lost data.
26
25
 
27
26
  ## 3. Does the layout hold
28
27
 
@@ -30,13 +29,12 @@ does not parse, slide count drift and duplicate parts, then reports part counts
30
29
  "<python>" "<skill>/container_tools/inspect_presentation_layout_geometry.py" --input deck.pptx --json-out geometry.json
31
30
  ```
32
31
 
33
- `fail` findings (block a delivery): shape outside the slide, degenerate size,
34
- text that cannot fit its frame, table outside the slide, chart or table covered
35
- by another shape. `review` findings (read them, then decide): text overlap,
36
- empty placeholder, title under 28 pt, body under 14 pt, heading ending in a full
37
- stop, connector across text, a chart duplicating a table's labels.
38
-
39
- Add `--strict` to make review findings blocking for a formal deck.
32
+ `fail` blocks delivery: shape outside the slide, degenerate size, text that
33
+ cannot fit its frame, table outside the slide, chart or table covered by another
34
+ shape. `review` needs a decision: text overlap, empty placeholder, title under
35
+ 28 pt, body under 14 pt, heading ending in a full stop, connector across text, a
36
+ chart duplicating a table's labels. `--strict` makes review blocking for a formal
37
+ deck.
40
38
 
41
39
  ## 4. Are the numbers real
42
40
 
@@ -51,11 +49,11 @@ Add `--strict` to make review findings blocking for a formal deck.
51
49
  - Quantitative charts: every declared chart must be a real chart part with a
52
50
  readable series, and in the default `portable` mode must carry its embedded
53
51
  workbook.
54
- - Table arithmetic: only declared totals are enforced, compared against the
55
- displayed rounding; columns whose header is not additive (unit price, ratio,
56
- percent) are skipped rather than summed wrongly.
52
+ - Table arithmetic: only declared totals are enforced, against displayed
53
+ rounding; non-additive columns (unit price, ratio, percent) are skipped rather
54
+ than summed wrongly.
57
55
 
58
- `totals.json` names the contract explicitly:
56
+ `totals.json` names the contract:
59
57
 
60
58
  ```json
61
59
  { "contracts": [{ "slide": 4, "table": 1, "total_row": 6, "columns": [1, 2] }] }
@@ -67,32 +65,31 @@ Add `--strict` to make review findings blocking for a formal deck.
67
65
  "<python>" "<skill>/container_tools/render_slides.py" --input deck.pptx --out-dir preview
68
66
  ```
69
67
 
70
- Writes `slide-NN.png` plus `render.json`. Then `read_image` every PNG — an
71
- unlooked-at render is not verification.
68
+ Writes `slide-NN.png` plus `render.json`; `read_image` every PNG — an unlooked-at
69
+ render is not verification.
72
70
 
73
- To see the whole deck at once:
71
+ Whole deck at once:
74
72
 
75
73
  ```bash
76
74
  "<python>" "<skill>/template_following_scripts/make_contact_sheet.py" --dir preview --out sheet.png --columns 3
77
75
  ```
78
76
 
79
- or `"<skill>/container_tools/create_montage.py` with an explicit file list.
77
+ Or `"<skill>/container_tools/create_montage.py` with an explicit file list.
80
78
 
81
- Look for: clipped text, overlapping blocks, a title that reflowed, a chart whose
82
- point is invisible at thumbnail size, a photograph stretched, a slide with no
83
- title.
79
+ Look for: clipped text, overlapping blocks, a reflowed title, a chart point
80
+ invisible at thumbnail size, a stretched photograph, a slide with no title.
84
81
 
85
82
  ## 6. When nothing can render
86
83
 
87
- With the DSH LibreOffice kit missing (`office_status` → `renderers.kit` /
88
- `renderers.can_render`), `render_slides.py` falls back to `--engine draft`, a
89
- PyMuPDF geometry preview. It shows placement, overflow and overlap — not
90
- typography or theme chrome. Say so when reporting: "verified as a geometry
91
- preview" is honest, "looks great" from an approximate render is not.
84
+ Without the DSH LibreOffice kit (`office_status` → `renderers.available: false`,
85
+ with a `remedy`), `render_slides.py` falls back to `--engine draft`, a
86
+ PyMuPDF geometry preview: placement, overflow, overlap — not typography or theme
87
+ chrome. Say so: "verified as a geometry preview" is honest; "looks great" from an
88
+ approximate render is not.
92
89
 
93
- If even the preview cannot run, the delivery is unverified: report the failing
94
- command, the file's slide count from `pptx read`, and the gate results, and tell
95
- the user which renderer to install for a visual check.
90
+ If even the preview cannot run, report the failing command, the slide count from
91
+ `pptx read`, and the gate results; name the renderer to install for a visual
92
+ check.
96
93
 
97
94
  ## Gate summary
98
95
 
@@ -1,8 +1,7 @@
1
1
  # Task: follow a supplied template
2
2
 
3
3
  Use this when the user hands over a `.pptx` and says "use our template" or "match
4
- this deck". The design is already decided; your job is to put content into its
5
- own slides.
4
+ this deck". The design is decided; put content into its own slides.
6
5
 
7
6
  ## 1. Inspect
8
7
 
@@ -10,16 +9,14 @@ own slides.
10
9
  "<python>" "<skill>/template_following_scripts/inspect_template_deck.py" --template brand.pptx --out-dir template-inspect
11
10
  ```
12
11
 
13
- Outputs:
14
-
15
12
  - `template-inspect.ndjson` — one JSON line per slide: layout name, layout
16
13
  placeholders, slide placeholders (index, kind, rect in inches, text), shape
17
- counts, text excerpt, whether the slide has full-bleed background art.
14
+ counts, text excerpt, full-bleed background art flag.
18
15
  - `template-manifest.json` — slide size, aspect ratio, layout names, theme font
19
- names, and `backgroundArtSlides`.
16
+ names, `backgroundArtSlides`.
20
17
 
21
- Read `backgroundArtSlides` before adding anything: those slides already carry
22
- artwork, so a new opaque panel will cover it.
18
+ Read `backgroundArtSlides` first: those slides already carry artwork, so a new
19
+ opaque panel covers it.
23
20
 
24
21
  ## 2. Plan
25
22
 
@@ -65,13 +62,13 @@ Write `frame-map.json`:
65
62
 
66
63
  Allowed actions: `rewrite`, `rewrite-and-reposition`, `replace`, `delete`,
67
64
  `keep`, `fill-placeholder`. `target.zone` is `[x, y, w, h]` in 0–1 slide
68
- fractions, used with `rewrite-and-reposition`. Elements whose `role` is
69
- `brand`, `logo`, `bumper`, `divider`, `section`, `chrome` or `footer` must stay
70
- `keep` — they are the template.
65
+ fractions, used with `rewrite-and-reposition`. Elements whose `role` is `brand`,
66
+ `logo`, `bumper`, `divider`, `section`, `chrome` or `footer` must stay `keep` —
67
+ they are the template.
71
68
 
72
- Adding new shapes is opt-in: set `newPrimitives.allowed` and write a
73
- justification. The validator rejects shapes added without it, because "one extra
74
- box" is how a branded deck stops matching brand.
69
+ New shapes are opt-in: set `newPrimitives.allowed` and justify it. The validator
70
+ rejects additions without that, because "one extra box" is how a branded deck
71
+ stops matching brand.
75
72
 
76
73
  ## 3. Validate
77
74
 
@@ -79,10 +76,10 @@ box" is how a branded deck stops matching brand.
79
76
  "<python>" "<skill>/template_following_scripts/validate_template_plan.py" --plan frame-map.json
80
77
  ```
81
78
 
82
- Rejects: unknown action, preserved role edited, zone outside 0–1, non-sequential
79
+ Rejects unknown action, edited preserved role, zone outside 0–1, non-sequential
83
80
  slide numbers, missing justification for new primitives, and duplicate source
84
- slides (a warning — it means two output slides share artwork, usually fine for a
85
- repeated section divider, usually a copy-paste mistake otherwise).
81
+ slides (a warning: shared artwork — fine for a repeated divider, usually a
82
+ copy-paste mistake otherwise).
86
83
 
87
84
  ## 4. Build
88
85
 
@@ -90,12 +87,11 @@ repeated section divider, usually a copy-paste mistake otherwise).
90
87
  "<python>" "<skill>/template_following_scripts/prepare_template_starter_deck.py" --template brand.pptx --plan frame-map.json --out starter.pptx
91
88
  ```
92
89
 
93
- The starter deck keeps only the mapped source slides, in plan order, and applies
94
- the actions. It refuses duplicate source slides (it reuses slides rather than
95
- cloning parts). The report lists applied actions and any placeholder left empty.
96
-
97
- From here, extend with `container_tools/add_slides.py` or the recipes when the
98
- template has no family for a slide you need.
90
+ Keeps only the mapped source slides in plan order and applies the actions. It
91
+ refuses duplicate source slides (reuses slides rather than cloning parts). The
92
+ report lists applied actions and any empty placeholder. Extend with
93
+ `container_tools/add_slides.py` or the recipes when the template has no family
94
+ for a slide you need.
99
95
 
100
96
  ## 5. Check fidelity
101
97
 
@@ -118,8 +114,8 @@ template has no family for a slide you need.
118
114
  }
119
115
  ```
120
116
 
121
- Both print `passed`. With no requirements, the fidelity gate is a deliberate
122
- no-op pass — pass a requirements file or you have not checked anything.
117
+ Both print `passed`. No requirements → deliberate no-op pass: pass a file or you
118
+ have checked nothing.
123
119
 
124
120
  ## 6. Look at it
125
121
 
@@ -127,6 +123,5 @@ no-op pass — pass a requirements file or you have not checked anything.
127
123
  "<python>" "<skill>/container_tools/render_slides.py" --input starter.pptx --out-dir starter-preview
128
124
  ```
129
125
 
130
- Compare against the source slides. A filled placeholder that overflows, a title
131
- in the wrong family, or a panel over the corner logo is exactly what this step
132
- exists to catch.
126
+ Compare with the source slides: this catches an overflowed placeholder, a title
127
+ in the wrong family, a panel over the corner logo.
@@ -1,24 +1,24 @@
1
1
  ---
2
- description: Create, inspect, edit, recalculate, and verify Excel workbooks (.xlsx/.csv) using openpyxl recipes and the bundled Office helper CLI.
2
+ description: Create, inspect, edit, recalculate, render, and verify Excel spreadsheets (.xlsx/.csv) with openpyxl recipes, formula patterns, and the bundled Office helper CLI.
3
3
  ---
4
4
 
5
5
  # Spreadsheets (.xlsx)
6
6
 
7
- A workbook is cells: each one holds a value, a format, and possibly a formula *string*. openpyxl writes all three and evaluates none of them, so a formula you just wrote has no cached result and `xlsx read` shows `=SUM(B2:B9)` where the user expects `1,950,400`. The calculation happens in an engine — the DSH LibreOffice via `xlsx recalc` (cross-platform), or whatever app the user opens the file in. Everything below follows from that: write values and formulas, then verify structure by reading back, then verify numbers by recalculating, then verify appearance by rendering.
7
+ A cell holds a value, a format, and possibly a formula string. openpyxl writes all three and evaluates none: a new formula has no cached result, so `xlsx read` shows `=SUM(B2:B9)` where the user expects `1,950,400`. Only an engine calculates — `xlsx recalc` through the DSH LibreOffice kit (cross-platform), or the app the user opens the file in. Work in that order: write values and formulas, read back for structure, recalculate for numbers, render for appearance.
8
8
 
9
- | User job | What is really happening | Fast path |
9
+ | User job | What is happening | Fast path |
10
10
  | --- | --- | --- |
11
- | Build a new workbook | Cells written top-left at A1; `=`-prefixed strings become formulas; styles are per-cell objects; sheets get names, widths, freeze panes, merges | `xlsx create` spec, `tasks/create-workbook.md` |
11
+ | Build a new workbook | Cells written from A1; `=`-prefixed strings become formulas; styles are per-cell; sheets get names, widths, freeze panes, merges | `xlsx create` spec, `tasks/create-workbook.md` |
12
12
  | Change cells in an existing file | Only the cells you name change; a re-save can drop objects openpyxl does not model (pivots, foreign charts) | `container_tools/set_cells.py` and friends, `tasks/edit-workbook.md` |
13
- | The workbook is open in Excel/WPS and the user wants it changed live | The target is the window, not the file on disk: unsaved user edits are in play and a COM write is not transactional. **Windows only** — on macOS/Linux the live tool exits 3 with a remedy; edit the file instead | `../excel-live-control/SKILL.md` |
14
- | Inventory a file you did not write | Iterate sheets, used range, formulas vs values, merged ranges, conditional formats, defined names, charts | `container_tools/inspect_workbook.py` |
15
- | Compare two versions | Cell-by-cell walk with formula-aware, format-aware, structure-aware levels | `container_tools/diff_workbooks.py`, `tasks/diff-workbooks.md` |
16
- | Prove the numbers are real | Recalculate in Excel, then check every formula cell has a value, no error, no dangling sheet | `xlsx recalc` + `container_tools/recalc_gate.py`, `tasks/recalc-and-check.md` |
17
- | Format numbers, conditions, names, charts, tables | Number formats, conditional-formatting rules, defined names, native chart objects, Excel Tables | `recipes/*.md` (openpyxl patterns, runnable) |
13
+ | Workbook open in Excel/WPS must change live | The target is the window, not the file: unsaved user edits are in play and a COM write is not transactional. **Windows only** — on macOS/Linux the live tool exits 3 with a remedy; edit the file instead | `../excel-live-control/SKILL.md` |
14
+ | Inventory a file you did not write | Sheets, used range, formulas vs values, merged ranges, conditional formats, defined names, charts | `container_tools/inspect_workbook.py` |
15
+ | Compare two versions | Cell-by-cell walk at formula-, format-, and structure-aware levels | `container_tools/diff_workbooks.py`, `tasks/diff-workbooks.md` |
16
+ | Prove the numbers are real | Recalculate, then check every formula cell has a value, no error, no dangling sheet | `xlsx recalc` + `container_tools/recalc_gate.py`, `tasks/recalc-and-check.md` |
17
+ | Format numbers, conditions, names, charts, tables | Number formats, conditional-formatting rules, defined names, native chart objects, Excel Tables | `recipes/*.md` (runnable openpyxl patterns) |
18
18
  | Answer a question about a file | Read values, not formulas; quote the cells you read | `tasks/analyze-workbook.md` |
19
19
  | Spreadsheet lives in Google Sheets | Not this runtime — see `routing/google-sheets.md` | — |
20
20
 
21
- Sheet and range semantics matter before any edit: `B4:D9` is a rectangle, `'Build'!E14` is a cross-sheet reference whose sheet name needs quotes when it contains spaces, and a merged range is one value plus a lot of emptiness. Number formats are display only — the stored value keeps full precision, so never round data to make it look right.
21
+ Sheet and range semantics come before any edit: `B4:D9` is a rectangle, `'Build'!E14` is a cross-sheet reference whose sheet name needs quotes when it contains spaces, and a merged range is one value plus a lot of emptiness. Number formats are display only — the stored value keeps full precision, so never round data to make it look right.
22
22
 
23
23
  ## Before any file work
24
24
 
@@ -29,54 +29,47 @@ Sheet and range semantics matter before any edit: `B4:D9` is a rectangle, `'Buil
29
29
 
30
30
  ## Delivery
31
31
 
32
- Always hand the finished file to the user with the `present` tool, then summarise in one sentence what changed. A bare path is not delivery: the chat transcript renders `.docx`/`.pptx`/`.xlsx`/`.pdf` links as "二进制文件,无法显示改动" and the user cannot open them.
32
+ Hand the finished file to the user with the `present` tool, then summarise in one sentence what changed. A bare path is not delivery: the chat transcript renders `.docx`/`.pptx`/`.xlsx`/`.pdf` links as "二进制文件,无法显示改动" and the user cannot open them.
33
33
 
34
34
  - Creating a file: write it into the user's workspace, verify it, then `present`.
35
- - Editing an existing file: never overwrite the original. Write `<original>-edited.<ext>` (or a name the user asked for), verify it, `present` it, and state both paths.
35
+ - Editing an existing file: never overwrite the original. Write `<original>-edited.<ext>` (or the name the user asked for), verify it, `present` it, and state both paths.
36
36
 
37
37
  ## Annotations
38
38
 
39
- The user may reply with an `office-annotations` block: `[{ page, text, requirement, region: { left, top, width, height } }]`. `region` is normalised 0–1 against the rendered preview page the user drew on; `requirement` is free-form natural language. Treat it as a change request, not as editor state: locate what the region covers, apply the smallest edit that satisfies `requirement`, re-render, and confirm the region now looks right.
39
+ The user may reply with an `office-annotations` block: `[{ page, text, requirement, region: { left, top, width, height } }]`. `region` is normalised 0–1 against the rendered preview page; `requirement` is free-form natural language. Treat it as a change request, not editor state.
40
40
 
41
- When the payload cannot be mapped to a concrete object (the region is empty or the file has no geometry), do not guess silently — say what you could not locate.
42
-
43
- For xlsx the payload is `{ target, fileName, text: "", requirement, region, imageName, unmapped: true }`: no `page`, no `sheet`, no `range`. The preview client cannot resolve a cell from the drag and refuses to fake one. So:
44
-
45
- 1. `read_image` the attachment named `imageName` — it is a screenshot of the area the user marked. Note visible headers, row labels, and values.
46
- 2. Run `"<python>" "<cli>" xlsx read --input "<file>" --json-out "<dump>.json"` and match those values to sheets and A1 addresses; `container_tools/inspect_workbook.py` adds formulas, merged ranges, and names when the match is ambiguous.
47
- 3. State the resolved sheet and range back to the user before editing ("`Pipeline!D2:D13`, the Amount column"), and ask if two sheets or columns match.
48
- 4. Never convert region pixels into a cell address. Full recipe: `tasks/annotations.md` and `"<shared>/annotation-recipes.md"`.
41
+ For xlsx the payload is `{ target, fileName, text: "", requirement, region, imageName, unmapped: true }`: no `page`, no `sheet`, no `range`, because the preview client cannot resolve a cell from the drag and refuses to fake one. So: `read_image` the attachment named `imageName`, match the visible values to sheets and A1 addresses with `"<python>" "<cli>" xlsx read --input "<file>" --json-out "<dump>.json"`, state the resolved sheet and range before editing ("`Pipeline!D2:D13`, the Amount column"), ask when two sheets or columns match, then apply the smallest edit that satisfies `requirement`, re-render, and confirm the region now looks right. Never convert region pixels into a cell address. When the payload cannot be mapped to a concrete object, do not guess silently — say what you could not locate. Full recipe: `tasks/annotations.md` and `"<shared>/annotation-recipes.md"`.
49
42
 
50
43
  ## Verify
51
44
 
52
45
  Three checks, in this order, after every mutation:
53
46
 
54
- 1. **Structure and values.** `"<python>" "<cli>" xlsx read --input "<file>"` proves the cells you wrote are where you wrote them; `container_tools/inspect_workbook.py` proves charts, tables, conditional formats, names, and merges survived.
55
- 2. **Numbers.** If any formula changed or was added, run `"<python>" "<cli>" xlsx recalc --input "<file>" --out "<file>"` and then `container_tools/recalc_gate.py --input "<file>"`. The kit recalculates on every platform; only when the kit itself is missing does the recalc fail, and `recalc_gate.py` then reports `unverified` — say that plainly instead of presenting an empty cache as a result.
56
- 3. **Appearance.** `"<python>" "<cli>" xlsx render --input "<file>" --out-dir "<render-dir>"`, then `read_image` each PNG. Check titles and labels, `###` columns, clipped numbers, charts cut off by the print area, plots with no categories, legends naming `Series 1`, conditional formatting that never fired, and blank pages. The render goes through the DSH LibreOffice kit; when it is missing the command fails explicitly: report the file as structurally verified but visually unchecked, and offer to rebuild from a spec.
47
+ 1. **Structure and values.** `"<python>" "<cli>" xlsx read --input "<file>"` proves the cells you wrote are where you wrote them. `container_tools/inspect_workbook.py` proves charts, tables, conditional formats, names, and merges survived.
48
+ 2. **Numbers.** If a formula changed or was added, run `"<python>" "<cli>" xlsx recalc --input "<file>" --out "<file>"`, then `container_tools/recalc_gate.py --input "<file>"`. Recalc fails only when the kit is missing, and `recalc_gate.py` then reports `unverified` — say that plainly instead of presenting an empty cache as a result. Flags, exit codes, and what the gate reports: `tasks/recalc-and-check.md`.
49
+ 3. **Appearance.** `"<python>" "<cli>" xlsx render --input "<file>" --out-dir "<render-dir>"`, then `read_image` each PNG. Check titles and labels, `###` columns, clipped numbers, charts cut off by the print area, plots with no categories, legends naming `Series 1`, conditional formatting that never fired, and blank pages. When the LibreOffice kit is missing the command fails explicitly: report the file as structurally verified but visually unchecked, and offer to rebuild from a spec.
57
50
 
58
51
  Two or three render/fix passes are normal. If a defect survives three, say what still looks wrong.
59
52
 
60
53
  ## Mutation tools
61
54
 
62
- The CLI is read-only for `.xlsx`: `create`, `read`, `render`, `status`, `recalc` and nothing else. Every change to an existing workbook goes through these openpyxl tools. Each one reads `--input`, writes `<input>-edited.xlsx` unless you pass `--out`, prints one JSON object on stdout, and exits non-zero with a JSON `error` on stderr when it refuses.
55
+ The CLI is read-only for `.xlsx`: `create`, `read`, `render`, `status`, `recalc`, and nothing else. Every change to an existing workbook goes through these openpyxl tools. Each reads `--input`, writes `<input>-edited.xlsx` unless you pass `--out`, prints one JSON object on stdout, and exits non-zero with a JSON `error` on stderr when it refuses.
63
56
 
64
- | Tool | Does | Does not |
65
- | --- | --- | --- |
66
- | `sheet_ops.py` | `--add NAME`, `--rename OLD=NEW`, `--delete NAME`, `--order "A,B,C"` | rename the formulas that point at a renamed sheet; deleting the last sheet is refused |
67
- | `set_cells.py` | `--sheet S --set B2=42 --set C3="=SUM(C2:C9)"`, or `--spec cells.json` | parse dates for you — write `2026-01-31` and format the cell, or pass a serial |
68
- | `append_rows.py` | `--sheet S --rows '[[...],[...]]'`, or `--rows-file rows.json` | extend an Excel Table, copy the row above's formula, or grow charts and conditional formats |
69
- | `style_cells.py` | `--sheet S --range A1:D1 --style '{"bold":true}'`, or `--spec styles.json` | autofit columns or restyle cells outside the range |
70
- | `add_chart.py` | `--sheet S --type line --data-min-col ... --cat-min-row ...`, or `--spec chart.json` | set axis number formats, series colours, or a legend position; a one-row data range is treated as one series of many points |
71
- | `add_image.py` | `--sheet S --path logo.png --anchor B2 [--width 480]` | update an embedded image when the file on disk changes |
57
+ - `sheet_ops.py` — `--add NAME`, `--rename OLD=NEW`, `--delete NAME`, `--order "A,B,C"`. Renaming a sheet does not update the formulas that point at it; deleting the last sheet is refused.
58
+ - `set_cells.py` — `--sheet S --set B2=42 --set C3="=SUM(C2:C9)"`, or `--spec cells.json`. It does not parse dates for you: write `2026-01-31` and format the cell, or pass a serial.
59
+ - `append_rows.py` — `--sheet S --rows '[[...],[...]]'`, or `--rows-file rows.json`. It does not extend an Excel Table, copy the row above's formula, or grow charts and conditional formats.
60
+ - `style_cells.py` — `--sheet S --range A1:D1 --style '{"bold":true}'`, or `--spec styles.json`. No autofit, and it will not restyle cells outside the range.
61
+ - `add_chart.py` — `--sheet S --type line --data-min-col ... --cat-min-row ...`, or `--spec chart.json`. It cannot set axis number formats, series colours, or a legend position, and a one-row data range is treated as one series of many points.
62
+ - `add_image.py` — `--sheet S --path logo.png --anchor B2 [--width 480]`. It cannot update an embedded image when the file on disk changes.
63
+
64
+ Chain by naming outputs: `set_cells.py --input book.xlsx --out step1.xlsx`, then `style_cells.py --input step1.xlsx --out step2.xlsx`; without `--out` each tool writes `book-edited.xlsx` next to the input and the next step would read the unedited original.
72
65
 
73
- Chain them by naming the output: `set_cells.py --input book.xlsx --out step1.xlsx`, then `style_cells.py --input step1.xlsx --out step2.xlsx`. Without `--out` each tool writes `book-edited.xlsx` next to the input and the next step would read the unedited original.
66
+ Values: numbers, booleans, `null`, and JSON arrays parse; anything else is text, and a leading `=` is stored as a formula. `--set B3=` stores an empty string, which is not a blank cell — leave a cell out of the assignment to keep it blank.
74
67
 
75
- Values: numbers, booleans, `null`, and JSON arrays parse; anything else is text, and a leading `=` is stored as a formula. `--set B3=` stores an empty string, which is not the same as a blank cell — leave a cell out of the assignment to keep it blank.
68
+ Runnable invocations with real paths: `tasks/edit-workbook.md` `## Mutation tools`.
76
69
 
77
70
  ## Formulas you will write
78
71
 
79
- Write the formula text a person would type; openpyxl stores it verbatim and never evaluates it.
72
+ Write the formula text a person would type. openpyxl stores it verbatim and never evaluates it.
80
73
 
81
74
  - Anchoring: `C8` moves when filled, `C$4` pins the row (a period header), `$A8` pins the column (an item label), `$B$3` pins one cell (a rate or case selector). `=SUMIFS(Amount,Month,C$4,Item,$A8)` is the shape a grid needs.
82
75
  - Aggregation: `SUM`, `SUMIFS`, `COUNTIFS`, `AVERAGEIFS`, `SUMPRODUCT` for quantity × rate pairs, `PRODUCT` for chained factors (it silently skips blanks, so a missing input looks valid).
@@ -85,7 +78,7 @@ Write the formula text a person would type; openpyxl stores it verbatim and neve
85
78
  - No `LET`, no dynamic arrays, no `LAMBDA`: the engines that read these files disagree on them.
86
79
  - Cross-sheet references quote the name: `='Build'!E14`, `='Case A'!$B$4`.
87
80
 
88
- After writing formulas, recalculate before anyone reads a number — see `## Verify`.
81
+ Recalculate before anyone reads a number — see `## Verify`. Patterns and dates: `references/formula-patterns.md`.
89
82
 
90
83
  ## Tasks
91
84
 
@@ -107,8 +100,8 @@ Background: `references/workbook-structure.md` (tab roles and layout), `referenc
107
100
 
108
101
  ## Edit discipline
109
102
 
110
- An existing workbook is the reference: its structure, formula style, formats, and terminology are what the user expects to keep seeing. Change the cells the request names and the formulas those cells feed. Everything else — other sheets, pivot sources, shared formulas, named ranges, conditional formats, data validation, protection, hidden rows, freeze panes, chart contents — stays untouched unless the request or a real dependency forces it. Never flatten formulas to values because it is easier, never autofit whole sheets for a visual tweak, and never quietly repair errors the user did not ask about: list them and ask. Details and failure modes: `tasks/edit-workbook.md`.
103
+ An existing workbook is the reference: its structure, formula style, formats, and terminology are what the user expects to keep seeing. Change the cells the request names and the formulas those cells feed. Everything else — other sheets, pivot sources, shared formulas, named ranges, conditional formats, data validation, protection, hidden rows, freeze panes, chart contents — stays untouched unless the request or a real dependency forces it. Never flatten formulas to values because it is easier, never autofit whole sheets for a visual tweak, and never quietly repair errors the user did not ask about: list them and ask. Failure modes: `tasks/edit-workbook.md`.
111
104
 
112
105
  ## Shared workflow
113
106
 
114
- Follow `"<shared>/common-workflow.md"` for the create-or-edit decision, the failure ladder, and the edit naming rule, and `"<shared>/annotation-recipes.md"` for the payload shapes the client sends.
107
+ `"<shared>/common-workflow.md"` owns the create-or-edit decision, the failure ladder, and the edit naming rule. `"<shared>/annotation-recipes.md"` owns the payload shapes the client sends.