@kortix/sandbox 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/config/customize.sh +143 -0
  2. package/config/kortix-env-setup.sh +25 -0
  3. package/kortix-master/package.json +22 -0
  4. package/kortix-master/src/config.ts +22 -0
  5. package/kortix-master/src/index.ts +44 -0
  6. package/kortix-master/src/routes/env.ts +65 -0
  7. package/kortix-master/src/routes/proxy.ts +108 -0
  8. package/kortix-master/src/routes/update.ts +185 -0
  9. package/kortix-master/src/services/proxy.ts +43 -0
  10. package/kortix-master/src/services/secret-store.ts +156 -0
  11. package/kortix-master/tsconfig.json +14 -0
  12. package/opencode/agents/kortix-browser.md +142 -0
  13. package/opencode/agents/kortix-build.md +62 -0
  14. package/opencode/agents/kortix-explore.md +66 -0
  15. package/opencode/agents/kortix-image-gen.md +33 -0
  16. package/opencode/agents/kortix-main.md +450 -0
  17. package/opencode/agents/kortix-plan.md +100 -0
  18. package/opencode/agents/kortix-research.md +84 -0
  19. package/opencode/agents/kortix-sheets.md +61 -0
  20. package/opencode/agents/kortix-slides.md +64 -0
  21. package/opencode/agents/kortix-web-dev.md +572 -0
  22. package/opencode/commands/email.md +36 -0
  23. package/opencode/commands/init.md +43 -0
  24. package/opencode/commands/journal.md +44 -0
  25. package/opencode/commands/memory-init.md +81 -0
  26. package/opencode/commands/memory-search.md +50 -0
  27. package/opencode/commands/memory-status.md +56 -0
  28. package/opencode/commands/research.md +36 -0
  29. package/opencode/commands/search.md +38 -0
  30. package/opencode/commands/slides.md +32 -0
  31. package/opencode/commands/spreadsheet.md +30 -0
  32. package/opencode/memory.json +37 -0
  33. package/opencode/ocx.jsonc +10 -0
  34. package/opencode/opencode.jsonc +103 -0
  35. package/opencode/package.json +25 -0
  36. package/opencode/patches/apply.sh +19 -0
  37. package/opencode/patches/opencode-pty-spawn.txt +49 -0
  38. package/opencode/plugin/background-agents.ts.disabled +483 -0
  39. package/opencode/plugin/kdco-primitives/get-project-id.ts +172 -0
  40. package/opencode/plugin/kdco-primitives/index.ts +26 -0
  41. package/opencode/plugin/kdco-primitives/log-warn.ts +51 -0
  42. package/opencode/plugin/kdco-primitives/mutex.ts +122 -0
  43. package/opencode/plugin/kdco-primitives/shell.ts +138 -0
  44. package/opencode/plugin/kdco-primitives/temp.ts +36 -0
  45. package/opencode/plugin/kdco-primitives/terminal-detect.ts +34 -0
  46. package/opencode/plugin/kdco-primitives/types.ts +13 -0
  47. package/opencode/plugin/kdco-primitives/with-timeout.ts +84 -0
  48. package/opencode/plugin/memory.ts +306 -0
  49. package/opencode/plugin/worktree/state.ts +412 -0
  50. package/opencode/plugin/worktree/terminal.ts +1002 -0
  51. package/opencode/plugin/worktree.ts +861 -0
  52. package/opencode/skills/KORTIX-browser/SKILL.md +478 -0
  53. package/opencode/skills/KORTIX-cron-triggers/SKILL.md +173 -0
  54. package/opencode/skills/KORTIX-deep-research/SKILL.md +278 -0
  55. package/opencode/skills/KORTIX-docx/SKILL.md +398 -0
  56. package/opencode/skills/KORTIX-docx/scripts/__init__.py +1 -0
  57. package/opencode/skills/KORTIX-docx/scripts/accept_changes.py +104 -0
  58. package/opencode/skills/KORTIX-docx/scripts/comment.py +244 -0
  59. package/opencode/skills/KORTIX-docx/scripts/office/helpers/__init__.py +0 -0
  60. package/opencode/skills/KORTIX-docx/scripts/office/helpers/merge_runs.py +199 -0
  61. package/opencode/skills/KORTIX-docx/scripts/office/helpers/simplify_redlines.py +197 -0
  62. package/opencode/skills/KORTIX-docx/scripts/office/pack.py +159 -0
  63. package/opencode/skills/KORTIX-docx/scripts/office/soffice.py +183 -0
  64. package/opencode/skills/KORTIX-docx/scripts/office/unpack.py +132 -0
  65. package/opencode/skills/KORTIX-docx/scripts/office/validate.py +111 -0
  66. package/opencode/skills/KORTIX-docx/scripts/office/validators/__init__.py +15 -0
  67. package/opencode/skills/KORTIX-docx/scripts/office/validators/base.py +847 -0
  68. package/opencode/skills/KORTIX-docx/scripts/office/validators/docx.py +446 -0
  69. package/opencode/skills/KORTIX-docx/scripts/office/validators/pptx.py +275 -0
  70. package/opencode/skills/KORTIX-docx/scripts/office/validators/redlining.py +247 -0
  71. package/opencode/skills/KORTIX-docx/scripts/render_docx.py +179 -0
  72. package/opencode/skills/KORTIX-docx/scripts/templates/comments.xml +3 -0
  73. package/opencode/skills/KORTIX-docx/scripts/templates/commentsExtended.xml +3 -0
  74. package/opencode/skills/KORTIX-docx/scripts/templates/commentsExtensible.xml +3 -0
  75. package/opencode/skills/KORTIX-docx/scripts/templates/commentsIds.xml +3 -0
  76. package/opencode/skills/KORTIX-docx/scripts/templates/people.xml +3 -0
  77. package/opencode/skills/KORTIX-domain-research/SKILL.md +96 -0
  78. package/opencode/skills/KORTIX-domain-research/scripts/domain-lookup.py +810 -0
  79. package/opencode/skills/KORTIX-elevenlabs/SKILL.md +230 -0
  80. package/opencode/skills/KORTIX-elevenlabs/scripts/tts.py +389 -0
  81. package/opencode/skills/KORTIX-email/SKILL.md +145 -0
  82. package/opencode/skills/KORTIX-legal-writer/SKILL.md +409 -0
  83. package/opencode/skills/KORTIX-legal-writer/references/bluebook.md +152 -0
  84. package/opencode/skills/KORTIX-legal-writer/references/document-types.md +416 -0
  85. package/opencode/skills/KORTIX-legal-writer/scripts/courtlistener.py +291 -0
  86. package/opencode/skills/KORTIX-legal-writer/scripts/ecfr_lookup.py +299 -0
  87. package/opencode/skills/KORTIX-legal-writer/scripts/verify-legal.py +507 -0
  88. package/opencode/skills/KORTIX-logo-creator/SKILL.md +293 -0
  89. package/opencode/skills/KORTIX-logo-creator/references/prompt-patterns.md +134 -0
  90. package/opencode/skills/KORTIX-logo-creator/scripts/compose_logo.py +406 -0
  91. package/opencode/skills/KORTIX-logo-creator/scripts/create_logo_sheet.py +258 -0
  92. package/opencode/skills/KORTIX-logo-creator/scripts/remove_bg.py +96 -0
  93. package/opencode/skills/KORTIX-memory/SKILL.md +261 -0
  94. package/opencode/skills/KORTIX-memory/scripts/export-sessions.py +409 -0
  95. package/opencode/skills/KORTIX-paper-creator/SKILL.md +549 -0
  96. package/opencode/skills/KORTIX-paper-creator/assets/template.tex +101 -0
  97. package/opencode/skills/KORTIX-paper-creator/scripts/compile.sh +177 -0
  98. package/opencode/skills/KORTIX-paper-creator/scripts/openalex_to_bibtex.py +220 -0
  99. package/opencode/skills/KORTIX-paper-creator/scripts/verify.sh +354 -0
  100. package/opencode/skills/KORTIX-paper-search/SKILL.md +418 -0
  101. package/opencode/skills/KORTIX-pdf/SKILL.md +232 -0
  102. package/opencode/skills/KORTIX-pdf/forms.md +36 -0
  103. package/opencode/skills/KORTIX-pdf/reference.md +105 -0
  104. package/opencode/skills/KORTIX-pdf/scripts/check_bounding_boxes.py +65 -0
  105. package/opencode/skills/KORTIX-pdf/scripts/check_fillable_fields.py +11 -0
  106. package/opencode/skills/KORTIX-pdf/scripts/convert_pdf_to_images.py +33 -0
  107. package/opencode/skills/KORTIX-pdf/scripts/create_validation_image.py +37 -0
  108. package/opencode/skills/KORTIX-pdf/scripts/extract_form_field_info.py +122 -0
  109. package/opencode/skills/KORTIX-pdf/scripts/extract_form_structure.py +115 -0
  110. package/opencode/skills/KORTIX-pdf/scripts/fill_fillable_fields.py +98 -0
  111. package/opencode/skills/KORTIX-pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  112. package/opencode/skills/KORTIX-plan/SKILL.md +228 -0
  113. package/opencode/skills/KORTIX-presentation-viewer/SKILL.md +87 -0
  114. package/opencode/skills/KORTIX-presentation-viewer/serve.ts +136 -0
  115. package/opencode/skills/KORTIX-presentation-viewer/viewer.html +559 -0
  116. package/opencode/skills/KORTIX-presentations/SKILL.md +344 -0
  117. package/opencode/skills/KORTIX-remotion/SKILL.md +56 -0
  118. package/opencode/skills/KORTIX-remotion/rules/3d.md +86 -0
  119. package/opencode/skills/KORTIX-remotion/rules/animations.md +29 -0
  120. package/opencode/skills/KORTIX-remotion/rules/assets.md +78 -0
  121. package/opencode/skills/KORTIX-remotion/rules/audio-visualization.md +198 -0
  122. package/opencode/skills/KORTIX-remotion/rules/audio.md +169 -0
  123. package/opencode/skills/KORTIX-remotion/rules/calculate-metadata.md +104 -0
  124. package/opencode/skills/KORTIX-remotion/rules/can-decode.md +75 -0
  125. package/opencode/skills/KORTIX-remotion/rules/charts.md +120 -0
  126. package/opencode/skills/KORTIX-remotion/rules/compositions.md +141 -0
  127. package/opencode/skills/KORTIX-remotion/rules/display-captions.md +184 -0
  128. package/opencode/skills/KORTIX-remotion/rules/extract-frames.md +229 -0
  129. package/opencode/skills/KORTIX-remotion/rules/ffmpeg.md +38 -0
  130. package/opencode/skills/KORTIX-remotion/rules/fonts.md +152 -0
  131. package/opencode/skills/KORTIX-remotion/rules/get-audio-duration.md +58 -0
  132. package/opencode/skills/KORTIX-remotion/rules/get-video-dimensions.md +68 -0
  133. package/opencode/skills/KORTIX-remotion/rules/get-video-duration.md +58 -0
  134. package/opencode/skills/KORTIX-remotion/rules/gifs.md +141 -0
  135. package/opencode/skills/KORTIX-remotion/rules/images.md +130 -0
  136. package/opencode/skills/KORTIX-remotion/rules/import-srt-captions.md +69 -0
  137. package/opencode/skills/KORTIX-remotion/rules/light-leaks.md +73 -0
  138. package/opencode/skills/KORTIX-remotion/rules/lottie.md +68 -0
  139. package/opencode/skills/KORTIX-remotion/rules/maps.md +401 -0
  140. package/opencode/skills/KORTIX-remotion/rules/measuring-dom-nodes.md +35 -0
  141. package/opencode/skills/KORTIX-remotion/rules/measuring-text.md +143 -0
  142. package/opencode/skills/KORTIX-remotion/rules/parameters.md +98 -0
  143. package/opencode/skills/KORTIX-remotion/rules/sequencing.md +118 -0
  144. package/opencode/skills/KORTIX-remotion/rules/subtitles.md +36 -0
  145. package/opencode/skills/KORTIX-remotion/rules/tailwind.md +11 -0
  146. package/opencode/skills/KORTIX-remotion/rules/text-animations.md +20 -0
  147. package/opencode/skills/KORTIX-remotion/rules/timing.md +179 -0
  148. package/opencode/skills/KORTIX-remotion/rules/transcribe-captions.md +70 -0
  149. package/opencode/skills/KORTIX-remotion/rules/transitions.md +197 -0
  150. package/opencode/skills/KORTIX-remotion/rules/transparent-videos.md +106 -0
  151. package/opencode/skills/KORTIX-remotion/rules/trimming.md +53 -0
  152. package/opencode/skills/KORTIX-remotion/rules/videos.md +171 -0
  153. package/opencode/skills/KORTIX-secrets/SKILL.md +280 -0
  154. package/opencode/skills/KORTIX-semantic-search/SKILL.md +213 -0
  155. package/opencode/skills/KORTIX-session-search/SKILL.md +807 -0
  156. package/opencode/skills/KORTIX-session-search/Untitled +1 -0
  157. package/opencode/skills/KORTIX-skill-creator/SKILL.md +163 -0
  158. package/opencode/skills/KORTIX-web-research/SKILL.md +69 -0
  159. package/opencode/skills/KORTIX-xlsx/LICENSE.txt +30 -0
  160. package/opencode/skills/KORTIX-xlsx/SKILL.md +549 -0
  161. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/__init__.py +0 -0
  162. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/merge_runs.py +199 -0
  163. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  164. package/opencode/skills/KORTIX-xlsx/scripts/office/pack.py +159 -0
  165. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  166. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  167. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  168. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  169. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  170. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  171. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  172. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  173. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  174. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  175. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  176. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  177. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  178. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  179. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  180. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  181. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  182. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  183. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  184. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  185. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  186. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  187. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  188. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  189. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  190. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  191. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  192. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  193. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  194. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  195. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  196. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  197. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  198. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  199. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  200. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  201. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  202. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  203. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  204. package/opencode/skills/KORTIX-xlsx/scripts/office/soffice.py +183 -0
  205. package/opencode/skills/KORTIX-xlsx/scripts/office/unpack.py +132 -0
  206. package/opencode/skills/KORTIX-xlsx/scripts/office/validate.py +111 -0
  207. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/__init__.py +15 -0
  208. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/base.py +847 -0
  209. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/docx.py +446 -0
  210. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/pptx.py +275 -0
  211. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/redlining.py +247 -0
  212. package/opencode/skills/KORTIX-xlsx/scripts/recalc.py +184 -0
  213. package/opencode/tools/image-gen.ts +342 -0
  214. package/opencode/tools/image-search.ts +190 -0
  215. package/opencode/tools/memory-get.ts +168 -0
  216. package/opencode/tools/memory-search.ts +247 -0
  217. package/opencode/tools/presentation-gen.ts +723 -0
  218. package/opencode/tools/scrape-webpage.ts +115 -0
  219. package/opencode/tools/scripts/.python-version +1 -0
  220. package/opencode/tools/scripts/convert_pdf.py +184 -0
  221. package/opencode/tools/scripts/convert_pptx.py +562 -0
  222. package/opencode/tools/scripts/pyproject.toml +11 -0
  223. package/opencode/tools/scripts/uv.lock +287 -0
  224. package/opencode/tools/scripts/validate_slide.py +74 -0
  225. package/opencode/tools/show-user.ts +217 -0
  226. package/opencode/tools/tests/e2e-presentation-fix.ts +277 -0
  227. package/opencode/tools/tests/image-gen.test.ts +215 -0
  228. package/opencode/tools/tests/image-search.test.ts +125 -0
  229. package/opencode/tools/tests/memory-system-benchmark.ts +1076 -0
  230. package/opencode/tools/tests/presentation-gen.test.ts +389 -0
  231. package/opencode/tools/tests/scrape-webpage.test.ts +74 -0
  232. package/opencode/tools/tests/show-user.test.ts +241 -0
  233. package/opencode/tools/tests/video-gen.test.ts +110 -0
  234. package/opencode/tools/tests/web-search.test.ts +106 -0
  235. package/opencode/tools/video-gen.ts +200 -0
  236. package/opencode/tools/web-search.ts +153 -0
  237. package/opencode/tsconfig.json +29 -0
  238. package/package.json +36 -0
  239. package/patch-agent-browser.js +100 -0
  240. package/postinstall.sh +88 -0
  241. package/services/KORTIX-presentation-viewer/run +37 -0
  242. package/services/agent-browser-viewer/run +48 -0
  243. package/services/kortix-master/run +16 -0
  244. package/services/lss-sync/run +22 -0
  245. package/services/opencode-serve/run +25 -0
  246. package/services/opencode-web/run +21 -0
@@ -0,0 +1,549 @@
1
+ ---
2
+ name: kortix-xlsx
3
+ description: "Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like 'the xlsx in my downloads') — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved."
4
+ ---
5
+
6
+ # Kortix XLSX — Spreadsheet Skill
7
+
8
+ You are loading the spreadsheet skill. Follow these instructions for ALL spreadsheet work.
9
+
10
+ ---
11
+
12
+ ## Autonomy Doctrine
13
+
14
+ **Act, don't ask.** Receive the task, build the spreadsheet, verify it, deliver it. No permission requests. No presenting options. Pick the best approach and execute.
15
+
16
+ - Write the Python script, run it, verify the output, clean up.
17
+ - If it fails, debug and retry. Only surface blockers after exhausting options.
18
+ - Every spreadsheet gets professional formatting by default — headers, borders, number formats, frozen panes, auto-width columns.
19
+ - Verify your own work: read the file back, check structure, run `recalc.py`, confirm zero errors.
20
+
21
+ ---
22
+
23
+ ## Communication Rules
24
+
25
+ **The user is non-technical. NEVER expose implementation details.**
26
+
27
+ **DO say:**
28
+ - "I'll create that spreadsheet for you"
29
+ - "Here's your budget spreadsheet with the calculations"
30
+ - "I've organized the data and the totals calculate automatically"
31
+ - "I've added a new sheet for Q2 data"
32
+
33
+ **NEVER say:**
34
+ - "I'll use openpyxl to create an .xlsx file"
35
+ - "I'm executing a Python script"
36
+ - "I'll load_workbook and update cells"
37
+ - "I'll use PatternFill and Font classes"
38
+ - "Running recalc.py to evaluate formulas"
39
+
40
+ **Tone:** Friendly, conversational. Describe WHAT the spreadsheet does, not HOW you built it. Make it feel effortless.
41
+
42
+ ---
43
+
44
+ # Requirements for Outputs
45
+
46
+ ## All Excel Files
47
+
48
+ ### Professional Font
49
+ - Use a consistent, professional font (e.g., Arial, Calibri) for all deliverables unless otherwise instructed
50
+
51
+ ### Zero Formula Errors
52
+ - Every Excel file MUST be delivered with ZERO formula errors (#REF!, #DIV/0!, #VALUE!, #N/A, #NAME?)
53
+ - Run `scripts/recalc.py` on every file that contains formulas before delivering
54
+ - If errors are found, fix them and recalculate until clean
55
+
56
+ ### Preserve Existing Templates (when updating)
57
+ - Study and EXACTLY match existing format, style, and conventions when modifying files
58
+ - Never impose standardized formatting on files with established patterns
59
+ - Existing template conventions ALWAYS override these guidelines
60
+
61
+ ### Professional Styling (new files)
62
+ - Styled headers (dark fill, white bold text)
63
+ - Borders on all data cells
64
+ - Number formatting (currency, percentages, dates)
65
+ - Frozen header row (`ws.freeze_panes = "A2"`)
66
+ - Auto-fit column widths
67
+ - Alternating row fills for large datasets
68
+
69
+ ## Financial Models
70
+
71
+ ### Color Coding Standards
72
+ Unless otherwise stated by the user or existing template:
73
+
74
+ | Color | RGB | Use |
75
+ |---|---|---|
76
+ | Blue text | 0,0,255 | Hardcoded inputs, scenario-changeable numbers |
77
+ | Black text | 0,0,0 | ALL formulas and calculations |
78
+ | Green text | 0,128,0 | Links pulling from other worksheets |
79
+ | Red text | 255,0,0 | External links to other files |
80
+ | Yellow background | 255,255,0 | Key assumptions needing attention |
81
+
82
+ ### Number Formatting Standards
83
+
84
+ | Type | Format | Example |
85
+ |---|---|---|
86
+ | Years | Text string | "2024" not "2,024" |
87
+ | Currency | `$#,##0` | Specify units in headers: "Revenue ($mm)" |
88
+ | Zeros | Dash format | `$#,##0;($#,##0);-` |
89
+ | Percentages | `0.0%` | One decimal default |
90
+ | Multiples | `0.0x` | EV/EBITDA, P/E ratios |
91
+ | Negative numbers | Parentheses | (123) not -123 |
92
+
93
+ ### Formula Construction Rules
94
+
95
+ **Assumptions Placement:**
96
+ - Place ALL assumptions (growth rates, margins, multiples) in separate assumption cells
97
+ - Use cell references, not hardcoded values: `=B5*(1+$B$6)` not `=B5*1.05`
98
+
99
+ **Formula Error Prevention:**
100
+ - Verify all cell references are correct
101
+ - Check for off-by-one errors in ranges
102
+ - Ensure consistent formulas across all projection periods
103
+ - Test with edge cases (zero values, negative numbers)
104
+ - Verify no circular references
105
+
106
+ **Documentation Requirements for Hardcodes:**
107
+ - Add cell comments with source info: `"Source: [System/Document], [Date], [Reference], [URL]"`
108
+ - Examples:
109
+ - "Source: Company 10-K, FY2024, Page 45, Revenue Note"
110
+ - "Source: Bloomberg Terminal, 8/15/2025, AAPL US Equity"
111
+
112
+ ---
113
+
114
+ # XLSX Creation, Editing, and Analysis
115
+
116
+ ## CRITICAL: Use Formulas, Not Hardcoded Values
117
+
118
+ **Always use Excel formulas instead of calculating values in Python and hardcoding them.** The spreadsheet must remain dynamic and updateable.
119
+
120
+ ```python
121
+ # WRONG — hardcoding calculated values
122
+ total = df['Sales'].sum()
123
+ sheet['B10'] = total # Hardcodes 5000
124
+
125
+ # CORRECT — Excel formulas
126
+ sheet['B10'] = '=SUM(B2:B9)'
127
+ sheet['C5'] = '=(C4-C2)/C2'
128
+ sheet['D20'] = '=AVERAGE(D2:D19)'
129
+ ```
130
+
131
+ This applies to ALL calculations — totals, percentages, ratios, differences. The spreadsheet should recalculate when source data changes.
132
+
133
+ ## Execution Workflow
134
+
135
+ 1. **Choose tool**: pandas for data analysis/bulk ops, openpyxl for formulas/formatting
136
+ 2. **Create/Load**: New workbook or load existing
137
+ 3. **Modify**: Add data, formulas, formatting
138
+ 4. **Save**: Write to file
139
+ 5. **Recalculate (MANDATORY for formulas)**: `python scripts/recalc.py output.xlsx`
140
+ 6. **Verify**: Check recalc output JSON — if `errors_found`, fix and recalculate again
141
+ 7. **Clean up**: Remove temp Python scripts
142
+ 8. **Report**: Describe result in user-friendly language with file path
143
+
144
+ ### Script Path Resolution
145
+
146
+ The `scripts/` directory lives alongside this SKILL.md file. When running recalc:
147
+ ```bash
148
+ python <skill_dir>/scripts/recalc.py output.xlsx
149
+ ```
150
+
151
+ Where `<skill_dir>` is the directory containing this SKILL.md (e.g., `skills/KORTIX-xlsx/` or `.opencode/skills/kortix-xlsx/`).
152
+
153
+ ---
154
+
155
+ ## Reading and Analyzing Data
156
+
157
+ ### pandas (data analysis)
158
+ ```python
159
+ import pandas as pd
160
+
161
+ df = pd.read_excel('file.xlsx') # First sheet
162
+ all_sheets = pd.read_excel('file.xlsx', sheet_name=None) # All sheets as dict
163
+
164
+ df.head() # Preview
165
+ df.info() # Column types
166
+ df.describe() # Statistics
167
+
168
+ df.to_excel('output.xlsx', index=False)
169
+ ```
170
+
171
+ ### openpyxl (read with formulas preserved)
172
+ ```python
173
+ from openpyxl import load_workbook
174
+
175
+ wb = load_workbook('file.xlsx') # Preserves formulas
176
+ wb_values = load_workbook('file.xlsx', data_only=True) # Reads calculated values (WARNING: saving loses formulas)
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Creating New Excel Files
182
+
183
+ ```python
184
+ from openpyxl import Workbook
185
+ from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
186
+ from openpyxl.utils import get_column_letter
187
+
188
+ wb = Workbook()
189
+ ws = wb.active
190
+ ws.title = "Sheet Name"
191
+
192
+ # Headers
193
+ headers = ["Product", "Revenue", "Cost", "Profit", "Margin %"]
194
+ header_fill = PatternFill('solid', start_color='1F4E79')
195
+ header_font = Font(bold=True, color='FFFFFF', name='Calibri', size=11)
196
+ header_align = Alignment(horizontal='center', vertical='center')
197
+
198
+ for col, header in enumerate(headers, 1):
199
+ cell = ws.cell(row=1, column=col, value=header)
200
+ cell.fill = header_fill
201
+ cell.font = header_font
202
+ cell.alignment = header_align
203
+
204
+ # Data with formulas
205
+ data = [
206
+ ["Product A", 50000, 35000, "=B2-C2", "=IFERROR(D2/B2*100,0)"],
207
+ ["Product B", 75000, 45000, "=B3-C3", "=IFERROR(D3/B3*100,0)"],
208
+ ]
209
+
210
+ for row_idx, row_data in enumerate(data, 2):
211
+ for col_idx, value in enumerate(row_data, 1):
212
+ ws.cell(row=row_idx, column=col_idx, value=value)
213
+
214
+ # Summary row (dynamic — never hardcode row numbers)
215
+ summary_row = len(data) + 2
216
+ last_data_row = summary_row - 1
217
+ ws.cell(row=summary_row, column=1, value="Total").font = Font(bold=True)
218
+ ws.cell(row=summary_row, column=2, value=f"=SUM(B2:B{last_data_row})")
219
+ ws.cell(row=summary_row, column=3, value=f"=SUM(C2:C{last_data_row})")
220
+ ws.cell(row=summary_row, column=4, value=f"=SUM(D2:D{last_data_row})")
221
+ ws.cell(row=summary_row, column=5, value=f"=IFERROR(D{summary_row}/B{summary_row}*100,0)")
222
+
223
+ # Borders
224
+ thin_border = Border(
225
+ left=Side(style='thin'), right=Side(style='thin'),
226
+ top=Side(style='thin'), bottom=Side(style='thin')
227
+ )
228
+ for row in ws.iter_rows(min_row=1, max_row=summary_row, max_col=len(headers)):
229
+ for cell in row:
230
+ cell.border = thin_border
231
+
232
+ # Number formatting
233
+ for row in range(2, summary_row + 1):
234
+ for col in [2, 3, 4]:
235
+ ws.cell(row=row, column=col).number_format = '#,##0'
236
+ ws.cell(row=row, column=5).number_format = '0.0'
237
+
238
+ # Auto-width columns
239
+ for col in range(1, len(headers) + 1):
240
+ max_len = max(len(str(ws.cell(row=r, column=col).value or "")) for r in range(1, summary_row + 1))
241
+ ws.column_dimensions[get_column_letter(col)].width = min(max_len + 4, 50)
242
+
243
+ # Freeze header row
244
+ ws.freeze_panes = "A2"
245
+
246
+ wb.save('output.xlsx')
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Editing Existing Files
252
+
253
+ ```python
254
+ from openpyxl import load_workbook
255
+
256
+ wb = load_workbook('existing.xlsx')
257
+ ws = wb.active # or wb['SheetName']
258
+
259
+ # Modify cells
260
+ ws['A1'] = 'New Value'
261
+ ws.insert_rows(2)
262
+ ws.delete_cols(3)
263
+
264
+ # Add new sheet (preserves existing sheets)
265
+ new_sheet = wb.create_sheet('NewSheet')
266
+ new_sheet['A1'] = 'Data'
267
+
268
+ wb.save('modified.xlsx')
269
+ ```
270
+
271
+ Use `wb.create_sheet()` to add sheets — NEVER recreate the workbook.
272
+
273
+ ---
274
+
275
+ ## Cross-Sheet References
276
+
277
+ ```python
278
+ ws = wb.create_sheet(title="Summary")
279
+
280
+ data = [
281
+ ["Q1 Total Revenue", "=SUM('Q1 Sales'!B2:B100)"],
282
+ ["Q2 Total Revenue", "=SUM('Q2 Sales'!B2:B100)"],
283
+ ["Combined Total", "=B2+B3"],
284
+ ]
285
+ ```
286
+
287
+ ---
288
+
289
+ ## CSV Import and Transform
290
+
291
+ ```python
292
+ import csv
293
+ from openpyxl import Workbook
294
+ from openpyxl.styles import Font, PatternFill
295
+
296
+ with open('input.csv', 'r') as f:
297
+ rows = list(csv.reader(f))
298
+
299
+ wb = Workbook()
300
+ ws = wb.active
301
+ ws.title = "Imported Data"
302
+
303
+ header_fill = PatternFill('solid', start_color='1F4E79')
304
+ header_font = Font(bold=True, color='FFFFFF')
305
+
306
+ for row_idx, row_data in enumerate(rows, 1):
307
+ for col_idx, value in enumerate(row_data, 1):
308
+ cell = ws.cell(row=row_idx, column=col_idx, value=value)
309
+ if row_idx == 1:
310
+ cell.fill = header_fill
311
+ cell.font = header_font
312
+
313
+ ws.freeze_panes = "A2"
314
+ wb.save('output.xlsx')
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Pandas + openpyxl (Analysis to Formatted Output)
320
+
321
+ ```python
322
+ import pandas as pd
323
+ from openpyxl import Workbook
324
+ from openpyxl.styles import Font, PatternFill
325
+ from openpyxl.utils.dataframe import dataframe_to_rows
326
+
327
+ df = pd.read_csv('data.csv')
328
+ summary = df.groupby('category').agg(
329
+ total_revenue=('revenue', 'sum'),
330
+ avg_price=('price', 'mean'),
331
+ count=('id', 'count')
332
+ ).reset_index()
333
+
334
+ wb = Workbook()
335
+ ws = wb.active
336
+ ws.title = "Analysis"
337
+
338
+ for r_idx, row in enumerate(dataframe_to_rows(summary, index=False, header=True), 1):
339
+ for c_idx, value in enumerate(row, 1):
340
+ ws.cell(row=r_idx, column=c_idx, value=value)
341
+
342
+ header_fill = PatternFill('solid', start_color='1F4E79')
343
+ header_font = Font(bold=True, color='FFFFFF')
344
+ for cell in ws[1]:
345
+ cell.fill = header_fill
346
+ cell.font = header_font
347
+
348
+ ws.freeze_panes = "A2"
349
+ wb.save('analysis.xlsx')
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Recalculating Formulas
355
+
356
+ openpyxl writes formulas as strings but does NOT evaluate them. Use LibreOffice via the bundled `recalc.py`:
357
+
358
+ ```bash
359
+ python scripts/recalc.py <excel_file> [timeout_seconds]
360
+ ```
361
+
362
+ The script:
363
+ - Sets up a LibreOffice macro on first run
364
+ - Recalculates ALL formulas in ALL sheets
365
+ - Scans every cell for Excel errors (#REF!, #DIV/0!, #VALUE!, #NAME?, #NULL!, #NUM!, #N/A)
366
+ - Returns JSON with error locations and counts
367
+ - Works on Linux and macOS (handles sandboxed environments via `soffice.py` shim)
368
+
369
+ ### Interpreting Output
370
+
371
+ ```json
372
+ {
373
+ "status": "success",
374
+ "total_errors": 0,
375
+ "total_formulas": 42,
376
+ "error_summary": {}
377
+ }
378
+ ```
379
+
380
+ If `status` is `errors_found`:
381
+ 1. Check `error_summary` for error types and cell locations
382
+ 2. Fix the formulas in Python
383
+ 3. Save and recalculate again
384
+ 4. Repeat until `total_errors: 0`
385
+
386
+ ---
387
+
388
+ ## Formula Safety Rules
389
+
390
+ ### Preventing Circular References
391
+
392
+ Headers = ROW 1. Data starts ROW 2. Summary/total row = LAST row.
393
+
394
+ **CORRECT** — total row references only data rows above it:
395
+ ```python
396
+ # 3 data rows (rows 2-4), total in row 5
397
+ summary_row = len(data) + 2
398
+ last_data_row = summary_row - 1
399
+ ws.cell(row=summary_row, column=2, value=f"=SUM(B2:B{last_data_row})")
400
+ ```
401
+
402
+ **WRONG** — total row includes itself:
403
+ ```python
404
+ # BAD: row 5 formula references B2:B5 which includes itself
405
+ ["Total", "=SUM(B2:B5)", "=SUM(C2:C5)"]
406
+ ```
407
+
408
+ ### Preventing #DIV/0! Errors
409
+
410
+ ALWAYS wrap division with IFERROR:
411
+ ```python
412
+ "=IFERROR(C2/B2*100,0)" # Returns 0 if division fails
413
+ "=IFERROR(A1/B1,\"N/A\")" # Returns "N/A" if division fails
414
+ ```
415
+
416
+ ---
417
+
418
+ ## Formula Verification Checklist
419
+
420
+ ### Essential
421
+ - [ ] Test 2-3 sample references before building full model
422
+ - [ ] Column mapping correct (column 64 = BL, not BK)
423
+ - [ ] Row offset correct (Excel is 1-indexed; DataFrame row 5 = Excel row 6)
424
+
425
+ ### Common Pitfalls
426
+ - [ ] NaN handling: use `pd.notna()` before writing
427
+ - [ ] Division by zero: wrap all division in IFERROR
428
+ - [ ] Wrong references: verify cell refs point to intended cells
429
+ - [ ] Cross-sheet refs: use `'Sheet Name'!A1` format (quotes around names with spaces)
430
+ - [ ] Off-by-one: summary row formulas end at `last_data_row`, not `summary_row`
431
+
432
+ ### Testing Strategy
433
+ - [ ] Start small: test on 2-3 cells before applying broadly
434
+ - [ ] Verify all referenced cells exist
435
+ - [ ] Test edge cases: zero, negative, very large values
436
+ - [ ] Run `recalc.py` and confirm `total_errors: 0`
437
+
438
+ ---
439
+
440
+ ## Formatting Reference
441
+
442
+ ### Standard Style Objects
443
+
444
+ ```python
445
+ from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
446
+ from openpyxl.formatting.rule import CellIsRule
447
+
448
+ # Fills
449
+ header_fill = PatternFill('solid', start_color='1F4E79')
450
+ alt_row_fill = PatternFill('solid', start_color='F2F2F2')
451
+ green_fill = PatternFill('solid', start_color='E8F5E9')
452
+ red_fill = PatternFill('solid', start_color='FFEBEE')
453
+ yellow_fill = PatternFill('solid', start_color='FFFF00')
454
+
455
+ # Fonts
456
+ header_font = Font(bold=True, color='FFFFFF', name='Calibri', size=11)
457
+ title_font = Font(bold=True, name='Calibri', size=14)
458
+ input_font = Font(color='0000FF') # Blue — hardcoded inputs
459
+ formula_font = Font(color='000000') # Black — formulas
460
+ link_font = Font(color='008000') # Green — cross-sheet links
461
+
462
+ # Alignment
463
+ center = Alignment(horizontal='center', vertical='center')
464
+ wrap = Alignment(horizontal='left', vertical='top', wrap_text=True)
465
+
466
+ # Borders
467
+ thin_border = Border(
468
+ left=Side(style='thin'), right=Side(style='thin'),
469
+ top=Side(style='thin'), bottom=Side(style='thin')
470
+ )
471
+ thick_bottom = Border(bottom=Side(style='medium'))
472
+ ```
473
+
474
+ ### Alternating Row Colors
475
+ ```python
476
+ for row_idx in range(2, ws.max_row + 1):
477
+ if row_idx % 2 == 0:
478
+ for col_idx in range(1, ws.max_column + 1):
479
+ ws.cell(row=row_idx, column=col_idx).fill = alt_row_fill
480
+ ```
481
+
482
+ ### Conditional Formatting (positive/negative)
483
+ ```python
484
+ ws.conditional_formatting.add(
485
+ f'D2:D{ws.max_row}',
486
+ CellIsRule(operator='greaterThan', formula=['0'],
487
+ fill=PatternFill('solid', start_color='E8F5E9'))
488
+ )
489
+ ws.conditional_formatting.add(
490
+ f'D2:D{ws.max_row}',
491
+ CellIsRule(operator='lessThan', formula=['0'],
492
+ fill=PatternFill('solid', start_color='FFEBEE'))
493
+ )
494
+ ```
495
+
496
+ ### Auto-Fit Column Widths
497
+ ```python
498
+ from openpyxl.utils import get_column_letter
499
+
500
+ for col in range(1, ws.max_column + 1):
501
+ max_len = max(len(str(ws.cell(row=r, column=col).value or "")) for r in range(1, ws.max_row + 1))
502
+ ws.column_dimensions[get_column_letter(col)].width = min(max_len + 4, 50)
503
+ ```
504
+
505
+ ---
506
+
507
+ ## Best Practices
508
+
509
+ ### Library Selection
510
+ - **pandas**: Data analysis, bulk operations, simple data export
511
+ - **openpyxl**: Formatting, formulas, Excel-specific features
512
+ - **Both**: pandas for analysis, openpyxl for final formatted output
513
+
514
+ ### openpyxl
515
+ - Cell indices are 1-based (row=1, column=1 = A1)
516
+ - `data_only=True` reads calculated values — WARNING: saving LOSES formulas permanently
517
+ - `read_only=True` / `write_only=True` for large files
518
+ - Formulas are strings, not evaluated — always run `recalc.py`
519
+
520
+ ### pandas
521
+ - Specify dtypes: `pd.read_excel('f.xlsx', dtype={'id': str})`
522
+ - Read specific columns: `usecols=['A', 'C', 'E']`
523
+ - Handle dates: `parse_dates=['date_column']`
524
+
525
+ ### Code Style
526
+ - Minimal, concise Python — no unnecessary comments or verbose variable names
527
+ - No unnecessary print statements
528
+ - Add cell comments for complex formulas and assumptions
529
+ - Document data sources for all hardcoded values
530
+
531
+ ---
532
+
533
+ ## Common Formulas Quick Reference
534
+
535
+ | Formula | Example | Use |
536
+ |---|---|---|
537
+ | SUM | `=SUM(B2:B10)` | Total a range |
538
+ | AVERAGE | `=AVERAGE(B2:B10)` | Mean |
539
+ | COUNT | `=COUNT(A1:A100)` | Count numbers |
540
+ | COUNTA | `=COUNTA(A1:A100)` | Count non-empty |
541
+ | IF | `=IF(A1>100,"High","Low")` | Conditional |
542
+ | VLOOKUP | `=VLOOKUP(A1,Sheet2!A:B,2,FALSE)` | Cross-sheet lookup |
543
+ | SUMIF | `=SUMIF(A:A,"Product A",B:B)` | Conditional sum |
544
+ | COUNTIF | `=COUNTIF(A:A,"Product A")` | Conditional count |
545
+ | IFERROR | `=IFERROR(C2/B2*100,0)` | Safe division |
546
+ | Cross-sheet | `=SUM('Sheet Name'!B2:B10)` | Reference another sheet |
547
+ | INDEX/MATCH | `=INDEX(B:B,MATCH(D1,A:A,0))` | Flexible lookup |
548
+ | MIN/MAX | `=MIN(B2:B10)` | Range extremes |
549
+ | CONCATENATE | `=A1&" "&B1` | Join text |