dsh-office-kit 0.4.1 → 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 (116) hide show
  1. package/assets/skills/excel-live-control/SKILL.md +120 -148
  2. package/assets/skills/excel-live-control/container_tools/live_excel.py +9 -0
  3. package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
  4. package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
  5. package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
  6. package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
  7. package/assets/skills/excel-live-control/references/office-automation.md +127 -153
  8. package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
  9. package/assets/skills/excel-live-control/style_guidelines.md +56 -64
  10. package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
  11. package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
  12. package/assets/skills/office-documents/SKILL.md +24 -60
  13. package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
  14. package/assets/skills/office-documents/ooxml/comments.md +8 -8
  15. package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
  16. package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
  17. package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
  18. package/assets/skills/office-documents/references/docx-structure.md +11 -13
  19. package/assets/skills/office-documents/references/template-elicitation.md +11 -13
  20. package/assets/skills/office-documents/references/writing-quality.md +20 -20
  21. package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
  22. package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
  23. package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
  24. package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
  25. package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
  26. package/assets/skills/office-documents/tasks/create_edit.md +14 -16
  27. package/assets/skills/office-documents/tasks/equations.md +17 -28
  28. package/assets/skills/office-documents/tasks/fields_update.md +14 -16
  29. package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
  30. package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
  31. package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
  32. package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
  33. package/assets/skills/office-documents/tasks/images_figures.md +15 -25
  34. package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
  35. package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
  36. package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
  37. package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
  38. package/assets/skills/office-documents/tasks/read_review.md +9 -20
  39. package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
  40. package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
  41. package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
  42. package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
  43. package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
  44. package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
  45. package/assets/skills/office-documents/tasks/verify_render.md +11 -23
  46. package/assets/skills/office-documents/tasks/watermarks_background.md +11 -15
  47. package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +9 -9
  48. package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
  49. package/assets/skills/office-pdf/SKILL.md +36 -51
  50. package/assets/skills/office-pdf/references/form-fields.md +20 -20
  51. package/assets/skills/office-pdf/references/geometry.md +10 -10
  52. package/assets/skills/office-pdf/references/layout-quality.md +13 -13
  53. package/assets/skills/office-pdf/references/limits.md +12 -56
  54. package/assets/skills/office-pdf/tasks/annotations.md +5 -5
  55. package/assets/skills/office-pdf/tasks/create.md +6 -9
  56. package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
  57. package/assets/skills/office-pdf/tasks/forms.md +15 -15
  58. package/assets/skills/office-pdf/tasks/read.md +9 -9
  59. package/assets/skills/office-pdf/tasks/redact.md +18 -18
  60. package/assets/skills/office-pdf/tasks/stamp.md +10 -10
  61. package/assets/skills/office-presentations/SKILL.md +71 -91
  62. package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
  63. package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
  64. package/assets/skills/office-presentations/recipes/README.md +24 -35
  65. package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
  66. package/assets/skills/office-presentations/recipes/connectors.md +11 -12
  67. package/assets/skills/office-presentations/recipes/images.md +11 -12
  68. package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
  69. package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
  70. package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
  71. package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
  72. package/assets/skills/office-presentations/recipes/tables.md +14 -14
  73. package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
  74. package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
  75. package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
  76. package/assets/skills/office-presentations/references/finalization.md +10 -12
  77. package/assets/skills/office-presentations/references/native-bullets.md +14 -18
  78. package/assets/skills/office-presentations/references/native-evidence.md +18 -32
  79. package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
  80. package/assets/skills/office-presentations/references/templates.md +31 -60
  81. package/assets/skills/office-presentations/routing/google_slides.md +4 -4
  82. package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
  83. package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
  84. package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
  85. package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
  86. package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
  87. package/assets/skills/office-presentations/tasks/template-following.md +23 -28
  88. package/assets/skills/office-spreadsheets/SKILL.md +32 -39
  89. package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
  90. package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
  91. package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
  92. package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
  93. package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
  94. package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
  95. package/assets/skills/office-spreadsheets/references/charts.md +15 -34
  96. package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
  97. package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
  98. package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
  99. package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
  100. package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
  101. package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
  102. package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
  103. package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
  104. package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
  105. package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
  106. package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
  107. package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
  108. package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
  109. package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
  110. package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
  111. package/assets/skills/shared/annotation-recipes.md +98 -120
  112. package/assets/skills/shared/common-workflow.md +70 -80
  113. package/dist/index.js +105 -29
  114. package/package.json +1 -1
  115. package/postinstall.mjs +58 -17
  116. package/python/office_cli.py +70 -7
@@ -1,46 +1,42 @@
1
1
  ---
2
- description: Drive a workbook that is already open in Excel or WPS Spreadsheets over COM — read cells, write values and formulas, style ranges, add charts and tables, recalculate, save, and report the exact ranges touched.
2
+ description: Drive a workbook that is already open in Excel or WPS Spreadsheets on Windows over COM: read cells, write values and formulas, style ranges, add charts and tables, recalculate, save, and report the exact ranges touched.
3
3
  ---
4
4
 
5
5
  # Live spreadsheets (Excel / WPS)
6
6
 
7
- ## What "live" means here
7
+ Windows only. Drives an open Excel or WPS Spreadsheets window through COM with Windows
8
+ PowerShell 5.1 (`Marshal.GetActiveObject`; PowerShell 7 dropped it). On macOS and Linux
9
+ every command exits `3` with `stage: "powershell"` and a remedy; use the file-based `xlsx`
10
+ verbs there.
8
11
 
9
- The workbook is open in a running Excel or WPS Spreadsheets window, and the user is
10
- looking at it. The file on disk may be behind the window, may not exist yet, and may
11
- carry edits the user has not saved. A live call changes the *open document*: the cells
12
- the user is staring at update while they watch, and saving is a separate decision.
12
+ ## What "live" means here
13
13
 
14
- That one sentence drives everything below:
14
+ The workbook is open and the user is watching. The disk file may lag the window, not exist
15
+ yet, or hold unsaved edits. A live call changes the open document; saving is a separate
16
+ decision.
15
17
 
16
- - The target is `Application.ActiveWorkbook`-shaped state, not a path. Address it by
17
- workbook name, sheet name and A1 range, never by "the active sheet" or "the selection".
18
- - Nothing is transactional. A failed call leaves whatever already landed exactly where
19
- it landed. Read before retrying; never replay a half-applied batch.
20
- - The disk file is not the deliverable. What the user sees in the window is. Saving is
21
- an explicit act you announce.
18
+ - Address the open state, not a path: workbook name, sheet name, A1 range. Never "the
19
+ active sheet" or "the selection".
20
+ - Nothing is transactional. A failed call leaves what landed. Read before retrying; never
21
+ replay a half-applied batch.
22
+ - What the user sees matters, not the file on disk.
22
23
 
23
24
  ## Live or file editing?
24
25
 
25
26
  | Situation | Route |
26
27
  | --- | --- |
27
28
  | The user says the file is open, or asks for "the sheet I'm looking at" | this skill |
28
- | They want to watch cells change, iterate on a model with them, or add a chart to the visible sheet | this skill |
29
- | No spreadsheet application is running | `../office-spreadsheets/SKILL.md` — edit the file, then tell them to reopen it |
30
- | Bulk generation, batch jobs, CI, or work that outlives the session | `../office-spreadsheets/SKILL.md` |
31
- | Reading a file to answer a question, with no app open | `../office-spreadsheets/SKILL.md` |
29
+ | They want to watch cells change, iterate on a model, or add a chart to the visible sheet | this skill |
30
+ | Nothing is running, or the job is bulk/CI work, outlives the session, or is a question about a file | `../office-spreadsheets/SKILL.md` — edit the file, then tell them to reopen it |
32
31
 
33
- Never force the live path. If nothing is running, do not launch an application to avoid
34
- talking to the user: say plainly that the workbook must be open, or switch to the file
35
- route and say so.
32
+ Never force the live path. If nothing is running, say the workbook must be open, or switch
33
+ to the file route and say so. Do not launch an application.
36
34
 
37
35
  ## Before you touch anything
38
36
 
39
- 1. Call the `office_status` tool, then take the `## Office runtime` JSON block that the
40
- host appends to `../office-spreadsheets/SKILL.md` (this sub-skill is routed from
41
- there, so that block is where the paths live). Use its `python` value verbatim and
42
- quote every path; this pack's directory is `<skill>/../excel-live-control`, which is
43
- what `<skill>` below means.
37
+ 1. Call `office_status`. The runtime block in `../office-spreadsheets/SKILL.md` holds the
38
+ verified paths: `python` runs these scripts, and its `skill` value is the
39
+ office-spreadsheets directory, so this pack is `<skill>/../excel-live-control`. Quote every path.
44
40
  2. Run `"<python>" "<skill>/container_tools/live_excel.py" --help` once per session.
45
41
  3. Attach and look before writing:
46
42
 
@@ -48,76 +44,64 @@ route and say so.
48
44
  "<python>" "<skill>/container_tools/live_excel.py" info
49
45
  ```
50
46
 
51
- `info` lists every open workbook, the target workbook, its sheets, and per sheet the
52
- used range, charts, tables, pivot tables and protection state.
53
-
54
- 4. If attach fails, the JSON carries a `remediation` string. Relay it as written: open
55
- the workbook in Excel or WPS and keep it open, then ask for the change again. Do not
56
- start an application on the user's behalf.
57
- 5. If more than one workbook is open, the tool refuses to guess. Pass `--workbook` with
58
- the file name (`Budget FY26.xlsx`) or enough of the path to be unambiguous.
59
- 6. Something looks wrong with the environment — attach works but calls fail, or the
60
- application name and vendor disagree — run `--diagnose`. It reports the attach
61
- mechanism, the running application, every workbook and every sheet without mutating
62
- anything.
63
-
64
- Attachment uses `[Runtime.InteropServices.Marshal]::GetActiveObject` from Windows
65
- PowerShell 5.1, trying `Excel.Application` then `Ket.Application` (WPS Spreadsheets).
66
- WPS registers `Excel.Application` as an alias, so the reported application name is not
67
- proof of which product is running; the JSON's `engine.vendor` is derived from
68
- `Application.Path`. Mechanics and the COM object model: `references/office-automation.md`.
47
+ `info` lists open workbooks, the target workbook, its sheets, and per sheet the used
48
+ range, charts, tables, pivots and protection.
49
+ 4. Attach failure returns a `remediation` string. Relay it as written: open the workbook in
50
+ Excel or WPS and keep it open, then retry. Never start an application for the user.
51
+ 5. Several workbooks open: the tool refuses to guess. Pass `--workbook` with a file name
52
+ (`Budget FY26.xlsx`) or an unambiguous path fragment.
53
+ 6. Attach works but calls fail, or name and vendor disagree: run `--diagnose` for the
54
+ attach mechanism, application, workbooks and sheets, with no mutation.
55
+
56
+ Attachment tries `Excel.Application` then `Ket.Application` (WPS). WPS registers
57
+ `Excel.Application` as an alias, so the app name proves nothing; `engine.vendor` comes from
58
+ `Application.Path`. COM object model: `references/office-automation.md`.
69
59
 
70
60
  ## The edit contract
71
61
 
72
- These are not preferences. Every mutating call has to satisfy them.
73
-
74
- - **Touch only what was asked for.** The named sheet and the named ranges. Not the
75
- neighbouring column, not the whole sheet, not "while I'm here".
76
- - **Read before you write.** Call `read_range` on the target first. You need to know
77
- whether a cell holds a value, a formula, or a merged-region fragment, and whether the
78
- user's edits are unsaved before you replace them.
79
- - **Never destroy structure you did not create**: formulas (never flatten to values),
80
- named ranges, conditional formats, shared formulas, data validation, pivots and their
81
- sources, chart series definitions, filters, hidden rows, freeze panes, protection.
82
- - **Never clear more than you can name.** `write_range --clear` clears contents of an
83
- explicit range; it does not remove charts, tables or formats. Clearing a used range to
84
- "start clean" is off-limits.
85
- - **Small writes, batched.** One call per logical block (a column of assumptions, a
86
- sheet of outputs). Rectangular data only: if the range is 6 rows × 2 columns, the JSON
87
- array must be 6 rows of 2 values.
88
- - **Report exactly what you touched.** Every mutating op answers with workbook name and
89
- path, sheet, exact address, row/column/cell counts, and a `warnings` list. Quote that
90
- in your reply — "wrote `Assumptions!C4:D8` (10 cells)" — not "updated the assumptions".
91
- - **Saving is a separate, announced act.** See Delivery.
92
- - **No decorative edits without a request.** Do not restyle a sheet to your taste, do not
93
- autofit whole columns, do not add a header row the user did not ask for.
94
-
95
- If a call fails partway, `read_range` the block you were writing and continue from what
96
- actually landed. Retrying the identical call is how duplicate rows and reversed edits
97
- happen.
62
+ Every mutating call must satisfy these.
63
+
64
+ - **Touch only what was asked for** — the named sheet and ranges.
65
+ - **Read before you write.** `read_range` the target: value, formula or merged fragment,
66
+ and whether user edits are unsaved.
67
+ - **Never destroy structure you did not create**: formulas (never flatten to values), named
68
+ ranges, conditional formats, shared formulas, data validation, pivots and sources, chart
69
+ series, filters, hidden rows, freeze panes, protection.
70
+ - **Never clear more than you can name.** `write_range --clear` clears an explicit range's
71
+ contents; charts, tables and formats survive. Never clear a used range to "start clean".
72
+ - **Batch small writes.** One call per logical block; rectangular only. A 6 × 2 range takes
73
+ 6 rows of 2 values.
74
+ - **Report exactly what you touched.** Every mutating op returns workbook name and path,
75
+ sheet, address, row/column/cell counts and `warnings`. Quote it — "wrote
76
+ `Assumptions!C4:D8` (10 cells)" — not "updated the assumptions".
77
+ - **Saving is separate and announced.** See Delivery.
78
+ - **No decorative edits without a request.** No restyling, whole-column autofit, or
79
+ unrequested header row.
80
+
81
+ If a call fails partway, `read_range` the block and continue from what landed; retrying
82
+ the identical call duplicates rows and reverses edits.
98
83
 
99
84
  ## The tool
100
85
 
101
- `"<skill>/container_tools/live_excel.py"` — one command per operation, one JSON object on
102
- stdout, non-zero exit on failure. It shells out to `powershell.exe`; pywin32, comtypes and
103
- Excel interop assemblies are neither used nor needed.
86
+ `"<skill>/container_tools/live_excel.py"` runs one command per operation, prints one JSON
87
+ object, and exits non-zero on failure. It shells out to `powershell.exe`; pywin32, comtypes
88
+ and Excel interop assemblies are neither used nor needed.
104
89
 
105
90
  | Op | Does | Key options |
106
91
  | --- | --- | --- |
107
- | `info` | workbooks, target workbook, sheet inventory | `--workbook` |
108
- | `read_range` | typed values, optionally formulas and displayed text | `--sheet --range`, `--formulas`, `--display`, `--max-cells` |
109
- | `write_range` | one rectangular block of values | `--sheet --range --data`/`--data-file`, `--clear` |
110
- | `set_formula` | a formula filled across a range, or a cell→formula map | `--range --formula`, or `--cells '{"C1":"=A1+B1"}'`/`--cells-file`, `--r1c1` |
92
+ | `info` | workbooks, target, sheet inventory | `--workbook` |
93
+ | `read_range` | typed values; optional formulas, display text | `--sheet --range`, `--formulas`, `--display`, `--max-cells` |
94
+ | `write_range` | a rectangular block of values | `--sheet --range --data`/`--data-file`, `--clear` |
95
+ | `set_formula` | one formula filled across a range, or a cell→formula map | `--range --formula`, or `--cells '{"C1":"=A1+B1"}'`/`--cells-file`, `--r1c1` |
111
96
  | `style_range` | font, fill, number format, alignment, borders, width, merge | `--style` JSON or `--style-file`, `--merge` |
112
97
  | `add_table` | native table (ListObject) over a range | `--name`, `--style TableStyleMedium2`, `--no-headers` |
113
- | `add_chart` | embedded chart pointed at a range | `--type`, `--data`, `--anchor`, `--title`, `--width`, `--height` |
98
+ | `add_chart` | embedded chart at an anchor, over a source range | `--type`, `--data`, `--anchor`, `--title`, `--width`, `--height` |
114
99
  | `recalc` | `CalculateFull` on every open workbook | — |
115
- | `save` | save in place, or `SaveAs` a copy | `--path` |
116
- | `close` | close the workbook, optionally quit the application | `--save`, `--discard`, `--quit-app` |
100
+ | `save` | in place, or `SaveAs` a copy | `--path` |
101
+ | `close` | close the workbook, optionally quit the app | `--save`, `--discard`, `--quit-app` |
117
102
 
118
- Global options on every op: `--workbook NAME|PATH`, `--timeout SECONDS` (default 180;
119
- a live call is allowed to take seconds), and `--launch-hidden` (**self-tests only** — it
120
- starts a hidden application, which is wrong for any user-facing edit).
103
+ Global options on every op: `--workbook NAME|PATH`, `--timeout SECONDS` (default 180) and
104
+ `--launch-hidden` (**self-tests only** — a hidden app is wrong for user edits).
121
105
 
122
106
  Style keys: `font_name`, `font_size`, `bold`, `italic`, `color`, `fill` (hex RGB, e.g.
123
107
  `#FFF2CC`), `number_format`, `h_align` (`left|center|right|general|justify`), `v_align`
@@ -138,96 +122,84 @@ Typical first calls:
138
122
  ```
139
123
 
140
124
  Failures print `{"ok": false, "stage": "...", "error": "...", "remediation": "..."}` and
141
- exit 1 (2 for usage errors, 3 when PowerShell itself is unavailable). `stage: "attach"`
142
- means nothing was running; `stage: "com"` means the application refused or failed the
143
- call; read the message before changing the approach.
125
+ exit `1` (operation failure), `2` (usage) or `3` (PowerShell unavailable, timed out, or
126
+ non-Windows). Stages: `attach` (nothing running), `com` (application refused the call),
127
+ `timeout` (dialog or oversized batch), `powershell` (no usable PowerShell), `usage` (bad
128
+ arguments). Read the message before changing approach.
144
129
 
145
- The CLI is the fast path, not the ceiling. When a job needs a COM call it does not wrap —
146
- a sheet tab, freeze panes, a pivot, data validation, shape geometry — extend the script or
147
- drive the application from a short PowerShell snippet, and keep the same reporting and
148
- verification rules. The object model is in `references/office-automation.md`.
130
+ The CLI is the fast path, not the ceiling. For a COM call it does not wrap (a sheet tab,
131
+ freeze panes, a pivot, data validation, shape geometry), extend the script or drive the app
132
+ from a short PowerShell snippet, keeping the reporting and verification rules. Object
133
+ model: `references/office-automation.md`.
149
134
 
150
- What this tool deliberately does not do: create, rename, delete or reorder sheets; delete
151
- ranges or objects; run macros; open a file from disk. A job that needs one of those asks
152
- the user for it, or belongs to the file route in `../office-spreadsheets/SKILL.md`.
135
+ The tool does not create, rename, delete or reorder sheets; delete ranges or objects; run
136
+ macros; or open a file. Such a job asks the user for it, or uses the file route in
137
+ `../office-spreadsheets/SKILL.md`.
153
138
 
154
139
  ## Verification
155
140
 
156
- Do these in order after every batch of edits, before you report anything as done.
157
-
158
- 1. **Read it back.** `read_range` the exact ranges you wrote, with `--formulas` when you
159
- wrote formulas. Compare against what you intended cell by cell.
160
- 2. **No error cells.** The `errors` array in `read_range` lists every cell whose *live*
161
- value is an error (`#DIV/0!`, `#VALUE!`, `#REF!`, `#NAME?`, `#N/A`, …) with its
162
- formula and address. An edit that leaves an error is not finished. A pre-existing
163
- error you did not cause is reported to the user, not silently fixed.
164
- 3. **Numbers.** Run `recalc` after adding or changing formulas, then read the cells
165
- again. A formula that has not been calculated tells you nothing.
166
- 4. **Objects.** If you added a table or chart, run `info` and confirm it in the sheet's
167
- inventory, and read the chart's `source` from `add_chart`'s reply to confirm it points
168
- at the range you meant.
169
- 5. **Appearance.** You cannot screenshot the user's window from here. `--display` on
170
- `read_range` shows the rendered text of each cell (up to 500), which catches `###`
171
- widths, applied number formats and stray `#` — use it when formatting is part of the
172
- request. Otherwise say the visual check is the user's, and ask them to confirm if it
173
- matters.
174
- 6. **Structure.** If the sheet had tables, pivots or charts before you started, `info`
175
- after the edit proves they are still there.
176
- 7. **Report.** Name the workbook, the sheet, every range, and the cell counts.
141
+ After every batch, in order, before reporting done:
142
+
143
+ 1. **Read it back.** `read_range` every range you wrote, `--formulas` when you wrote
144
+ formulas; compare cell by cell.
145
+ 2. **No error cells.** `errors` lists every live error cell (`#DIV/0!`, `#VALUE!`, `#REF!`,
146
+ `#NAME?`, `#N/A`, …) with formula and address. An edit that leaves an error is
147
+ unfinished. Report a pre-existing error; do not silently fix it.
148
+ 3. **Numbers.** `recalc` after formula changes, then re-read. An uncalculated formula tells
149
+ you nothing.
150
+ 4. **Objects.** After adding a table or chart, `info` confirms it in the sheet inventory;
151
+ `add_chart`'s `source` confirms the source range.
152
+ 5. **Appearance.** You cannot screenshot the user's window. `--display` shows up to 500
153
+ cells of rendered text and catches `###`, applied number formats and stray `#`; use it
154
+ when formatting matters. Otherwise the visual check is the user's — ask them to confirm.
155
+ 6. **Structure.** `info` after the edit proves pre-existing tables, pivots and charts
156
+ survive.
157
+ 7. **Report.** Workbook, sheet, every range, cell counts.
177
158
 
178
159
  ## Delivery
179
160
 
180
- The workbook is the user's open document, not an artifact you produced. Say what you did
181
- and what state the document is in; do not save quietly.
182
-
183
- - **Default: leave the document modified and unsaved.** The change is visible in their
184
- window. Tell them so, and tell them Ctrl+S keeps it. This is what keeps you from
185
- overwriting a file they were editing by hand.
186
- - **They asked you to save**: `save` with no `--path` writes the workbook over its own
187
- file. Say "saved `Budget FY26.xlsx`" and give the full path from the reply.
188
- - **Unsaved workbook, or they want an artifact to keep**: `save --path <copy>.xlsx`
189
- writes a copy and leaves the original window dirty. Then `present` that copy — it is a
190
- real file they can open, send, or archive.
191
- - **`.xlsx` in chat**: a path on its own is not delivery. Use the `present` tool on a
192
- saved file, and state both paths when the original and the copy differ.
193
- - **Never** save over the user's file to "make sure it's persisted" without telling them,
194
- and never close their workbook. `close --quit-app` is for cleaning up a self-test
195
- instance, not for tidying the user's desktop.
196
- - If the edit failed partway and the document is dirty with a half-finished change, say
197
- exactly which ranges landed, and offer either to finish them or to close without saving.
161
+ The workbook is the user's document; state what you did and its state. Never save quietly.
162
+
163
+ - **Default: modified and unsaved.** Say so, and that Ctrl+S keeps it. Never overwrite a
164
+ file they were editing by hand.
165
+ - **They asked to save**: `save` with no `--path` overwrites the workbook's file. Say
166
+ "saved `Budget FY26.xlsx`" with the full path from the reply.
167
+ - **Unsaved workbook, or an artifact is wanted**: `save --path <copy>.xlsx` writes a copy
168
+ and leaves the original dirty. `present` that copy.
169
+ - **`.xlsx` in chat**: a path alone is not delivery. `present` a saved file; state both
170
+ paths when original and copy differ.
171
+ - **Never** save over the user's file "to make sure" without telling them, and never close
172
+ their workbook. `close --quit-app` is for self-test cleanup, not the user's desktop.
173
+ - If the edit failed partway, say exactly which ranges landed and offer to finish them or
174
+ close without saving.
198
175
 
199
176
  ## What good content looks like
200
177
 
201
- The mechanics above keep the document intact; these rules keep it useful. The same rules
202
- as the file-editing skill, because a careless live edit damages a document the user is
203
- looking at.
204
-
205
- - **Structure by role, not by tab count.** Inputs, assumptions, calculations, outputs.
206
- Outputs on the left of the tab strip, builds in the middle, inputs on the right; a
207
- terminal check/audit tab for models that need one. Do not restructure a workbook the
208
- user already organised — `workflows/edit_workflows.md`.
209
- - **Formulas that a reviewer can audit.** Anchored references (`$B$3`, `C$4`, `$A8`),
178
+ - **Structure by role, not tab count.** Inputs, assumptions, calculations, outputs. Outputs
179
+ at the left of the tab strip, builds in the middle, inputs on the right; a terminal
180
+ check/audit tab if the model needs one. Do not restructure a workbook the user already
181
+ organised — `workflows/edit_workflows.md`.
182
+ - **Formulas a reviewer can audit.** Anchored references (`$B$3`, `C$4`, `$A8`),
210
183
  `SUMIFS`/`COUNTIFS`/`AVERAGEIFS` over hand-rolled sums, short `IF`, no blanket
211
184
  `IFERROR(...,0)` (`#VALUE!` is information), no `LET`/`LAMBDA`/spill arrays.
212
- `workflows/create_workflows.md` and `references/office-automation.md` for what COM
185
+ `workflows/create_workflows.md` and `references/office-automation.md` explain what COM
213
186
  stores when you write these.
214
187
  - **Typed values.** Numbers as numbers, dates as dates, one number format per column.
215
188
  Invariant format codes (`#,##0`, `0.0%`, `"$"#,##0.00`) — never swap `.` and `,`.
216
189
  - **Reading someone else's workbook is read-only.** `references/read_only_qna.md`.
217
- - **Domain conventions** — finance, healthcare, marketing, scientific data — carry real
218
- meaning in their cells: `domain_guidance/`. Read the matching file before modelling in
219
- that area.
190
+ - **Domain conventions** — finance, healthcare, marketing, scientific data — read the
191
+ matching `domain_guidance/` file before modelling.
220
192
  - **Visual defaults** (headers, input fills, borders, tab colours, one font family):
221
193
  `style_guidelines.md`.
222
- - **Citations** for external data go next to the input table they support, not in a
223
- tab of their own.
194
+ - **Citations** for external data go next to the input table they support, not in a tab of
195
+ their own.
224
196
 
225
197
  ## Files in this skill
226
198
 
227
199
  | File | Use it when |
228
200
  | --- | --- |
229
- | `references/office-automation.md` | you need the COM object model: addressing, `Value2` vs `Formula`, colour encoding, locale, latency |
230
- | `references/read_only_qna.md` | answering a question about the open workbook without changing it |
201
+ | `references/office-automation.md` | COM object model: addressing, `Value2` vs `Formula`, colour, locale, latency |
202
+ | `references/read_only_qna.md` | answering a question without changing the workbook |
231
203
  | `style_guidelines.md` | the request involves how the sheet looks |
232
204
  | `workflows/create_workflows.md` | building a new sheet or workbook live |
233
205
  | `workflows/edit_workflows.md` | changing cells in a workbook the user already built |
@@ -605,6 +605,15 @@ def main() -> int:
605
605
  except ToolError as error:
606
606
  return emit(failure_payload(op, error), 2)
607
607
 
608
+ # macOS and Linux ship pwsh but no COM, and `shutil.which('powershell')` can find
609
+ # that binary; fail on the platform instead of surfacing a cryptic attach error.
610
+ if sys.platform != "win32":
611
+ return emit(failure_payload(op, ToolError(
612
+ "Excel/WPS live control drives the application through Windows PowerShell 5.1 "
613
+ "COM, which only exists on Windows",
614
+ "powershell",
615
+ )), 3)
616
+
608
617
  request = {
609
618
  "op": op,
610
619
  "launch_hidden": bool(getattr(args, "launch_hidden", False)),
@@ -1,7 +1,6 @@
1
1
  # Financial models
2
2
 
3
- Financial modelling has a short list of distinctions that decide whether a sheet is
4
- right, and a live edit makes each of them visible to a user who is watching.
3
+ A live edit makes every modelling distinction visible to a watching user.
5
4
 
6
5
  ## The distinctions that matter
7
6
 
@@ -11,76 +10,61 @@ right, and a live edit makes each of them visible to a user who is watching.
11
10
  | Payroll expense | Cash paid to employees — accruals, timing, employer costs |
12
11
  | Capex | Depreciation / amortisation — cash out once, expense over life |
13
12
  | Earnings | Cash flow — working capital, non-cash items, financing |
14
- | Budget | Forecast — one is a target, the other an expectation; never mix them silently |
13
+ | Budget | Forecast — a target vs an expectation; never mix them silently |
15
14
 
16
- Also, before typing a number: which fiscal calendar, which horizon (monthly / quarterly /
17
- annual), and which grain (total company, segment, product)? A number without those three
18
- is not a model input.
19
-
20
- Actuals and forecast must be visibly different (a divide, a label, a different fill). The
21
- reader has to know where history stops.
15
+ Establish fiscal calendar, horizon (monthly / quarterly / annual) and grain (company,
16
+ segment, product) before typing a number; without all three it is not a model input. Show
17
+ actuals and forecast apart (divide, label or fill) so the reader sees where history stops.
22
18
 
23
19
  ## Schedules
24
20
 
25
- Build a driver schedule per line, then a statement, then the output. Each step is a range
26
- the user can audit:
27
-
28
- - **Revenue**: volume × price, with mix if there are segments; recognition timing if
29
- contracts span periods. Do not model revenue as a straight growth percentage unless the
30
- user asked for that — it hides the drivers.
31
- - **Payroll**: headcount, FTE and paid FTE are three different numbers. Prorate hires and
32
- exits by month; do not divide an annual salary by 12 twice (an annual figure already
33
- contains the monthly rate); make the commission and employer-cost basis explicit.
34
- - **Opex**: units × rate, fixed amounts, or one-time costs — say which. A growing opex line
35
- needs a driver, not a percent of revenue, unless that is the stated policy.
36
- - **D&A**: cost, residual value, in-service date, useful life, convention. Reconcile gross
37
- asset and accumulated depreciation roll-forwards to the prior period.
38
- - **Statements**: retained earnings rolls from opening + net income − dividends; the
39
- cash-flow statement's ending cash equals the balance sheet's cash. If it does not, there
40
- is a plug, and a plug is a finding, not a fix.
41
-
42
- A worked unit check, done in the cells: actual salary cost $60,000 across 10 paid FTE is
43
- $6,000 per FTE; a forecast of $6,300 per FTE on 11 FTE gives $69,300 against $66,000 for
44
- the prior per-FTE rate — the difference is rate *and* headcount, and both drivers belong
45
- on separate rows. If either missing pay or zero FTE is in the source, the implied rate
46
- cannot be established; mark it unavailable, do not divide by zero and call it 0.
21
+ Build a driver schedule per line, then a statement, then the output.
22
+
23
+ - **Revenue**: volume × price; mix for segments; recognition timing for multi-period
24
+ contracts. No straight growth percentage unless the user asked.
25
+ - **Payroll**: headcount, FTE and paid FTE are three numbers. Prorate hires and exits by
26
+ month; never divide an annual salary by 12 twice; state commission and employer-cost basis.
27
+ - **Opex**: units × rate, fixed, or one-time — say which. A growing line needs a driver, not
28
+ a percent of revenue, unless that is stated policy.
29
+ - **D&A**: cost, residual value, in-service date, useful life, convention; reconcile
30
+ gross-asset and accumulated-depreciation roll-forwards to the prior period.
31
+ - **Statements**: retained earnings = opening + net income − dividends; cash-flow ending
32
+ cash = balance-sheet cash. A mismatch is a plug: report it, do not fix it.
33
+
34
+ Worked unit check, in the cells: $60,000 of salary over 10 paid FTE is $6,000 per FTE;
35
+ $6,300 per FTE × 11 is $69,300 against $66,000 at the prior rate — rate and headcount both
36
+ moved, so both need a row. Missing pay or zero FTE: implied rate unavailable; never divide
37
+ by zero into 0.
47
38
 
48
39
  ## Refreshes and merges
49
40
 
50
- A refresh merges complete periods on the business key (a date that exists in the calendar,
51
- a product code that exists in the master). Never append a partial period as if it were
52
- complete, and never let a merge drop a dimension silently — report rows that did not match.
41
+ Merge complete periods on the business key (calendar date, master product code). Never append
42
+ a partial period as complete; never drop a dimension silently — report unmatched rows.
53
43
 
54
44
  ## Variances and audit
55
45
 
56
- - Variances need an amount **and** a percent. When the base is zero or missing, the percent
57
- is unavailable — write `n.a.`, not `0%`.
46
+ - A variance needs an amount **and** a percent. Zero or missing base: write `n.a.`, not `0%`.
58
47
  - Check totals: parts sum to the whole, schedules tie to statements, the bridge closes to
59
- zero. Compare to two decimals, including `0.00`; a check that passes at 0.01 is not
60
- passing.
61
- - Failed checks: light red fill (`#FFC7CE`) with bold red text (`#9C0006`), neutral for
62
- passes. Missing or untested data is "unavailable", never "PASS".
48
+ zero; compare to two decimals including `0.00`; a check that passes at 0.01 is failing.
49
+ - Failed checks: `#FFC7CE` fill with bold `#9C0006` text; passes stay neutral. Missing or
50
+ untested data is "unavailable", never "PASS".
63
51
 
64
52
  ## Valuation, if it comes up
65
53
 
66
- - Build the method the user asked for. A DCF needs drivers, tax, D&A, capex, working
67
- capital, unlevered free cash flow, the discounting convention, a terminal value method
68
- and the enterprise-to-equity bridge — skipping two of these is not a shortcut, it is a
69
- wrong answer.
70
- - IRR/XIRR need cash flows with valid signs and dates; a series with no sign change has no
71
- IRR, and the function returning `#NUM!` is the correct answer to report.
72
- - Sensitivities the user asks for belong in a native what-if data table, not in a grid of
73
- hand-typed scenarios that will drift.
54
+ - A DCF needs drivers, tax, D&A, capex, working capital, unlevered free cash flow, the
55
+ discounting convention, a terminal-value method and the enterprise-to-equity bridge;
56
+ skipping two is a wrong answer, not a shortcut.
57
+ - IRR/XIRR need valid signs and dates; with no sign change there is no IRR, and `#NUM!` is
58
+ the answer to report.
59
+ - Sensitivities belong in a native what-if data table, not a grid of hand-typed scenarios.
74
60
 
75
61
  ## Doing it live
76
62
 
77
- - Read the workbook before you model: `info` for tabs and objects, then
78
- `read_range --formulas` across the rows you are extending. Match the existing anchoring
79
- (`$C$4` for a rate, `C$9` for a period header) and the existing aggregation style
80
- (`SUMIFS` over hand-rolled sums).
81
- - Add one driver row at a time, each with a formula you can point at, and verify after each
82
- block; a 200-cell scenario grid written blind is the expensive way to fail.
83
- - If the model has a check tab, extend the checks to cover your new rows. If it has none
84
- and the model is small, add one labelled verification row next to the output.
85
- - Never write a hard-coded total when a formula can tie it. And never "fix" an existing
86
- `#REF!` — report it.
63
+ - Read first: `info` for tabs and objects; `read_range --formulas` over the rows you will
64
+ extend; match existing anchoring (`$C$4` rate, `C$9` period header) and `SUMIFS`
65
+ aggregation.
66
+ - One driver row at a time, each with a formula you can point at; verify after each block. A
67
+ 200-cell scenario grid written blind is the expensive way to fail.
68
+ - Extend the check tab to cover new rows; on a small model with none, add one labelled
69
+ verification row beside the output.
70
+ - Never hard-code a total a formula can tie; never "fix" an existing `#REF!` — report it.